Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_runtime_context_fd_exec_txn_ctx_h 2 : #define HEADER_fd_src_flamenco_runtime_context_fd_exec_txn_ctx_h 3 : 4 : #include "fd_exec_instr_ctx.h" 5 : #include "../../../util/fd_util_base.h" 6 : #include "../../log_collector/fd_log_collector_base.h" 7 : 8 : #include "../fd_borrowed_account.h" 9 : 10 : #include "../../../ballet/txn/fd_txn.h" 11 : 12 : /* Return data for syscalls */ 13 : 14 : struct fd_txn_return_data { 15 : fd_pubkey_t program_id; 16 : ulong len; 17 : uchar data[1024]; 18 : }; 19 : 20 : typedef struct fd_txn_return_data fd_txn_return_data_t; 21 : 22 : /* fd_exec_txn_ctx_t is the context needed to execute a transaction. */ 23 : 24 : /* Cache of deserialized vote accounts to support iteration after replaying a slot (required for fork choice) */ 25 : struct fd_vote_account_cache_entry { 26 : fd_pubkey_t pubkey; 27 : ulong next; 28 : fd_vote_state_t vote_account; 29 : }; 30 : typedef struct fd_vote_account_cache_entry fd_vote_account_cache_entry_t; 31 : 32 : #define POOL_NAME fd_vote_account_pool 33 : #define POOL_T fd_vote_account_cache_entry_t 34 : #include "../../../util/tmpl/fd_pool.c" 35 : 36 : #define MAP_NAME fd_vote_account_cache 37 : #define MAP_ELE_T fd_vote_account_cache_entry_t 38 : #define MAP_KEY pubkey 39 : #define MAP_KEY_T fd_pubkey_t 40 : #define MAP_KEY_EQ(k0,k1) (!(memcmp((k0)->key,(k1)->key,sizeof(fd_hash_t)))) 41 : #define MAP_KEY_HASH(key,seed) ( ((key)->ui[0]) ^ (seed) ) 42 : #include "../../../util/tmpl/fd_map_chain.c" 43 : 44 : /* An entry in the instruction trace */ 45 : struct fd_exec_instr_trace_entry { 46 : /* Metadata about the instruction */ 47 : fd_instr_info_t * instr_info; 48 : /* Stack height when this instruction was pushed onto the stack (including itself) 49 : https://github.com/anza-xyz/agave/blob/d87e23d8d91c32d5f2be2bb3557c730bee1e9434/sdk/src/transaction_context.rs#L475-L480 */ 50 : ulong stack_height; 51 : }; 52 : typedef struct fd_exec_instr_trace_entry fd_exec_instr_trace_entry_t; 53 : 54 : /* https://github.com/anza-xyz/agave/blob/0d34a1a160129c4293dac248e14231e9e773b4ce/program-runtime/src/compute_budget.rs#L139 */ 55 : #define FD_MAX_INSTRUCTION_TRACE_LENGTH (64UL) 56 : /* https://github.com/anza-xyz/agave/blob/f70ab5598ccd86b216c3928e4397bf4a5b58d723/compute-budget/src/compute_budget.rs#L13 */ 57 : #define FD_MAX_INSTRUCTION_STACK_DEPTH (5UL) 58 : 59 : struct __attribute__((aligned(8UL))) fd_exec_txn_ctx { 60 : ulong magic; /* ==FD_EXEC_TXN_CTX_MAGIC */ 61 : 62 : fd_exec_epoch_ctx_t const * epoch_ctx; 63 : fd_exec_slot_ctx_t const * slot_ctx; 64 : 65 : fd_funk_txn_t * funk_txn; 66 : fd_acc_mgr_t * acc_mgr; 67 : fd_valloc_t valloc; 68 : 69 : ulong paid_fees; 70 : ulong compute_unit_limit; /* Compute unit limit for this transaction. */ 71 : ulong compute_unit_price; /* Compute unit price for this transaction. */ 72 : ulong compute_meter; /* Remaining compute units */ 73 : ulong heap_size; /* Heap size for VMs for this transaction. */ 74 : ulong loaded_accounts_data_size_limit; /* Loaded accounts data size limit for this transaction. */ 75 : uint prioritization_fee_type; /* The type of prioritization fee to use. */ 76 : fd_txn_t const * txn_descriptor; /* Descriptor of the transaction. */ 77 : fd_rawtxn_b_t _txn_raw[1]; /* Raw bytes of the transaction. */ 78 : uint custom_err; /* When a custom error is returned, this is where the numeric value gets stashed */ 79 : uchar instr_stack_sz; /* Current depth of the instruction execution stack. */ 80 : fd_exec_instr_ctx_t instr_stack[FD_MAX_INSTRUCTION_STACK_DEPTH]; /* Instruction execution stack. */ 81 : fd_exec_instr_ctx_t * failed_instr; 82 : int instr_err_idx; 83 : /* During sanitization, v0 transactions are allowed to have up to 256 accounts: 84 : https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/sdk/program/src/message/versions/v0/mod.rs#L139 85 : Nonetheless, when Agave prepares a sanitized batch for execution and tries to lock accounts, a lower limit is enforced: 86 : https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/accounts-db/src/account_locks.rs#L118 87 : That is the limit we are going to use here. */ 88 : ulong accounts_cnt; /* Number of account pubkeys accessed by this transaction. */ 89 : fd_pubkey_t accounts[ MAX_TX_ACCOUNT_LOCKS ]; /* Array of account pubkeys accessed by this transaction. */ 90 : ulong executable_cnt; /* Number of BPF upgradeable loader accounts. */ 91 : fd_borrowed_account_t executable_accounts[ MAX_TX_ACCOUNT_LOCKS ]; /* Array of BPF upgradeable loader program data accounts */ 92 : fd_borrowed_account_t borrowed_accounts[ MAX_TX_ACCOUNT_LOCKS ]; /* Array of borrowed accounts accessed by this transaction. */ 93 : uchar nonce_accounts[ MAX_TX_ACCOUNT_LOCKS ]; /* Nonce accounts in the txn to be saved */ 94 : uint num_instructions; /* Counter for number of instructions in txn */ 95 : fd_txn_return_data_t return_data; /* Data returned from `return_data` syscalls */ 96 : fd_vote_account_cache_t * vote_accounts_map; /* Cache of bank's deserialized vote accounts to support fork choice */ 97 : fd_vote_account_cache_entry_t * vote_accounts_pool; /* Memory pool for deserialized vote account cache */ 98 : ulong accounts_resize_delta; /* Transaction level tracking for account resizing */ 99 : fd_hash_t blake_txn_msg_hash; /* Hash of raw transaction message used by the status cache */ 100 : ulong execution_fee; /* Execution fee paid by the fee payer in the transaction */ 101 : ulong priority_fee; /* Priority fee paid by the fee payer in the transaction */ 102 : ulong collected_rent; /* Rent collected from accounts in this transaction */ 103 : 104 : uchar dirty_vote_acc : 1; /* 1 if this transaction maybe modified a vote account */ 105 : uchar dirty_stake_acc : 1; /* 1 if this transaction maybe modified a stake account */ 106 : 107 : fd_capture_ctx_t * capture_ctx; 108 : 109 : /* The instr_infos for the entire transaction are allocated at the start of 110 : the transaction. However, this must preserve a different counter because 111 : the top level instructions must get set up at once. The instruction 112 : error check on a maximum instruction size can be done on the 113 : instr_info_cnt instead of the instr_trace_length because it is a proxy 114 : for the trace_length: the instr_info_cnt gets incremented faster than 115 : the instr_trace_length because it counts all of the top level instructions 116 : first. */ 117 : fd_instr_info_t instr_infos[FD_MAX_INSTRUCTION_TRACE_LENGTH]; 118 : ulong instr_info_cnt; 119 : 120 : fd_exec_instr_trace_entry_t instr_trace[FD_MAX_INSTRUCTION_TRACE_LENGTH]; /* Instruction trace */ 121 : ulong instr_trace_length; /* Number of instructions in the trace */ 122 : 123 : fd_log_collector_t log_collector; /* Log collector instance */ 124 : 125 : /* Execution error and type, to match Agave. */ 126 : int exec_err; 127 : int exec_err_kind; 128 : 129 : fd_spad_t * spad; 130 : }; 131 : 132 113193 : #define FD_EXEC_TXN_CTX_ALIGN (alignof(fd_exec_txn_ctx_t)) 133 113193 : #define FD_EXEC_TXN_CTX_FOOTPRINT ( sizeof(fd_exec_txn_ctx_t)) 134 108786 : #define FD_EXEC_TXN_CTX_MAGIC (0x9AD93EE71469F4D7UL ) /* random */ 135 : 136 : FD_PROTOTYPES_BEGIN 137 : 138 83610 : #define FD_TXN_ERR_FOR_LOG_INSTR( txn_ctx, err, idx ) (__extension__({ \ 139 83610 : txn_ctx->exec_err = err; \ 140 83610 : txn_ctx->exec_err_kind = FD_EXECUTOR_ERR_KIND_INSTR; \ 141 83610 : txn_ctx->instr_err_idx = idx; \ 142 83610 : })) 143 : 144 : void * 145 : fd_exec_txn_ctx_new( void * mem ); 146 : 147 : fd_exec_txn_ctx_t * 148 : fd_exec_txn_ctx_join( void * mem ); 149 : 150 : void * 151 : fd_exec_txn_ctx_leave( fd_exec_txn_ctx_t * ctx ); 152 : 153 : void * 154 : fd_exec_txn_ctx_delete( void * mem ); 155 : 156 : void 157 : fd_exec_txn_ctx_setup( fd_exec_txn_ctx_t * txn_ctx, 158 : fd_txn_t const * txn_descriptor, 159 : fd_rawtxn_b_t const * txn_raw ); 160 : void 161 : fd_exec_txn_ctx_from_exec_slot_ctx( fd_exec_slot_ctx_t * slot_ctx, 162 : fd_exec_txn_ctx_t * txn_ctx ); 163 : 164 : void 165 : fd_exec_txn_ctx_teardown( fd_exec_txn_ctx_t * txn_ctx ); 166 : 167 : int 168 : fd_txn_borrowed_account_view_idx( fd_exec_txn_ctx_t * ctx, 169 : uchar idx, 170 : fd_borrowed_account_t * * account ); 171 : 172 : /* Same as above, except that this function doesn't check if the account 173 : is dead (0 balance, 0 data, etc.) or not. When agave obtains a 174 : borrowed account, it doesn't always check if the account is dead or 175 : not. For example 176 : https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/program-runtime/src/invoke_context.rs#L453 177 : This function allows us to more closely emulate that behavior. */ 178 : int 179 : fd_txn_borrowed_account_view_idx_allow_dead( fd_exec_txn_ctx_t * ctx, 180 : uchar idx, 181 : fd_borrowed_account_t * * account ); 182 : 183 : int 184 : fd_txn_borrowed_account_view( fd_exec_txn_ctx_t * ctx, 185 : fd_pubkey_t const * pubkey, 186 : fd_borrowed_account_t * * account ); 187 : 188 : int 189 : fd_txn_borrowed_account_executable_view( fd_exec_txn_ctx_t * ctx, 190 : fd_pubkey_t const * pubkey, 191 : fd_borrowed_account_t * * account ); 192 : 193 : int 194 : fd_txn_borrowed_account_modify_idx( fd_exec_txn_ctx_t * ctx, 195 : uchar idx, 196 : ulong min_data_sz, 197 : fd_borrowed_account_t * * account ); 198 : int 199 : fd_txn_borrowed_account_modify( fd_exec_txn_ctx_t * ctx, 200 : fd_pubkey_t const * pubkey, 201 : ulong min_data_sz, 202 : fd_borrowed_account_t * * account ); 203 : void 204 : fd_exec_txn_ctx_reset_return_data( fd_exec_txn_ctx_t * txn_ctx ); 205 : 206 : FD_PROTOTYPES_END 207 : 208 : #endif /* HEADER_fd_src_flamenco_runtime_context_fd_exec_txn_ctx_h */