LCOV - code coverage report
Current view: top level - flamenco/runtime/context - fd_exec_txn_ctx.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 240 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 18 0.0 %

          Line data    Source code
       1             : #include "fd_exec_txn_ctx.h"
       2             : #include "../fd_acc_mgr.h"
       3             : #include "../fd_executor.h"
       4             : #include "../../vm/fd_vm.h"
       5             : #include "../fd_system_ids.h"
       6             : #include "fd_exec_epoch_ctx.h"
       7             : 
       8             : void *
       9           0 : fd_exec_txn_ctx_new( void * mem ) {
      10           0 :   if( FD_UNLIKELY( !mem ) ) {
      11           0 :     FD_LOG_WARNING(( "NULL mem" ));
      12           0 :     return NULL;
      13           0 :   }
      14             : 
      15           0 :   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           0 :   fd_exec_txn_ctx_t * self = (fd_exec_txn_ctx_t *) mem;
      21             : 
      22           0 :   FD_COMPILER_MFENCE();
      23           0 :   self->magic = FD_EXEC_TXN_CTX_MAGIC;
      24           0 :   FD_COMPILER_MFENCE();
      25             : 
      26           0 :   return mem;
      27           0 : }
      28             : 
      29             : fd_exec_txn_ctx_t *
      30           0 : fd_exec_txn_ctx_join( void * mem ) {
      31           0 :   if( FD_UNLIKELY( !mem ) ) {
      32           0 :     FD_LOG_WARNING(( "NULL block" ));
      33           0 :     return NULL;
      34           0 :   }
      35             : 
      36           0 :   fd_exec_txn_ctx_t * ctx = (fd_exec_txn_ctx_t *) mem;
      37             : 
      38           0 :   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           0 :   return ctx;
      44           0 : }
      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_exec_txn_ctx_get_account_view_idx( fd_exec_txn_ctx_t * ctx,
      88             :                                       uchar               idx,
      89           0 :                                       fd_txn_account_t * * account ) {
      90           0 :   if( FD_UNLIKELY( idx>=ctx->accounts_cnt ) ) {
      91           0 :     return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
      92           0 :   }
      93             : 
      94           0 :   fd_txn_account_t * txn_account = &ctx->accounts[idx];
      95           0 :   *account = txn_account;
      96             : 
      97           0 :   if( FD_UNLIKELY( !fd_acc_exists( txn_account->const_meta ) ) ) {
      98           0 :     return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
      99           0 :   }
     100             : 
     101           0 :   return FD_ACC_MGR_SUCCESS;
     102           0 : }
     103             : 
     104             : int
     105             : fd_exec_txn_ctx_get_account_view_idx_allow_dead( fd_exec_txn_ctx_t *  ctx,
     106             :                                                  uchar                idx,
     107           0 :                                                  fd_txn_account_t * * account ) {
     108           0 :   if( FD_UNLIKELY( idx>=ctx->accounts_cnt ) ) {
     109           0 :     return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
     110           0 :   }
     111             : 
     112           0 :   fd_txn_account_t * txn_account = &ctx->accounts[idx];
     113           0 :   *account = txn_account;
     114             : 
     115           0 :   return FD_ACC_MGR_SUCCESS;
     116           0 : }
     117             : 
     118             : int
     119             : fd_exec_txn_ctx_get_account_view( fd_exec_txn_ctx_t *  ctx,
     120             :                                   fd_pubkey_t const *  pubkey,
     121           0 :                                   fd_txn_account_t * * account ) {
     122           0 :   for( ulong i = 0; i < ctx->accounts_cnt; i++ ) {
     123           0 :     if( memcmp( pubkey->uc, ctx->account_keys[i].uc, sizeof(fd_pubkey_t) )==0 ) {
     124             :       // TODO: check if readable???
     125           0 :       fd_txn_account_t * txn_account = &ctx->accounts[i];
     126           0 :       *account = txn_account;
     127             : 
     128           0 :       if( FD_UNLIKELY( !fd_acc_exists( txn_account->const_meta ) ) ) {
     129           0 :         return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
     130           0 :       }
     131             : 
     132           0 :       return FD_ACC_MGR_SUCCESS;
     133           0 :     }
     134           0 :   }
     135             : 
     136           0 :   return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
     137           0 : }
     138             : 
     139             : int
     140             : fd_exec_txn_ctx_get_account_executable_view( fd_exec_txn_ctx_t *  ctx,
     141             :                                              fd_pubkey_t const *  pubkey,
     142           0 :                                              fd_txn_account_t * * account ) {
     143             :   /* First try to fetch the executable account from the existing borrowed accounts.
     144             :      If the pubkey is in the account keys, then we want to re-use that
     145             :      borrowed account since it reflects changes from prior instructions. Referencing the
     146             :      read-only executable accounts list is incorrect behavior when the program
     147             :      data account is written to in a prior instruction (e.g. program upgrade + invoke within the same txn) */
     148           0 :   int err = fd_exec_txn_ctx_get_account_view( ctx, pubkey, account );
     149           0 :   if( FD_UNLIKELY( err==FD_ACC_MGR_SUCCESS ) ) {
     150           0 :     return FD_ACC_MGR_SUCCESS;
     151           0 :   }
     152             : 
     153           0 :   for( ulong i = 0; i < ctx->executable_cnt; i++ ) {
     154           0 :     if( memcmp( pubkey->uc, ctx->executable_accounts[i].pubkey->uc, sizeof(fd_pubkey_t) )==0 ) {
     155             :       // TODO: check if readable???
     156           0 :       fd_txn_account_t * txn_account = &ctx->executable_accounts[i];
     157           0 :       *account = txn_account;
     158             : 
     159           0 :       if( FD_UNLIKELY( !fd_acc_exists( txn_account->const_meta ) ) )
     160           0 :         return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
     161             : 
     162           0 :       return FD_ACC_MGR_SUCCESS;
     163           0 :     }
     164           0 :   }
     165             : 
     166           0 :   return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
     167           0 : }
     168             : 
     169             : int
     170             : fd_exec_txn_ctx_get_account_modify_fee_payer( fd_exec_txn_ctx_t *  ctx,
     171           0 :                                               fd_txn_account_t * * account ) {
     172             : 
     173           0 :   *account = &ctx->accounts[ FD_FEE_PAYER_TXN_IDX ];
     174             : 
     175           0 :   if( FD_UNLIKELY( !fd_txn_is_writable( ctx->txn_descriptor, FD_FEE_PAYER_TXN_IDX ) ) ) {
     176           0 :     return FD_ACC_MGR_ERR_WRITE_FAILED;
     177           0 :   }
     178           0 :   return FD_ACC_MGR_SUCCESS;
     179           0 : }
     180             : 
     181             : int
     182             : fd_exec_txn_ctx_get_account_modify_idx( fd_exec_txn_ctx_t *   ctx,
     183             :                                         uchar                 idx,
     184             :                                         ulong                 min_data_sz,
     185           0 :                                         fd_txn_account_t * *  account ) {
     186           0 :   if( idx >= ctx->accounts_cnt ) {
     187           0 :     return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
     188           0 :   }
     189             : 
     190           0 :   fd_txn_account_t * txn_account = &ctx->accounts[idx];
     191           0 :   if( FD_UNLIKELY( !fd_txn_account_is_writable_idx( ctx, (int)idx ) ) ) {
     192           0 :     return FD_ACC_MGR_ERR_WRITE_FAILED;
     193           0 :   }
     194             : 
     195           0 :   if( min_data_sz > txn_account->const_meta->dlen ) {
     196           0 :     fd_txn_account_resize( txn_account, min_data_sz );
     197           0 :   }
     198             : 
     199           0 :   *account = txn_account;
     200           0 :   return FD_ACC_MGR_SUCCESS;
     201           0 : }
     202             : 
     203             : int
     204             : fd_exec_txn_ctx_get_account_modify( fd_exec_txn_ctx_t *  ctx,
     205             :                                     fd_pubkey_t const *  pubkey,
     206             :                                     ulong                min_data_sz,
     207           0 :                                     fd_txn_account_t * * account ) {
     208           0 :   for( ulong i = 0; i < ctx->accounts_cnt; i++ ) {
     209           0 :     if( memcmp( pubkey->uc, ctx->account_keys[i].uc, sizeof(fd_pubkey_t) )==0 ) {
     210             :       // TODO: check if writable???
     211           0 :       fd_txn_account_t * txn_account = &ctx->accounts[i];
     212           0 :       if( min_data_sz > txn_account->const_meta->dlen ) {
     213           0 :         fd_txn_account_resize( txn_account, min_data_sz );
     214           0 :       }
     215           0 :       *account = txn_account;
     216           0 :       return FD_ACC_MGR_SUCCESS;
     217           0 :     }
     218           0 :   }
     219             : 
     220           0 :   return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
     221           0 : }
     222             : 
     223             : void
     224           0 : fd_exec_txn_ctx_setup_basic( fd_exec_txn_ctx_t * txn_ctx ) {
     225           0 :   txn_ctx->compute_unit_limit = 200000;
     226           0 :   txn_ctx->compute_unit_price = 0;
     227           0 :   txn_ctx->compute_meter      = 200000;
     228           0 :   txn_ctx->prioritization_fee_type = FD_COMPUTE_BUDGET_PRIORITIZATION_FEE_TYPE_DEPRECATED;
     229           0 :   txn_ctx->custom_err         = UINT_MAX;
     230             : 
     231           0 :   txn_ctx->instr_stack_sz                  = 0;
     232           0 :   txn_ctx->accounts_cnt                    = 0UL;
     233           0 :   txn_ctx->executable_cnt                  = 0UL;
     234           0 :   txn_ctx->paid_fees                       = 0UL;
     235           0 :   txn_ctx->heap_size                       = FD_VM_HEAP_DEFAULT;
     236           0 :   txn_ctx->loaded_accounts_data_size_limit = FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT;
     237           0 :   txn_ctx->loaded_accounts_data_size       = 0UL;
     238           0 :   txn_ctx->accounts_resize_delta           = 0UL;
     239           0 :   txn_ctx->collected_rent                  = 0UL;
     240             : 
     241           0 :   txn_ctx->num_instructions = 0;
     242           0 :   memset( txn_ctx->return_data.program_id.key, 0, sizeof(fd_pubkey_t) );
     243           0 :   txn_ctx->return_data.len = 0;
     244             : 
     245           0 :   txn_ctx->dirty_vote_acc  = 0;
     246           0 :   txn_ctx->dirty_stake_acc = 0;
     247           0 :   txn_ctx->failed_instr    = NULL;
     248           0 :   txn_ctx->instr_err_idx   = INT_MAX;
     249           0 :   txn_ctx->capture_ctx     = NULL;
     250             : 
     251           0 :   txn_ctx->instr_info_cnt     = 0;
     252           0 :   txn_ctx->instr_trace_length = 0;
     253             : 
     254           0 :   txn_ctx->exec_err      = 0;
     255           0 :   txn_ctx->exec_err_kind = FD_EXECUTOR_ERR_KIND_NONE;
     256           0 : }
     257             : 
     258             : void
     259             : fd_exec_txn_ctx_setup( fd_exec_txn_ctx_t   * txn_ctx,
     260             :                        fd_txn_t      const * txn_descriptor,
     261           0 :                        fd_rawtxn_b_t const * txn_raw ) {
     262           0 :   fd_exec_txn_ctx_setup_basic( txn_ctx );
     263           0 :   txn_ctx->txn_descriptor   = txn_descriptor;
     264           0 :   txn_ctx->_txn_raw->raw    = txn_raw->raw;
     265           0 :   txn_ctx->_txn_raw->txn_sz = txn_raw->txn_sz;
     266           0 : }
     267             : 
     268             : void
     269           0 : fd_exec_txn_ctx_teardown( fd_exec_txn_ctx_t * txn_ctx ) {
     270           0 :   (void)txn_ctx;
     271           0 : }
     272             : 
     273             : void
     274             : fd_exec_txn_ctx_from_exec_slot_ctx( fd_exec_slot_ctx_t const * slot_ctx,
     275             :                                     fd_exec_txn_ctx_t *        txn_ctx,
     276             :                                     fd_wksp_t const *          funk_wksp,
     277             :                                     fd_wksp_t const *          runtime_pub_wksp,
     278             :                                     ulong                      funk_txn_gaddr,
     279             :                                     ulong                      acc_mgr_gaddr,
     280             :                                     ulong                      sysvar_cache_gaddr,
     281           0 :                                     ulong                      funk_gaddr ) {
     282             : 
     283           0 :   txn_ctx->runtime_pub_wksp = (fd_wksp_t *)runtime_pub_wksp;
     284             : 
     285           0 :   txn_ctx->funk_txn = fd_wksp_laddr( funk_wksp, funk_txn_gaddr );
     286           0 :   if( FD_UNLIKELY( !txn_ctx->funk_txn ) ) {
     287           0 :     FD_LOG_ERR(( "Could not find valid funk transaction" ));
     288           0 :   }
     289             : 
     290           0 :   txn_ctx->acc_mgr = fd_wksp_laddr( runtime_pub_wksp, acc_mgr_gaddr );
     291           0 :   if( FD_UNLIKELY( !txn_ctx->acc_mgr ) ) {
     292           0 :     FD_LOG_ERR(( "Could not find valid account manager" ));
     293           0 :   }
     294           0 :   txn_ctx->acc_mgr->funk = fd_wksp_laddr( funk_wksp, funk_gaddr );
     295             : 
     296           0 :   txn_ctx->sysvar_cache = fd_wksp_laddr( runtime_pub_wksp, sysvar_cache_gaddr );
     297             : 
     298           0 :   txn_ctx->features     = slot_ctx->epoch_ctx->features;
     299           0 :   txn_ctx->status_cache = slot_ctx->status_cache;
     300             : 
     301           0 :   txn_ctx->bank_hash_cmp = slot_ctx->epoch_ctx->bank_hash_cmp;
     302             : 
     303           0 :   txn_ctx->prev_lamports_per_signature = slot_ctx->prev_lamports_per_signature;
     304           0 :   txn_ctx->enable_exec_recording       = slot_ctx->enable_exec_recording;
     305           0 :   txn_ctx->total_epoch_stake           = slot_ctx->epoch_ctx->total_epoch_stake;
     306             : 
     307           0 :   txn_ctx->slot                        = slot_ctx->slot_bank.slot;
     308           0 :   txn_ctx->fee_rate_governor           = slot_ctx->slot_bank.fee_rate_governor;
     309           0 :   txn_ctx->block_hash_queue            = slot_ctx->slot_bank.block_hash_queue; /* MAKE GLOBAL */
     310             : 
     311           0 :   fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank_const( slot_ctx->epoch_ctx );
     312           0 :   txn_ctx->schedule                    = epoch_bank->epoch_schedule;
     313           0 :   txn_ctx->rent                        = epoch_bank->rent;
     314           0 :   txn_ctx->slots_per_year              = epoch_bank->slots_per_year;
     315           0 :   txn_ctx->stakes                      = epoch_bank->stakes;
     316             : 
     317           0 : }
     318             : 
     319             : void
     320           0 : fd_exec_txn_ctx_reset_return_data( fd_exec_txn_ctx_t * txn_ctx ) {
     321           0 :   txn_ctx->return_data.len = 0;
     322           0 : }
     323             : 
     324             : /* https://github.com/anza-xyz/agave/blob/v2.1.1/sdk/program/src/message/versions/v0/loaded.rs#L162 */
     325             : int
     326             : fd_txn_account_is_demotion( fd_exec_txn_ctx_t const * txn_ctx, int idx )
     327           0 : {
     328           0 :   uint is_program = 0U;
     329           0 :   for( ulong j=0UL; j<txn_ctx->txn_descriptor->instr_cnt; j++ ) {
     330           0 :     if( txn_ctx->txn_descriptor->instr[j].program_id == idx ) {
     331           0 :       is_program = 1U;
     332           0 :       break;
     333           0 :     }
     334           0 :   }
     335             : 
     336           0 :   uint bpf_upgradeable_in_txn = 0U;
     337           0 :   for( ulong j = 0; j < txn_ctx->accounts_cnt; j++ ) {
     338           0 :     const fd_pubkey_t * acc = &txn_ctx->account_keys[j];
     339           0 :     if ( memcmp( acc->uc, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) == 0 ) {
     340           0 :       bpf_upgradeable_in_txn = 1U;
     341           0 :       break;
     342           0 :     }
     343           0 :   }
     344           0 :   return (is_program && !bpf_upgradeable_in_txn);
     345           0 : }
     346             : 
     347             : /* This function aims to mimic the writable accounts check to populate the writable accounts cache, used
     348             :    to determine if accounts are writable or not.
     349             : 
     350             :    https://github.com/anza-xyz/agave/blob/v2.1.11/sdk/program/src/message/sanitized.rs#L38-L47 */
     351             : int
     352           0 : fd_txn_account_is_writable_idx( fd_exec_txn_ctx_t const * txn_ctx, int idx ) {
     353             : 
     354             :   /* https://github.com/anza-xyz/agave/blob/v2.1.11/sdk/program/src/message/sanitized.rs#L43 */
     355           0 :   if( !fd_txn_is_writable( txn_ctx->txn_descriptor, idx ) ) {
     356           0 :     return 0;
     357           0 :   }
     358             : 
     359             :   /* See comments in fd_system_ids.h.
     360             :      https://github.com/anza-xyz/agave/blob/v2.1.11/sdk/program/src/message/sanitized.rs#L44 */
     361           0 :   if( fd_pubkey_is_active_reserved_key(&txn_ctx->account_keys[idx] ) ||
     362           0 :       ( FD_FEATURE_ACTIVE( txn_ctx->slot, txn_ctx->features, add_new_reserved_account_keys ) &&
     363           0 :                            fd_pubkey_is_pending_reserved_key( &txn_ctx->account_keys[idx] ) ) ||
     364           0 :       ( FD_FEATURE_ACTIVE( txn_ctx->slot, txn_ctx->features, enable_secp256r1_precompile ) &&
     365           0 :                            fd_pubkey_is_secp256r1_key( &txn_ctx->account_keys[idx] ) ) ) {
     366           0 :     return 0;
     367           0 :   }
     368             : 
     369             :   /* https://github.com/anza-xyz/agave/blob/v2.1.11/sdk/program/src/message/sanitized.rs#L45 */
     370           0 :   if( fd_txn_account_is_demotion( txn_ctx, idx ) ) {
     371           0 :     return 0;
     372           0 :   }
     373             : 
     374           0 :   return 1;
     375           0 : }

Generated by: LCOV version 1.14