LCOV - code coverage report
Current view: top level - flamenco/runtime/tests/harness - fd_instr_harness.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 335 0.0 %
Date: 2025-07-01 05:00:49 Functions: 0 3 0.0 %

          Line data    Source code
       1             : 
       2             : #undef FD_SPAD_USE_HANDHOLDING
       3             : #define FD_SPAD_USE_HANDHOLDING 1
       4             : 
       5             : #include "fd_instr_harness.h"
       6             : #include "../../fd_system_ids.h"
       7             : #include "../../sysvar/fd_sysvar_clock.h"
       8             : #include "../../sysvar/fd_sysvar_epoch_schedule.h"
       9             : #include "../../sysvar/fd_sysvar_recent_hashes.h"
      10             : #include "../../sysvar/fd_sysvar_last_restart_slot.h"
      11             : #include "../../sysvar/fd_sysvar_rent.h"
      12             : 
      13             : int
      14             : fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t *           runner,
      15             :                                   fd_exec_instr_ctx_t *                ctx,
      16             :                                   fd_exec_test_instr_context_t const * test_ctx,
      17           0 :                                   bool                                 is_syscall ) {
      18             : 
      19           0 :   memset( ctx, 0, sizeof(fd_exec_instr_ctx_t) );
      20             : 
      21           0 :   fd_funk_t * funk = runner->funk;
      22             : 
      23             :   /* Generate unique ID for funk txn */
      24             : 
      25           0 :   fd_funk_txn_xid_t xid[1] = {0};
      26           0 :   xid[0] = fd_funk_generate_xid();
      27             : 
      28             :   /* Create temporary funk transaction and txn / slot / epoch contexts */
      29             : 
      30           0 :   fd_funk_txn_start_write( funk );
      31           0 :   fd_funk_txn_t * funk_txn = fd_funk_txn_prepare( funk, NULL, xid, 1 );
      32           0 :   fd_funk_txn_end_write( funk );
      33             : 
      34             :   /* Allocate contexts */
      35           0 :   uchar *               slot_ctx_mem  = fd_spad_alloc( runner->spad,FD_EXEC_SLOT_CTX_ALIGN,  FD_EXEC_SLOT_CTX_FOOTPRINT  );
      36           0 :   uchar *               txn_ctx_mem   = fd_spad_alloc( runner->spad,FD_EXEC_TXN_CTX_ALIGN,   FD_EXEC_TXN_CTX_FOOTPRINT   );
      37             : 
      38           0 :   fd_exec_slot_ctx_t *  slot_ctx      = fd_exec_slot_ctx_join ( fd_exec_slot_ctx_new ( slot_ctx_mem ) );
      39           0 :   fd_exec_txn_ctx_t *   txn_ctx       = fd_exec_txn_ctx_join  ( fd_exec_txn_ctx_new  ( txn_ctx_mem ), runner->spad, fd_wksp_containing( runner->spad ) );
      40             : 
      41           0 :   assert( slot_ctx  );
      42             : 
      43           0 :   ctx->txn_ctx = txn_ctx;
      44             : 
      45             :   /* Set up slot context */
      46             : 
      47           0 :   slot_ctx->funk_txn     = funk_txn;
      48           0 :   slot_ctx->funk         = funk;
      49             : 
      50             :   /* Bank manager */
      51             : 
      52           0 :   slot_ctx->bank = runner->bank;
      53           0 :   fd_bank_clear_bank( slot_ctx->bank );
      54             : 
      55           0 :   fd_features_t * features = fd_bank_features_modify( slot_ctx->bank );
      56           0 :   fd_exec_test_feature_set_t const * feature_set = &test_ctx->epoch_context.features;
      57           0 :   if( !fd_runtime_fuzz_restore_features( features, feature_set ) ) {
      58           0 :     return 0;
      59           0 :   }
      60             : 
      61             :   /* Set up epoch context. Defaults obtained from GenesisConfig::Default() */
      62             : 
      63           0 :   fd_rent_t * rent_bm = fd_bank_rent_modify( slot_ctx->bank );
      64           0 :   rent_bm->lamports_per_uint8_year = 3480;
      65           0 :   rent_bm->exemption_threshold = 2;
      66           0 :   rent_bm->burn_percent = 50;
      67             : 
      68             :   /* Blockhash queue init */
      69             : 
      70           0 :   fd_block_hash_queue_global_t * block_hash_queue = fd_bank_block_hash_queue_modify( slot_ctx->bank );
      71             : 
      72           0 :   uchar * last_hash_mem = (uchar *)fd_ulong_align_up( (ulong)block_hash_queue + sizeof(fd_block_hash_queue_global_t), alignof(fd_hash_t) );
      73           0 :   uchar * ages_pool_mem = (uchar *)fd_ulong_align_up( (ulong)last_hash_mem + sizeof(fd_hash_t), fd_hash_hash_age_pair_t_map_align() );
      74           0 :   fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_hash_hash_age_pair_t_map_join( fd_hash_hash_age_pair_t_map_new( ages_pool_mem, 400 ) );
      75             : 
      76           0 :   block_hash_queue->max_age          = FD_BLOCKHASH_QUEUE_MAX_ENTRIES;
      77           0 :   block_hash_queue->ages_root_offset = 0UL;
      78           0 :   fd_block_hash_queue_ages_pool_update( block_hash_queue, ages_pool );
      79           0 :   block_hash_queue->last_hash_index  = 0UL;
      80           0 :   block_hash_queue->last_hash_offset = (ulong)last_hash_mem - (ulong)block_hash_queue;
      81             : 
      82           0 :   memset( last_hash_mem, 0, sizeof(fd_hash_t) );
      83             : 
      84             :   /* Set up txn context */
      85             : 
      86           0 :   fd_wksp_t * funk_wksp          = fd_funk_wksp( funk );
      87           0 :   fd_wksp_t * runtime_wksp       = fd_wksp_containing( slot_ctx );
      88           0 :   ulong       funk_txn_gaddr     = fd_wksp_gaddr( funk_wksp, funk_txn );
      89           0 :   ulong       funk_gaddr         = fd_wksp_gaddr( funk_wksp, funk->shmem );
      90             : 
      91             :   /* Set up mock txn descriptor */
      92           0 :   fd_txn_t * txn_descriptor           = fd_spad_alloc( runner->spad, fd_txn_align(), fd_txn_footprint( 1UL, 0UL ) );
      93           0 :   txn_descriptor->transaction_version = FD_TXN_V0;
      94           0 :   txn_descriptor->acct_addr_cnt       = (ushort)test_ctx->accounts_count;
      95             : 
      96           0 :   fd_exec_txn_ctx_from_exec_slot_ctx( slot_ctx,
      97           0 :                                       txn_ctx,
      98           0 :                                       funk_wksp,
      99           0 :                                       runtime_wksp,
     100           0 :                                       funk_txn_gaddr,
     101           0 :                                       funk_gaddr,
     102           0 :                                       NULL );
     103           0 :   fd_exec_txn_ctx_setup_basic( txn_ctx );
     104             : 
     105           0 :   txn_ctx->txn_descriptor     = txn_descriptor;
     106           0 :   txn_ctx->compute_unit_limit = test_ctx->cu_avail;
     107           0 :   txn_ctx->compute_meter      = test_ctx->cu_avail;
     108           0 :   txn_ctx->vote_accounts_pool = NULL;
     109           0 :   txn_ctx->spad               = runner->spad;
     110           0 :   txn_ctx->instr_info_cnt     = 1UL;
     111             : 
     112             :   /* Set up instruction context */
     113             : 
     114           0 :   fd_instr_info_t * info = fd_spad_alloc( runner->spad, 8UL, sizeof(fd_instr_info_t) );
     115           0 :   assert( info );
     116           0 :   memset( info, 0, sizeof(fd_instr_info_t) );
     117             : 
     118           0 :   if( test_ctx->data ) {
     119           0 :     info->data_sz = (ushort)test_ctx->data->size;
     120           0 :     info->data    = test_ctx->data->bytes;
     121           0 :   }
     122             : 
     123             :   /* Prepare borrowed account table (correctly handles aliasing) */
     124             : 
     125           0 :   if( FD_UNLIKELY( test_ctx->accounts_count > MAX_TX_ACCOUNT_LOCKS ) ) {
     126           0 :     FD_LOG_NOTICE(( "too many accounts" ));
     127           0 :     return 0;
     128           0 :   }
     129             : 
     130             :   /* Load accounts into database */
     131             : 
     132           0 :   fd_txn_account_t * accts = txn_ctx->accounts;
     133           0 :   fd_memset( accts, 0, test_ctx->accounts_count * sizeof(fd_txn_account_t) );
     134           0 :   txn_ctx->accounts_cnt = test_ctx->accounts_count;
     135             : 
     136           0 :   int has_program_id = 0;
     137             : 
     138           0 :   for( ulong j=0UL; j < test_ctx->accounts_count; j++ ) {
     139           0 :     memcpy(  &(txn_ctx->account_keys[j]), test_ctx->accounts[j].address, sizeof(fd_pubkey_t) );
     140           0 :     if( !fd_runtime_fuzz_load_account( &accts[j], funk, funk_txn, &test_ctx->accounts[j], 0 ) ) {
     141           0 :       return 0;
     142           0 :     }
     143             : 
     144           0 :     fd_txn_account_t * acc = &accts[j];
     145           0 :     if( acc->vt->get_meta( acc ) ) {
     146           0 :       uchar * data = fd_spad_alloc( txn_ctx->spad, FD_ACCOUNT_REC_ALIGN, FD_ACC_TOT_SZ_MAX );
     147           0 :       ulong   dlen = acc->vt->get_data_len( acc );
     148           0 :       fd_memcpy( data, acc->vt->get_meta( acc ), sizeof(fd_account_meta_t)+dlen );
     149           0 :       fd_txn_account_init_from_meta_and_data_readonly( acc,
     150           0 :                                                        (fd_account_meta_t const *)data,
     151           0 :                                                        data + sizeof(fd_account_meta_t) );
     152           0 :     }
     153             : 
     154           0 :     if( !memcmp( accts[j].pubkey, test_ctx->program_id, sizeof(fd_pubkey_t) ) ) {
     155           0 :       has_program_id = 1;
     156           0 :       info->program_id = (uchar)txn_ctx->accounts_cnt;
     157           0 :     }
     158             : 
     159             :     /* Since the instructions sysvar is set as mutable at the txn level, we need to make it mutable here as well. */
     160           0 :     if( !memcmp( accts[j].pubkey, &fd_sysvar_instructions_id, sizeof(fd_pubkey_t) ) ) {
     161           0 :       acc->vt->set_mutable( acc );
     162           0 :     }
     163           0 :   }
     164             : 
     165             :   /* If the program id is not in the set of accounts it must be added to the set of accounts. */
     166           0 :   if( FD_UNLIKELY( !has_program_id ) ) {
     167           0 :     fd_txn_account_t * program_acc = &accts[ test_ctx->accounts_count ];
     168           0 :     fd_pubkey_t *      program_key = &txn_ctx->account_keys[ txn_ctx->accounts_cnt ];
     169           0 :     fd_txn_account_init( program_acc );
     170           0 :     memcpy( program_key, test_ctx->program_id, sizeof(fd_pubkey_t) );
     171           0 :     memcpy( program_acc->pubkey, test_ctx->program_id, sizeof(fd_pubkey_t) );
     172           0 :     fd_account_meta_t * meta = fd_spad_alloc( txn_ctx->spad, alignof(fd_account_meta_t), sizeof(fd_account_meta_t) );
     173           0 :     fd_account_meta_init( meta );
     174           0 :     program_acc->vt->set_meta_mutable( program_acc, meta );
     175           0 :     info->program_id = (uchar)txn_ctx->accounts_cnt;
     176           0 :     txn_ctx->accounts_cnt++;
     177           0 :   }
     178             : 
     179             :   /* Load in executable accounts */
     180           0 :   for( ulong i = 0; i < txn_ctx->accounts_cnt; i++ ) {
     181           0 :     fd_txn_account_t * acc = &accts[i];
     182           0 :     if ( !fd_executor_pubkey_is_bpf_loader( acc->vt->get_owner( acc ) ) ) {
     183           0 :       continue;
     184           0 :     }
     185             : 
     186           0 :     fd_account_meta_t const * meta = acc->vt->get_meta( acc );
     187           0 :     if (meta == NULL) {
     188           0 :       fd_txn_account_setup_sentinel_meta_readonly( acc, txn_ctx->spad, txn_ctx->spad_wksp );
     189           0 :       continue;
     190           0 :     }
     191             : 
     192           0 :     if( FD_UNLIKELY( 0 == memcmp(meta->info.owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t)) ) ) {
     193           0 :       int err = 0;
     194           0 :       fd_bpf_upgradeable_loader_state_t * program_loader_state = read_bpf_upgradeable_loader_state_for_program( txn_ctx,
     195           0 :                                                                                                                 (ushort)i,
     196           0 :                                                                                                                 &err );
     197             : 
     198           0 :       if( FD_UNLIKELY( !program_loader_state ) ) {
     199           0 :         continue;
     200           0 :       }
     201             : 
     202           0 :       if( !fd_bpf_upgradeable_loader_state_is_program( program_loader_state ) ) {
     203           0 :         continue;
     204           0 :       }
     205             : 
     206           0 :       fd_pubkey_t * programdata_acc = &program_loader_state->inner.program.programdata_address;
     207           0 :       if( FD_UNLIKELY( fd_txn_account_init_from_funk_readonly( &txn_ctx->executable_accounts[txn_ctx->executable_cnt],
     208           0 :                                                                programdata_acc,
     209           0 :                                                                txn_ctx->funk,
     210           0 :                                                                txn_ctx->funk_txn ) ) ) {
     211           0 :         continue;
     212           0 :       }
     213           0 :       txn_ctx->executable_cnt++;
     214           0 :     }
     215           0 :   }
     216             : 
     217             :   /* Add accounts to bpf program cache */
     218           0 :   fd_bpf_scan_and_create_bpf_program_cache_entry( slot_ctx, runner->spad );
     219             : 
     220             :   /* Fill missing sysvar cache values with defaults */
     221             :   /* We create mock accounts for each of the sysvars and hardcode the data fields before loading it into the account manager */
     222             :   /* We use Agave sysvar defaults for data field values */
     223             : 
     224             :   /* Clock */
     225             :   // https://github.com/firedancer-io/solfuzz-agave/blob/agave-v2.0/src/lib.rs#L466-L474
     226           0 :   fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( funk, funk_txn, runner->spad );
     227           0 :   if( !clock ) {
     228           0 :     fd_sol_sysvar_clock_t sysvar_clock = {
     229           0 :                                           .slot                  = 10UL,
     230           0 :                                           .epoch_start_timestamp = 0L,
     231           0 :                                           .epoch                 = 0UL,
     232           0 :                                           .leader_schedule_epoch = 0UL,
     233           0 :                                           .unix_timestamp        = 0L
     234           0 :                                         };
     235           0 :     fd_sysvar_clock_write( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, &sysvar_clock );
     236           0 :   }
     237             : 
     238             :   /* Epoch schedule */
     239             :   // https://github.com/firedancer-io/solfuzz-agave/blob/agave-v2.0/src/lib.rs#L476-L483
     240           0 :   fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_epoch_schedule_read( funk, funk_txn, runner->spad );
     241           0 :   if( !epoch_schedule ) {
     242           0 :     fd_epoch_schedule_t sysvar_epoch_schedule = {
     243           0 :                                                   .slots_per_epoch             = 432000UL,
     244           0 :                                                   .leader_schedule_slot_offset = 432000UL,
     245           0 :                                                   .warmup                      = 1,
     246           0 :                                                   .first_normal_epoch          = 14UL,
     247           0 :                                                   .first_normal_slot           = 524256UL
     248           0 :                                                 };
     249           0 :     fd_sysvar_epoch_schedule_write( slot_ctx, &sysvar_epoch_schedule );
     250           0 :   }
     251             : 
     252             :   /* Rent */
     253             :   // https://github.com/firedancer-io/solfuzz-agave/blob/agave-v2.0/src/lib.rs#L487-L500
     254           0 :   fd_rent_t const * rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad );
     255           0 :   if( !rent ) {
     256           0 :     fd_rent_t sysvar_rent = {
     257           0 :                               .lamports_per_uint8_year = 3480UL,
     258           0 :                               .exemption_threshold     = 2.0,
     259           0 :                               .burn_percent            = 50
     260           0 :                             };
     261           0 :     fd_sysvar_rent_write( slot_ctx, &sysvar_rent );
     262           0 :   }
     263             : 
     264           0 :   fd_sol_sysvar_last_restart_slot_t const * last_restart_slot = fd_sysvar_last_restart_slot_read( funk, funk_txn, runner->spad );
     265           0 :   if( !last_restart_slot ) {
     266             : 
     267           0 :     fd_sol_sysvar_last_restart_slot_t restart = { .slot = 5000UL };
     268             : 
     269           0 :     fd_sysvar_set( slot_ctx->bank,
     270           0 :                    slot_ctx->funk,
     271           0 :                    slot_ctx->funk_txn,
     272           0 :                    &fd_sysvar_owner_id,
     273           0 :                    &fd_sysvar_last_restart_slot_id,
     274           0 :                    &restart.slot,
     275           0 :                    sizeof(ulong),
     276           0 :                    slot_ctx->slot );
     277             : 
     278           0 :   }
     279             : 
     280             :   /* Set slot bank variables */
     281           0 :   clock = fd_sysvar_clock_read( funk, funk_txn, runner->spad );
     282             : 
     283           0 :   slot_ctx->slot = clock->slot;
     284           0 :   slot_ctx->bank->slot = clock->slot;
     285             : 
     286             :   /* Handle undefined behavior if sysvars are malicious (!!!) */
     287             : 
     288             :   /* Override epoch bank rent setting */
     289           0 :   rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad );
     290           0 :   if( rent ) {
     291           0 :     fd_bank_rent_set( slot_ctx->bank, *rent );
     292           0 :   }
     293             : 
     294             :   /* Override most recent blockhash if given */
     295           0 :   fd_recent_block_hashes_global_t const * rbh_global = fd_sysvar_recent_hashes_read( funk, funk_txn, runner->spad );
     296           0 :   fd_recent_block_hashes_t rbh[1];
     297           0 :   if( rbh_global ) {
     298           0 :     rbh->hashes = deq_fd_block_block_hash_entry_t_join( (uchar*)rbh_global + rbh_global->hashes_offset );
     299           0 :   }
     300             : 
     301           0 :   if( rbh_global && !deq_fd_block_block_hash_entry_t_empty( rbh->hashes ) ) {
     302           0 :     fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_tail_const( rbh->hashes );
     303           0 :     if( last ) {
     304           0 :       block_hash_queue = (fd_block_hash_queue_global_t *)&slot_ctx->bank->block_hash_queue[0];
     305           0 :       fd_hash_t * last_hash = fd_block_hash_queue_last_hash_join( block_hash_queue );
     306           0 :       fd_memcpy( last_hash, &last->blockhash, sizeof(fd_hash_t) );
     307             : 
     308           0 :       fd_bank_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature );
     309             : 
     310           0 :       fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature );
     311           0 :     }
     312           0 :   }
     313             : 
     314             :   /* Load instruction accounts */
     315             : 
     316           0 :   if( FD_UNLIKELY( test_ctx->instr_accounts_count > MAX_TX_ACCOUNT_LOCKS ) ) {
     317           0 :     FD_LOG_NOTICE(( "too many instruction accounts" ));
     318           0 :     return 0;
     319           0 :   }
     320             : 
     321           0 :   uchar acc_idx_seen[ FD_INSTR_ACCT_MAX ] = {0};
     322           0 :   for( ulong j=0UL; j < test_ctx->instr_accounts_count; j++ ) {
     323           0 :     uint index = test_ctx->instr_accounts[j].index;
     324           0 :     if( index >= test_ctx->accounts_count ) {
     325           0 :       FD_LOG_NOTICE( ( "instruction account index out of range (%u > %u)", index, test_ctx->instr_accounts_count ) );
     326           0 :       return 0;
     327           0 :     }
     328             : 
     329           0 :     fd_txn_account_t * acc = &accts[ index ];
     330             : 
     331             :     /* Setup instruction accounts */
     332           0 :     fd_instr_info_setup_instr_account( info,
     333           0 :                                        acc_idx_seen,
     334           0 :                                        (ushort)index,
     335           0 :                                        (ushort)j,
     336           0 :                                        (ushort)j,
     337           0 :                                        test_ctx->instr_accounts[j].is_writable,
     338           0 :                                        test_ctx->instr_accounts[j].is_signer );
     339             : 
     340           0 :     if( test_ctx->instr_accounts[j].is_writable ) {
     341           0 :       acc->vt->set_mutable( acc );
     342           0 :     }
     343           0 :   }
     344           0 :   info->acct_cnt = (uchar)test_ctx->instr_accounts_count;
     345             : 
     346             :   /* The remaining checks enforce that the program is in the accounts list. */
     347           0 :   bool found_program_id = false;
     348           0 :   for( uint i = 0; i < test_ctx->accounts_count; i++ ) {
     349           0 :     if( 0 == memcmp( test_ctx->accounts[i].address, test_ctx->program_id, sizeof(fd_pubkey_t) ) ) {
     350           0 :       info->program_id = (uchar) i;
     351           0 :       found_program_id = true;
     352           0 :       break;
     353           0 :     }
     354           0 :   }
     355             : 
     356             :   /* Early returning only happens in instruction execution. */
     357           0 :   if( !is_syscall && !found_program_id ) {
     358           0 :     FD_LOG_NOTICE(( " Unable to find program_id in accounts" ));
     359           0 :     return 0;
     360           0 :   }
     361             : 
     362           0 :   ctx->instr = info;
     363             : 
     364             :   /* Refresh the setup from the updated slot and epoch ctx. */
     365           0 :   fd_exec_txn_ctx_from_exec_slot_ctx( slot_ctx,
     366           0 :                                       txn_ctx,
     367           0 :                                       funk_wksp,
     368           0 :                                       runtime_wksp,
     369           0 :                                       funk_txn_gaddr,
     370           0 :                                       funk_gaddr,
     371           0 :                                       NULL );
     372             : 
     373           0 :   fd_log_collector_init( &ctx->txn_ctx->log_collector, 1 );
     374           0 :   fd_base58_encode_32( txn_ctx->account_keys[ ctx->instr->program_id ].uc, NULL, ctx->program_id_base58 );
     375             : 
     376           0 :   return 1;
     377           0 : }
     378             : 
     379             : 
     380             : 
     381             : void
     382             : fd_runtime_fuzz_instr_ctx_destroy( fd_runtime_fuzz_runner_t * runner,
     383           0 :                                    fd_exec_instr_ctx_t *      ctx ) {
     384           0 :   if( !ctx ) return;
     385           0 :   fd_funk_txn_t * funk_txn = ctx->txn_ctx->funk_txn;
     386             : 
     387           0 :   fd_funk_txn_cancel( runner->funk, funk_txn, 1 );
     388           0 : }
     389             : 
     390             : 
     391             : ulong
     392             : fd_runtime_fuzz_instr_run( fd_runtime_fuzz_runner_t * runner,
     393             :                            void const *               input_,
     394             :                            void **                    output_,
     395             :                            void *                     output_buf,
     396           0 :                            ulong                      output_bufsz ) {
     397           0 :   fd_exec_test_instr_context_t const * input  = fd_type_pun_const( input_ );
     398           0 :   fd_exec_test_instr_effects_t **      output = fd_type_pun( output_ );
     399             : 
     400             :   /* Convert the Protobuf inputs to a fd_exec context */
     401           0 :   fd_exec_instr_ctx_t ctx[1];
     402           0 :   if( !fd_runtime_fuzz_instr_ctx_create( runner, ctx, input, false ) ) {
     403           0 :     fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
     404           0 :     return 0UL;
     405           0 :   }
     406             : 
     407           0 :   fd_instr_info_t * instr = (fd_instr_info_t *) ctx->instr;
     408             : 
     409             :   /* Execute the test */
     410           0 :   int exec_result = fd_execute_instr(ctx->txn_ctx, instr);
     411             : 
     412             :   /* Allocate space to capture outputs */
     413             : 
     414           0 :   ulong output_end = (ulong)output_buf + output_bufsz;
     415           0 :   FD_SCRATCH_ALLOC_INIT( l, output_buf );
     416             : 
     417           0 :   fd_exec_test_instr_effects_t * effects =
     418           0 :     FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_instr_effects_t),
     419           0 :                                 sizeof (fd_exec_test_instr_effects_t) );
     420           0 :   if( FD_UNLIKELY( _l > output_end ) ) {
     421           0 :     fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
     422           0 :     return 0UL;
     423           0 :   }
     424           0 :   fd_memset( effects, 0, sizeof(fd_exec_test_instr_effects_t) );
     425             : 
     426             :   /* Capture error code */
     427             : 
     428           0 :   effects->result   = -exec_result;
     429           0 :   effects->cu_avail = ctx->txn_ctx->compute_meter;
     430             : 
     431           0 :   if( exec_result == FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR ) {
     432           0 :     effects->custom_err     = ctx->txn_ctx->custom_err;
     433           0 :   }
     434             : 
     435             :   /* Allocate space for captured accounts */
     436           0 :   ulong modified_acct_cnt = ctx->txn_ctx->accounts_cnt;
     437             : 
     438           0 :   fd_exec_test_acct_state_t * modified_accts =
     439           0 :     FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_acct_state_t),
     440           0 :                                 sizeof (fd_exec_test_acct_state_t) * modified_acct_cnt );
     441           0 :   if( FD_UNLIKELY( _l > output_end ) ) {
     442           0 :     fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
     443           0 :     return 0;
     444           0 :   }
     445           0 :   effects->modified_accounts       = modified_accts;
     446           0 :   effects->modified_accounts_count = 0UL;
     447             : 
     448             :   /* Capture borrowed accounts */
     449             : 
     450           0 :   for( ulong j=0UL; j < ctx->txn_ctx->accounts_cnt; j++ ) {
     451           0 :     fd_txn_account_t * acc = &ctx->txn_ctx->accounts[j];
     452           0 :     if( !acc->vt->get_meta( acc ) ) {
     453           0 :       continue;
     454           0 :     }
     455             : 
     456           0 :     ulong modified_idx = effects->modified_accounts_count;
     457           0 :     assert( modified_idx < modified_acct_cnt );
     458             : 
     459           0 :     fd_exec_test_acct_state_t * out_acct = &effects->modified_accounts[ modified_idx ];
     460           0 :     memset( out_acct, 0, sizeof(fd_exec_test_acct_state_t) );
     461             :     /* Copy over account content */
     462             : 
     463           0 :     memcpy( out_acct->address, acc->pubkey, sizeof(fd_pubkey_t) );
     464           0 :     out_acct->lamports = acc->vt->get_lamports( acc );
     465           0 :     if( acc->vt->get_data_len( acc )>0UL ) {
     466           0 :       out_acct->data =
     467           0 :         FD_SCRATCH_ALLOC_APPEND( l, alignof(pb_bytes_array_t),
     468           0 :                                     PB_BYTES_ARRAY_T_ALLOCSIZE( acc->vt->get_data_len( acc ) ) );
     469           0 :       if( FD_UNLIKELY( _l > output_end ) ) {
     470           0 :         fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
     471           0 :         return 0UL;
     472           0 :       }
     473           0 :       out_acct->data->size = (pb_size_t)acc->vt->get_data_len( acc );
     474           0 :       fd_memcpy( out_acct->data->bytes, acc->vt->get_data( acc ), acc->vt->get_data_len( acc ) );
     475           0 :     }
     476             : 
     477           0 :     out_acct->executable     = acc->vt->is_executable( acc );
     478           0 :     out_acct->rent_epoch     = acc->vt->get_rent_epoch( acc );
     479           0 :     memcpy( out_acct->owner, acc->vt->get_owner( acc ), sizeof(fd_pubkey_t) );
     480             : 
     481           0 :     effects->modified_accounts_count++;
     482           0 :   }
     483             : 
     484             :   /* Capture return data */
     485           0 :   fd_txn_return_data_t * return_data = &ctx->txn_ctx->return_data;
     486           0 :   if( return_data->len>0UL ) {
     487           0 :     effects->return_data = FD_SCRATCH_ALLOC_APPEND(l, alignof(pb_bytes_array_t),
     488           0 :                                 PB_BYTES_ARRAY_T_ALLOCSIZE( return_data->len ) );
     489           0 :     if( FD_UNLIKELY( _l > output_end ) ) {
     490           0 :       fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
     491           0 :       return 0UL;
     492           0 :     }
     493           0 :     effects->return_data->size = (pb_size_t)return_data->len;
     494           0 :     fd_memcpy( effects->return_data->bytes, return_data->data, return_data->len );
     495           0 :   }
     496             : 
     497           0 :   ulong actual_end = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     498           0 :   fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
     499             : 
     500           0 :   *output = effects;
     501           0 :   return actual_end - (ulong)output_buf;
     502             : 
     503           0 : }

Generated by: LCOV version 1.14