Line data Source code
1 : #include "fd_exec_txn_ctx.h" 2 : #include "fd_exec_slot_ctx.h" 3 : #include "../fd_acc_mgr.h" 4 : #include "../fd_executor.h" 5 : #include "../../vm/fd_vm.h" 6 : #include "../fd_account.h" 7 : 8 : void * 9 407859 : fd_exec_txn_ctx_new( void * mem ) { 10 407859 : if( FD_UNLIKELY( !mem ) ) { 11 0 : FD_LOG_WARNING(( "NULL mem" )); 12 0 : return NULL; 13 0 : } 14 : 15 407859 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_TXN_CTX_ALIGN ) ) ) { 16 0 : FD_LOG_WARNING(( "misaligned mem" )); 17 0 : return NULL; 18 0 : } 19 : 20 407859 : fd_exec_txn_ctx_t * self = (fd_exec_txn_ctx_t *) mem; 21 : 22 407859 : FD_COMPILER_MFENCE(); 23 407859 : self->magic = FD_EXEC_TXN_CTX_MAGIC; 24 407859 : FD_COMPILER_MFENCE(); 25 : 26 407859 : return mem; 27 407859 : } 28 : 29 : fd_exec_txn_ctx_t * 30 395118 : fd_exec_txn_ctx_join( void * mem ) { 31 395118 : if( FD_UNLIKELY( !mem ) ) { 32 0 : FD_LOG_WARNING(( "NULL block" )); 33 0 : return NULL; 34 0 : } 35 : 36 395118 : fd_exec_txn_ctx_t * ctx = (fd_exec_txn_ctx_t *) mem; 37 : 38 395118 : if( FD_UNLIKELY( ctx->magic!=FD_EXEC_TXN_CTX_MAGIC ) ) { 39 0 : FD_LOG_WARNING(( "bad magic" )); 40 0 : return NULL; 41 0 : } 42 : 43 395118 : return ctx; 44 395118 : } 45 : 46 : void * 47 0 : fd_exec_txn_ctx_leave( fd_exec_txn_ctx_t * ctx) { 48 0 : if( FD_UNLIKELY( !ctx ) ) { 49 0 : FD_LOG_WARNING(( "NULL block" )); 50 0 : return NULL; 51 0 : } 52 : 53 0 : if( FD_UNLIKELY( ctx->magic!=FD_EXEC_TXN_CTX_MAGIC ) ) { 54 0 : FD_LOG_WARNING(( "bad magic" )); 55 0 : return NULL; 56 0 : } 57 : 58 0 : return (void *) ctx; 59 0 : } 60 : 61 : void * 62 0 : fd_exec_txn_ctx_delete( void * mem ) { 63 0 : if( FD_UNLIKELY( !mem ) ) { 64 0 : FD_LOG_WARNING(( "NULL mem" )); 65 0 : return NULL; 66 0 : } 67 : 68 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_TXN_CTX_ALIGN) ) ) { 69 0 : FD_LOG_WARNING(( "misaligned mem" )); 70 0 : return NULL; 71 0 : } 72 : 73 0 : fd_exec_txn_ctx_t * hdr = (fd_exec_txn_ctx_t *)mem; 74 0 : if( FD_UNLIKELY( hdr->magic!=FD_EXEC_TXN_CTX_MAGIC ) ) { 75 0 : FD_LOG_WARNING(( "bad magic" )); 76 0 : return NULL; 77 0 : } 78 : 79 0 : FD_COMPILER_MFENCE(); 80 0 : FD_VOLATILE( hdr->magic ) = 0UL; 81 0 : FD_COMPILER_MFENCE(); 82 : 83 0 : return mem; 84 0 : } 85 : 86 : int 87 : fd_txn_borrowed_account_view_idx( fd_exec_txn_ctx_t * ctx, 88 : uchar idx, 89 96378 : fd_borrowed_account_t * * account ) { 90 96378 : if( FD_UNLIKELY( idx>=ctx->accounts_cnt ) ) { 91 0 : return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT; 92 0 : } 93 : 94 96378 : fd_borrowed_account_t * txn_account = &ctx->borrowed_accounts[idx]; 95 96378 : *account = txn_account; 96 : 97 96378 : if( FD_UNLIKELY( !fd_acc_exists( txn_account->const_meta ) ) ) { 98 2265 : return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT; 99 2265 : } 100 : 101 94113 : return FD_ACC_MGR_SUCCESS; 102 96378 : } 103 : 104 : int 105 : fd_txn_borrowed_account_view_idx_allow_dead( fd_exec_txn_ctx_t * ctx, 106 : uchar idx, 107 10953 : fd_borrowed_account_t * * account ) { 108 10953 : if( FD_UNLIKELY( idx>=ctx->accounts_cnt ) ) { 109 0 : return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT; 110 0 : } 111 : 112 10953 : fd_borrowed_account_t * txn_account = &ctx->borrowed_accounts[idx]; 113 10953 : *account = txn_account; 114 : 115 10953 : return FD_ACC_MGR_SUCCESS; 116 10953 : } 117 : 118 : int 119 : fd_txn_borrowed_account_view( fd_exec_txn_ctx_t * ctx, 120 : fd_pubkey_t const * pubkey, 121 93 : fd_borrowed_account_t * * account ) { 122 309 : for( ulong i = 0; i < ctx->accounts_cnt; i++ ) { 123 309 : if( memcmp( pubkey->uc, ctx->accounts[i].uc, sizeof(fd_pubkey_t) )==0 ) { 124 : // TODO: check if readable??? 125 93 : fd_borrowed_account_t * txn_account = &ctx->borrowed_accounts[i]; 126 93 : *account = txn_account; 127 : 128 93 : if( FD_UNLIKELY( !fd_acc_exists( txn_account->const_meta ) ) ) { 129 87 : return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT; 130 87 : } 131 : 132 6 : return FD_ACC_MGR_SUCCESS; 133 93 : } 134 309 : } 135 : 136 0 : return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT; 137 93 : } 138 : 139 : int 140 : fd_txn_borrowed_account_executable_view( fd_exec_txn_ctx_t * ctx, 141 : fd_pubkey_t const * pubkey, 142 918 : fd_borrowed_account_t * * account ) { 143 1071 : for( ulong i = 0; i < ctx->executable_cnt; i++ ) { 144 1062 : if( memcmp( pubkey->uc, ctx->executable_accounts[i].pubkey->uc, sizeof(fd_pubkey_t) )==0 ) { 145 : // TODO: check if readable??? 146 909 : fd_borrowed_account_t * txn_account = &ctx->executable_accounts[i]; 147 909 : *account = txn_account; 148 : 149 909 : if( FD_UNLIKELY( !fd_acc_exists( txn_account->const_meta ) ) ) 150 0 : return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT; 151 : 152 909 : return FD_ACC_MGR_SUCCESS; 153 909 : } 154 1062 : } 155 : 156 9 : return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT; 157 918 : } 158 : 159 : int 160 : fd_txn_borrowed_account_modify_fee_payer( fd_exec_txn_ctx_t * ctx, 161 6831 : fd_borrowed_account_t * * account ) { 162 : 163 6831 : *account = &ctx->borrowed_accounts[ FD_FEE_PAYER_TXN_IDX ]; 164 : 165 6831 : if( FD_UNLIKELY( !fd_txn_is_writable( ctx->txn_descriptor, FD_FEE_PAYER_TXN_IDX ) ) ) { 166 0 : return FD_ACC_MGR_ERR_WRITE_FAILED; 167 0 : } 168 6831 : return FD_ACC_MGR_SUCCESS; 169 6831 : } 170 : 171 : int 172 : fd_txn_borrowed_account_modify_idx( fd_exec_txn_ctx_t * ctx, 173 : uchar idx, 174 : ulong min_data_sz, 175 0 : fd_borrowed_account_t * * account ) { 176 0 : if( idx >= ctx->accounts_cnt ) { 177 0 : return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT; 178 0 : } 179 : 180 0 : fd_borrowed_account_t * txn_account = &ctx->borrowed_accounts[idx]; 181 0 : if( FD_UNLIKELY( !fd_txn_account_is_writable_idx( ctx, (int)idx ) ) ) { 182 0 : return FD_ACC_MGR_ERR_WRITE_FAILED; 183 0 : } 184 : 185 0 : if( min_data_sz > txn_account->const_meta->dlen ) { 186 0 : fd_borrowed_account_resize( txn_account, min_data_sz ); 187 0 : } 188 : 189 0 : *account = txn_account; 190 0 : return FD_ACC_MGR_SUCCESS; 191 0 : } 192 : 193 : int 194 : fd_txn_borrowed_account_modify( fd_exec_txn_ctx_t * ctx, 195 : fd_pubkey_t const * pubkey, 196 : ulong min_data_sz, 197 0 : fd_borrowed_account_t * * account ) { 198 0 : for( ulong i = 0; i < ctx->accounts_cnt; i++ ) { 199 0 : if( memcmp( pubkey->uc, ctx->accounts[i].uc, sizeof(fd_pubkey_t) )==0 ) { 200 : // TODO: check if writable??? 201 0 : fd_borrowed_account_t * txn_account = &ctx->borrowed_accounts[i]; 202 0 : if( min_data_sz > txn_account->const_meta->dlen ) { 203 0 : fd_borrowed_account_resize( txn_account, min_data_sz ); 204 0 : } 205 0 : *account = txn_account; 206 0 : return FD_ACC_MGR_SUCCESS; 207 0 : } 208 0 : } 209 : 210 0 : return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT; 211 0 : } 212 : 213 : void 214 407859 : fd_exec_txn_ctx_setup_basic( fd_exec_txn_ctx_t * txn_ctx ) { 215 407859 : txn_ctx->compute_unit_limit = 200000; 216 407859 : txn_ctx->compute_unit_price = 0; 217 407859 : txn_ctx->compute_meter = 200000; 218 407859 : txn_ctx->prioritization_fee_type = FD_COMPUTE_BUDGET_PRIORITIZATION_FEE_TYPE_DEPRECATED; 219 407859 : txn_ctx->custom_err = UINT_MAX; 220 : 221 407859 : txn_ctx->instr_stack_sz = 0; 222 407859 : txn_ctx->accounts_cnt = 0; 223 407859 : txn_ctx->executable_cnt = 0; 224 407859 : txn_ctx->paid_fees = 0; 225 407859 : txn_ctx->heap_size = FD_VM_HEAP_DEFAULT; 226 407859 : txn_ctx->loaded_accounts_data_size_limit = FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT; 227 407859 : txn_ctx->accounts_resize_delta = 0; 228 407859 : txn_ctx->collected_rent = 0UL; 229 : 230 407859 : txn_ctx->num_instructions = 0; 231 407859 : memset( txn_ctx->return_data.program_id.key, 0, sizeof(fd_pubkey_t) ); 232 407859 : txn_ctx->return_data.len = 0; 233 : 234 407859 : txn_ctx->dirty_vote_acc = 0; 235 407859 : txn_ctx->dirty_stake_acc = 0; 236 407859 : txn_ctx->failed_instr = NULL; 237 407859 : txn_ctx->instr_err_idx = INT_MAX; 238 407859 : txn_ctx->capture_ctx = NULL; 239 : 240 407859 : txn_ctx->instr_info_cnt = 0; 241 407859 : txn_ctx->instr_trace_length = 0; 242 : 243 407859 : txn_ctx->exec_err = 0; 244 407859 : txn_ctx->exec_err_kind = FD_EXECUTOR_ERR_KIND_EBPF; 245 : 246 407859 : txn_ctx->has_program_id = 0; 247 407859 : } 248 : 249 : void 250 : fd_exec_txn_ctx_setup( fd_exec_txn_ctx_t * txn_ctx, 251 : fd_txn_t const * txn_descriptor, 252 12741 : fd_rawtxn_b_t const * txn_raw ) { 253 12741 : fd_exec_txn_ctx_setup_basic( txn_ctx ); 254 12741 : txn_ctx->txn_descriptor = txn_descriptor; 255 12741 : txn_ctx->_txn_raw->raw = txn_raw->raw; 256 12741 : txn_ctx->_txn_raw->txn_sz = txn_raw->txn_sz; 257 12741 : } 258 : 259 : void 260 0 : fd_exec_txn_ctx_teardown( fd_exec_txn_ctx_t * txn_ctx ) { 261 0 : (void)txn_ctx; 262 0 : } 263 : 264 : void 265 : fd_exec_txn_ctx_from_exec_slot_ctx( fd_exec_slot_ctx_t * slot_ctx, 266 407859 : fd_exec_txn_ctx_t * txn_ctx ) { 267 407859 : txn_ctx->slot_ctx = slot_ctx; 268 407859 : txn_ctx->epoch_ctx = slot_ctx->epoch_ctx; 269 407859 : txn_ctx->funk_txn = NULL; 270 407859 : txn_ctx->acc_mgr = slot_ctx->acc_mgr; 271 407859 : } 272 : 273 : void 274 68793 : fd_exec_txn_ctx_reset_return_data( fd_exec_txn_ctx_t * txn_ctx ) { 275 68793 : txn_ctx->return_data.len = 0; 276 68793 : } 277 : 278 : /* https://github.com/anza-xyz/agave/blob/v2.1.1/sdk/program/src/message/versions/v0/loaded.rs#L162 */ 279 : int 280 : fd_txn_account_is_demotion( fd_exec_txn_ctx_t const * txn_ctx, int idx ) 281 118596 : { 282 118596 : uint is_program = 0U; 283 314025 : for( ulong j=0UL; j<txn_ctx->txn_descriptor->instr_cnt; j++ ) { 284 216885 : if( txn_ctx->txn_descriptor->instr[j].program_id == idx ) { 285 21456 : is_program = 1U; 286 21456 : break; 287 21456 : } 288 216885 : } 289 : 290 118596 : uint bpf_upgradeable_in_txn = 0U; 291 1459209 : for( ulong j = 0; j < txn_ctx->accounts_cnt; j++ ) { 292 1358691 : const fd_pubkey_t * acc = &txn_ctx->accounts[j]; 293 1358691 : if ( memcmp( acc->uc, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) == 0 ) { 294 18078 : bpf_upgradeable_in_txn = 1U; 295 18078 : break; 296 18078 : } 297 1358691 : } 298 118596 : return (is_program && !bpf_upgradeable_in_txn); 299 118596 : } 300 : 301 : int 302 166962 : fd_txn_account_is_writable_idx( fd_exec_txn_ctx_t const * txn_ctx, int idx ) { 303 : 304 166962 : int acct_addr_cnt = txn_ctx->txn_descriptor->acct_addr_cnt; 305 166962 : if( txn_ctx->txn_descriptor->transaction_version == FD_TXN_V0 ) { 306 157473 : acct_addr_cnt += txn_ctx->txn_descriptor->addr_table_adtl_cnt; 307 157473 : } 308 : 309 166962 : if( idx==acct_addr_cnt ) { 310 3 : return 0; 311 3 : } 312 : 313 166959 : if( fd_pubkey_is_active_reserved_key(&txn_ctx->accounts[idx] ) || 314 166959 : ( FD_FEATURE_ACTIVE( txn_ctx->slot_ctx, add_new_reserved_account_keys ) && 315 119763 : fd_pubkey_is_pending_reserved_key( &txn_ctx->accounts[idx] ) )) { 316 48363 : return 0; 317 48363 : } 318 : 319 118596 : if( fd_txn_account_is_demotion( txn_ctx, idx ) ) { 320 20148 : return 0; 321 20148 : } 322 : 323 98448 : return fd_txn_is_writable( txn_ctx->txn_descriptor, idx ); 324 118596 : }