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 388 0.0 %
Date: 2025-07-01 05:00: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 FD_FN_UNUSED
     184             : fd_runtime_fuzz_block_ctx_destroy( fd_runtime_fuzz_runner_t * runner,
     185             :                                    fd_exec_slot_ctx_t *       slot_ctx,
     186             :                                    fd_wksp_t *                wksp,
     187           0 :                                    fd_alloc_t *               alloc ) {
     188           0 :   if( !slot_ctx ) return; // This shouldn't be false either
     189             : 
     190           0 :   fd_wksp_free_laddr( fd_alloc_delete( fd_alloc_leave( alloc ) ) );
     191           0 :   fd_wksp_detach( wksp );
     192             : 
     193           0 :   fd_funk_txn_cancel_all( runner->funk, 1 );
     194           0 : }
     195             : 
     196             : /* Sets up block execution context from an input test case to execute against the runtime.
     197             :    Returns block_info on success and NULL on failure. */
     198             : static fd_runtime_block_info_t *
     199             : fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t *           runner,
     200             :                                   fd_exec_slot_ctx_t *                 slot_ctx,
     201           0 :                                   fd_exec_test_block_context_t const * test_ctx ) {
     202           0 :   fd_funk_t * funk = runner->funk;
     203             : 
     204           0 :   slot_ctx->bank = runner->bank;
     205           0 :   fd_bank_clear_bank( slot_ctx->bank );
     206             : 
     207             :   /* Generate unique ID for funk txn */
     208           0 :   fd_funk_txn_xid_t xid[1] = {0};
     209           0 :   xid[0] = fd_funk_generate_xid();
     210             : 
     211             :   /* Create temporary funk transaction and slot / epoch contexts */
     212           0 :   fd_funk_txn_start_write( funk );
     213           0 :   fd_funk_txn_t * funk_txn = fd_funk_txn_prepare( funk, NULL, xid, 1 );
     214           0 :   fd_funk_txn_end_write( funk );
     215             : 
     216             :   /* Allocate contexts */
     217           0 :   ulong vote_acct_max = fd_ulong_max( 128UL, test_ctx->acct_states_count );
     218             : 
     219             :   /* Restore feature flags */
     220           0 :   fd_features_t features = {0};
     221           0 :   if( !fd_runtime_fuzz_restore_features( &features, &test_ctx->epoch_ctx.features ) ) {
     222           0 :     return NULL;
     223           0 :   }
     224           0 :   fd_bank_features_set( slot_ctx->bank, features );
     225             : 
     226             :   /* Set up slot context */
     227           0 :   ulong slot = test_ctx->slot_ctx.slot;
     228             : 
     229           0 :   slot_ctx->funk_txn                    = funk_txn;
     230           0 :   slot_ctx->funk                        = funk;
     231           0 :   slot_ctx->slot                        = slot;
     232             : 
     233           0 :   fd_hash_t * bank_hash = fd_bank_bank_hash_modify( slot_ctx->bank );
     234           0 :   fd_memcpy( bank_hash, test_ctx->slot_ctx.parent_bank_hash, sizeof(fd_hash_t) );
     235             : 
     236             :   /* All bank mgr stuff here. */
     237             : 
     238             :   /* Initialize vote timestamps cache */
     239           0 :   fd_clock_timestamp_votes_global_t * clock_timestamp_votes = fd_bank_clock_timestamp_votes_locking_modify( slot_ctx->bank );
     240           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() );
     241           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 ) );
     242           0 :   fd_clock_timestamp_vote_t_mapnode_t * clock_root = NULL;
     243             : 
     244           0 :   fd_clock_timestamp_votes_votes_pool_update( clock_timestamp_votes, clock_pool );
     245           0 :   fd_clock_timestamp_votes_votes_root_update( clock_timestamp_votes, clock_root );
     246           0 :   fd_bank_clock_timestamp_votes_end_locking_modify( slot_ctx->bank );
     247             : 
     248           0 :   slot_ctx->bank->slot = slot;
     249             : 
     250           0 :   fd_bank_block_height_set( slot_ctx->bank, test_ctx->slot_ctx.block_height );
     251             : 
     252           0 :   fd_bank_prev_slot_set( slot_ctx->bank, test_ctx->slot_ctx.prev_slot );
     253             : 
     254           0 :   fd_bank_capitalization_set( slot_ctx->bank, test_ctx->slot_ctx.prev_epoch_capitalization );
     255             : 
     256           0 :   fd_bank_lamports_per_signature_set( slot_ctx->bank, 5000UL );
     257             : 
     258           0 :   fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, test_ctx->slot_ctx.prev_lps );
     259             : 
     260             :   // self.max_tick_height = (self.slot + 1) * self.ticks_per_slot;
     261           0 :   fd_bank_hashes_per_tick_set( slot_ctx->bank, test_ctx->epoch_ctx.hashes_per_tick );
     262             : 
     263           0 :   fd_bank_ticks_per_slot_set( slot_ctx->bank, test_ctx->epoch_ctx.ticks_per_slot );
     264             : 
     265           0 :   fd_bank_ns_per_slot_set( slot_ctx->bank, 400000000 ); // TODO: restore from input
     266             : 
     267           0 :   fd_bank_genesis_creation_time_set( slot_ctx->bank, test_ctx->epoch_ctx.genesis_creation_time );
     268             : 
     269           0 :   fd_bank_slots_per_year_set( slot_ctx->bank, test_ctx->epoch_ctx.slots_per_year );
     270             : 
     271           0 :   fd_fee_rate_governor_t * fee_rate_governor = fd_bank_fee_rate_governor_modify( slot_ctx->bank );
     272           0 :   fee_rate_governor->target_lamports_per_signature = 10000UL;
     273           0 :   fee_rate_governor->target_signatures_per_slot = 20000UL;
     274           0 :   fee_rate_governor->min_lamports_per_signature = 5000UL;
     275           0 :   fee_rate_governor->max_lamports_per_signature = 100000UL;
     276           0 :   fee_rate_governor->burn_percent = 50;
     277             : 
     278           0 :   fd_inflation_t * inflation = fd_bank_inflation_modify( slot_ctx->bank );
     279           0 :   inflation->initial         = test_ctx->epoch_ctx.inflation.initial;
     280           0 :   inflation->terminal        = test_ctx->epoch_ctx.inflation.terminal;
     281           0 :   inflation->taper           = test_ctx->epoch_ctx.inflation.taper;
     282           0 :   inflation->foundation      = test_ctx->epoch_ctx.inflation.foundation;
     283           0 :   inflation->foundation_term = test_ctx->epoch_ctx.inflation.foundation_term;
     284             : 
     285           0 :   fd_bank_block_height_set( slot_ctx->bank, test_ctx->slot_ctx.block_height );
     286             : 
     287             :   // /* Initialize the current running epoch stake and vote accounts */
     288             : 
     289             :   /* TODO: should be stake account max */
     290           0 :   fd_account_keys_global_t * stake_account_keys = fd_bank_stake_account_keys_locking_modify( slot_ctx->bank );
     291           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() );
     292           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 ) );
     293           0 :   fd_account_keys_pair_t_mapnode_t * account_keys_root = NULL;
     294           0 :   fd_account_keys_account_keys_pool_update( stake_account_keys, account_keys_pool );
     295           0 :   fd_account_keys_account_keys_root_update( stake_account_keys, account_keys_root );
     296           0 :   fd_bank_stake_account_keys_end_locking_modify( slot_ctx->bank );
     297             : 
     298           0 :   fd_account_keys_global_t * vote_account_keys = fd_bank_vote_account_keys_locking_modify( slot_ctx->bank );
     299           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() );
     300           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 ) );
     301           0 :   fd_account_keys_pair_t_mapnode_t * vote_account_keys_root = NULL;
     302           0 :   fd_account_keys_account_keys_pool_update( vote_account_keys, vote_account_keys_pool );
     303           0 :   fd_account_keys_account_keys_root_update( vote_account_keys, vote_account_keys_root );
     304           0 :   fd_bank_vote_account_keys_end_locking_modify( slot_ctx->bank );
     305             : 
     306             : 
     307             :   /* SETUP STAKES HERE */
     308           0 :   fd_stakes_global_t * stakes = fd_bank_stakes_locking_modify( slot_ctx->bank );
     309           0 :   pool_mem = (uchar *)fd_ulong_align_up( (ulong)stakes + sizeof(fd_stakes_global_t), fd_vote_accounts_pair_t_map_align() );
     310           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 ) );
     311           0 :   fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_root = NULL;
     312           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() );
     313           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 ) );
     314           0 :   fd_delegation_pair_t_mapnode_t * stake_delegations_root = NULL;
     315             : 
     316             :   /* Load in all accounts with > 0 lamports provided in the context. The input expects unique account pubkeys. */
     317           0 :   for( ushort i=0; i<test_ctx->acct_states_count; i++ ) {
     318           0 :     FD_TXN_ACCOUNT_DECL(acc);
     319           0 :     fd_runtime_fuzz_load_account( acc, funk, funk_txn, &test_ctx->acct_states[i], 1 );
     320             : 
     321             :     /* Update vote accounts cache for epoch T */
     322           0 :     fd_pubkey_t pubkey;
     323           0 :     memcpy( &pubkey, test_ctx->acct_states[i].address, sizeof(fd_pubkey_t) );
     324           0 :     fd_runtime_fuzz_block_register_vote_account( slot_ctx,
     325           0 :                                                  vote_accounts_pool,
     326           0 :                                                  &vote_accounts_root,
     327           0 :                                                  &pubkey,
     328           0 :                                                  runner->spad );
     329             : 
     330             :     /* Update the stake delegations cache for epoch T */
     331           0 :     fd_runtime_fuzz_block_register_stake_delegation( slot_ctx,
     332           0 :                                                      stake_delegations_pool,
     333           0 :                                                      &stake_delegations_root,
     334           0 :                                                      &pubkey );
     335           0 :   }
     336             : 
     337             :   /* Refresh vote accounts to calculate stake delegations */
     338           0 :   fd_runtime_fuzz_block_refresh_vote_accounts( vote_accounts_pool,
     339           0 :                                                vote_accounts_root,
     340           0 :                                                stake_delegations_pool,
     341           0 :                                                stake_delegations_root );
     342             : 
     343           0 :   fd_vote_accounts_vote_accounts_pool_update( &stakes->vote_accounts, vote_accounts_pool );
     344           0 :   fd_vote_accounts_vote_accounts_root_update( &stakes->vote_accounts, vote_accounts_root );
     345             : 
     346           0 :   fd_stakes_stake_delegations_pool_update( stakes, stake_delegations_pool );
     347           0 :   fd_stakes_stake_delegations_root_update( stakes, stake_delegations_root );
     348             : 
     349             : 
     350             :   /* Add accounts to bpf program cache */
     351           0 :   fd_bpf_scan_and_create_bpf_program_cache_entry( slot_ctx, runner->spad );
     352             : 
     353             :   /* Finish init epoch bank sysvars */
     354           0 :   fd_epoch_schedule_t * epoch_schedule = fd_sysvar_epoch_schedule_read( funk, funk_txn, runner->spad );
     355           0 :   fd_bank_epoch_schedule_set( slot_ctx->bank, *epoch_schedule );
     356             : 
     357           0 :   fd_rent_t const * rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad );
     358           0 :   fd_bank_rent_set( slot_ctx->bank, *rent );
     359             : 
     360           0 :   stakes->epoch = fd_slot_to_epoch( epoch_schedule, test_ctx->slot_ctx.prev_slot, NULL );
     361             : 
     362           0 :   fd_bank_stakes_end_locking_modify( slot_ctx->bank );
     363             : 
     364           0 :   fd_vote_accounts_global_t * vote_accounts = fd_bank_next_epoch_stakes_locking_modify( slot_ctx->bank );
     365           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() );
     366           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 ) );
     367           0 :   vote_accounts_root = NULL;
     368             : 
     369             :   /* Update vote cache for epoch T-1 */
     370           0 :   fd_runtime_fuzz_block_update_prev_epoch_votes_cache( vote_accounts_pool,
     371           0 :                                                        &vote_accounts_root,
     372           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_1,
     373           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_1_count,
     374           0 :                                                        runner->spad );
     375             : 
     376           0 :   fd_vote_accounts_vote_accounts_pool_update( vote_accounts, vote_accounts_pool );
     377           0 :   fd_vote_accounts_vote_accounts_root_update( vote_accounts, vote_accounts_root );
     378             : 
     379           0 :   fd_bank_next_epoch_stakes_end_locking_modify( slot_ctx->bank );
     380             : 
     381             :   /* Update vote cache for epoch T-2 */
     382           0 :   vote_accounts = fd_bank_epoch_stakes_locking_modify( slot_ctx->bank );
     383           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() );
     384           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 ) );
     385           0 :   vote_accounts_root = NULL;
     386             : 
     387           0 :   fd_runtime_fuzz_block_update_prev_epoch_votes_cache( vote_accounts_pool,
     388           0 :                                                        &vote_accounts_root,
     389           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_2,
     390           0 :                                                        test_ctx->epoch_ctx.vote_accounts_t_2_count,
     391           0 :                                                        runner->spad );
     392             : 
     393           0 :   fd_vote_accounts_vote_accounts_pool_update( vote_accounts, vote_accounts_pool );
     394           0 :   fd_vote_accounts_vote_accounts_root_update( vote_accounts, vote_accounts_root );
     395           0 :   fd_bank_epoch_stakes_end_locking_modify( slot_ctx->bank );
     396             : 
     397             :   /* Update leader schedule */
     398           0 :   fd_runtime_update_leaders( slot_ctx->bank, slot_ctx->slot, runner->spad );
     399             : 
     400             :   /* Initialize the blockhash queue and recent blockhashes sysvar from the input blockhash queue */
     401           0 :   fd_block_hash_queue_global_t * block_hash_queue = (fd_block_hash_queue_global_t *)&slot_ctx->bank->block_hash_queue[0];
     402           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) );
     403           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() );
     404           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, FD_BLOCKHASH_QUEUE_MAX_ENTRIES ) );
     405             : 
     406           0 :   block_hash_queue->max_age          = FD_BLOCKHASH_QUEUE_MAX_ENTRIES; // Max age is fixed at 300
     407           0 :   block_hash_queue->ages_root_offset = 0UL;
     408           0 :   block_hash_queue->ages_pool_offset = (ulong)fd_hash_hash_age_pair_t_map_leave( ages_pool ) - (ulong)block_hash_queue;
     409           0 :   block_hash_queue->last_hash_index  = 0UL;
     410           0 :   block_hash_queue->last_hash_offset = (ulong)last_hash_mem - (ulong)block_hash_queue;
     411             : 
     412           0 :   fd_memset( last_hash_mem, 0, sizeof(fd_hash_t) );
     413             : 
     414             :   /* TODO: We might need to load this in from the input. We also need to
     415             :      size this out for worst case, but this also blows up the memory
     416             :      requirement. */
     417             :   /* Allocate all the memory for the rent fresh accounts list */
     418             : 
     419             :   // Set genesis hash to {0}
     420           0 :   fd_hash_t * genesis_hash = fd_bank_genesis_hash_modify( slot_ctx->bank );
     421           0 :   fd_memset( genesis_hash->hash, 0, sizeof(fd_hash_t) );
     422             : 
     423             :   // Use the latest lamports per signature
     424           0 :   fd_recent_block_hashes_global_t const * rbh_global = fd_sysvar_recent_hashes_read( funk, funk_txn, runner->spad );
     425           0 :   fd_recent_block_hashes_t rbh[1];
     426           0 :   if( rbh_global ) {
     427           0 :     rbh->hashes = deq_fd_block_block_hash_entry_t_join( (uchar*)rbh_global + rbh_global->hashes_offset );
     428           0 :   }
     429             : 
     430           0 :   if( rbh_global && !deq_fd_block_block_hash_entry_t_empty( rbh->hashes ) ) {
     431           0 :     fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_head_const( rbh->hashes );
     432           0 :     if( last && last->fee_calculator.lamports_per_signature!=0UL ) {
     433           0 :       fd_bank_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature );
     434           0 :       fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature );
     435           0 :     }
     436           0 :   }
     437             : 
     438             :   // Populate blockhash queue and recent blockhashes sysvar
     439           0 :   for( ushort i=0; i<test_ctx->blockhash_queue_count; ++i ) {
     440           0 :     fd_block_block_hash_entry_t blockhash_entry;
     441           0 :     memcpy( &blockhash_entry.blockhash, test_ctx->blockhash_queue[i]->bytes, sizeof(fd_hash_t) );
     442           0 :     fd_bank_poh_set( slot_ctx->bank, blockhash_entry.blockhash );
     443           0 :     fd_sysvar_recent_hashes_update( slot_ctx, runner->spad );
     444           0 :   }
     445             : 
     446             :   // Set the current poh from the input (we skip POH verification in this fuzzing target)
     447           0 :   fd_hash_t * poh = fd_bank_poh_modify( slot_ctx->bank );
     448           0 :   fd_memcpy( poh->hash, test_ctx->slot_ctx.poh, sizeof(fd_hash_t) );
     449             : 
     450             :   /* Make a new funk transaction since we're done loading in accounts for context */
     451           0 :   fd_funk_txn_xid_t fork_xid[1] = {0};
     452           0 :   fork_xid[0] = fd_funk_generate_xid();
     453           0 :   fd_funk_txn_start_write( funk );
     454           0 :   slot_ctx->funk_txn = fd_funk_txn_prepare( funk, slot_ctx->funk_txn, fork_xid, 1 );
     455           0 :   fd_funk_txn_end_write( funk );
     456             : 
     457             :   /* Calculate epoch account hash values. This sets epoch_bank.eah_{start_slot, stop_slot, interval} */
     458           0 :   fd_calculate_epoch_accounts_hash_values( slot_ctx );
     459             : 
     460             :   /* Prepare raw transaction pointers and block / microblock infos */
     461           0 :   ulong txn_cnt = test_ctx->txns_count;
     462             : 
     463             :   // For fuzzing, we're using a single microblock batch that contains a single microblock containing all transactions
     464           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) );
     465           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) );
     466           0 :   fd_microblock_info_t *       microblock_info  = fd_spad_alloc( runner->spad, alignof(fd_microblock_info_t), sizeof(fd_microblock_info_t) );
     467           0 :   fd_memset( block_info, 0, sizeof(fd_runtime_block_info_t) );
     468           0 :   fd_memset( batch_info, 0, sizeof(fd_microblock_batch_info_t) );
     469           0 :   fd_memset( microblock_info, 0, sizeof(fd_microblock_info_t) );
     470             : 
     471           0 :   block_info->microblock_batch_cnt   = 1UL;
     472           0 :   block_info->microblock_cnt         = 1UL;
     473           0 :   block_info->microblock_batch_infos = batch_info;
     474             : 
     475           0 :   batch_info->microblock_cnt         = 1UL;
     476           0 :   batch_info->microblock_infos       = microblock_info;
     477             : 
     478           0 :   ulong batch_signature_cnt          = 0UL;
     479           0 :   ulong batch_txn_cnt                = 0UL;
     480           0 :   ulong batch_account_cnt            = 0UL;
     481           0 :   ulong signature_cnt                = 0UL;
     482           0 :   ulong account_cnt                  = 0UL;
     483             : 
     484           0 :   fd_microblock_hdr_t * microblock_hdr = fd_spad_alloc( runner->spad, alignof(fd_microblock_hdr_t), sizeof(fd_microblock_hdr_t) );
     485           0 :   fd_memset( microblock_hdr, 0, sizeof(fd_microblock_hdr_t) );
     486             : 
     487           0 :   fd_txn_p_t * txn_ptrs = fd_spad_alloc( runner->spad, alignof(fd_txn_p_t), txn_cnt * sizeof(fd_txn_p_t) );
     488           0 :   for( ulong i=0UL; i<txn_cnt; i++ ) {
     489           0 :     fd_txn_p_t * txn = &txn_ptrs[i];
     490             : 
     491           0 :     ushort _instr_count, _addr_table_cnt;
     492           0 :     ulong msg_sz = fd_runtime_fuzz_serialize_txn( txn->payload, &test_ctx->txns[i], &_instr_count, &_addr_table_cnt );
     493             : 
     494             :     // Reject any transactions over 1232 bytes
     495           0 :     if( FD_UNLIKELY( msg_sz==ULONG_MAX ) ) {
     496           0 :       return NULL;
     497           0 :     }
     498           0 :     txn->payload_sz = msg_sz;
     499             : 
     500             :     // Reject any transactions that cannot be parsed
     501           0 :     if( FD_UNLIKELY( !fd_txn_parse( txn->payload, msg_sz, TXN( txn ), NULL ) ) ) {
     502           0 :       return NULL;
     503           0 :     }
     504             : 
     505           0 :     signature_cnt += TXN( txn )->signature_cnt;
     506           0 :     account_cnt   += fd_txn_account_cnt( TXN( txn ), FD_TXN_ACCT_CAT_ALL );
     507           0 :   }
     508             : 
     509           0 :   microblock_hdr->txn_cnt         = txn_cnt;
     510           0 :   microblock_info->microblock.raw = (uchar *)microblock_hdr;
     511             : 
     512           0 :   microblock_info->signature_cnt  = signature_cnt;
     513           0 :   microblock_info->account_cnt    = account_cnt;
     514           0 :   microblock_info->txns           = txn_ptrs;
     515             : 
     516           0 :   batch_signature_cnt            += signature_cnt;
     517           0 :   batch_txn_cnt                  += txn_cnt;
     518           0 :   batch_account_cnt              += account_cnt;
     519             : 
     520           0 :   block_info->signature_cnt = batch_info->signature_cnt = batch_signature_cnt;
     521           0 :   block_info->txn_cnt       = batch_info->txn_cnt       = batch_txn_cnt;
     522           0 :   block_info->account_cnt   = batch_info->account_cnt   = batch_account_cnt;
     523             : 
     524           0 :   return block_info;
     525           0 : }
     526             : 
     527             : /* Takes in a block_info created from `fd_runtime_fuzz_block_ctx_create()`
     528             :    and executes it against the runtime. Returns the execution result. */
     529             : static int
     530             : fd_runtime_fuzz_block_ctx_exec( fd_runtime_fuzz_runner_t * runner,
     531             :                                 fd_exec_slot_ctx_t *       slot_ctx,
     532           0 :                                 fd_runtime_block_info_t *  block_info ) {
     533           0 :   int res = 0;
     534             : 
     535             :   /* Initialize tpool and spad(s) */
     536           0 :   ulong        worker_max = FD_BLOCK_HARNESS_TPOOL_WORKER_CNT;
     537           0 :   void *       tpool_mem  = fd_spad_alloc( runner->spad, FD_TPOOL_ALIGN, FD_TPOOL_FOOTPRINT( worker_max ) );
     538           0 :   fd_tpool_t * tpool      = fd_tpool_init( tpool_mem, worker_max, 0UL );
     539           0 :   fd_tpool_worker_push( tpool, 1UL );
     540             : 
     541           0 :   fd_spad_t * runtime_spad = runner->spad;
     542             : 
     543             :   /* Format chunks of memory for the exec spads
     544             :      TODO: This memory needs a better bound. */
     545           0 :   fd_spad_t * exec_spads[FD_BLOCK_HARNESS_TPOOL_WORKER_CNT] = { 0 };
     546           0 :   ulong       exec_spads_cnt                                = FD_BLOCK_HARNESS_TPOOL_WORKER_CNT;
     547           0 :   for( ulong i=0UL; i<worker_max; i++ ) {
     548           0 :     void *      exec_spad_mem = fd_spad_alloc( runtime_spad, FD_SPAD_ALIGN, FD_SPAD_FOOTPRINT( FD_BLOCK_HARNESS_MEM_PER_SPAD ) );
     549           0 :     fd_spad_t * exec_spad     = fd_spad_join( fd_spad_new( exec_spad_mem, FD_BLOCK_HARNESS_MEM_PER_SPAD ) );
     550           0 :     exec_spads[i] = exec_spad;
     551           0 :   }
     552             : 
     553             :   // Prepare. Execute. Finalize.
     554           0 :   FD_SPAD_FRAME_BEGIN( runtime_spad ) {
     555           0 :     fd_rewards_recalculate_partitioned_rewards( slot_ctx, tpool, exec_spads, exec_spads_cnt, runtime_spad );
     556             : 
     557             :     /* Process new epoch may push a new spad frame onto the runtime spad. We should make sure this frame gets
     558             :        cleared (if it was allocated) before executing the block. */
     559           0 :     int   is_epoch_boundary = 0;
     560           0 :     fd_runtime_block_pre_execute_process_new_epoch( slot_ctx, tpool, exec_spads, exec_spads_cnt, runtime_spad, &is_epoch_boundary );
     561             : 
     562           0 :     res = fd_runtime_block_execute_tpool( slot_ctx, NULL, NULL, block_info, tpool, exec_spads, exec_spads_cnt, runtime_spad );
     563           0 :   } FD_SPAD_FRAME_END;
     564             : 
     565           0 :   fd_tpool_worker_pop( tpool );
     566             : 
     567           0 :   return res;
     568           0 : }
     569             : 
     570             : ulong
     571             : fd_runtime_fuzz_block_run( fd_runtime_fuzz_runner_t * runner,
     572             :                            void const *               input_,
     573             :                            void **                    output_,
     574             :                            void *                     output_buf,
     575           0 :                            ulong                      output_bufsz ) {
     576           0 :   fd_exec_test_block_context_t const * input  = fd_type_pun_const( input_ );
     577           0 :   fd_exec_test_block_effects_t **      output = fd_type_pun( output_ );
     578             : 
     579           0 :   FD_SPAD_FRAME_BEGIN( runner->spad ) {
     580             :     /* Initialize memory */
     581           0 :     fd_wksp_t *           wksp          = fd_wksp_attach( "wksp" );
     582           0 :     fd_alloc_t *          alloc         = fd_alloc_join( fd_alloc_new( fd_wksp_alloc_laddr( wksp, fd_alloc_align(), fd_alloc_footprint(), 2 ), 2 ), 0 );
     583           0 :     uchar *               slot_ctx_mem  = fd_spad_alloc( runner->spad, FD_EXEC_SLOT_CTX_ALIGN,  FD_EXEC_SLOT_CTX_FOOTPRINT );
     584           0 :     fd_exec_slot_ctx_t *  slot_ctx      = fd_exec_slot_ctx_join ( fd_exec_slot_ctx_new ( slot_ctx_mem ) );
     585             : 
     586             :     /* Set up the block execution context */
     587           0 :     fd_runtime_block_info_t * block_info = fd_runtime_fuzz_block_ctx_create( runner, slot_ctx, input );
     588           0 :     if( block_info==NULL ) {
     589           0 :       fd_runtime_fuzz_block_ctx_destroy( runner, slot_ctx, wksp, alloc );
     590           0 :       return 0;
     591           0 :     }
     592             : 
     593             :     /* Execute the constructed block against the runtime. */
     594           0 :     int res = fd_runtime_fuzz_block_ctx_exec( runner, slot_ctx, block_info);
     595             : 
     596             :     /* Start saving block exec results */
     597           0 :     FD_SCRATCH_ALLOC_INIT( l, output_buf );
     598           0 :     ulong output_end = (ulong)output_buf + output_bufsz;
     599             : 
     600           0 :     fd_exec_test_block_effects_t * effects =
     601           0 :     FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_block_effects_t),
     602           0 :                                   sizeof (fd_exec_test_block_effects_t) );
     603           0 :     if( FD_UNLIKELY( _l > output_end ) ) {
     604           0 :       abort();
     605           0 :     }
     606           0 :     fd_memset( effects, 0, sizeof(fd_exec_test_block_effects_t) );
     607             : 
     608             :     /* Capture error status */
     609           0 :     effects->has_error = !!( res );
     610             : 
     611             :     /* Capture capitalization */
     612           0 :     effects->slot_capitalization = fd_bank_capitalization_get( slot_ctx->bank );
     613             : 
     614             :     /* Capture hashes */
     615           0 :     fd_hash_t bank_hash = fd_bank_bank_hash_get( slot_ctx->bank );
     616           0 :     fd_memcpy( effects->bank_hash, bank_hash.hash, sizeof(fd_hash_t) );
     617             : 
     618           0 :     ulong actual_end = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     619           0 :     fd_runtime_fuzz_block_ctx_destroy( runner, slot_ctx, wksp, alloc );
     620             : 
     621           0 :     *output = effects;
     622           0 :     return actual_end - (ulong)output_buf;
     623           0 :   } FD_SPAD_FRAME_END;
     624           0 : }

Generated by: LCOV version 1.14