LCOV - code coverage report
Current view: top level - flamenco/runtime/tests/harness - fd_block_harness.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 378 0.0 %
Date: 2025-08-05 05:04:49 Functions: 0 8 0.0 %

          Line data    Source code
       1             : #include "fd_block_harness.h"
       2             : 
       3             : /* Stripped down version of `fd_refresh_vote_accounts()` that simply refreshes the stake delegation amount
       4             :    for each of the vote accounts using the stake delegations cache. */
       5             : static void
       6             : fd_runtime_fuzz_block_refresh_vote_accounts( fd_vote_accounts_pair_global_t_mapnode_t *  vote_accounts_pool,
       7             :                                              fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_root,
       8             :                                              fd_delegation_pair_t_mapnode_t *  stake_delegations_pool,
       9           0 :                                              fd_delegation_pair_t_mapnode_t * stake_delegations_root ) {
      10           0 :   for( fd_delegation_pair_t_mapnode_t * node = fd_delegation_pair_t_map_minimum( stake_delegations_pool, stake_delegations_root );
      11           0 :        node;
      12           0 :        node = fd_delegation_pair_t_map_successor( stake_delegations_pool, node ) ) {
      13           0 :     fd_pubkey_t * voter_pubkey = &node->elem.delegation.voter_pubkey;
      14           0 :     ulong         stake        = node->elem.delegation.stake;
      15             : 
      16             :     /* Find the voter in the vote accounts cache and update their delegation amount */
      17           0 :     fd_vote_accounts_pair_global_t_mapnode_t vode_node[1];
      18           0 :     fd_memcpy( vode_node->elem.key.uc, voter_pubkey, sizeof(fd_pubkey_t) );
      19           0 :     fd_vote_accounts_pair_global_t_mapnode_t * found_node = fd_vote_accounts_pair_global_t_map_find( vote_accounts_pool, vote_accounts_root, vode_node );
      20           0 :     if( FD_LIKELY( found_node ) ) {
      21           0 :       found_node->elem.stake += stake;
      22           0 :     }
      23           0 :   }
      24           0 : }
      25             : 
      26             : /* Registers a single vote account into the current votes cache. The entry is derived
      27             :    from the current present account state. This function also registers a vote timestamp
      28             :    for the vote account */
      29             : static void
      30             : fd_runtime_fuzz_block_register_vote_account( fd_exec_slot_ctx_t *                        slot_ctx,
      31             :                                              fd_vote_accounts_pair_global_t_mapnode_t *  pool,
      32             :                                              fd_vote_accounts_pair_global_t_mapnode_t ** root,
      33             :                                              fd_pubkey_t *                               pubkey,
      34           0 :                                              fd_spad_t *                                 spad ) {
      35           0 :   FD_TXN_ACCOUNT_DECL( acc );
      36           0 :   if( FD_UNLIKELY( fd_txn_account_init_from_funk_readonly( acc, pubkey, slot_ctx->funk, slot_ctx->funk_txn ) ) ) {
      37           0 :     return;
      38           0 :   }
      39             : 
      40             :   /* Account must be owned by the vote program */
      41           0 :   if( memcmp( acc->vt->get_owner( acc ), fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) ) {
      42           0 :     return;
      43           0 :   }
      44             : 
      45             :   /* Account must have > 0 lamports */
      46           0 :   if( acc->vt->get_lamports( acc )==0UL ) {
      47           0 :     return;
      48           0 :   }
      49             : 
      50             :   /* Account must be initialized correctly */
      51           0 :   if( FD_UNLIKELY( !fd_vote_state_versions_is_correct_and_initialized( acc ) ) ) {
      52           0 :     return;
      53           0 :   }
      54             : 
      55             :   /* Get the vote state from the account data */
      56           0 :   fd_vote_state_versioned_t * vsv = NULL;
      57           0 :   int err = fd_vote_get_state( acc, spad, &vsv );
      58           0 :   if( FD_UNLIKELY( err ) ) {
      59           0 :     return;
      60           0 :   }
      61             : 
      62             :   /* Nothing to do if the account already exists in the cache */
      63           0 :   fd_vote_accounts_pair_global_t_mapnode_t existing_node[1];
      64           0 :   fd_memcpy( existing_node->elem.key.uc, pubkey, sizeof(fd_pubkey_t) );
      65           0 :   if( fd_vote_accounts_pair_global_t_map_find( pool, *root, existing_node ) ) {
      66           0 :     return;
      67           0 :   }
      68             : 
      69             :   /* At this point, the node is new and needs to be inserted into the cache. */
      70           0 :   fd_vote_accounts_pair_global_t_mapnode_t * node_to_insert = fd_vote_accounts_pair_global_t_map_acquire( pool );
      71           0 :   fd_memcpy( node_to_insert->elem.key.uc, pubkey, sizeof(fd_pubkey_t) );
      72             : 
      73           0 :   ulong account_dlen                    = acc->vt->get_data_len( acc );
      74           0 :   node_to_insert->elem.stake            = 0UL; // This will get set later
      75           0 :   node_to_insert->elem.value.executable = !!acc->vt->is_executable( acc );
      76           0 :   node_to_insert->elem.value.lamports   = acc->vt->get_lamports( acc );
      77           0 :   node_to_insert->elem.value.rent_epoch = acc->vt->get_rent_epoch( acc );
      78           0 :   node_to_insert->elem.value.data_len   = account_dlen;
      79             : 
      80           0 :   uchar * data = fd_spad_alloc( spad, alignof(uchar), account_dlen );
      81           0 :   memcpy( data, acc->vt->get_data( acc ), account_dlen );
      82           0 :   fd_solana_account_data_update( &node_to_insert->elem.value, data );
      83             : 
      84           0 :   fd_vote_accounts_pair_global_t_map_insert( pool, root, node_to_insert );
      85             : 
      86             :   /* Record a timestamp for the vote account */
      87           0 :   fd_vote_block_timestamp_t const * ts = NULL;
      88           0 :   switch( vsv->discriminant ) {
      89           0 :     case fd_vote_state_versioned_enum_v0_23_5:
      90           0 :       ts = &vsv->inner.v0_23_5.last_timestamp;
      91           0 :       break;
      92           0 :     case fd_vote_state_versioned_enum_v1_14_11:
      93           0 :       ts = &vsv->inner.v1_14_11.last_timestamp;
      94           0 :       break;
      95           0 :     case fd_vote_state_versioned_enum_current:
      96           0 :       ts = &vsv->inner.current.last_timestamp;
      97           0 :       break;
      98           0 :     default:
      99           0 :       __builtin_unreachable();
     100           0 :   }
     101             : 
     102           0 :   fd_vote_record_timestamp_vote_with_slot( pubkey, ts->timestamp, ts->slot, slot_ctx->bank );
     103           0 : }
     104             : 
     105             : /* Stores an entry in the stake delegations cache for the given vote account. Deserializes and uses the present
     106             :    account state to derive delegation information. */
     107             : static void
     108             : fd_runtime_fuzz_block_register_stake_delegation( fd_exec_slot_ctx_t *              slot_ctx,
     109             :                                                  fd_delegation_pair_t_mapnode_t *  pool,
     110             :                                                  fd_delegation_pair_t_mapnode_t ** root,
     111           0 :                                                  fd_pubkey_t *                     pubkey ) {
     112           0 :  FD_TXN_ACCOUNT_DECL( acc );
     113           0 :   if( FD_UNLIKELY( fd_txn_account_init_from_funk_readonly( acc, pubkey, slot_ctx->funk, slot_ctx->funk_txn ) ) ) {
     114           0 :     return;
     115           0 :   }
     116             : 
     117             :   /* Account must be owned by the stake program */
     118           0 :   if( memcmp( acc->vt->get_owner( acc ), fd_solana_stake_program_id.key, sizeof(fd_pubkey_t) ) ) {
     119           0 :     return;
     120           0 :   }
     121             : 
     122             :   /* Account must have > 0 lamports */
     123           0 :   if( acc->vt->get_lamports( acc )==0UL ) {
     124           0 :     return;
     125           0 :   }
     126             : 
     127             :   /* Stake state must exist and be initialized correctly */
     128           0 :   fd_stake_state_v2_t stake_state;
     129           0 :   if( FD_UNLIKELY( fd_stake_get_state( acc, &stake_state ) || !fd_stake_state_v2_is_stake( &stake_state ) ) ) {
     130           0 :     return;
     131           0 :   }
     132             : 
     133             :   /* Skip 0-stake accounts */
     134           0 :   if( FD_UNLIKELY( stake_state.inner.stake.stake.delegation.stake==0UL ) ) {
     135           0 :     return;
     136           0 :   }
     137             : 
     138             :   /* Nothing to do if the account already exists in the cache */
     139           0 :   fd_delegation_pair_t_mapnode_t existing_node[1];
     140           0 :   fd_memcpy( existing_node->elem.account.uc, pubkey, sizeof(fd_pubkey_t) );
     141           0 :   if( fd_delegation_pair_t_map_find( pool, *root, existing_node ) ) {
     142           0 :     return;
     143           0 :   }
     144             : 
     145             :   /* At this point, the node is new and needs to be inserted into the cache. */
     146           0 :   fd_delegation_pair_t_mapnode_t * node_to_insert = fd_delegation_pair_t_map_acquire( pool );
     147           0 :   fd_memcpy( node_to_insert->elem.account.uc, pubkey, sizeof(fd_pubkey_t) );
     148             : 
     149           0 :   node_to_insert->elem.account    = *pubkey;
     150           0 :   node_to_insert->elem.delegation = stake_state.inner.stake.stake.delegation;
     151             : 
     152           0 :   fd_delegation_pair_t_map_insert( pool, root, node_to_insert );
     153           0 : }
     154             : 
     155             : /* Common helper method for populating a previous epoch's vote cache. */
     156             : static void
     157             : fd_runtime_fuzz_block_update_prev_epoch_votes_cache( fd_vote_accounts_pair_global_t_mapnode_t *  pool,
     158             :                                                      fd_vote_accounts_pair_global_t_mapnode_t ** root,
     159             :                                                      fd_exec_test_vote_account_t *        vote_accounts,
     160             :                                                      pb_size_t                            vote_accounts_cnt,
     161           0 :                                                      fd_spad_t *                          spad ) {
     162           0 :   for( uint i=0U; i<vote_accounts_cnt; i++ ) {
     163           0 :     fd_exec_test_acct_state_t * vote_account = &vote_accounts[i].vote_account;
     164           0 :     ulong                       stake        = vote_accounts[i].stake;
     165             : 
     166           0 :     fd_vote_accounts_pair_global_t_mapnode_t * vote_node = fd_vote_accounts_pair_global_t_map_acquire( pool );
     167           0 :     vote_node->elem.stake = stake;
     168           0 :     fd_memcpy( &vote_node->elem.key, vote_account->address, sizeof(fd_pubkey_t) );
     169           0 :     vote_node->elem.value.executable = vote_account->executable;
     170           0 :     vote_node->elem.value.lamports   = vote_account->lamports;
     171           0 :     vote_node->elem.value.rent_epoch = vote_account->rent_epoch;
     172           0 :     vote_node->elem.value.data_len   = vote_account->data->size;
     173           0 :     fd_memcpy( &vote_node->elem.value.owner, vote_account->owner, sizeof(fd_pubkey_t) );
     174             : 
     175           0 :     uchar * data = fd_spad_alloc( spad, alignof(uchar), vote_account->data->size );
     176           0 :     memcpy( data, vote_account->data->bytes, vote_account->data->size );
     177           0 :     fd_solana_account_data_update( &vote_node->elem.value, data );
     178             : 
     179           0 :     fd_vote_accounts_pair_global_t_map_insert( pool, root, vote_node );
     180           0 :   }
     181           0 : }
     182             : 
     183             : static void
     184             : fd_runtime_fuzz_block_ctx_destroy( fd_runtime_fuzz_runner_t * runner,
     185           0 :                                    fd_wksp_t *                wksp ) {
     186           0 :   fd_funk_txn_cancel_all( runner->funk, 1 );
     187           0 :   fd_wksp_detach( wksp );
     188           0 : }
     189             : 
     190             : /* Sets up block execution context from an input test case to execute against the runtime.
     191             :    Returns block_info on success and NULL on failure. */
     192             : static fd_runtime_block_info_t *
     193             : fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t *           runner,
     194             :                                   fd_exec_slot_ctx_t *                 slot_ctx,
     195           0 :                                   fd_exec_test_block_context_t const * test_ctx ) {
     196           0 :   fd_funk_t * funk = runner->funk;
     197             : 
     198           0 :   slot_ctx->banks = runner->banks;
     199           0 :   slot_ctx->bank  = runner->bank;
     200           0 :   fd_banks_clear_bank( slot_ctx->banks, slot_ctx->bank );
     201             : 
     202             :   /* Generate unique ID for funk txn */
     203           0 :   fd_funk_txn_xid_t xid[1] = {0};
     204           0 :   xid[0] = fd_funk_generate_xid();
     205             : 
     206             :   /* Create temporary funk transaction and slot / epoch contexts */
     207           0 :   fd_funk_txn_start_write( funk );
     208           0 :   fd_funk_txn_t * funk_txn = fd_funk_txn_prepare( funk, NULL, xid, 1 );
     209           0 :   fd_funk_txn_end_write( funk );
     210             : 
     211             :   /* Allocate contexts */
     212           0 :   ulong vote_acct_max = fd_ulong_max( 128UL, test_ctx->acct_states_count );
     213             : 
     214             :   /* Restore feature flags */
     215           0 :   fd_features_t features = {0};
     216           0 :   if( !fd_runtime_fuzz_restore_features( &features, &test_ctx->epoch_ctx.features ) ) {
     217           0 :     return NULL;
     218           0 :   }
     219           0 :   fd_bank_features_set( slot_ctx->bank, features );
     220             : 
     221             :   /* Set up slot context */
     222           0 :   ulong slot = test_ctx->slot_ctx.slot;
     223             : 
     224           0 :   slot_ctx->funk_txn  = funk_txn;
     225           0 :   slot_ctx->funk      = funk;
     226           0 :   runner->bank->slot_ = slot;
     227             : 
     228           0 :   fd_hash_t * bank_hash = fd_bank_bank_hash_modify( slot_ctx->bank );
     229           0 :   fd_memcpy( bank_hash, test_ctx->slot_ctx.parent_bank_hash, sizeof(fd_hash_t) );
     230             : 
     231             :   /* All bank mgr stuff here. */
     232             : 
     233             :   /* Initialize vote timestamps cache */
     234           0 :   fd_clock_timestamp_votes_global_t * clock_timestamp_votes = fd_bank_clock_timestamp_votes_locking_modify( slot_ctx->bank );
     235           0 :   uchar * pool_mem = (uchar *)fd_ulong_align_up( (ulong)clock_timestamp_votes + sizeof(fd_clock_timestamp_votes_global_t), fd_clock_timestamp_vote_t_map_align() );
     236           0 :   fd_clock_timestamp_vote_t_mapnode_t * clock_pool = fd_clock_timestamp_vote_t_map_join( fd_clock_timestamp_vote_t_map_new( pool_mem, 15000UL ) );
     237           0 :   fd_clock_timestamp_vote_t_mapnode_t * clock_root = NULL;
     238             : 
     239           0 :   fd_clock_timestamp_votes_votes_pool_update( clock_timestamp_votes, clock_pool );
     240           0 :   fd_clock_timestamp_votes_votes_root_update( clock_timestamp_votes, clock_root );
     241           0 :   fd_bank_clock_timestamp_votes_end_locking_modify( slot_ctx->bank );
     242             : 
     243           0 :   slot_ctx->bank->slot_ = slot;
     244             : 
     245           0 :   fd_bank_block_height_set( slot_ctx->bank, test_ctx->slot_ctx.block_height );
     246             : 
     247           0 :   fd_bank_parent_slot_set( slot_ctx->bank, test_ctx->slot_ctx.prev_slot );
     248             : 
     249           0 :   fd_bank_capitalization_set( slot_ctx->bank, test_ctx->slot_ctx.prev_epoch_capitalization );
     250             : 
     251           0 :   fd_bank_lamports_per_signature_set( slot_ctx->bank, 5000UL );
     252             : 
     253           0 :   fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, test_ctx->slot_ctx.prev_lps );
     254             : 
     255             :   // self.max_tick_height = (self.slot + 1) * self.ticks_per_slot;
     256           0 :   fd_bank_hashes_per_tick_set( slot_ctx->bank, test_ctx->epoch_ctx.hashes_per_tick );
     257             : 
     258           0 :   fd_bank_ticks_per_slot_set( slot_ctx->bank, test_ctx->epoch_ctx.ticks_per_slot );
     259             : 
     260           0 :   fd_bank_ns_per_slot_set( slot_ctx->bank, 400000000 ); // TODO: restore from input
     261             : 
     262           0 :   fd_bank_genesis_creation_time_set( slot_ctx->bank, test_ctx->epoch_ctx.genesis_creation_time );
     263             : 
     264           0 :   fd_bank_slots_per_year_set( slot_ctx->bank, test_ctx->epoch_ctx.slots_per_year );
     265             : 
     266           0 :   fd_fee_rate_governor_t * fee_rate_governor = fd_bank_fee_rate_governor_modify( slot_ctx->bank );
     267           0 :   fee_rate_governor->target_lamports_per_signature = 10000UL;
     268           0 :   fee_rate_governor->target_signatures_per_slot = 20000UL;
     269           0 :   fee_rate_governor->min_lamports_per_signature = 5000UL;
     270           0 :   fee_rate_governor->max_lamports_per_signature = 100000UL;
     271           0 :   fee_rate_governor->burn_percent = 50;
     272             : 
     273           0 :   fd_inflation_t * inflation = fd_bank_inflation_modify( slot_ctx->bank );
     274           0 :   inflation->initial         = test_ctx->epoch_ctx.inflation.initial;
     275           0 :   inflation->terminal        = test_ctx->epoch_ctx.inflation.terminal;
     276           0 :   inflation->taper           = test_ctx->epoch_ctx.inflation.taper;
     277           0 :   inflation->foundation      = test_ctx->epoch_ctx.inflation.foundation;
     278           0 :   inflation->foundation_term = test_ctx->epoch_ctx.inflation.foundation_term;
     279             : 
     280           0 :   fd_bank_block_height_set( slot_ctx->bank, test_ctx->slot_ctx.block_height );
     281             : 
     282             :   // /* Initialize the current running epoch stake and vote accounts */
     283             : 
     284             :   /* TODO: should be stake account max */
     285           0 :   fd_account_keys_global_t * stake_account_keys = fd_bank_stake_account_keys_locking_modify( slot_ctx->bank );
     286           0 :   pool_mem = (uchar *)fd_ulong_align_up( (ulong)stake_account_keys + sizeof(fd_account_keys_global_t), fd_account_keys_pair_t_map_align() );
     287           0 :   fd_account_keys_pair_t_mapnode_t * account_keys_pool = fd_account_keys_pair_t_map_join( fd_account_keys_pair_t_map_new( pool_mem, vote_acct_max ) );
     288           0 :   fd_account_keys_pair_t_mapnode_t * account_keys_root = NULL;
     289           0 :   fd_account_keys_account_keys_pool_update( stake_account_keys, account_keys_pool );
     290           0 :   fd_account_keys_account_keys_root_update( stake_account_keys, account_keys_root );
     291           0 :   fd_bank_stake_account_keys_end_locking_modify( slot_ctx->bank );
     292             : 
     293           0 :   fd_account_keys_global_t * vote_account_keys = fd_bank_vote_account_keys_locking_modify( slot_ctx->bank );
     294           0 :   pool_mem = (uchar *)fd_ulong_align_up( (ulong)vote_account_keys + sizeof(fd_account_keys_global_t), fd_account_keys_pair_t_map_align() );
     295           0 :   fd_account_keys_pair_t_mapnode_t * vote_account_keys_pool = fd_account_keys_pair_t_map_join( fd_account_keys_pair_t_map_new( pool_mem, vote_acct_max ) );
     296           0 :   fd_account_keys_pair_t_mapnode_t * vote_account_keys_root = NULL;
     297           0 :   fd_account_keys_account_keys_pool_update( vote_account_keys, vote_account_keys_pool );
     298           0 :   fd_account_keys_account_keys_root_update( vote_account_keys, vote_account_keys_root );
     299           0 :   fd_bank_vote_account_keys_end_locking_modify( slot_ctx->bank );
     300             : 
     301             : 
     302             :   /* SETUP STAKES HERE */
     303           0 :   fd_stakes_global_t * stakes = fd_bank_stakes_locking_modify( slot_ctx->bank );
     304           0 :   pool_mem = (uchar *)fd_ulong_align_up( (ulong)stakes + sizeof(fd_stakes_global_t), fd_vote_accounts_pair_t_map_align() );
     305           0 :   fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_pool = fd_vote_accounts_pair_global_t_map_join( fd_vote_accounts_pair_global_t_map_new( pool_mem, vote_acct_max ) );
     306           0 :   fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_root = NULL;
     307           0 :   pool_mem = (uchar *)fd_ulong_align_up( (ulong)pool_mem + fd_vote_accounts_pair_global_t_map_footprint( vote_acct_max ), fd_delegation_pair_t_map_align() );
     308           0 :   fd_delegation_pair_t_mapnode_t * stake_delegations_pool = fd_delegation_pair_t_map_join( fd_delegation_pair_t_map_new( pool_mem, vote_acct_max ) );
     309           0 :   fd_delegation_pair_t_mapnode_t * stake_delegations_root = NULL;
     310             : 
     311             :   /* Load in all accounts with > 0 lamports provided in the context. The input expects unique account pubkeys. */
     312           0 :   for( ushort i=0; i<test_ctx->acct_states_count; i++ ) {
     313           0 :     FD_TXN_ACCOUNT_DECL(acc);
     314           0 :     fd_runtime_fuzz_load_account( acc, funk, funk_txn, &test_ctx->acct_states[i], 1 );
     315             : 
     316             :     /* Update vote accounts cache for epoch T */
     317           0 :     fd_pubkey_t pubkey;
     318           0 :     memcpy( &pubkey, test_ctx->acct_states[i].address, sizeof(fd_pubkey_t) );
     319           0 :     fd_runtime_fuzz_block_register_vote_account( slot_ctx,
     320           0 :                                                  vote_accounts_pool,
     321           0 :                                                  &vote_accounts_root,
     322           0 :                                                  &pubkey,
     323           0 :                                                  runner->spad );
     324             : 
     325             :     /* Update the stake delegations cache for epoch T */
     326           0 :     fd_runtime_fuzz_block_register_stake_delegation( slot_ctx,
     327           0 :                                                      stake_delegations_pool,
     328           0 :                                                      &stake_delegations_root,
     329           0 :                                                      &pubkey );
     330           0 :   }
     331             : 
     332             :   /* Refresh vote accounts to calculate stake delegations */
     333           0 :   fd_runtime_fuzz_block_refresh_vote_accounts( vote_accounts_pool,
     334           0 :                                                vote_accounts_root,
     335           0 :                                                stake_delegations_pool,
     336           0 :                                                stake_delegations_root );
     337             : 
     338           0 :   fd_vote_accounts_vote_accounts_pool_update( &stakes->vote_accounts, vote_accounts_pool );
     339           0 :   fd_vote_accounts_vote_accounts_root_update( &stakes->vote_accounts, vote_accounts_root );
     340             : 
     341           0 :   fd_stakes_stake_delegations_pool_update( stakes, stake_delegations_pool );
     342           0 :   fd_stakes_stake_delegations_root_update( stakes, stake_delegations_root );
     343             : 
     344             :   /* Finish init epoch bank sysvars */
     345           0 :   fd_epoch_schedule_t epoch_schedule_[1];
     346           0 :   fd_epoch_schedule_t * epoch_schedule = fd_sysvar_epoch_schedule_read( funk, funk_txn, epoch_schedule_ );
     347           0 :   fd_bank_epoch_schedule_set( slot_ctx->bank, *epoch_schedule );
     348             : 
     349           0 :   fd_rent_t const * rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad );
     350           0 :   fd_bank_rent_set( slot_ctx->bank, *rent );
     351             : 
     352           0 :   stakes->epoch = fd_slot_to_epoch( epoch_schedule, test_ctx->slot_ctx.prev_slot, NULL );
     353             : 
     354           0 :   fd_bank_stakes_end_locking_modify( slot_ctx->bank );
     355             : 
     356             :   /* Refresh the program cache */
     357           0 :   fd_runtime_fuzz_refresh_program_cache( slot_ctx, test_ctx->acct_states, test_ctx->acct_states_count, runner->spad );
     358             : 
     359           0 :   fd_vote_accounts_global_t * vote_accounts = fd_bank_next_epoch_stakes_locking_modify( slot_ctx->bank );
     360           0 :   pool_mem = (uchar *)fd_ulong_align_up( (ulong)vote_accounts + sizeof(fd_vote_accounts_global_t), fd_vote_accounts_pair_global_t_map_align() );
     361           0 :   vote_accounts_pool = fd_vote_accounts_pair_global_t_map_join( fd_vote_accounts_pair_global_t_map_new( pool_mem, vote_acct_max ) );
     362           0 :   vote_accounts_root = NULL;
     363             : 
     364             :   /* Update vote cache for epoch T-1 */
     365           0 :   fd_runtime_fuzz_block_update_prev_epoch_votes_cache( vote_accounts_pool,
     366           0 :                                                        &vote_accounts_root,
     367           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_1,
     368           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_1_count,
     369           0 :                                                        runner->spad );
     370             : 
     371           0 :   fd_vote_accounts_vote_accounts_pool_update( vote_accounts, vote_accounts_pool );
     372           0 :   fd_vote_accounts_vote_accounts_root_update( vote_accounts, vote_accounts_root );
     373             : 
     374           0 :   fd_bank_next_epoch_stakes_end_locking_modify( slot_ctx->bank );
     375             : 
     376             :   /* Update vote cache for epoch T-2 */
     377           0 :   vote_accounts = fd_bank_epoch_stakes_locking_modify( slot_ctx->bank );
     378           0 :   pool_mem = (uchar *)fd_ulong_align_up( (ulong)vote_accounts + sizeof(fd_vote_accounts_global_t), fd_vote_accounts_pair_global_t_map_align() );
     379           0 :   vote_accounts_pool = fd_vote_accounts_pair_global_t_map_join( fd_vote_accounts_pair_global_t_map_new( pool_mem, vote_acct_max ) );
     380           0 :   vote_accounts_root = NULL;
     381             : 
     382           0 :   fd_runtime_fuzz_block_update_prev_epoch_votes_cache( vote_accounts_pool,
     383           0 :                                                        &vote_accounts_root,
     384           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_2,
     385           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_2_count,
     386           0 :                                                        runner->spad );
     387             : 
     388           0 :   fd_vote_accounts_vote_accounts_pool_update( vote_accounts, vote_accounts_pool );
     389           0 :   fd_vote_accounts_vote_accounts_root_update( vote_accounts, vote_accounts_root );
     390           0 :   fd_bank_epoch_stakes_end_locking_modify( slot_ctx->bank );
     391             : 
     392             :   /* Update leader schedule */
     393           0 :   fd_runtime_update_leaders( slot_ctx->bank, fd_bank_slot_get( slot_ctx->bank ), runner->spad );
     394             : 
     395             :   /* Initialize the blockhash queue and recent blockhashes sysvar from the input blockhash queue */
     396           0 :   ulong blockhash_seed; FD_TEST( fd_rng_secure( &blockhash_seed, sizeof(ulong) ) );
     397           0 :   fd_blockhashes_init( fd_bank_block_hash_queue_modify( slot_ctx->bank ), blockhash_seed );
     398             : 
     399             :   /* TODO: We might need to load this in from the input. We also need to
     400             :      size this out for worst case, but this also blows up the memory
     401             :      requirement. */
     402             :   /* Allocate all the memory for the rent fresh accounts list */
     403             : 
     404             :   // Set genesis hash to {0}
     405           0 :   fd_hash_t * genesis_hash = fd_bank_genesis_hash_modify( slot_ctx->bank );
     406           0 :   fd_memset( genesis_hash->hash, 0, sizeof(fd_hash_t) );
     407             : 
     408             :   // Use the latest lamports per signature
     409           0 :   fd_recent_block_hashes_t const * rbh = fd_sysvar_recent_hashes_read( funk, funk_txn, runner->spad );
     410           0 :   if( rbh && !deq_fd_block_block_hash_entry_t_empty( rbh->hashes ) ) {
     411           0 :     fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_head_const( rbh->hashes );
     412           0 :     if( last && last->fee_calculator.lamports_per_signature!=0UL ) {
     413           0 :       fd_bank_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature );
     414           0 :       fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature );
     415           0 :     }
     416           0 :   }
     417             : 
     418             :   // Populate blockhash queue and recent blockhashes sysvar
     419           0 :   for( ushort i=0; i<test_ctx->blockhash_queue_count; ++i ) {
     420           0 :     fd_hash_t hash;
     421           0 :     memcpy( &hash, test_ctx->blockhash_queue[i]->bytes, sizeof(fd_hash_t) );
     422           0 :     fd_bank_poh_set( slot_ctx->bank, hash );
     423           0 :     fd_sysvar_recent_hashes_update( slot_ctx ); /* appends an entry */
     424           0 :   }
     425             : 
     426             :   // Set the current poh from the input (we skip POH verification in this fuzzing target)
     427           0 :   fd_hash_t * poh = fd_bank_poh_modify( slot_ctx->bank );
     428           0 :   fd_memcpy( poh->hash, test_ctx->slot_ctx.poh, sizeof(fd_hash_t) );
     429             : 
     430             :   /* Make a new funk transaction since we're done loading in accounts for context */
     431           0 :   fd_funk_txn_xid_t fork_xid[1] = {0};
     432           0 :   fork_xid[0] = fd_funk_generate_xid();
     433           0 :   fd_funk_txn_start_write( funk );
     434           0 :   slot_ctx->funk_txn = fd_funk_txn_prepare( funk, slot_ctx->funk_txn, fork_xid, 1 );
     435           0 :   fd_funk_txn_end_write( funk );
     436             : 
     437             :   /* Calculate epoch account hash values. This sets epoch_bank.eah_{start_slot, stop_slot, interval} */
     438           0 :   fd_calculate_epoch_accounts_hash_values( slot_ctx );
     439             : 
     440             :   /* Restore sysvar cache */
     441           0 :   fd_sysvar_cache_restore_fuzz( slot_ctx );
     442             : 
     443             :   /* Prepare raw transaction pointers and block / microblock infos */
     444           0 :   ulong txn_cnt = test_ctx->txns_count;
     445             : 
     446             :   // For fuzzing, we're using a single microblock batch that contains a single microblock containing all transactions
     447           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) );
     448           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) );
     449           0 :   fd_microblock_info_t *       microblock_info  = fd_spad_alloc( runner->spad, alignof(fd_microblock_info_t), sizeof(fd_microblock_info_t) );
     450           0 :   fd_memset( block_info, 0, sizeof(fd_runtime_block_info_t) );
     451           0 :   fd_memset( batch_info, 0, sizeof(fd_microblock_batch_info_t) );
     452           0 :   fd_memset( microblock_info, 0, sizeof(fd_microblock_info_t) );
     453             : 
     454           0 :   block_info->microblock_batch_cnt   = 1UL;
     455           0 :   block_info->microblock_cnt         = 1UL;
     456           0 :   block_info->microblock_batch_infos = batch_info;
     457             : 
     458           0 :   batch_info->microblock_cnt         = 1UL;
     459           0 :   batch_info->microblock_infos       = microblock_info;
     460             : 
     461           0 :   ulong batch_signature_cnt          = 0UL;
     462           0 :   ulong batch_txn_cnt                = 0UL;
     463           0 :   ulong batch_account_cnt            = 0UL;
     464           0 :   ulong signature_cnt                = 0UL;
     465           0 :   ulong account_cnt                  = 0UL;
     466             : 
     467           0 :   fd_microblock_hdr_t * microblock_hdr = fd_spad_alloc( runner->spad, alignof(fd_microblock_hdr_t), sizeof(fd_microblock_hdr_t) );
     468           0 :   fd_memset( microblock_hdr, 0, sizeof(fd_microblock_hdr_t) );
     469             : 
     470           0 :   fd_txn_p_t * txn_ptrs = fd_spad_alloc( runner->spad, alignof(fd_txn_p_t), txn_cnt * sizeof(fd_txn_p_t) );
     471           0 :   for( ulong i=0UL; i<txn_cnt; i++ ) {
     472           0 :     fd_txn_p_t * txn = &txn_ptrs[i];
     473             : 
     474           0 :     ushort _instr_count, _addr_table_cnt;
     475           0 :     ulong msg_sz = fd_runtime_fuzz_serialize_txn( txn->payload, &test_ctx->txns[i], &_instr_count, &_addr_table_cnt );
     476             : 
     477             :     // Reject any transactions over 1232 bytes
     478           0 :     if( FD_UNLIKELY( msg_sz==ULONG_MAX ) ) {
     479           0 :       return NULL;
     480           0 :     }
     481           0 :     txn->payload_sz = msg_sz;
     482             : 
     483             :     // Reject any transactions that cannot be parsed
     484           0 :     if( FD_UNLIKELY( !fd_txn_parse( txn->payload, msg_sz, TXN( txn ), NULL ) ) ) {
     485           0 :       return NULL;
     486           0 :     }
     487             : 
     488           0 :     signature_cnt += TXN( txn )->signature_cnt;
     489           0 :     account_cnt   += fd_txn_account_cnt( TXN( txn ), FD_TXN_ACCT_CAT_ALL );
     490           0 :   }
     491             : 
     492           0 :   microblock_hdr->txn_cnt         = txn_cnt;
     493           0 :   microblock_info->microblock.raw = (uchar *)microblock_hdr;
     494             : 
     495           0 :   microblock_info->signature_cnt  = signature_cnt;
     496           0 :   microblock_info->account_cnt    = account_cnt;
     497           0 :   microblock_info->txns           = txn_ptrs;
     498             : 
     499           0 :   batch_signature_cnt            += signature_cnt;
     500           0 :   batch_txn_cnt                  += txn_cnt;
     501           0 :   batch_account_cnt              += account_cnt;
     502             : 
     503           0 :   block_info->signature_cnt = batch_info->signature_cnt = batch_signature_cnt;
     504           0 :   block_info->txn_cnt       = batch_info->txn_cnt       = batch_txn_cnt;
     505           0 :   block_info->account_cnt   = batch_info->account_cnt   = batch_account_cnt;
     506             : 
     507           0 :   return block_info;
     508           0 : }
     509             : 
     510             : /* Takes in a block_info created from `fd_runtime_fuzz_block_ctx_create()`
     511             :    and executes it against the runtime. Returns the execution result. */
     512             : static int
     513             : fd_runtime_fuzz_block_ctx_exec( fd_runtime_fuzz_runner_t * runner,
     514             :                                 fd_exec_slot_ctx_t *       slot_ctx,
     515           0 :                                 fd_runtime_block_info_t *  block_info ) {
     516           0 :   int res = 0;
     517             : 
     518           0 :   fd_spad_t * runtime_spad = runner->spad;
     519             : 
     520             :   // Prepare. Execute. Finalize.
     521           0 :   FD_SPAD_FRAME_BEGIN( runtime_spad ) {
     522           0 :     fd_capture_ctx_t * capture_ctx = NULL;
     523           0 :     fd_capture_ctx_t capture_ctx_[1];
     524           0 :     if( runner->solcap ) {
     525           0 :       capture_ctx_[0] = (fd_capture_ctx_t) {
     526           0 :         .capture            = runner->solcap,
     527           0 :         .capture_txns       = 1,
     528           0 :         .dump_instr_to_pb   = 1,
     529           0 :         .dump_txn_to_pb     = 1,
     530           0 :         .dump_block_to_pb   = 1,
     531           0 :         .dump_syscall_to_pb = 1,
     532           0 :         .dump_elf_to_pb     = 1
     533           0 :       };
     534           0 :       capture_ctx = capture_ctx_;
     535           0 :     }
     536             : 
     537           0 :     fd_rewards_recalculate_partitioned_rewards( slot_ctx, capture_ctx, runtime_spad );
     538             : 
     539             :     /* Process new epoch may push a new spad frame onto the runtime spad. We should make sure this frame gets
     540             :        cleared (if it was allocated) before executing the block. */
     541           0 :     int   is_epoch_boundary = 0;
     542           0 :     fd_runtime_block_pre_execute_process_new_epoch( slot_ctx, capture_ctx, runtime_spad, &is_epoch_boundary );
     543             : 
     544           0 :     res = fd_runtime_block_execute( slot_ctx, capture_ctx, block_info, runtime_spad );
     545           0 :   } FD_SPAD_FRAME_END;
     546             : 
     547           0 :   return res;
     548           0 : }
     549             : 
     550             : ulong
     551             : fd_runtime_fuzz_block_run( fd_runtime_fuzz_runner_t * runner,
     552             :                            void const *               input_,
     553             :                            void **                    output_,
     554             :                            void *                     output_buf,
     555           0 :                            ulong                      output_bufsz ) {
     556           0 :   fd_exec_test_block_context_t const * input  = fd_type_pun_const( input_ );
     557           0 :   fd_exec_test_block_effects_t **      output = fd_type_pun( output_ );
     558             : 
     559           0 :   FD_SPAD_FRAME_BEGIN( runner->spad ) {
     560             :     /* Initialize memory */
     561           0 :     fd_wksp_t *           wksp          = fd_wksp_attach( "wksp" );
     562           0 :     uchar *               slot_ctx_mem  = fd_spad_alloc( runner->spad, FD_EXEC_SLOT_CTX_ALIGN,  FD_EXEC_SLOT_CTX_FOOTPRINT );
     563           0 :     fd_exec_slot_ctx_t *  slot_ctx      = fd_exec_slot_ctx_join ( fd_exec_slot_ctx_new ( slot_ctx_mem ) );
     564             : 
     565             :     /* Set up the block execution context */
     566           0 :     fd_runtime_block_info_t * block_info = fd_runtime_fuzz_block_ctx_create( runner, slot_ctx, input );
     567           0 :     if( block_info==NULL ) {
     568           0 :       fd_runtime_fuzz_block_ctx_destroy( runner, wksp );
     569           0 :       return 0;
     570           0 :     }
     571             : 
     572             :     /* Execute the constructed block against the runtime. */
     573           0 :     int res = fd_runtime_fuzz_block_ctx_exec( runner, slot_ctx, block_info);
     574             : 
     575             :     /* Start saving block exec results */
     576           0 :     FD_SCRATCH_ALLOC_INIT( l, output_buf );
     577           0 :     ulong output_end = (ulong)output_buf + output_bufsz;
     578             : 
     579           0 :     fd_exec_test_block_effects_t * effects =
     580           0 :     FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_block_effects_t),
     581           0 :                                   sizeof (fd_exec_test_block_effects_t) );
     582           0 :     if( FD_UNLIKELY( _l > output_end ) ) {
     583           0 :       abort();
     584           0 :     }
     585           0 :     fd_memset( effects, 0, sizeof(fd_exec_test_block_effects_t) );
     586             : 
     587             :     /* Capture error status */
     588           0 :     effects->has_error = !!( res );
     589             : 
     590             :     /* Capture capitalization */
     591           0 :     effects->slot_capitalization = fd_bank_capitalization_get( slot_ctx->bank );
     592             : 
     593             :     /* Capture hashes */
     594           0 :     fd_hash_t bank_hash = fd_bank_bank_hash_get( slot_ctx->bank );
     595           0 :     fd_memcpy( effects->bank_hash, bank_hash.hash, sizeof(fd_hash_t) );
     596             : 
     597           0 :     ulong actual_end = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     598           0 :     fd_runtime_fuzz_block_ctx_destroy( runner, wksp );
     599             : 
     600           0 :     *output = effects;
     601           0 :     return actual_end - (ulong)output_buf;
     602           0 :   } FD_SPAD_FRAME_END;
     603           0 : }

Generated by: LCOV version 1.14