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: 0 432 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 8 0.0 %

          Line data    Source code
       1             : #include "fd_exec_slot_ctx.h"
       2             : #include "fd_exec_epoch_ctx.h"
       3             : #include "../sysvar/fd_sysvar_epoch_schedule.h"
       4             : #include "../program/fd_vote_program.h"
       5             : #include "../../../ballet/lthash/fd_lthash.h"
       6             : 
       7             : #include <assert.h>
       8             : #include <time.h>
       9             : 
      10             : void *
      11             : fd_exec_slot_ctx_new( void *      mem,
      12           0 :                       fd_spad_t * runtime_spad ) {
      13           0 :   if( FD_UNLIKELY( !mem ) ) {
      14           0 :     FD_LOG_WARNING(( "NULL mem" ));
      15           0 :     return NULL;
      16           0 :   }
      17             : 
      18           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_SLOT_CTX_ALIGN ) ) ) {
      19           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      20           0 :     return NULL;
      21           0 :   }
      22             : 
      23           0 :   fd_memset( mem, 0, sizeof(fd_exec_slot_ctx_t) );
      24             : 
      25           0 :   fd_exec_slot_ctx_t * self = (fd_exec_slot_ctx_t *)mem;
      26           0 :   fd_slot_bank_new( &self->slot_bank );
      27             : 
      28           0 :   self->sysvar_cache = fd_sysvar_cache_new( fd_spad_alloc( runtime_spad, fd_sysvar_cache_align(), fd_sysvar_cache_footprint() ) );
      29             : 
      30             :   /* This is inactive by default */
      31           0 :   self->epoch_reward_status.discriminant = fd_epoch_reward_status_enum_Inactive;
      32             : 
      33           0 :   FD_COMPILER_MFENCE();
      34           0 :   self->magic = FD_EXEC_SLOT_CTX_MAGIC;
      35           0 :   FD_COMPILER_MFENCE();
      36             : 
      37           0 :   return mem;
      38           0 : }
      39             : 
      40             : fd_exec_slot_ctx_t *
      41           0 : fd_exec_slot_ctx_join( void * mem ) {
      42           0 :   if( FD_UNLIKELY( !mem ) ) {
      43           0 :     FD_LOG_WARNING(( "NULL block" ));
      44           0 :     return NULL;
      45           0 :   }
      46             : 
      47           0 :   fd_exec_slot_ctx_t * ctx = (fd_exec_slot_ctx_t *) mem;
      48             : 
      49           0 :   if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
      50           0 :     FD_LOG_WARNING(( "bad magic" ));
      51           0 :     return NULL;
      52           0 :   }
      53             : 
      54           0 :   return ctx;
      55           0 : }
      56             : 
      57             : void *
      58           0 : fd_exec_slot_ctx_leave( fd_exec_slot_ctx_t * ctx) {
      59           0 :   if( FD_UNLIKELY( !ctx ) ) {
      60           0 :     FD_LOG_WARNING(( "NULL block" ));
      61           0 :     return NULL;
      62           0 :   }
      63             : 
      64           0 :   if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
      65           0 :     FD_LOG_WARNING(( "bad magic" ));
      66           0 :     return NULL;
      67           0 :   }
      68             : 
      69           0 :   return (void *) ctx;
      70           0 : }
      71             : 
      72             : void *
      73           0 : fd_exec_slot_ctx_delete( void * mem ) {
      74           0 :   if( FD_UNLIKELY( !mem ) ) {
      75           0 :     FD_LOG_WARNING(( "NULL mem" ));
      76           0 :     return NULL;
      77           0 :   }
      78             : 
      79           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_SLOT_CTX_ALIGN) ) )  {
      80           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      81           0 :     return NULL;
      82           0 :   }
      83             : 
      84           0 :   fd_exec_slot_ctx_t * hdr = (fd_exec_slot_ctx_t *)mem;
      85           0 :   if( FD_UNLIKELY( hdr->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
      86           0 :     FD_LOG_WARNING(( "bad magic" ));
      87           0 :     return NULL;
      88           0 :   }
      89             : 
      90           0 :   hdr->sysvar_cache = NULL;
      91             : 
      92           0 :   FD_COMPILER_MFENCE();
      93           0 :   FD_VOLATILE( hdr->magic ) = 0UL;
      94           0 :   FD_COMPILER_MFENCE();
      95             : 
      96           0 :   return mem;
      97           0 : }
      98             : 
      99             : /* recover_clock recovers PoH/wallclock synchronization.  Walks all vote
     100             :    accounts in current epoch stakes. */
     101             : 
     102             : static int
     103           0 : recover_clock( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
     104             : 
     105           0 :   fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
     106           0 :   fd_vote_accounts_t const * vote_accounts = &epoch_bank->stakes.vote_accounts;
     107             : 
     108           0 :   fd_vote_accounts_pair_t_mapnode_t * vote_accounts_pool = vote_accounts->vote_accounts_pool;
     109           0 :   fd_vote_accounts_pair_t_mapnode_t * vote_accounts_root = vote_accounts->vote_accounts_root;
     110             : 
     111           0 :   for( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(vote_accounts_pool, vote_accounts_root);
     112           0 :        n;
     113           0 :        n = fd_vote_accounts_pair_t_map_successor( vote_accounts_pool, n ) ) {
     114             : 
     115             :    /* Extract vote timestamp of account */
     116             : 
     117           0 :    fd_bincode_decode_ctx_t ctx = {
     118           0 :     .data    = n->elem.value.data,
     119           0 :     .dataend = n->elem.value.data + n->elem.value.data_len,
     120           0 :   };
     121             : 
     122           0 :   ulong total_sz = 0UL;
     123           0 :   int err = fd_vote_state_versioned_decode_footprint( &ctx, &total_sz );
     124           0 :   if( FD_UNLIKELY( err ) ) {
     125           0 :     FD_LOG_WARNING(( "vote state decode footprint failed" ));
     126           0 :     return 0;
     127           0 :   }
     128             : 
     129           0 :   uchar * mem = fd_spad_alloc( runtime_spad, fd_vote_state_versioned_align(), total_sz );
     130           0 :   if( FD_UNLIKELY( !mem ) ) {
     131           0 :     FD_LOG_ERR(( "Unable to allocate memory for versioned vote state" ));
     132           0 :   }
     133             : 
     134           0 :   fd_vote_state_versioned_t * vsv = fd_vote_state_versioned_decode( mem, &ctx );
     135             : 
     136           0 :   long timestamp = 0;
     137           0 :   ulong slot = 0;
     138           0 :   switch( vsv->discriminant ) {
     139           0 :     case fd_vote_state_versioned_enum_v0_23_5:
     140           0 :       timestamp = vsv->inner.v0_23_5.last_timestamp.timestamp;
     141           0 :       slot = vsv->inner.v0_23_5.last_timestamp.slot;
     142           0 :       break;
     143           0 :     case fd_vote_state_versioned_enum_v1_14_11:
     144           0 :       timestamp = vsv->inner.v1_14_11.last_timestamp.timestamp;
     145           0 :       slot = vsv->inner.v1_14_11.last_timestamp.slot;
     146           0 :       break;
     147           0 :     case fd_vote_state_versioned_enum_current:
     148           0 :       timestamp = vsv->inner.current.last_timestamp.timestamp;
     149           0 :       slot = vsv->inner.current.last_timestamp.slot;
     150           0 :       break;
     151           0 :     default:
     152           0 :       __builtin_unreachable();
     153           0 :   }
     154             : 
     155             : 
     156             : 
     157             :     /* Record timestamp */
     158           0 :     if( slot != 0 || n->elem.stake != 0 ) {
     159           0 :       fd_vote_record_timestamp_vote_with_slot( slot_ctx, &n->elem.key, timestamp, slot );
     160           0 :     }
     161           0 :   }
     162             : 
     163           0 :   return 1;
     164           0 : }
     165             : 
     166             : /* Implementation note: fd_exec_slot_ctx_recover moves objects from
     167             :    manifest to slot_ctx.  This function must not share pointers between
     168             :    slot_ctx and manifest.  Otherwise, would cause a use-after-free. */
     169             : 
     170             : static fd_exec_slot_ctx_t *
     171             : fd_exec_slot_ctx_recover_( fd_exec_slot_ctx_t *   slot_ctx,
     172             :                            fd_solana_manifest_t * manifest,
     173           0 :                            fd_spad_t *            runtime_spad ) {
     174             : 
     175           0 :   fd_valloc_t valloc = fd_spad_virtual( runtime_spad );
     176             : 
     177           0 :   fd_exec_epoch_ctx_t * epoch_ctx   = slot_ctx->epoch_ctx;
     178           0 :   fd_epoch_bank_t *     epoch_bank  = fd_exec_epoch_ctx_epoch_bank( epoch_ctx );
     179             : 
     180             :   /* Clean out prior bank */
     181           0 :   fd_slot_bank_t * slot_bank = &slot_ctx->slot_bank;
     182           0 :   fd_slot_bank_destroy( slot_bank );
     183           0 :   fd_slot_bank_new( slot_bank );
     184             : 
     185           0 :   for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
     186           0 :           epoch_bank->stakes.vote_accounts.vote_accounts_pool,
     187           0 :           epoch_bank->stakes.vote_accounts.vote_accounts_root );
     188           0 :           n;
     189           0 :           n = fd_vote_accounts_pair_t_map_successor( epoch_bank->stakes.vote_accounts.vote_accounts_pool, n ) ) {
     190             : 
     191           0 :       const fd_pubkey_t null_pubkey = {{ 0 }};
     192           0 :       if ( memcmp( &n->elem.key, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
     193           0 :         continue;
     194           0 :       }
     195           0 :   }
     196             : 
     197           0 :   fd_versioned_bank_t * oldbank = &manifest->bank;
     198             : 
     199             :   /* Populate the epoch context, using the already-allocated statically allocated memory */
     200             :   /* Copy stakes */
     201           0 :   epoch_bank->stakes.epoch = oldbank->stakes.epoch;
     202             : 
     203             :   /* Copy stakes->vote_accounts */
     204           0 :   for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
     205           0 :           oldbank->stakes.vote_accounts.vote_accounts_pool,
     206           0 :           oldbank->stakes.vote_accounts.vote_accounts_root );
     207           0 :               n;
     208           0 :               n = fd_vote_accounts_pair_t_map_successor( oldbank->stakes.vote_accounts.vote_accounts_pool, n ) ) {
     209             : 
     210           0 :       const fd_pubkey_t null_pubkey = {{ 0 }};
     211           0 :       if ( memcmp( &n->elem.key, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
     212           0 :         continue;
     213           0 :       }
     214             : 
     215           0 :       FD_TEST( fd_vote_accounts_pair_t_map_free( epoch_bank->stakes.vote_accounts.vote_accounts_pool ) );
     216           0 :       fd_vote_accounts_pair_t_mapnode_t * new_node = fd_vote_accounts_pair_t_map_acquire( epoch_bank->stakes.vote_accounts.vote_accounts_pool );
     217           0 :       FD_TEST( new_node );
     218           0 :       fd_memcpy( &new_node->elem, &n->elem, FD_VOTE_ACCOUNTS_PAIR_FOOTPRINT );
     219           0 :       fd_vote_accounts_pair_t_map_insert(
     220           0 :         epoch_bank->stakes.vote_accounts.vote_accounts_pool,
     221           0 :         &epoch_bank->stakes.vote_accounts.vote_accounts_root,
     222           0 :         new_node
     223           0 :       );
     224           0 :   }
     225             : 
     226             :   /* Copy stakes->stake_delegations */
     227           0 :   for ( fd_delegation_pair_t_mapnode_t * n = fd_delegation_pair_t_map_minimum(
     228           0 :           oldbank->stakes.stake_delegations_pool,
     229           0 :           oldbank->stakes.stake_delegations_root );
     230           0 :           n;
     231           0 :           n = fd_delegation_pair_t_map_successor( oldbank->stakes.stake_delegations_pool, n ) ) {
     232             : 
     233           0 :       const fd_pubkey_t null_pubkey = {{ 0 }};
     234           0 :       if ( memcmp( &n->elem.account, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
     235           0 :         continue;
     236           0 :       }
     237             : 
     238           0 :       fd_delegation_pair_t_mapnode_t * new_node = fd_delegation_pair_t_map_acquire( epoch_bank->stakes.stake_delegations_pool );
     239           0 :       FD_TEST( new_node );
     240           0 :       fd_memcpy( &new_node->elem, &n->elem, FD_DELEGATION_PAIR_FOOTPRINT );
     241           0 :       fd_delegation_pair_t_map_insert(
     242           0 :         epoch_bank->stakes.stake_delegations_pool,
     243           0 :         &epoch_bank->stakes.stake_delegations_root,
     244           0 :         new_node
     245           0 :       );
     246           0 :   }
     247             : 
     248             :   /* Copy stakes->stake_history */
     249           0 :   fd_memcpy( &epoch_bank->stakes.stake_history, &oldbank->stakes.stake_history, sizeof(oldbank->stakes.stake_history));
     250             : 
     251           0 :   fd_stakes_destroy( &oldbank->stakes );
     252             : 
     253             :   /* Index vote accounts */
     254             : 
     255             :   /* Copy over fields */
     256             : 
     257           0 :   slot_ctx->slot_bank.parent_signature_cnt = oldbank->signature_count;
     258           0 :   slot_ctx->slot_bank.tick_height          = oldbank->tick_height;
     259             : 
     260           0 :   if( oldbank->blockhash_queue.last_hash )
     261           0 :     slot_bank->poh = *oldbank->blockhash_queue.last_hash;
     262           0 :   slot_bank->slot = oldbank->slot;
     263           0 :   slot_bank->prev_slot = oldbank->parent_slot;
     264           0 :   fd_memcpy(&slot_bank->banks_hash, &oldbank->hash, sizeof(oldbank->hash));
     265           0 :   fd_memcpy(&slot_ctx->slot_bank.prev_banks_hash, &oldbank->parent_hash, sizeof(oldbank->parent_hash));
     266           0 :   fd_memcpy(&slot_bank->fee_rate_governor, &oldbank->fee_rate_governor, sizeof(oldbank->fee_rate_governor));
     267           0 :   slot_bank->lamports_per_signature = manifest->lamports_per_signature;
     268           0 :   slot_ctx->prev_lamports_per_signature = manifest->lamports_per_signature;
     269           0 :   slot_ctx->slot_bank.parent_signature_cnt = oldbank->signature_count;
     270           0 :   if( oldbank->hashes_per_tick )
     271           0 :     epoch_bank->hashes_per_tick = *oldbank->hashes_per_tick;
     272           0 :   else
     273           0 :     epoch_bank->hashes_per_tick = 0;
     274           0 :   epoch_bank->ticks_per_slot = oldbank->ticks_per_slot;
     275           0 :   fd_memcpy(&epoch_bank->ns_per_slot, &oldbank->ns_per_slot, sizeof(oldbank->ns_per_slot));
     276           0 :   epoch_bank->genesis_creation_time = oldbank->genesis_creation_time;
     277           0 :   epoch_bank->slots_per_year = oldbank->slots_per_year;
     278           0 :   slot_bank->max_tick_height = oldbank->max_tick_height;
     279           0 :   fd_memcpy( &epoch_bank->inflation, &oldbank->inflation, FD_INFLATION_FOOTPRINT );
     280           0 :   fd_memcpy( &epoch_bank->epoch_schedule, &oldbank->epoch_schedule, FD_EPOCH_SCHEDULE_FOOTPRINT );
     281           0 :   epoch_bank->rent = oldbank->rent_collector.rent;
     282           0 :   fd_memcpy( &epoch_bank->rent, &oldbank->rent_collector.rent, FD_RENT_FOOTPRINT );
     283           0 :   fd_memcpy( &epoch_bank->rent_epoch_schedule, &oldbank->rent_collector.epoch_schedule, FD_EPOCH_SCHEDULE_FOOTPRINT );
     284             : 
     285           0 :   if( manifest->epoch_account_hash )
     286           0 :     slot_bank->epoch_account_hash = *manifest->epoch_account_hash;
     287             : 
     288           0 :   slot_bank->collected_rent = oldbank->collected_rent;
     289             :   // did they not change the bank?!
     290           0 :   slot_bank->collected_execution_fees = oldbank->collector_fees;
     291           0 :   slot_bank->collected_priority_fees = 0;
     292           0 :   slot_bank->capitalization = oldbank->capitalization;
     293           0 :   slot_bank->block_height = oldbank->block_height;
     294           0 :   slot_bank->transaction_count = oldbank->transaction_count;
     295           0 :   if ( oldbank->blockhash_queue.last_hash ) {
     296           0 :     slot_bank->block_hash_queue.last_hash = fd_valloc_malloc( valloc, FD_HASH_ALIGN, FD_HASH_FOOTPRINT );
     297           0 :     fd_memcpy( slot_bank->block_hash_queue.last_hash, oldbank->blockhash_queue.last_hash, sizeof(fd_hash_t) );
     298           0 :   } else {
     299           0 :     slot_bank->block_hash_queue.last_hash = NULL;
     300           0 :   }
     301             : 
     302             :   /* FIXME: Avoid using magic number for allocations */
     303           0 :   slot_bank->block_hash_queue.last_hash_index = oldbank->blockhash_queue.last_hash_index;
     304           0 :   slot_bank->block_hash_queue.max_age = oldbank->blockhash_queue.max_age;
     305           0 :   slot_bank->block_hash_queue.ages_root = NULL;
     306           0 :   uchar * pool_mem = fd_spad_alloc( runtime_spad, fd_hash_hash_age_pair_t_map_align(), fd_hash_hash_age_pair_t_map_footprint( 400 ) );
     307           0 :   slot_bank->block_hash_queue.ages_pool = fd_hash_hash_age_pair_t_map_join( fd_hash_hash_age_pair_t_map_new( pool_mem, 400 ) );
     308           0 :   for ( ulong i = 0; i < oldbank->blockhash_queue.ages_len; i++ ) {
     309           0 :     fd_hash_hash_age_pair_t * elem = &oldbank->blockhash_queue.ages[i];
     310           0 :     fd_hash_hash_age_pair_t_mapnode_t * node = fd_hash_hash_age_pair_t_map_acquire( slot_bank->block_hash_queue.ages_pool );
     311           0 :     fd_memcpy( &node->elem, elem, FD_HASH_HASH_AGE_PAIR_FOOTPRINT );
     312           0 :     fd_hash_hash_age_pair_t_map_insert( slot_bank->block_hash_queue.ages_pool, &slot_bank->block_hash_queue.ages_root, node );
     313           0 :   }
     314             : 
     315             :   /* FIXME: Remove the magic number here. */
     316           0 :   if( !slot_ctx->slot_bank.timestamp_votes.votes_pool ) {
     317           0 :     pool_mem = fd_spad_alloc( runtime_spad, fd_clock_timestamp_vote_t_map_align(), fd_clock_timestamp_vote_t_map_footprint( 15000UL ) );
     318           0 :     slot_ctx->slot_bank.timestamp_votes.votes_pool = fd_clock_timestamp_vote_t_map_join( fd_clock_timestamp_vote_t_map_new( pool_mem, 15000UL ) );
     319           0 :   }
     320           0 :   recover_clock( slot_ctx, runtime_spad );
     321             : 
     322             :   /* Pass in the hard forks */
     323             : 
     324             :   /* The hard forks should be deep copied over.
     325             :      TODO:This should be in the epoch bank and not the slot bank. */
     326           0 :   slot_bank->hard_forks.hard_forks_len = oldbank->hard_forks.hard_forks_len;
     327           0 :   slot_bank->hard_forks.hard_forks     = fd_valloc_malloc( valloc,
     328           0 :                                                            FD_SLOT_PAIR_ALIGN,
     329           0 :                                                            oldbank->hard_forks.hard_forks_len * FD_SLOT_PAIR_FOOTPRINT );
     330           0 :   memcpy( slot_bank->hard_forks.hard_forks, oldbank->hard_forks.hard_forks,
     331           0 :           oldbank->hard_forks.hard_forks_len * FD_SLOT_PAIR_FOOTPRINT );
     332             : 
     333             :   /* Update last restart slot
     334             :      https://github.com/solana-labs/solana/blob/30531d7a5b74f914dde53bfbb0bc2144f2ac92bb/runtime/src/bank.rs#L2152
     335             : 
     336             :      oldbank->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 :     slot_bank->last_restart_slot.slot = 0UL;
     342           0 :     if( FD_UNLIKELY( oldbank->hard_forks.hard_forks_len == 0 ) ) {
     343             :       /* SIMD-0047: The first restart slot should be `0` */
     344           0 :       break;
     345           0 :     }
     346             : 
     347           0 :     fd_slot_pair_t const * head = oldbank->hard_forks.hard_forks;
     348           0 :     fd_slot_pair_t const * tail = head + oldbank->hard_forks.hard_forks_len - 1UL;
     349             : 
     350           0 :     for( fd_slot_pair_t const *pair = tail; pair >= head; pair-- ) {
     351           0 :       if( pair->slot <= slot_bank->slot ) {
     352           0 :         slot_bank->last_restart_slot.slot = pair->slot;
     353           0 :         break;
     354           0 :       }
     355           0 :     }
     356           0 :   } while (0);
     357             : 
     358             :   /* Move EpochStakes */
     359           0 :   do {
     360           0 :     ulong epoch = fd_slot_to_epoch( &epoch_bank->epoch_schedule, slot_bank->slot, NULL );
     361             : 
     362             :     /* We need to save the vote accounts for the current epoch and the next
     363             :        epoch as it is used to calculate the leader schedule at the epoch
     364             :        boundary. */
     365             : 
     366           0 :     fd_vote_accounts_t curr_stakes = { .vote_accounts_pool = NULL, .vote_accounts_root = NULL };
     367           0 :     fd_vote_accounts_t next_stakes = { .vote_accounts_pool = NULL, .vote_accounts_root = NULL };
     368             : 
     369           0 :     for( ulong i=0UL; i<manifest->bank.epoch_stakes_len; i++ ) {
     370           0 :       if( manifest->bank.epoch_stakes[i].key == epoch ) {
     371           0 :         curr_stakes.vote_accounts_pool = manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_pool;
     372           0 :         curr_stakes.vote_accounts_root = manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_root;
     373           0 :         manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_pool = NULL;
     374           0 :         manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_root = NULL;
     375           0 :       }
     376           0 :       if( manifest->bank.epoch_stakes[i].key == epoch+1UL ) {
     377           0 :         next_stakes.vote_accounts_pool = manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_pool;
     378           0 :         next_stakes.vote_accounts_root = manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_root;
     379           0 :         manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_pool = NULL;
     380           0 :         manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_root = NULL;
     381           0 :       }
     382             : 
     383             :       /* When loading from a snapshot, Agave's stake caches mean that we have to special-case the epoch stakes
     384             :          that are used for the second epoch E+2 after the snapshot epoch E.
     385             : 
     386             :          If the snapshot contains the epoch stakes for E+2, we should use those.
     387             : 
     388             :          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
     389             :          all other epochs. */
     390             : 
     391           0 :       if( manifest->bank.epoch_stakes[i].key==epoch+2UL ) {
     392           0 :         slot_ctx->slot_bank.has_use_preceeding_epoch_stakes = 0;
     393           0 :       }
     394           0 :     }
     395             : 
     396           0 :     for( ulong i=0UL; i<manifest->versioned_epoch_stakes_len; i++ ) {
     397           0 :       if( manifest->versioned_epoch_stakes[i].epoch == epoch ) {
     398           0 :         curr_stakes.vote_accounts_pool = manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_pool;
     399           0 :         curr_stakes.vote_accounts_root = manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_root;
     400           0 :         manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_pool = NULL;
     401           0 :         manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_root = NULL;
     402           0 :       }
     403           0 :       if( manifest->versioned_epoch_stakes[i].epoch == epoch+1UL ) {
     404           0 :         next_stakes.vote_accounts_pool = manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_pool;
     405           0 :         next_stakes.vote_accounts_root = manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_root;
     406           0 :         manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_pool = NULL;
     407           0 :         manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_root = NULL;
     408           0 :       }
     409             : 
     410           0 :       if( manifest->versioned_epoch_stakes[i].epoch==epoch+2UL ) {
     411           0 :         slot_ctx->slot_bank.has_use_preceeding_epoch_stakes = 0;
     412           0 :       }
     413           0 :     }
     414             : 
     415           0 :     slot_ctx->slot_bank.has_use_preceeding_epoch_stakes = 1;
     416           0 :     slot_ctx->slot_bank.use_preceeding_epoch_stakes     = epoch + 2UL;
     417             : 
     418           0 :     if( FD_UNLIKELY( (!curr_stakes.vote_accounts_root) | (!next_stakes.vote_accounts_root) ) ) {
     419           0 :       FD_LOG_WARNING(( "snapshot missing EpochStakes for epochs %lu and/or %lu", epoch, epoch+1UL ));
     420           0 :       return 0;
     421           0 :     }
     422             : 
     423             :     /* Move current EpochStakes */
     424           0 :     pool_mem = fd_spad_alloc( runtime_spad, fd_vote_accounts_pair_t_map_align(), fd_vote_accounts_pair_t_map_footprint( 100000 ) );
     425           0 :     slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool =
     426           0 :       fd_vote_accounts_pair_t_map_join( fd_vote_accounts_pair_t_map_new( pool_mem, 100000 ) ); /* FIXME: Remove magic constant */
     427           0 :     slot_ctx->slot_bank.epoch_stakes.vote_accounts_root = NULL;
     428             : 
     429           0 :     for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
     430           0 :           curr_stakes.vote_accounts_pool,
     431           0 :           curr_stakes.vote_accounts_root );
     432           0 :           n;
     433           0 :           n = fd_vote_accounts_pair_t_map_successor( curr_stakes.vote_accounts_pool, n ) ) {
     434             : 
     435           0 :         fd_vote_accounts_pair_t_mapnode_t * elem = fd_vote_accounts_pair_t_map_acquire(
     436           0 :           slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool );
     437           0 :         FD_TEST( elem );
     438             : 
     439           0 :         fd_memcpy( &elem->elem, &n->elem, sizeof(fd_vote_accounts_pair_t));
     440             : 
     441           0 :         fd_vote_accounts_pair_t_map_insert(
     442           0 :           slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool,
     443           0 :           &slot_ctx->slot_bank.epoch_stakes.vote_accounts_root,
     444           0 :           elem );
     445           0 :     }
     446             : 
     447           0 :     fd_vote_accounts_destroy( &curr_stakes );
     448             : 
     449             :     /* Move next EpochStakes
     450             :        TODO Can we derive this instead of trusting the snapshot? */
     451             : 
     452           0 :     fd_vote_accounts_pair_t_mapnode_t * pool = next_stakes.vote_accounts_pool;
     453           0 :     fd_vote_accounts_pair_t_mapnode_t * root = next_stakes.vote_accounts_root;
     454             : 
     455           0 :     for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(pool, root);
     456           0 :           n;
     457           0 :           n = fd_vote_accounts_pair_t_map_successor(pool, n) ) {
     458             : 
     459           0 :       fd_vote_accounts_pair_t_mapnode_t * elem = fd_vote_accounts_pair_t_map_acquire(
     460           0 :         epoch_bank->next_epoch_stakes.vote_accounts_pool );
     461           0 :       FD_TEST( elem );
     462             : 
     463           0 :       fd_memcpy( &elem->elem, &n->elem, sizeof(fd_vote_accounts_pair_t));
     464             : 
     465           0 :       fd_vote_accounts_pair_t_map_insert(
     466           0 :         epoch_bank->next_epoch_stakes.vote_accounts_pool,
     467           0 :         &epoch_bank->next_epoch_stakes.vote_accounts_root,
     468           0 :         elem );
     469             : 
     470           0 :     }
     471             : 
     472           0 :     fd_vote_accounts_destroy( &next_stakes );
     473           0 :   } while(0);
     474             : 
     475           0 :   if ( NULL != manifest->lthash )
     476           0 :     slot_ctx->slot_bank.lthash = *manifest->lthash;
     477           0 :   else
     478           0 :     fd_lthash_zero( (fd_lthash_value_t *) slot_ctx->slot_bank.lthash.lthash );
     479             : 
     480             :   /* Allocate all the memory for the rent fresh accounts lists */
     481           0 :   slot_ctx->rent_fresh_accounts.partitions_root = NULL;
     482           0 :   slot_ctx->rent_fresh_accounts.partitions_pool = fd_rent_fresh_accounts_partition_t_map_join(
     483           0 :     fd_rent_fresh_accounts_partition_t_map_new(
     484           0 :       fd_spad_alloc(
     485           0 :         runtime_spad,
     486           0 :         fd_rent_fresh_accounts_partition_t_map_align(),
     487           0 :         fd_rent_fresh_accounts_partition_t_map_footprint( 432000UL * 2UL ) ), /* MAX_SLOTS_PER_EPOCH * 2 */
     488           0 :         432000UL * 2UL
     489           0 :     )
     490           0 :   );
     491           0 :   for( ulong i = 0; i < 432000UL * 2UL; i++ ) {
     492           0 :     ulong partition = i;
     493           0 :     fd_rent_fresh_accounts_partition_t_mapnode_t * new_node = fd_rent_fresh_accounts_partition_t_map_acquire(
     494           0 :       slot_ctx->rent_fresh_accounts.partitions_pool
     495           0 :     );
     496           0 :     if( FD_UNLIKELY(( new_node == NULL )) ) {
     497           0 :       FD_LOG_ERR(( "fd_rent_fresh_accounts_partition_t_map_acquire failed" ));
     498           0 :     }
     499             : 
     500           0 :     new_node->elem.partition     = partition;
     501           0 :     new_node->elem.accounts_root = NULL;
     502           0 :     new_node->elem.accounts_pool = fd_pubkey_node_t_map_join( fd_pubkey_node_t_map_new(
     503           0 :       fd_spad_alloc( runtime_spad, fd_pubkey_node_t_map_align(), fd_pubkey_node_t_map_footprint( 100 ) ),
     504           0 :       100
     505           0 :     ) );
     506           0 :     fd_rent_fresh_accounts_partition_t_map_insert(
     507           0 :       slot_ctx->rent_fresh_accounts.partitions_pool,
     508           0 :       &slot_ctx->rent_fresh_accounts.partitions_root,
     509           0 :       new_node
     510           0 :     );
     511           0 :   }
     512             : 
     513           0 :   return slot_ctx;
     514           0 : }
     515             : 
     516             : fd_exec_slot_ctx_t *
     517             : fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t *   slot_ctx,
     518             :                           fd_solana_manifest_t * manifest,
     519           0 :                           fd_spad_t *            spad ) {
     520             : 
     521           0 :   fd_exec_slot_ctx_t * res = fd_exec_slot_ctx_recover_( slot_ctx, manifest, spad );
     522             : 
     523             :   /* Regardless of result, always destroy manifest.
     524             :      TODO: This doesn't do anything. */
     525           0 :   fd_solana_manifest_destroy( manifest );
     526           0 :   fd_memset( manifest, 0, sizeof(fd_solana_manifest_t) );
     527             : 
     528           0 :   return res;
     529           0 : }
     530             : 
     531             : fd_exec_slot_ctx_t *
     532             : fd_exec_slot_ctx_recover_status_cache( fd_exec_slot_ctx_t *    ctx,
     533             :                                        fd_bank_slot_deltas_t * slot_deltas,
     534           0 :                                        fd_spad_t *             runtime_spad ) {
     535             : 
     536           0 :   fd_txncache_t * status_cache = ctx->status_cache;
     537           0 :   if( !status_cache ) {
     538           0 :     FD_LOG_WARNING(("No status cache in slot ctx"));
     539           0 :     return NULL;
     540           0 :   }
     541             : 
     542           0 :   FD_SPAD_FRAME_BEGIN( runtime_spad ) {
     543             : 
     544           0 :   ulong num_entries = 0;
     545           0 :   for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
     546           0 :     fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[i];
     547           0 :     for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
     548           0 :       num_entries += slot_delta->slot_delta_vec[j].value.statuses_len;
     549           0 :     }
     550           0 :   }
     551           0 :   fd_txncache_insert_t * insert_vals = fd_spad_alloc( runtime_spad, alignof(fd_txncache_insert_t), num_entries * sizeof(fd_txncache_insert_t) );
     552             : 
     553             :   /* Dumb sort for 300 slot entries to insert in order. */
     554           0 :   fd_slot_delta_t ** deltas = fd_spad_alloc( runtime_spad, alignof(fd_slot_delta_t*), slot_deltas->slot_deltas_len * sizeof(fd_slot_delta_t*) );
     555             : 
     556           0 :   long curr = -1;
     557           0 :   for( ulong i = 0UL; i < slot_deltas->slot_deltas_len; i++ ) {
     558           0 :     ulong curr_min     = ULONG_MAX;
     559           0 :     ulong curr_min_idx = ULONG_MAX;
     560           0 :     for( ulong j = 0; j < slot_deltas->slot_deltas_len; j++ ) {
     561           0 :       fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[j];
     562           0 :       if( (long)slot_delta->slot <= curr ) continue;
     563             : 
     564           0 :       if( curr_min > slot_delta->slot ) {
     565           0 :         curr_min = slot_delta->slot;
     566           0 :         curr_min_idx = j;
     567           0 :       }
     568           0 :     }
     569           0 :     deltas[i] = &slot_deltas->slot_deltas[curr_min_idx];
     570           0 :     curr = (long)slot_deltas->slot_deltas[curr_min_idx].slot;
     571           0 :   }
     572             : 
     573           0 :   ulong idx = 0;
     574           0 :   for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
     575           0 :     fd_slot_delta_t * slot_delta = deltas[i];
     576           0 :     ulong slot = slot_delta->slot;
     577           0 :     if( slot_delta->is_root ) {
     578           0 :       fd_txncache_register_root_slot( ctx->status_cache, slot );
     579           0 :     }
     580           0 :     for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
     581           0 :       fd_status_pair_t * pair = &slot_delta->slot_delta_vec[j];
     582           0 :       fd_hash_t * blockhash = &pair->hash;
     583           0 :       uchar * results = fd_spad_alloc( runtime_spad, FD_SPAD_ALIGN, pair->value.statuses_len );
     584           0 :       for( ulong k = 0; k < pair->value.statuses_len; k++ ) {
     585           0 :         fd_cache_status_t * status = &pair->value.statuses[k];
     586           0 :         uchar * result = results + k;
     587           0 :         *result = (uchar)status->result.discriminant;
     588           0 :         insert_vals[idx++] = (fd_txncache_insert_t){
     589           0 :           .blockhash = blockhash->uc,
     590           0 :           .slot = slot,
     591           0 :           .txnhash = status->key_slice,
     592           0 :           .result = result
     593           0 :         };
     594           0 :       }
     595           0 :     }
     596           0 :   }
     597           0 :   fd_txncache_insert_batch( ctx->status_cache, insert_vals, num_entries );
     598             : 
     599           0 :   for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
     600           0 :     fd_slot_delta_t * slot_delta = deltas[i];
     601           0 :     ulong slot = slot_delta->slot;
     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 :       fd_txncache_set_txnhash_offset( ctx->status_cache, slot, blockhash->uc, pair->value.txn_idx );
     606           0 :     }
     607           0 :   }
     608             : 
     609           0 :   } FD_SPAD_FRAME_END;
     610           0 :   return ctx;
     611           0 : }

Generated by: LCOV version 1.14