LCOV - code coverage report
Current view: top level - flamenco/runtime/tests - fd_block_harness.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 352 0.0 %
Date: 2025-09-19 04:41:14 Functions: 0 8 0.0 %

          Line data    Source code
       1             : #include "fd_solfuzz_private.h"
       2             : #include "../fd_cost_tracker.h"
       3             : #include "fd_txn_harness.h"
       4             : #include "../fd_runtime.h"
       5             : #include "../fd_system_ids.h"
       6             : #include "../fd_txn_account.h"
       7             : #include "../context/fd_exec_slot_ctx.h"
       8             : #include "../info/fd_runtime_block_info.h"
       9             : #include "../program/fd_stake_program.h"
      10             : #include "../program/fd_vote_program.h"
      11             : #include "../sysvar/fd_sysvar_epoch_schedule.h"
      12             : #include "../sysvar/fd_sysvar_rent.h"
      13             : #include "../sysvar/fd_sysvar_recent_hashes.h"
      14             : #include "../../rewards/fd_rewards.h"
      15             : #include "../../stakes/fd_stakes.h"
      16             : #include "../../types/fd_types.h"
      17             : #include "../../../disco/pack/fd_pack.h"
      18             : #include "generated/block.pb.h"
      19             : 
      20             : /* Stripped down version of `fd_refresh_vote_accounts()` that simply refreshes the stake delegation amount
      21             :    for each of the vote accounts using the stake delegations cache. */
      22             : static void
      23             : fd_runtime_fuzz_block_refresh_vote_accounts( fd_vote_states_t *       vote_states,
      24           0 :                                              fd_stake_delegations_t * stake_delegations ) {
      25           0 :   fd_stake_delegations_iter_t iter_[1];
      26           0 :   for( fd_stake_delegations_iter_t * iter = fd_stake_delegations_iter_init( iter_, stake_delegations );
      27           0 :        !fd_stake_delegations_iter_done( iter );
      28           0 :        fd_stake_delegations_iter_next( iter ) ) {
      29           0 :     fd_stake_delegation_t * node = fd_stake_delegations_iter_ele( iter );
      30             : 
      31           0 :     fd_pubkey_t * voter_pubkey = &node->vote_account;
      32           0 :     ulong         stake        = node->stake;
      33             : 
      34             :     /* Find the voter in the vote accounts cache and update their
      35             :        delegation amount */
      36           0 :     fd_vote_state_ele_t * vote_state = fd_vote_states_query( vote_states, voter_pubkey );
      37           0 :     if( !vote_state ) continue;
      38             : 
      39           0 :     ulong vote_stake = vote_state->stake;
      40           0 :     fd_vote_states_update_stake( vote_states, voter_pubkey, vote_stake + stake );
      41             : 
      42           0 :   }
      43           0 : }
      44             : 
      45             : /* Registers a single vote account into the current votes cache. The entry is derived
      46             :    from the current present account state. This function also registers a vote timestamp
      47             :    for the vote account */
      48             : static void
      49             : fd_runtime_fuzz_block_register_vote_account( fd_exec_slot_ctx_t * slot_ctx,
      50             :                                              fd_vote_states_t *   vote_states,
      51             :                                              fd_pubkey_t *        pubkey,
      52           0 :                                              fd_spad_t *          spad ) {
      53           0 :   FD_TXN_ACCOUNT_DECL( acc );
      54           0 :   if( FD_UNLIKELY( fd_txn_account_init_from_funk_readonly( acc, pubkey, slot_ctx->funk, slot_ctx->funk_txn ) ) ) {
      55           0 :     return;
      56           0 :   }
      57             : 
      58             :   /* Account must be owned by the vote program */
      59           0 :   if( memcmp( fd_txn_account_get_owner( acc ), fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) ) {
      60           0 :     return;
      61           0 :   }
      62             : 
      63             :   /* Account must have > 0 lamports */
      64           0 :   if( fd_txn_account_get_lamports( acc )==0UL ) {
      65           0 :     return;
      66           0 :   }
      67             : 
      68             :   /* Account must be initialized correctly */
      69           0 :   if( FD_UNLIKELY( !fd_vote_state_versions_is_correct_and_initialized( acc ) ) ) {
      70           0 :     return;
      71           0 :   }
      72             : 
      73             :   /* Get the vote state from the account data */
      74           0 :   fd_vote_state_versioned_t * vsv = NULL;
      75           0 :   int err = fd_vote_get_state( acc, spad, &vsv );
      76           0 :   if( FD_UNLIKELY( err ) ) {
      77           0 :     return;
      78           0 :   }
      79             : 
      80           0 :   fd_vote_states_update_from_account(
      81           0 :       vote_states,
      82           0 :       acc->pubkey,
      83           0 :       fd_txn_account_get_data( acc ),
      84           0 :       fd_txn_account_get_data_len( acc ) );
      85           0 : }
      86             : 
      87             : /* Stores an entry in the stake delegations cache for the given vote account. Deserializes and uses the present
      88             :    account state to derive delegation information. */
      89             : static void
      90             : fd_runtime_fuzz_block_register_stake_delegation( fd_exec_slot_ctx_t *     slot_ctx,
      91             :                                                  fd_stake_delegations_t * stake_delegations,
      92           0 :                                                  fd_pubkey_t *            pubkey ) {
      93           0 :  FD_TXN_ACCOUNT_DECL( acc );
      94           0 :   if( FD_UNLIKELY( fd_txn_account_init_from_funk_readonly( acc, pubkey, slot_ctx->funk, slot_ctx->funk_txn ) ) ) {
      95           0 :     return;
      96           0 :   }
      97             : 
      98             :   /* Account must be owned by the stake program */
      99           0 :   if( memcmp( fd_txn_account_get_owner( acc ), fd_solana_stake_program_id.key, sizeof(fd_pubkey_t) ) ) {
     100           0 :     return;
     101           0 :   }
     102             : 
     103             :   /* Account must have > 0 lamports */
     104           0 :   if( fd_txn_account_get_lamports( acc )==0UL ) {
     105           0 :     return;
     106           0 :   }
     107             : 
     108             :   /* Stake state must exist and be initialized correctly */
     109           0 :   fd_stake_state_v2_t stake_state;
     110           0 :   if( FD_UNLIKELY( fd_stake_get_state( acc, &stake_state ) || !fd_stake_state_v2_is_stake( &stake_state ) ) ) {
     111           0 :     return;
     112           0 :   }
     113             : 
     114             :   /* Skip 0-stake accounts */
     115           0 :   if( FD_UNLIKELY( stake_state.inner.stake.stake.delegation.stake==0UL ) ) {
     116           0 :     return;
     117           0 :   }
     118             : 
     119             :   /* Nothing to do if the account already exists in the cache */
     120           0 :   fd_stake_delegations_update(
     121           0 :       stake_delegations,
     122           0 :       pubkey,
     123           0 :       &stake_state.inner.stake.stake.delegation.voter_pubkey,
     124           0 :       stake_state.inner.stake.stake.delegation.stake,
     125           0 :       stake_state.inner.stake.stake.delegation.activation_epoch,
     126           0 :       stake_state.inner.stake.stake.delegation.deactivation_epoch,
     127           0 :       stake_state.inner.stake.stake.credits_observed,
     128           0 :       stake_state.inner.stake.stake.delegation.warmup_cooldown_rate );
     129           0 : }
     130             : 
     131             : /* Common helper method for populating a previous epoch's vote cache. */
     132             : static void
     133             : fd_runtime_fuzz_block_update_prev_epoch_votes_cache( fd_vote_states_t *            vote_states,
     134             :                                                      fd_exec_test_vote_account_t * vote_accounts,
     135             :                                                      pb_size_t                     vote_accounts_cnt,
     136           0 :                                                      fd_spad_t *                   spad ) {
     137           0 :   FD_SPAD_FRAME_BEGIN( spad ) {
     138           0 :     for( uint i=0U; i<vote_accounts_cnt; i++ ) {
     139           0 :       fd_exec_test_acct_state_t * vote_account  = &vote_accounts[i].vote_account;
     140           0 :       ulong                       stake         = vote_accounts[i].stake;
     141           0 :       uchar *                     vote_data     = vote_account->data->bytes;
     142           0 :       ulong                       vote_data_len = vote_account->data->size;
     143           0 :       fd_pubkey_t                 vote_address  = {0};
     144           0 :       fd_memcpy( &vote_address, vote_account->address, sizeof(fd_pubkey_t) );
     145             : 
     146             :       /* Try decoding the vote state from the account data. If it isn't
     147             :          decodable, don't try inserting it into the cache. */
     148           0 :       fd_vote_state_versioned_t * res = fd_bincode_decode_spad(
     149           0 :           vote_state_versioned, spad,
     150           0 :           vote_data,
     151           0 :           vote_data_len,
     152           0 :           NULL );
     153           0 :       if( res==NULL ) continue;
     154             : 
     155           0 :       fd_vote_states_update_from_account( vote_states, &vote_address, vote_data, vote_data_len );
     156           0 :       fd_vote_states_update_stake( vote_states, &vote_address, stake );
     157           0 :     }
     158           0 :   } FD_SPAD_FRAME_END;
     159           0 : }
     160             : 
     161             : static void
     162           0 : fd_runtime_fuzz_block_ctx_destroy( fd_solfuzz_runner_t * runner ) {
     163           0 :   fd_funk_txn_cancel_all( runner->funk, 1 );
     164           0 : }
     165             : 
     166             : /* Sets up block execution context from an input test case to execute against the runtime.
     167             :    Returns block_info on success and NULL on failure. */
     168             : static fd_runtime_block_info_t *
     169             : fd_runtime_fuzz_block_ctx_create( fd_solfuzz_runner_t *                runner,
     170             :                                   fd_exec_slot_ctx_t *                 slot_ctx,
     171           0 :                                   fd_exec_test_block_context_t const * test_ctx ) {
     172           0 :   fd_funk_t * funk = runner->funk;
     173             : 
     174           0 :   slot_ctx->banks = runner->banks;
     175           0 :   slot_ctx->bank  = runner->bank;
     176           0 :   fd_banks_clear_bank( slot_ctx->banks, slot_ctx->bank );
     177             : 
     178             :   /* Generate unique ID for funk txn */
     179           0 :   fd_funk_txn_xid_t xid[1] = {0};
     180           0 :   xid[0] = fd_funk_generate_xid();
     181             : 
     182             :   /* Create temporary funk transaction and slot / epoch contexts */
     183           0 :   fd_funk_txn_start_write( funk );
     184           0 :   fd_funk_txn_t * funk_txn = fd_funk_txn_prepare( funk, NULL, xid, 1 );
     185           0 :   fd_funk_txn_end_write( funk );
     186             : 
     187             :   /* Restore feature flags */
     188           0 :   fd_features_t features = {0};
     189           0 :   if( !fd_runtime_fuzz_restore_features( &features, &test_ctx->epoch_ctx.features ) ) {
     190           0 :     return NULL;
     191           0 :   }
     192           0 :   fd_bank_features_set( slot_ctx->bank, features );
     193             : 
     194             :   /* Set up slot context */
     195           0 :   ulong slot = test_ctx->slot_ctx.slot;
     196             : 
     197           0 :   slot_ctx->funk_txn = funk_txn;
     198           0 :   slot_ctx->funk     = funk;
     199           0 :   slot_ctx->silent   = 1;
     200             : 
     201           0 :   fd_hash_t * bank_hash = fd_bank_bank_hash_modify( slot_ctx->bank );
     202           0 :   fd_memcpy( bank_hash, test_ctx->slot_ctx.parent_bank_hash, sizeof(fd_hash_t) );
     203             : 
     204             :   /* All bank mgr stuff here. */
     205             : 
     206           0 :   slot_ctx->bank->eslot_ = fd_eslot( slot, 0UL );
     207             : 
     208           0 :   fd_bank_block_height_set( slot_ctx->bank, test_ctx->slot_ctx.block_height );
     209             : 
     210           0 :   fd_bank_parent_eslot_set( slot_ctx->bank, fd_eslot( test_ctx->slot_ctx.prev_slot, 0UL ) );
     211             : 
     212           0 :   fd_bank_capitalization_set( slot_ctx->bank, test_ctx->slot_ctx.prev_epoch_capitalization );
     213             : 
     214           0 :   fd_bank_lamports_per_signature_set( slot_ctx->bank, 5000UL );
     215             : 
     216           0 :   fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, test_ctx->slot_ctx.prev_lps );
     217             : 
     218             :   // self.max_tick_height = (self.slot + 1) * self.ticks_per_slot;
     219           0 :   fd_bank_hashes_per_tick_set( slot_ctx->bank, test_ctx->epoch_ctx.hashes_per_tick );
     220             : 
     221           0 :   fd_bank_ticks_per_slot_set( slot_ctx->bank, test_ctx->epoch_ctx.ticks_per_slot );
     222             : 
     223           0 :   fd_bank_ns_per_slot_set( slot_ctx->bank, 400000000 ); // TODO: restore from input
     224             : 
     225           0 :   fd_bank_genesis_creation_time_set( slot_ctx->bank, test_ctx->epoch_ctx.genesis_creation_time );
     226             : 
     227           0 :   fd_bank_slots_per_year_set( slot_ctx->bank, test_ctx->epoch_ctx.slots_per_year );
     228             : 
     229           0 :   fd_bank_parent_signature_cnt_set( slot_ctx->bank, test_ctx->slot_ctx.parent_signature_count );
     230             : 
     231           0 :   fd_fee_rate_governor_t * fee_rate_governor = fd_bank_fee_rate_governor_modify( slot_ctx->bank );
     232           0 :   *fee_rate_governor = (fd_fee_rate_governor_t){
     233           0 :     .target_lamports_per_signature = test_ctx->slot_ctx.fee_rate_governor.target_lamports_per_signature,
     234           0 :     .target_signatures_per_slot    = test_ctx->slot_ctx.fee_rate_governor.target_signatures_per_slot,
     235           0 :     .min_lamports_per_signature    = test_ctx->slot_ctx.fee_rate_governor.min_lamports_per_signature,
     236           0 :     .max_lamports_per_signature    = test_ctx->slot_ctx.fee_rate_governor.max_lamports_per_signature,
     237           0 :     .burn_percent                  = (uchar)test_ctx->slot_ctx.fee_rate_governor.burn_percent
     238           0 :   };
     239             : 
     240           0 :   fd_inflation_t * inflation = fd_bank_inflation_modify( slot_ctx->bank );
     241           0 :   *inflation = (fd_inflation_t){
     242           0 :     .initial         = test_ctx->epoch_ctx.inflation.initial,
     243           0 :     .terminal        = test_ctx->epoch_ctx.inflation.terminal,
     244           0 :     .taper           = test_ctx->epoch_ctx.inflation.taper,
     245           0 :     .foundation      = test_ctx->epoch_ctx.inflation.foundation,
     246           0 :     .foundation_term = test_ctx->epoch_ctx.inflation.foundation_term
     247           0 :   };
     248             : 
     249           0 :   fd_bank_block_height_set( slot_ctx->bank, test_ctx->slot_ctx.block_height );
     250             : 
     251             :   /* Initialize the current running epoch stake and vote accounts */
     252             : 
     253             :   /* SETUP STAKES HERE */
     254           0 :   fd_vote_states_t * vote_states = fd_bank_vote_states_locking_modify( slot_ctx->bank );
     255           0 :   vote_states = fd_vote_states_join( fd_vote_states_new( vote_states, FD_RUNTIME_MAX_VOTE_ACCOUNTS, 999UL ) );
     256           0 :   fd_bank_vote_states_end_locking_modify( slot_ctx->bank );
     257             : 
     258           0 :   fd_vote_states_t * vote_states_prev = fd_bank_vote_states_prev_locking_modify( slot_ctx->bank );
     259           0 :   vote_states_prev = fd_vote_states_join( fd_vote_states_new( vote_states_prev, FD_RUNTIME_MAX_VOTE_ACCOUNTS, 999UL ) );
     260           0 :   fd_bank_vote_states_prev_end_locking_modify( slot_ctx->bank );
     261             : 
     262           0 :   fd_vote_states_t * vote_states_prev_prev = fd_bank_vote_states_prev_prev_locking_modify( slot_ctx->bank );
     263           0 :   vote_states_prev_prev = fd_vote_states_join( fd_vote_states_new( vote_states_prev_prev, FD_RUNTIME_MAX_VOTE_ACCOUNTS, 999UL ) );
     264           0 :   fd_bank_vote_states_prev_prev_end_locking_modify( slot_ctx->bank );
     265             : 
     266           0 :   fd_stake_delegations_t * stake_delegations = fd_banks_stake_delegations_root_query( slot_ctx->banks );
     267           0 :   stake_delegations = fd_stake_delegations_join( fd_stake_delegations_new( stake_delegations, FD_RUNTIME_MAX_STAKE_ACCOUNTS, 0 ) );
     268             : 
     269             :   /* Load in all accounts with > 0 lamports provided in the context. The input expects unique account pubkeys. */
     270           0 :   vote_states = fd_bank_vote_states_locking_modify( slot_ctx->bank );
     271           0 :   for( ushort i=0; i<test_ctx->acct_states_count; i++ ) {
     272           0 :     FD_TXN_ACCOUNT_DECL(acc);
     273           0 :     fd_runtime_fuzz_load_account( acc, funk, funk_txn, &test_ctx->acct_states[i], 1 );
     274             : 
     275             :     /* Update vote accounts cache for epoch T */
     276           0 :     fd_pubkey_t pubkey;
     277           0 :     memcpy( &pubkey, test_ctx->acct_states[i].address, sizeof(fd_pubkey_t) );
     278           0 :     fd_runtime_fuzz_block_register_vote_account(
     279           0 :         slot_ctx,
     280           0 :         vote_states,
     281           0 :         &pubkey,
     282           0 :         runner->spad );
     283             : 
     284             :     /* Update the stake delegations cache for epoch T */
     285           0 :     fd_runtime_fuzz_block_register_stake_delegation( slot_ctx,
     286           0 :                                                      stake_delegations,
     287           0 :                                                      &pubkey );
     288           0 :   }
     289             : 
     290             :   /* Refresh vote accounts to calculate stake delegations */
     291           0 :   fd_runtime_fuzz_block_refresh_vote_accounts( vote_states, stake_delegations );
     292           0 :   fd_bank_vote_states_end_locking_modify( slot_ctx->bank );
     293             : 
     294             :   /* Finish init epoch bank sysvars */
     295           0 :   fd_epoch_schedule_t epoch_schedule_[1];
     296           0 :   fd_epoch_schedule_t * epoch_schedule = fd_sysvar_epoch_schedule_read( funk, funk_txn, epoch_schedule_ );
     297           0 :   fd_bank_epoch_schedule_set( slot_ctx->bank, *epoch_schedule );
     298             : 
     299           0 :   fd_rent_t const * rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad );
     300           0 :   fd_bank_rent_set( slot_ctx->bank, *rent );
     301             : 
     302           0 :   fd_bank_epoch_set( slot_ctx->bank, fd_slot_to_epoch( epoch_schedule, test_ctx->slot_ctx.prev_slot, NULL ) );
     303             : 
     304             : 
     305             :   /* Refresh the program cache */
     306           0 :   fd_runtime_fuzz_refresh_program_cache( slot_ctx, test_ctx->acct_states, test_ctx->acct_states_count, runner->spad );
     307             : 
     308             :   /* Update vote cache for epoch T-1 */
     309           0 :   vote_states_prev = fd_bank_vote_states_prev_locking_modify( slot_ctx->bank );
     310           0 :   fd_runtime_fuzz_block_update_prev_epoch_votes_cache( vote_states_prev,
     311           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_1,
     312           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_1_count,
     313           0 :                                                        runner->spad );
     314           0 :   fd_bank_vote_states_prev_end_locking_modify( slot_ctx->bank );
     315             : 
     316             :   /* Update vote cache for epoch T-2 */
     317           0 :   vote_states_prev_prev = fd_bank_vote_states_prev_prev_locking_modify( slot_ctx->bank );
     318           0 :   fd_runtime_fuzz_block_update_prev_epoch_votes_cache( vote_states_prev_prev,
     319           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_2,
     320           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_2_count,
     321           0 :                                                        runner->spad );
     322           0 :   fd_bank_vote_states_prev_prev_end_locking_modify( slot_ctx->bank );
     323             : 
     324             :   /* Update leader schedule */
     325           0 :   fd_runtime_update_leaders( slot_ctx->bank, fd_bank_slot_get( slot_ctx->bank ), runner->spad );
     326             : 
     327             :   /* Initialize the blockhash queue and recent blockhashes sysvar from the input blockhash queue */
     328           0 :   ulong blockhash_seed; FD_TEST( fd_rng_secure( &blockhash_seed, sizeof(ulong) ) );
     329           0 :   fd_blockhashes_init( fd_bank_block_hash_queue_modify( slot_ctx->bank ), blockhash_seed );
     330             : 
     331             :   /* TODO: We might need to load this in from the input. We also need to
     332             :      size this out for worst case, but this also blows up the memory
     333             :      requirement. */
     334             :   /* Allocate all the memory for the rent fresh accounts list */
     335             : 
     336             :   // Set genesis hash to {0}
     337           0 :   fd_hash_t * genesis_hash = fd_bank_genesis_hash_modify( slot_ctx->bank );
     338           0 :   fd_memset( genesis_hash->hash, 0, sizeof(fd_hash_t) );
     339             : 
     340             :   // Use the latest lamports per signature
     341           0 :   fd_recent_block_hashes_t const * rbh = fd_sysvar_recent_hashes_read( funk, funk_txn, runner->spad );
     342           0 :   if( rbh && !deq_fd_block_block_hash_entry_t_empty( rbh->hashes ) ) {
     343           0 :     fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_head_const( rbh->hashes );
     344           0 :     if( last && last->fee_calculator.lamports_per_signature!=0UL ) {
     345           0 :       fd_bank_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature );
     346           0 :       fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature );
     347           0 :     }
     348           0 :   }
     349             : 
     350             :   /* Make a new funk transaction since we're done loading in accounts for context */
     351           0 :   fd_funk_txn_xid_t fork_xid = { .ul = { slot, slot } };
     352           0 :   fd_funk_txn_start_write( funk );
     353           0 :   slot_ctx->funk_txn = fd_funk_txn_prepare( funk, slot_ctx->funk_txn, &fork_xid, 1 );
     354           0 :   fd_funk_txn_end_write( funk );
     355             : 
     356             :   /* Reset the lthash to zero, because we are in a new Funk transaction now */
     357           0 :   fd_lthash_value_t lthash = {0};
     358           0 :   fd_bank_lthash_set( slot_ctx->bank, lthash );
     359             : 
     360             :   // Populate blockhash queue and recent blockhashes sysvar
     361           0 :   for( ushort i=0; i<test_ctx->blockhash_queue_count; ++i ) {
     362           0 :     fd_hash_t hash;
     363           0 :     memcpy( &hash, test_ctx->blockhash_queue[i]->bytes, sizeof(fd_hash_t) );
     364           0 :     fd_bank_poh_set( slot_ctx->bank, hash );
     365           0 :     fd_sysvar_recent_hashes_update( slot_ctx ); /* appends an entry */
     366           0 :   }
     367             : 
     368             :   // Set the current poh from the input (we skip POH verification in this fuzzing target)
     369           0 :   fd_hash_t * poh = fd_bank_poh_modify( slot_ctx->bank );
     370           0 :   fd_memcpy( poh->hash, test_ctx->slot_ctx.poh, sizeof(fd_hash_t) );
     371             : 
     372             :   /* Restore sysvar cache */
     373           0 :   fd_sysvar_cache_restore_fuzz( slot_ctx );
     374             : 
     375             :   /* Prepare raw transaction pointers and block / microblock infos */
     376           0 :   ulong txn_cnt = test_ctx->txns_count;
     377             : 
     378             :   // For fuzzing, we're using a single microblock batch that contains a single microblock containing all transactions
     379           0 :   fd_runtime_block_info_t *    block_info       = fd_spad_alloc( runner->spad, alignof(fd_runtime_block_info_t), sizeof(fd_runtime_block_info_t) );
     380           0 :   fd_microblock_batch_info_t * batch_info       = fd_spad_alloc( runner->spad, alignof(fd_microblock_batch_info_t), sizeof(fd_microblock_batch_info_t) );
     381           0 :   fd_microblock_info_t *       microblock_info  = fd_spad_alloc( runner->spad, alignof(fd_microblock_info_t), sizeof(fd_microblock_info_t) );
     382           0 :   fd_memset( block_info, 0, sizeof(fd_runtime_block_info_t) );
     383           0 :   fd_memset( batch_info, 0, sizeof(fd_microblock_batch_info_t) );
     384           0 :   fd_memset( microblock_info, 0, sizeof(fd_microblock_info_t) );
     385             : 
     386           0 :   block_info->microblock_batch_cnt   = 1UL;
     387           0 :   block_info->microblock_cnt         = 1UL;
     388           0 :   block_info->microblock_batch_infos = batch_info;
     389             : 
     390           0 :   batch_info->microblock_cnt         = 1UL;
     391           0 :   batch_info->microblock_infos       = microblock_info;
     392             : 
     393           0 :   ulong batch_signature_cnt          = 0UL;
     394           0 :   ulong batch_txn_cnt                = 0UL;
     395           0 :   ulong batch_account_cnt            = 0UL;
     396           0 :   ulong signature_cnt                = 0UL;
     397           0 :   ulong account_cnt                  = 0UL;
     398             : 
     399           0 :   fd_microblock_hdr_t * microblock_hdr = fd_spad_alloc( runner->spad, alignof(fd_microblock_hdr_t), sizeof(fd_microblock_hdr_t) );
     400           0 :   fd_memset( microblock_hdr, 0, sizeof(fd_microblock_hdr_t) );
     401             : 
     402           0 :   fd_txn_p_t * txn_ptrs = fd_spad_alloc( runner->spad, alignof(fd_txn_p_t), txn_cnt * sizeof(fd_txn_p_t) );
     403           0 :   for( ulong i=0UL; i<txn_cnt; i++ ) {
     404           0 :     fd_txn_p_t * txn    = &txn_ptrs[i];
     405           0 :     ulong        msg_sz = fd_runtime_fuzz_serialize_txn( txn->payload, &test_ctx->txns[i] );
     406             : 
     407             :     // Reject any transactions over 1232 bytes
     408           0 :     if( FD_UNLIKELY( msg_sz==ULONG_MAX ) ) {
     409           0 :       return NULL;
     410           0 :     }
     411           0 :     txn->payload_sz = msg_sz;
     412             : 
     413             :     // Reject any transactions that cannot be parsed
     414           0 :     if( FD_UNLIKELY( !fd_txn_parse( txn->payload, msg_sz, TXN( txn ), NULL ) ) ) {
     415           0 :       return NULL;
     416           0 :     }
     417             : 
     418           0 :     signature_cnt += TXN( txn )->signature_cnt;
     419           0 :     account_cnt   += fd_txn_account_cnt( TXN( txn ), FD_TXN_ACCT_CAT_ALL );
     420           0 :   }
     421             : 
     422           0 :   microblock_hdr->txn_cnt         = txn_cnt;
     423           0 :   microblock_info->microblock.raw = (uchar *)microblock_hdr;
     424             : 
     425           0 :   microblock_info->signature_cnt  = signature_cnt;
     426           0 :   microblock_info->account_cnt    = account_cnt;
     427           0 :   microblock_info->txns           = txn_ptrs;
     428             : 
     429           0 :   batch_signature_cnt            += signature_cnt;
     430           0 :   batch_txn_cnt                  += txn_cnt;
     431           0 :   batch_account_cnt              += account_cnt;
     432             : 
     433           0 :   block_info->signature_cnt = batch_info->signature_cnt = batch_signature_cnt;
     434           0 :   block_info->txn_cnt       = batch_info->txn_cnt       = batch_txn_cnt;
     435           0 :   block_info->account_cnt   = batch_info->account_cnt   = batch_account_cnt;
     436             : 
     437           0 :   return block_info;
     438           0 : }
     439             : 
     440             : /* Takes in a block_info created from `fd_runtime_fuzz_block_ctx_create()`
     441             :    and executes it against the runtime. Returns the execution result. */
     442             : static int
     443             : fd_runtime_fuzz_block_ctx_exec( fd_solfuzz_runner_t *      runner,
     444             :                                 fd_exec_slot_ctx_t *       slot_ctx,
     445           0 :                                 fd_runtime_block_info_t *  block_info ) {
     446           0 :   int res = 0;
     447             : 
     448             :   // Prepare. Execute. Finalize.
     449           0 :   FD_SPAD_FRAME_BEGIN( runner->spad ) {
     450           0 :     fd_capture_ctx_t * capture_ctx = NULL;
     451           0 :     fd_capture_ctx_t capture_ctx_[1];
     452           0 :     if( runner->solcap ) {
     453           0 :       capture_ctx_[0] = (fd_capture_ctx_t) {
     454           0 :         .capture            = runner->solcap,
     455           0 :         .capture_txns       = 1,
     456           0 :         .dump_instr_to_pb   = 1,
     457           0 :         .dump_txn_to_pb     = 1,
     458           0 :         .dump_block_to_pb   = 1,
     459           0 :         .dump_syscall_to_pb = 1,
     460           0 :         .dump_elf_to_pb     = 1
     461           0 :       };
     462           0 :       capture_ctx = capture_ctx_;
     463           0 :     }
     464           0 :     if( capture_ctx ) {
     465           0 :       slot_ctx->capture_ctx = capture_ctx;
     466           0 :       fd_solcap_writer_set_slot( slot_ctx->capture_ctx->capture, fd_bank_slot_get( slot_ctx->bank ) );
     467           0 :     }
     468             : 
     469           0 :     fd_rewards_recalculate_partitioned_rewards( slot_ctx, capture_ctx, runner->spad );
     470             : 
     471             :     /* Process new epoch may push a new spad frame onto the runtime spad. We should make sure this frame gets
     472             :        cleared (if it was allocated) before executing the block. */
     473           0 :     int is_epoch_boundary = 0;
     474           0 :     fd_runtime_block_pre_execute_process_new_epoch( slot_ctx, capture_ctx, runner->spad, &is_epoch_boundary );
     475             : 
     476           0 :     res = fd_runtime_block_execute_prepare( slot_ctx, runner->spad );
     477           0 :     if( FD_UNLIKELY( res ) ) {
     478           0 :       return res;
     479           0 :     }
     480             : 
     481           0 :     fd_txn_p_t * txn_ptrs = block_info->microblock_batch_infos[0].microblock_infos[0].txns;
     482           0 :     ulong        txn_cnt  = block_info->microblock_batch_infos[0].txn_cnt;
     483             : 
     484             :     /* Sequential transaction execution */
     485           0 :     for( ulong i=0UL; i<txn_cnt; i++ ) {
     486           0 :       fd_txn_p_t * txn = &txn_ptrs[i];
     487             : 
     488             :       /* Update the program cache */
     489           0 :       fd_runtime_update_program_cache( slot_ctx, txn, runner->spad );
     490             : 
     491             :       /* Execute the transaction against the runtime */
     492           0 :       res = FD_RUNTIME_EXECUTE_SUCCESS;
     493           0 :       fd_exec_txn_ctx_t * txn_ctx = fd_runtime_fuzz_txn_ctx_exec( runner, slot_ctx, txn, &res );
     494           0 :       txn_ctx->exec_err           = res;
     495             : 
     496           0 :       if( FD_UNLIKELY( !(txn_ctx->flags & FD_TXN_P_FLAGS_EXECUTE_SUCCESS) ) ) {
     497           0 :         break;
     498           0 :       }
     499             : 
     500             :       /* Finalize the transaction */
     501           0 :       fd_runtime_finalize_txn(
     502           0 :           slot_ctx->funk,
     503           0 :           slot_ctx->funk_txn,
     504           0 :           txn_ctx,
     505           0 :           slot_ctx->bank,
     506           0 :           capture_ctx );
     507             : 
     508           0 :       if( FD_UNLIKELY( !(txn_ctx->flags & FD_TXN_P_FLAGS_EXECUTE_SUCCESS) ) ) {
     509           0 :         break;
     510           0 :       }
     511             : 
     512           0 :       res = FD_RUNTIME_EXECUTE_SUCCESS;
     513           0 :     }
     514             : 
     515             :     /* Finalize the block */
     516           0 :     fd_runtime_block_execute_finalize( slot_ctx );
     517           0 :   } FD_SPAD_FRAME_END;
     518             : 
     519           0 :   return res;
     520           0 : }
     521             : 
     522             : ulong
     523             : fd_solfuzz_block_run( fd_solfuzz_runner_t * runner,
     524             :                       void const *          input_,
     525             :                       void **               output_,
     526             :                       void *                output_buf,
     527           0 :                       ulong                 output_bufsz ) {
     528           0 :   fd_exec_test_block_context_t const * input  = fd_type_pun_const( input_ );
     529           0 :   fd_exec_test_block_effects_t **      output = fd_type_pun( output_ );
     530             : 
     531           0 :   FD_SPAD_FRAME_BEGIN( runner->spad ) {
     532             :     /* Initialize memory */
     533           0 :     uchar *               slot_ctx_mem  = fd_spad_alloc( runner->spad, FD_EXEC_SLOT_CTX_ALIGN,  FD_EXEC_SLOT_CTX_FOOTPRINT );
     534           0 :     fd_exec_slot_ctx_t *  slot_ctx      = fd_exec_slot_ctx_join ( fd_exec_slot_ctx_new ( slot_ctx_mem ) );
     535             : 
     536             :     /* Set up the block execution context */
     537           0 :     fd_runtime_block_info_t * block_info = fd_runtime_fuzz_block_ctx_create( runner, slot_ctx, input );
     538           0 :     if( block_info==NULL ) {
     539           0 :       fd_runtime_fuzz_block_ctx_destroy( runner );
     540           0 :       return 0;
     541           0 :     }
     542             : 
     543             :     /* Execute the constructed block against the runtime. */
     544           0 :     int res = fd_runtime_fuzz_block_ctx_exec( runner, slot_ctx, block_info);
     545             : 
     546             :     /* Start saving block exec results */
     547           0 :     FD_SCRATCH_ALLOC_INIT( l, output_buf );
     548           0 :     ulong output_end = (ulong)output_buf + output_bufsz;
     549             : 
     550           0 :     fd_exec_test_block_effects_t * effects =
     551           0 :     FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_block_effects_t),
     552           0 :                                   sizeof (fd_exec_test_block_effects_t) );
     553           0 :     if( FD_UNLIKELY( _l > output_end ) ) {
     554           0 :       abort();
     555           0 :     }
     556           0 :     fd_memset( effects, 0, sizeof(fd_exec_test_block_effects_t) );
     557             : 
     558             :     /* Capture error status */
     559           0 :     effects->has_error = !!( res );
     560             : 
     561             :     /* Capture capitalization */
     562           0 :     effects->slot_capitalization = fd_bank_capitalization_get( slot_ctx->bank );
     563             : 
     564             :     /* Capture hashes */
     565           0 :     fd_hash_t bank_hash = fd_bank_bank_hash_get( slot_ctx->bank );
     566           0 :     fd_memcpy( effects->bank_hash, bank_hash.hash, sizeof(fd_hash_t) );
     567             : 
     568             :     /* Capture cost tracker */
     569           0 :     fd_cost_tracker_t cost_tracker = fd_bank_cost_tracker_get( slot_ctx->bank );
     570           0 :     effects->has_cost_tracker = 1;
     571           0 :     effects->cost_tracker = (fd_exec_test_cost_tracker_t) {
     572           0 :       .block_cost = cost_tracker.block_cost,
     573           0 :       .vote_cost  = cost_tracker.vote_cost,
     574           0 :     };
     575             : 
     576           0 :     ulong actual_end = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     577           0 :     fd_runtime_fuzz_block_ctx_destroy( runner );
     578             : 
     579           0 :     *output = effects;
     580           0 :     return actual_end - (ulong)output_buf;
     581           0 :   } FD_SPAD_FRAME_END;
     582           0 : }

Generated by: LCOV version 1.14