LCOV - code coverage report
Current view: top level - flamenco/runtime/context - fd_exec_slot_ctx.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 21 385 5.5 %
Date: 2025-07-01 05:00:49 Functions: 3 7 42.9 %

          Line data    Source code
       1             : #include "fd_exec_slot_ctx.h"
       2             : #include "../sysvar/fd_sysvar_epoch_schedule.h"
       3             : #include "../program/fd_vote_program.h"
       4             : #include "../../../ballet/lthash/fd_lthash.h"
       5             : 
       6             : #include <assert.h>
       7             : #include <time.h>
       8             : 
       9             : void *
      10           3 : fd_exec_slot_ctx_new( void * mem ) {
      11             : 
      12           3 :   if( FD_UNLIKELY( !mem ) ) {
      13           0 :     FD_LOG_WARNING(( "NULL mem" ));
      14           0 :     return NULL;
      15           0 :   }
      16             : 
      17           3 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_SLOT_CTX_ALIGN ) ) ) {
      18           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      19           0 :     return NULL;
      20           0 :   }
      21             : 
      22           3 :   fd_memset( mem, 0, sizeof(fd_exec_slot_ctx_t) );
      23             : 
      24           3 :   fd_exec_slot_ctx_t * self = (fd_exec_slot_ctx_t *)mem;
      25             : 
      26           3 :   FD_COMPILER_MFENCE();
      27           3 :   self->magic = FD_EXEC_SLOT_CTX_MAGIC;
      28           3 :   FD_COMPILER_MFENCE();
      29             : 
      30           3 :   return mem;
      31           3 : }
      32             : 
      33             : fd_exec_slot_ctx_t *
      34           3 : fd_exec_slot_ctx_join( void * mem ) {
      35           3 :   if( FD_UNLIKELY( !mem ) ) {
      36           0 :     FD_LOG_WARNING(( "NULL block" ));
      37           0 :     return NULL;
      38           0 :   }
      39             : 
      40           3 :   fd_exec_slot_ctx_t * ctx = (fd_exec_slot_ctx_t *) mem;
      41             : 
      42           3 :   if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
      43           0 :     FD_LOG_WARNING(( "bad magic" ));
      44           0 :     return NULL;
      45           0 :   }
      46             : 
      47           3 :   return ctx;
      48           3 : }
      49             : 
      50             : void *
      51           3 : fd_exec_slot_ctx_leave( fd_exec_slot_ctx_t * ctx) {
      52           3 :   if( FD_UNLIKELY( !ctx ) ) {
      53           0 :     FD_LOG_WARNING(( "NULL block" ));
      54           0 :     return NULL;
      55           0 :   }
      56             : 
      57           3 :   if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
      58           0 :     FD_LOG_WARNING(( "bad magic" ));
      59           0 :     return NULL;
      60           0 :   }
      61             : 
      62           3 :   return (void *) ctx;
      63           3 : }
      64             : 
      65             : void *
      66           0 : fd_exec_slot_ctx_delete( void * mem ) {
      67           0 :   if( FD_UNLIKELY( !mem ) ) {
      68           0 :     FD_LOG_WARNING(( "NULL mem" ));
      69           0 :     return NULL;
      70           0 :   }
      71             : 
      72           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_SLOT_CTX_ALIGN) ) )  {
      73           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      74           0 :     return NULL;
      75           0 :   }
      76             : 
      77           0 :   fd_exec_slot_ctx_t * hdr = (fd_exec_slot_ctx_t *)mem;
      78           0 :   if( FD_UNLIKELY( hdr->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
      79           0 :     FD_LOG_WARNING(( "bad magic" ));
      80           0 :     return NULL;
      81           0 :   }
      82             : 
      83           0 :   FD_COMPILER_MFENCE();
      84           0 :   FD_VOLATILE( hdr->magic ) = 0UL;
      85           0 :   FD_COMPILER_MFENCE();
      86             : 
      87           0 :   return mem;
      88           0 : }
      89             : 
      90             : /* recover_clock recovers PoH/wallclock synchronization.  Walks all vote
      91             :    accounts in current epoch stakes. */
      92             : 
      93             : static int
      94           0 : recover_clock( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
      95             : 
      96           0 :   fd_stakes_global_t const * stakes = fd_bank_stakes_locking_query( slot_ctx->bank );
      97           0 :   if( FD_UNLIKELY( stakes==NULL ) ) {
      98           0 :     FD_LOG_WARNING(( "stakes is NULL" ));
      99           0 :     fd_bank_stakes_end_locking_query( slot_ctx->bank );
     100           0 :     return 0;
     101           0 :   }
     102             : 
     103           0 :   fd_vote_accounts_global_t const *          vote_accounts      = &stakes->vote_accounts;
     104           0 :   fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_pool = fd_vote_accounts_vote_accounts_pool_join( vote_accounts );
     105           0 :   fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_root = fd_vote_accounts_vote_accounts_root_join( vote_accounts );
     106             : 
     107           0 :   if( FD_UNLIKELY( !vote_accounts_pool ) ) {
     108           0 :     FD_LOG_CRIT(( "vote_accounts_pool is NULL" ));
     109           0 :   }
     110           0 :   if( FD_UNLIKELY( !vote_accounts_root ) ) {
     111           0 :     FD_LOG_CRIT(( "vote_accounts_root is NULL" ));
     112           0 :   }
     113             : 
     114           0 :   for( fd_vote_accounts_pair_global_t_mapnode_t * n = fd_vote_accounts_pair_global_t_map_minimum(vote_accounts_pool, vote_accounts_root);
     115           0 :        n;
     116           0 :        n = fd_vote_accounts_pair_global_t_map_successor( vote_accounts_pool, n ) ) {
     117             : 
     118           0 :     FD_SPAD_FRAME_BEGIN( runtime_spad ) {
     119             : 
     120             :     /* Extract vote timestamp of account */
     121           0 :     int err;
     122             : 
     123           0 :     uchar * data     = fd_solana_account_data_join( &n->elem.value );
     124           0 :     ulong   data_len = n->elem.value.data_len;
     125             : 
     126           0 :     fd_vote_state_versioned_t * vsv = fd_bincode_decode_spad(
     127           0 :         vote_state_versioned, runtime_spad,
     128           0 :         data,
     129           0 :         data_len,
     130           0 :         &err );
     131           0 :     if( FD_UNLIKELY( err ) ) {
     132           0 :       FD_LOG_WARNING(( "vote state decode failed" ));
     133           0 :       fd_bank_stakes_end_locking_query( slot_ctx->bank );
     134           0 :       return 0;
     135           0 :     }
     136             : 
     137           0 :     long timestamp = 0;
     138           0 :     ulong slot = 0;
     139           0 :     switch( vsv->discriminant ) {
     140           0 :       case fd_vote_state_versioned_enum_v0_23_5:
     141           0 :         timestamp = vsv->inner.v0_23_5.last_timestamp.timestamp;
     142           0 :         slot = vsv->inner.v0_23_5.last_timestamp.slot;
     143           0 :         break;
     144           0 :       case fd_vote_state_versioned_enum_v1_14_11:
     145           0 :         timestamp = vsv->inner.v1_14_11.last_timestamp.timestamp;
     146           0 :         slot = vsv->inner.v1_14_11.last_timestamp.slot;
     147           0 :         break;
     148           0 :       case fd_vote_state_versioned_enum_current:
     149           0 :         timestamp = vsv->inner.current.last_timestamp.timestamp;
     150           0 :         slot = vsv->inner.current.last_timestamp.slot;
     151           0 :         break;
     152           0 :       default:
     153           0 :         __builtin_unreachable();
     154           0 :     }
     155             : 
     156             :     /* Record timestamp */
     157           0 :     if( slot != 0 || n->elem.stake != 0 ) {
     158           0 :       fd_vote_record_timestamp_vote_with_slot( &n->elem.key, timestamp, slot, slot_ctx->bank );
     159           0 :     }
     160           0 :   } FD_SPAD_FRAME_END;
     161           0 :   }
     162             : 
     163           0 :   fd_bank_stakes_end_locking_query( slot_ctx->bank );
     164           0 :   return 1;
     165           0 : }
     166             : 
     167             : fd_exec_slot_ctx_t *
     168             : fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t *                slot_ctx,
     169             :                           fd_solana_manifest_global_t const * manifest,
     170           0 :                           fd_spad_t *                         runtime_spad ) {
     171             : 
     172           0 :   slot_ctx->bank = fd_banks_clone_from_parent( slot_ctx->banks, manifest->bank.slot, 0UL );
     173           0 :   if( FD_UNLIKELY( !slot_ctx->bank ) ) {
     174           0 :     FD_LOG_CRIT(( "fd_banks_clone_from_parent failed" ));
     175           0 :   }
     176             : 
     177           0 :   fd_versioned_bank_global_t const * old_bank = &manifest->bank;
     178             : 
     179           0 :   ulong stakes_sz = fd_stakes_size_global( &manifest->bank.stakes );
     180           0 :   fd_stakes_global_t * stakes = fd_bank_stakes_locking_modify( slot_ctx->bank );
     181           0 :   fd_memcpy( stakes, &manifest->bank.stakes, stakes_sz );
     182             :   /* Verify stakes */
     183             : 
     184           0 :   fd_bank_stakes_end_locking_modify( slot_ctx->bank );
     185             : 
     186             :   /* Index vote accounts */
     187             : 
     188             :   /* Block Hash Queue */
     189             : 
     190           0 :   fd_block_hash_queue_global_t * bhq = (fd_block_hash_queue_global_t *)&slot_ctx->bank->block_hash_queue[0];
     191           0 :   uchar * last_hash_mem = (uchar *)fd_ulong_align_up( (ulong)bhq + sizeof(fd_block_hash_queue_global_t), alignof(fd_hash_t) );
     192           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() );
     193             : 
     194           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, 301 ) );
     195           0 :   fd_hash_hash_age_pair_t_mapnode_t * ages_root = NULL;
     196             : 
     197           0 :   bhq->last_hash_index = old_bank->blockhash_queue.last_hash_index;
     198             : 
     199           0 :   fd_hash_t const * last_hash = fd_block_hash_vec_last_hash_join( &old_bank->blockhash_queue );
     200             : 
     201           0 :   if( last_hash ) {
     202           0 :     fd_memcpy( last_hash_mem, last_hash, sizeof(fd_hash_t) );
     203           0 :   } else {
     204           0 :     fd_memset( last_hash_mem, 0, sizeof(fd_hash_t) );
     205           0 :   }
     206           0 :   bhq->last_hash_offset = (ulong)last_hash_mem - (ulong)bhq;
     207             : 
     208           0 :   fd_hash_hash_age_pair_t const * ages = fd_block_hash_vec_ages_join( &old_bank->blockhash_queue );
     209             : 
     210           0 :   for( ulong i=0UL; i<old_bank->blockhash_queue.ages_len; i++ ) {
     211           0 :     fd_hash_hash_age_pair_t const * elem = &ages[i];
     212           0 :     fd_hash_hash_age_pair_t_mapnode_t * node = fd_hash_hash_age_pair_t_map_acquire( ages_pool );
     213           0 :     node->elem = *elem;
     214           0 :     fd_hash_hash_age_pair_t_map_insert( ages_pool, &ages_root, node );
     215           0 :   }
     216             : 
     217           0 :   fd_block_hash_queue_ages_pool_update( bhq, ages_pool );
     218           0 :   fd_block_hash_queue_ages_root_update( bhq, ages_root );
     219             : 
     220           0 :   bhq->max_age = old_bank->blockhash_queue.max_age;
     221             : 
     222             :   /* Bank Hash */
     223             : 
     224           0 :   fd_bank_bank_hash_set( slot_ctx->bank, old_bank->hash );
     225             : 
     226             :   /* Slot */
     227             : 
     228           0 :   slot_ctx->slot = old_bank->slot;
     229             : 
     230             :   /* Fee Rate Governor */
     231             : 
     232           0 :   fd_fee_rate_governor_t * fee_rate_governor = fd_bank_fee_rate_governor_modify( slot_ctx->bank );
     233           0 :   fd_memcpy( fee_rate_governor, &old_bank->fee_rate_governor, sizeof(fd_fee_rate_governor_t) );
     234             : 
     235             :   /* Capitalization */
     236             : 
     237           0 :   fd_bank_capitalization_set( slot_ctx->bank, old_bank->capitalization );
     238             : 
     239             :   /* Lamports Per Signature */
     240             : 
     241           0 :   fd_bank_lamports_per_signature_set( slot_ctx->bank, manifest->lamports_per_signature );
     242             : 
     243             :   /* Previous Lamports Per Signature */
     244             : 
     245           0 :   fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, manifest->lamports_per_signature );
     246             : 
     247             :   /* Transaction Count */
     248             : 
     249           0 :   fd_bank_transaction_count_set( slot_ctx->bank, old_bank->transaction_count );
     250             : 
     251             :   /* Parent Signature Count */
     252             : 
     253           0 :   fd_bank_parent_signature_cnt_set( slot_ctx->bank, old_bank->signature_count );
     254             : 
     255             :   /* Tick Height */
     256             : 
     257           0 :   fd_bank_tick_height_set( slot_ctx->bank, old_bank->tick_height );
     258             : 
     259             :   /* Max Tick Height */
     260             : 
     261           0 :   fd_bank_max_tick_height_set( slot_ctx->bank, old_bank->max_tick_height );
     262             : 
     263             :   /* Hashes Per Tick */
     264             : 
     265           0 :   ulong * hashes_per_tick = fd_versioned_bank_hashes_per_tick_join( old_bank );
     266           0 :   fd_bank_hashes_per_tick_set( slot_ctx->bank, !!hashes_per_tick ? *hashes_per_tick : 0UL );
     267             : 
     268             :   /* NS Per Slot */
     269             : 
     270           0 :   fd_bank_ns_per_slot_set( slot_ctx->bank, old_bank->ns_per_slot );
     271             : 
     272             :   /* Ticks Per Slot */
     273             : 
     274           0 :   fd_bank_ticks_per_slot_set( slot_ctx->bank, old_bank->ticks_per_slot );
     275             : 
     276             :   /* Genesis Creation Time */
     277             : 
     278           0 :   fd_bank_genesis_creation_time_set( slot_ctx->bank, old_bank->genesis_creation_time );
     279             : 
     280             :   /* Slots Per Year */
     281             : 
     282           0 :   fd_bank_slots_per_year_set( slot_ctx->bank, old_bank->slots_per_year );
     283             : 
     284             :   /* Inflation */
     285             : 
     286           0 :   fd_bank_inflation_set( slot_ctx->bank, old_bank->inflation );
     287             : 
     288             :   /* Block Height */
     289             : 
     290           0 :   fd_bank_block_height_set( slot_ctx->bank, old_bank->block_height );
     291             : 
     292             :   /* Epoch Account Hash */
     293             : 
     294           0 :   fd_hash_t * epoch_account_hash = fd_solana_manifest_epoch_account_hash_join( manifest );
     295           0 :   if( !!epoch_account_hash ) {
     296           0 :     fd_bank_epoch_account_hash_set( slot_ctx->bank, *epoch_account_hash );
     297           0 :   } else {
     298           0 :     fd_bank_epoch_account_hash_set( slot_ctx->bank, (fd_hash_t){0} );
     299           0 :   }
     300             : 
     301             :   /* Prev Slot */
     302             : 
     303           0 :   fd_bank_prev_slot_set( slot_ctx->bank, old_bank->parent_slot );
     304             : 
     305             :   /* Execution Fees */
     306             : 
     307           0 :   fd_bank_execution_fees_set( slot_ctx->bank, old_bank->collector_fees );
     308             : 
     309             :   /* Priority Fees */
     310             : 
     311           0 :   fd_bank_priority_fees_set( slot_ctx->bank, 0UL );
     312             : 
     313             :   /* PoH */
     314             : 
     315           0 :   if( last_hash ) {
     316           0 :     fd_bank_poh_set( slot_ctx->bank, *last_hash );
     317           0 :   }
     318             : 
     319             :   /* Prev Bank Hash */
     320             : 
     321           0 :   fd_bank_prev_bank_hash_set( slot_ctx->bank, old_bank->parent_hash );
     322             : 
     323             :   /* Epoch Schedule */
     324             : 
     325           0 :   fd_bank_epoch_schedule_set( slot_ctx->bank, old_bank->epoch_schedule );
     326             : 
     327             :   /* Rent */
     328             : 
     329           0 :   fd_bank_rent_set( slot_ctx->bank, old_bank->rent_collector.rent );
     330             : 
     331             :   /* Last Restart Slot */
     332             : 
     333             :   /* Update last restart slot
     334             :      https://github.com/solana-labs/solana/blob/30531d7a5b74f914dde53bfbb0bc2144f2ac92bb/runtime/src/bank.rs#L2152
     335             : 
     336             :      old_bank->hard_forks is sorted ascending by slot number.
     337             :      To find the last restart slot, take the highest hard fork slot
     338             :      number that is less or equal than the current slot number.
     339             :      (There might be some hard forks in the future, ignore these) */
     340           0 :   do {
     341           0 :     fd_sol_sysvar_last_restart_slot_t * last_restart_slot = fd_bank_last_restart_slot_modify( slot_ctx->bank );
     342           0 :     last_restart_slot->slot = 0UL;
     343             : 
     344           0 :     if( FD_UNLIKELY( old_bank->hard_forks.hard_forks_len == 0 ) ) {
     345             :       /* SIMD-0047: The first restart slot should be `0` */
     346           0 :       break;
     347           0 :     }
     348             : 
     349           0 :     fd_slot_pair_t const * head = fd_hard_forks_hard_forks_join( &old_bank->hard_forks );
     350           0 :     fd_slot_pair_t const * tail = head + old_bank->hard_forks.hard_forks_len - 1UL;
     351             : 
     352           0 :     for( fd_slot_pair_t const *pair = tail; pair >= head; pair-- ) {
     353           0 :       if( pair->slot <= slot_ctx->slot ) {
     354           0 :         fd_sol_sysvar_last_restart_slot_t * last_restart_slot = fd_bank_last_restart_slot_modify( slot_ctx->bank );
     355           0 :         last_restart_slot->slot = pair->slot;
     356           0 :         break;
     357           0 :       }
     358           0 :     }
     359           0 :   } while (0);
     360             : 
     361             :   /* FIXME: Remove the magic number here. */
     362           0 :   fd_clock_timestamp_votes_global_t * clock_timestamp_votes = fd_bank_clock_timestamp_votes_locking_modify( slot_ctx->bank );
     363           0 :   uchar * clock_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() );
     364           0 :   fd_clock_timestamp_vote_t_mapnode_t * clock_pool = fd_clock_timestamp_vote_t_map_join( fd_clock_timestamp_vote_t_map_new(clock_pool_mem, 30000UL ) );
     365           0 :   clock_timestamp_votes->votes_pool_offset = (ulong)fd_clock_timestamp_vote_t_map_leave( clock_pool) - (ulong)clock_timestamp_votes;
     366           0 :   clock_timestamp_votes->votes_root_offset = 0UL;
     367           0 :   fd_bank_clock_timestamp_votes_end_locking_modify( slot_ctx->bank );
     368             : 
     369           0 :   recover_clock( slot_ctx, runtime_spad );
     370             : 
     371             : 
     372             :   /* Move EpochStakes */
     373           0 :   do {
     374             : 
     375           0 :     fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank );
     376           0 :     ulong epoch = fd_slot_to_epoch( epoch_schedule, slot_ctx->slot, NULL );
     377             : 
     378             :     /* We need to save the vote accounts for the current epoch and the next
     379             :        epoch as it is used to calculate the leader schedule at the epoch
     380             :        boundary. */
     381             : 
     382           0 :     fd_vote_accounts_global_t * vote_accounts_curr_stakes = NULL;
     383           0 :     fd_vote_accounts_global_t * vote_accounts_next_stakes = NULL;
     384             : 
     385           0 :     fd_epoch_epoch_stakes_pair_global_t * versioned_bank_epoch_stakes = fd_versioned_bank_epoch_stakes_join( &manifest->bank );
     386           0 :     for( ulong i=0UL; i<manifest->bank.epoch_stakes_len; i++ ) {
     387           0 :       if( versioned_bank_epoch_stakes[i].key == epoch ) {
     388           0 :         vote_accounts_curr_stakes = &versioned_bank_epoch_stakes[i].value.stakes.vote_accounts;
     389           0 :       }
     390           0 :       if( versioned_bank_epoch_stakes[i].key == epoch+1UL ) {
     391           0 :         vote_accounts_next_stakes = &versioned_bank_epoch_stakes[i].value.stakes.vote_accounts;
     392           0 :       }
     393             : 
     394             :       /* When loading from a snapshot, Agave's stake caches mean that we have to special-case the epoch stakes
     395             :          that are used for the second epoch E+2 after the snapshot epoch E.
     396             : 
     397             :          If the snapshot contains the epoch stakes for E+2, we should use those.
     398             : 
     399             :          If the snapshot does not, we should use the stakes at the end of the E-1 epoch, instead of E-2 as we do for
     400             :          all other epochs. */
     401           0 :     }
     402             : 
     403           0 :     fd_versioned_epoch_stakes_pair_global_t * versioned_epoch_stakes = fd_solana_manifest_versioned_epoch_stakes_join( manifest );
     404           0 :     for( ulong i=0UL; i<manifest->versioned_epoch_stakes_len; i++ ) {
     405             : 
     406           0 :       if( versioned_epoch_stakes[i].epoch == epoch ) {
     407           0 :         vote_accounts_curr_stakes = &versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts;
     408           0 :       }
     409           0 :       if( versioned_epoch_stakes[i].epoch == epoch+1UL ) {
     410           0 :         vote_accounts_next_stakes = &versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts;
     411             : 
     412             :         /* Save the initial value to be used for the get_epoch_stake
     413             :            syscall.
     414             : 
     415             :            A note on Agave's indexing scheme for their epoch_stakes
     416             :            structure:
     417             : 
     418             :            https://github.com/anza-xyz/agave/blob/v2.2.14/runtime/src/bank.rs#L6175
     419             : 
     420             :            If we are loading a snapshot and replaying in the middle of
     421             :            epoch 7, the syscall is supposed to return the total stake at
     422             :            the end of epoch 6.  The epoch_stakes structure is indexed in
     423             :            Agave by the epoch number of the leader schedule that the
     424             :            stakes are meant to determine.  For instance, to get the
     425             :            stakes at the end of epoch 6, we should query by 8, because
     426             :            the leader schedule for epoch 8 is determined based on the
     427             :            stakes at the end of epoch 6.  Therefore, we save the total
     428             :            epoch stake by querying for epoch+1. */
     429           0 :         fd_bank_total_epoch_stake_set( slot_ctx->bank, versioned_epoch_stakes[i].val.inner.Current.total_stake );
     430           0 :       }
     431           0 :     }
     432             : 
     433           0 :     fd_bank_use_prev_epoch_stake_set( slot_ctx->bank, epoch + 2UL );
     434             : 
     435           0 :     fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_curr_stakes_pool = fd_vote_accounts_vote_accounts_pool_join( vote_accounts_curr_stakes );
     436           0 :     fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_curr_stakes_root = fd_vote_accounts_vote_accounts_root_join( vote_accounts_curr_stakes );
     437             : 
     438           0 :     fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_next_stakes_pool = fd_vote_accounts_vote_accounts_pool_join( vote_accounts_next_stakes );
     439           0 :     fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_next_stakes_root = fd_vote_accounts_vote_accounts_root_join( vote_accounts_next_stakes );
     440             : 
     441           0 :     if( FD_UNLIKELY( (!vote_accounts_curr_stakes_pool) | (!vote_accounts_next_stakes_pool) ) ) {
     442           0 :       FD_LOG_WARNING(( "snapshot missing EpochStakes for epochs %lu and/or %lu", epoch, epoch+1UL ));
     443           0 :       return 0;
     444           0 :     }
     445             : 
     446             :     /* Move current EpochStakes */
     447             : 
     448           0 :     fd_vote_accounts_global_t * epoch_stakes = fd_bank_epoch_stakes_locking_modify( slot_ctx->bank );
     449           0 :     uchar * epoch_stakes_pool_mem = (uchar *)fd_ulong_align_up( (ulong)epoch_stakes + sizeof(fd_vote_accounts_global_t), fd_vote_accounts_pair_global_t_map_align() );
     450           0 :     fd_vote_accounts_pair_global_t_mapnode_t * epoch_stakes_pool = fd_vote_accounts_pair_global_t_map_join( fd_vote_accounts_pair_global_t_map_new( epoch_stakes_pool_mem, 50000UL ) );
     451           0 :     fd_vote_accounts_pair_global_t_mapnode_t * epoch_stakes_root = NULL;
     452             : 
     453           0 :     uchar * acc_region_curr = (uchar *)fd_ulong_align_up( (ulong)epoch_stakes_pool + fd_vote_accounts_pair_global_t_map_footprint( 50000UL ), 8UL );
     454             : 
     455           0 :     for( fd_vote_accounts_pair_global_t_mapnode_t * n = fd_vote_accounts_pair_global_t_map_minimum(
     456           0 :           vote_accounts_curr_stakes_pool,
     457           0 :           vote_accounts_curr_stakes_root );
     458           0 :           n;
     459           0 :           n = fd_vote_accounts_pair_global_t_map_successor( vote_accounts_curr_stakes_pool, n ) ) {
     460             : 
     461           0 :       fd_vote_accounts_pair_global_t_mapnode_t * elem = fd_vote_accounts_pair_global_t_map_acquire(
     462           0 :         epoch_stakes_pool );
     463           0 :       FD_TEST( elem );
     464             : 
     465           0 :       elem->elem.stake = n->elem.stake;
     466           0 :       elem->elem.key   = n->elem.key;
     467             : 
     468           0 :       elem->elem.value.lamports    = n->elem.value.lamports;
     469           0 :       elem->elem.value.data_len    = 0UL;
     470           0 :       elem->elem.value.data_offset = 0UL;
     471           0 :       elem->elem.value.owner       = n->elem.value.owner;
     472           0 :       elem->elem.value.executable  = n->elem.value.executable;
     473           0 :       elem->elem.value.rent_epoch  = n->elem.value.rent_epoch;
     474             : 
     475           0 :       elem->elem.value.data_offset = (ulong)(acc_region_curr - (uchar *)&elem->elem.value);
     476           0 :       elem->elem.value.data_len = n->elem.value.data_len;
     477             : 
     478           0 :       uchar * manifest_data = fd_solana_account_data_join( &n->elem.value );
     479           0 :       memcpy( acc_region_curr, manifest_data, n->elem.value.data_len );
     480           0 :       acc_region_curr += n->elem.value.data_len;
     481             : 
     482           0 :       fd_vote_accounts_pair_global_t_map_insert(
     483           0 :         epoch_stakes_pool,
     484           0 :         &epoch_stakes_root,
     485           0 :         elem );
     486           0 :     }
     487             : 
     488           0 :     fd_vote_accounts_vote_accounts_pool_update( epoch_stakes, epoch_stakes_pool );
     489           0 :     fd_vote_accounts_vote_accounts_root_update( epoch_stakes, epoch_stakes_root );
     490           0 :     fd_bank_epoch_stakes_end_locking_modify( slot_ctx->bank );
     491             : 
     492             :     /* Move next EpochStakes */
     493             : 
     494           0 :     fd_vote_accounts_global_t * next_epoch_stakes = fd_bank_next_epoch_stakes_locking_modify( slot_ctx->bank );
     495           0 :     uchar * next_epoch_stakes_pool_mem = (uchar *)fd_ulong_align_up( (ulong)next_epoch_stakes + sizeof(fd_vote_accounts_global_t), fd_vote_accounts_pair_global_t_map_align() );
     496           0 :     fd_vote_accounts_pair_global_t_mapnode_t * next_epoch_stakes_pool = fd_vote_accounts_pair_global_t_map_join( fd_vote_accounts_pair_global_t_map_new( next_epoch_stakes_pool_mem, 50000UL ) );
     497           0 :     fd_vote_accounts_pair_global_t_mapnode_t * next_epoch_stakes_root = NULL;
     498             : 
     499           0 :     fd_vote_accounts_pair_global_t_mapnode_t * pool = vote_accounts_next_stakes_pool;
     500           0 :     fd_vote_accounts_pair_global_t_mapnode_t * root = vote_accounts_next_stakes_root;
     501             : 
     502           0 :     acc_region_curr = (uchar *)fd_ulong_align_up( (ulong)next_epoch_stakes_pool + fd_vote_accounts_pair_global_t_map_footprint( 50000UL ), 8UL );
     503             : 
     504           0 :     for( fd_vote_accounts_pair_global_t_mapnode_t * n = fd_vote_accounts_pair_global_t_map_minimum( pool, root );
     505           0 :          n;
     506           0 :          n = fd_vote_accounts_pair_global_t_map_successor( pool, n ) ) {
     507             : 
     508           0 :       fd_vote_accounts_pair_global_t_mapnode_t * elem = fd_vote_accounts_pair_global_t_map_acquire( next_epoch_stakes_pool );
     509           0 :       FD_TEST( elem );
     510             : 
     511           0 :       elem->elem.stake = n->elem.stake;
     512           0 :       elem->elem.key   = n->elem.key;
     513             : 
     514           0 :       elem->elem.value.lamports    = n->elem.value.lamports;
     515           0 :       elem->elem.value.data_len    = 0UL;
     516           0 :       elem->elem.value.data_offset = 0UL;
     517           0 :       elem->elem.value.owner       = n->elem.value.owner;
     518           0 :       elem->elem.value.executable  = n->elem.value.executable;
     519           0 :       elem->elem.value.rent_epoch  = n->elem.value.rent_epoch;
     520             : 
     521           0 :       elem->elem.value.data_offset = (ulong)(acc_region_curr - (uchar *)&elem->elem.value);;
     522           0 :       elem->elem.value.data_len = n->elem.value.data_len;
     523             : 
     524           0 :       uchar * manifest_data = fd_solana_account_data_join( &n->elem.value );
     525           0 :       memcpy( acc_region_curr, manifest_data, n->elem.value.data_len );
     526           0 :       acc_region_curr += n->elem.value.data_len;
     527             : 
     528           0 :       fd_vote_accounts_pair_global_t_map_insert(
     529           0 :         next_epoch_stakes_pool,
     530           0 :         &next_epoch_stakes_root,
     531           0 :         elem );
     532             : 
     533           0 :     }
     534           0 :     fd_vote_accounts_vote_accounts_pool_update( next_epoch_stakes, next_epoch_stakes_pool );
     535           0 :     fd_vote_accounts_vote_accounts_root_update( next_epoch_stakes, next_epoch_stakes_root );
     536           0 :     fd_bank_next_epoch_stakes_end_locking_modify( slot_ctx->bank );
     537             : 
     538           0 :   } while(0);
     539             : 
     540           0 :   fd_slot_lthash_t * lthash = fd_bank_lthash_modify( slot_ctx->bank );
     541             : 
     542           0 :   fd_slot_lthash_t * lthash_value = fd_solana_manifest_lthash_join( manifest );
     543           0 :   if( !!lthash_value ) {
     544           0 :     *lthash = *lthash_value;
     545           0 :   } else {
     546           0 :     fd_lthash_zero( (fd_lthash_value_t *)lthash->lthash );
     547           0 :   }
     548             :   /* Setup next epoch stakes */
     549             : 
     550           0 :   return slot_ctx;
     551           0 : }
     552             : 
     553             : fd_exec_slot_ctx_t *
     554             : fd_exec_slot_ctx_recover_status_cache( fd_exec_slot_ctx_t *    ctx,
     555             :                                        fd_bank_slot_deltas_t * slot_deltas,
     556           0 :                                        fd_spad_t *             runtime_spad ) {
     557             : 
     558           0 :   fd_txncache_t * status_cache = ctx->status_cache;
     559           0 :   if( !status_cache ) {
     560           0 :     FD_LOG_WARNING(("No status cache in slot ctx"));
     561           0 :     return NULL;
     562           0 :   }
     563             : 
     564           0 :   FD_SPAD_FRAME_BEGIN( runtime_spad ) {
     565             : 
     566           0 :   ulong num_entries = 0;
     567           0 :   for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
     568           0 :     fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[i];
     569           0 :     for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
     570           0 :       num_entries += slot_delta->slot_delta_vec[j].value.statuses_len;
     571           0 :     }
     572           0 :   }
     573           0 :   fd_txncache_insert_t * insert_vals = fd_spad_alloc_check( runtime_spad, alignof(fd_txncache_insert_t), num_entries * sizeof(fd_txncache_insert_t) );
     574             : 
     575             :   /* Dumb sort for 300 slot entries to insert in order. */
     576           0 :   fd_slot_delta_t ** deltas = fd_spad_alloc_check( runtime_spad, alignof(fd_slot_delta_t*), slot_deltas->slot_deltas_len * sizeof(fd_slot_delta_t*) );
     577             : 
     578           0 :   long curr = -1;
     579           0 :   for( ulong i = 0UL; i < slot_deltas->slot_deltas_len; i++ ) {
     580           0 :     ulong curr_min     = ULONG_MAX;
     581           0 :     ulong curr_min_idx = ULONG_MAX;
     582           0 :     for( ulong j = 0; j < slot_deltas->slot_deltas_len; j++ ) {
     583           0 :       fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[j];
     584           0 :       if( (long)slot_delta->slot <= curr ) continue;
     585             : 
     586           0 :       if( curr_min > slot_delta->slot ) {
     587           0 :         curr_min = slot_delta->slot;
     588           0 :         curr_min_idx = j;
     589           0 :       }
     590           0 :     }
     591           0 :     deltas[i] = &slot_deltas->slot_deltas[curr_min_idx];
     592           0 :     curr = (long)slot_deltas->slot_deltas[curr_min_idx].slot;
     593           0 :   }
     594             : 
     595           0 :   ulong idx = 0;
     596           0 :   for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
     597           0 :     fd_slot_delta_t * slot_delta = deltas[i];
     598           0 :     ulong slot = slot_delta->slot;
     599           0 :     if( slot_delta->is_root ) {
     600           0 :       fd_txncache_register_root_slot( ctx->status_cache, slot );
     601           0 :     }
     602           0 :     for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
     603           0 :       fd_status_pair_t * pair = &slot_delta->slot_delta_vec[j];
     604           0 :       fd_hash_t * blockhash = &pair->hash;
     605           0 :       uchar * results = fd_spad_alloc( runtime_spad, FD_SPAD_ALIGN, pair->value.statuses_len );
     606           0 :       for( ulong k = 0; k < pair->value.statuses_len; k++ ) {
     607           0 :         fd_cache_status_t * status = &pair->value.statuses[k];
     608           0 :         uchar * result = results + k;
     609           0 :         *result = (uchar)status->result.discriminant;
     610           0 :         insert_vals[idx++] = (fd_txncache_insert_t){
     611           0 :           .blockhash = blockhash->uc,
     612           0 :           .slot = slot,
     613           0 :           .txnhash = status->key_slice,
     614           0 :           .result = result
     615           0 :         };
     616           0 :       }
     617           0 :     }
     618           0 :   }
     619           0 :   fd_txncache_insert_batch( ctx->status_cache, insert_vals, num_entries );
     620             : 
     621           0 :   for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
     622           0 :     fd_slot_delta_t * slot_delta = deltas[i];
     623           0 :     ulong slot = slot_delta->slot;
     624           0 :     for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
     625           0 :       fd_status_pair_t * pair      = &slot_delta->slot_delta_vec[j];
     626           0 :       fd_hash_t *        blockhash = &pair->hash;
     627           0 :       fd_txncache_set_txnhash_offset( ctx->status_cache, slot, blockhash->uc, pair->value.txn_idx );
     628           0 :     }
     629           0 :   }
     630             : 
     631           0 :   } FD_SPAD_FRAME_END;
     632           0 :   return ctx;
     633           0 : }

Generated by: LCOV version 1.14