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: 48 359 13.4 %
Date: 2024-11-13 11:58:15 Functions: 5 9 55.6 %

          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             : 
       6             : #include <assert.h>
       7             : #include <time.h>
       8             : 
       9             : void *
      10             : fd_exec_slot_ctx_new( void *      mem,
      11      108786 :                       fd_valloc_t valloc ) {
      12      108786 :   if( FD_UNLIKELY( !mem ) ) {
      13           0 :     FD_LOG_WARNING(( "NULL mem" ));
      14           0 :     return NULL;
      15           0 :   }
      16             : 
      17      108786 :   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      108786 :   fd_memset( mem, 0, sizeof(fd_exec_slot_ctx_t) );
      23             : 
      24      108786 :   fd_exec_slot_ctx_t * self = (fd_exec_slot_ctx_t *) mem;
      25      108786 :   self->valloc = valloc;
      26      108786 :   fd_slot_bank_new(&self->slot_bank);
      27             : 
      28      108786 :   self->sysvar_cache = fd_sysvar_cache_new( fd_valloc_malloc( valloc, fd_sysvar_cache_align(), fd_sysvar_cache_footprint() ), valloc );
      29      108786 :   self->account_compute_table = fd_account_compute_table_join( fd_account_compute_table_new( fd_valloc_malloc( valloc, fd_account_compute_table_align(), fd_account_compute_table_footprint( 10000 ) ), 10000, 0 ) );
      30             : 
      31             :   /* This is inactive by default */
      32      108786 :   self->epoch_reward_status.discriminant = fd_epoch_reward_status_enum_Inactive;
      33             : 
      34      108786 :   FD_COMPILER_MFENCE();
      35      108786 :   self->magic = FD_EXEC_SLOT_CTX_MAGIC;
      36      108786 :   FD_COMPILER_MFENCE();
      37             : 
      38      108786 :   return mem;
      39      108786 : }
      40             : 
      41             : fd_exec_slot_ctx_t *
      42      108786 : fd_exec_slot_ctx_join( void * mem ) {
      43      108786 :   if( FD_UNLIKELY( !mem ) ) {
      44           0 :     FD_LOG_WARNING(( "NULL block" ));
      45           0 :     return NULL;
      46           0 :   }
      47             : 
      48      108786 :   fd_exec_slot_ctx_t * ctx = (fd_exec_slot_ctx_t *) mem;
      49             : 
      50      108786 :   if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
      51           0 :     FD_LOG_WARNING(( "bad magic" ));
      52           0 :     return NULL;
      53           0 :   }
      54             : 
      55      108786 :   return ctx;
      56      108786 : }
      57             : 
      58             : void *
      59      108786 : fd_exec_slot_ctx_leave( fd_exec_slot_ctx_t * ctx) {
      60      108786 :   if( FD_UNLIKELY( !ctx ) ) {
      61           0 :     FD_LOG_WARNING(( "NULL block" ));
      62           0 :     return NULL;
      63           0 :   }
      64             : 
      65      108786 :   if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
      66           0 :     FD_LOG_WARNING(( "bad magic" ));
      67           0 :     return NULL;
      68           0 :   }
      69             : 
      70      108786 :   return (void *) ctx;
      71      108786 : }
      72             : 
      73             : void *
      74      108786 : fd_exec_slot_ctx_delete( void * mem ) {
      75      108786 :   if( FD_UNLIKELY( !mem ) ) {
      76           0 :     FD_LOG_WARNING(( "NULL mem" ));
      77           0 :     return NULL;
      78           0 :   }
      79             : 
      80      108786 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_SLOT_CTX_ALIGN) ) )  {
      81           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      82           0 :     return NULL;
      83           0 :   }
      84             : 
      85      108786 :   fd_exec_slot_ctx_t * hdr = (fd_exec_slot_ctx_t *)mem;
      86      108786 :   if( FD_UNLIKELY( hdr->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
      87           0 :     FD_LOG_WARNING(( "bad magic" ));
      88           0 :     return NULL;
      89           0 :   }
      90             : 
      91      108786 :   fd_bincode_destroy_ctx_t ctx = { .valloc = hdr->valloc };
      92      108786 :   fd_slot_bank_destroy(&hdr->slot_bank, &ctx);
      93             : 
      94      108786 :   fd_valloc_free( hdr->valloc, fd_sysvar_cache_delete( hdr->sysvar_cache ) );
      95      108786 :   hdr->sysvar_cache = NULL;
      96      108786 :   fd_valloc_free( hdr->valloc, fd_account_compute_table_delete( fd_account_compute_table_leave( hdr->account_compute_table ) ) );
      97      108786 :   hdr->account_compute_table = NULL;
      98             : 
      99      108786 :   FD_COMPILER_MFENCE();
     100      108786 :   FD_VOLATILE( hdr->magic ) = 0UL;
     101      108786 :   FD_COMPILER_MFENCE();
     102             : 
     103      108786 :   return mem;
     104      108786 : }
     105             : 
     106             : /* recover_clock recovers PoH/wallclock synchronization.  Walks all vote
     107             :    accounts in current epoch stakes. */
     108             : 
     109             : static int
     110           0 : recover_clock( fd_exec_slot_ctx_t * slot_ctx ) {
     111             : 
     112           0 :   fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
     113           0 :   fd_vote_accounts_t const * vote_accounts = &epoch_bank->stakes.vote_accounts;
     114             : 
     115           0 :   fd_vote_accounts_pair_t_mapnode_t * vote_accounts_pool = vote_accounts->vote_accounts_pool;
     116           0 :   fd_vote_accounts_pair_t_mapnode_t * vote_accounts_root = vote_accounts->vote_accounts_root;
     117             : 
     118           0 :   for( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(vote_accounts_pool, vote_accounts_root);
     119           0 :        n;
     120           0 :        n = fd_vote_accounts_pair_t_map_successor( vote_accounts_pool, n ) ) {
     121             :     /* Extract vote timestamp of account */
     122             : 
     123           0 :     fd_vote_block_timestamp_t vote_state_timestamp = {
     124           0 :       .timestamp = n->elem.value.last_timestamp_ts,
     125           0 :       .slot      = n->elem.value.last_timestamp_slot
     126           0 :     };
     127             : 
     128             :     /* Record timestamp */
     129           0 :     if( vote_state_timestamp.slot != 0 || n->elem.stake != 0 ) {
     130           0 :       fd_vote_record_timestamp_vote_with_slot(slot_ctx, &n->elem.key, vote_state_timestamp.timestamp, vote_state_timestamp.slot);
     131           0 :     }
     132           0 :   }
     133             : 
     134           0 :   return 1;
     135           0 : }
     136             : 
     137             : /* Implementation note: fd_exec_slot_ctx_recover moves objects from
     138             :    manifest to slot_ctx.  This function must not share pointers between
     139             :    slot_ctx and manifest.  Otherwise, would cause a use-after-free. */
     140             : 
     141             : static fd_exec_slot_ctx_t *
     142             : fd_exec_slot_ctx_recover_( fd_exec_slot_ctx_t *   slot_ctx,
     143           0 :                            fd_solana_manifest_t * manifest ) {
     144             : 
     145           0 :   fd_exec_epoch_ctx_t * epoch_ctx   = slot_ctx->epoch_ctx;
     146           0 :   fd_epoch_bank_t *     epoch_bank  = fd_exec_epoch_ctx_epoch_bank( epoch_ctx );
     147           0 :   fd_valloc_t           slot_valloc = slot_ctx->valloc;
     148             : 
     149             :   /* Clean out prior bank */
     150           0 :   fd_bincode_destroy_ctx_t destroy = { .valloc = slot_valloc };
     151           0 :   fd_slot_bank_t * slot_bank = &slot_ctx->slot_bank;
     152           0 :   fd_slot_bank_destroy( slot_bank, &destroy );
     153           0 :   fd_slot_bank_new( slot_bank );
     154             : 
     155           0 :   for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
     156           0 :           epoch_bank->stakes.vote_accounts.vote_accounts_pool,
     157           0 :           epoch_bank->stakes.vote_accounts.vote_accounts_root );
     158           0 :           n;
     159           0 :           n = fd_vote_accounts_pair_t_map_successor( epoch_bank->stakes.vote_accounts.vote_accounts_pool, n ) ) {
     160             : 
     161           0 :       const fd_pubkey_t null_pubkey = {{ 0 }};
     162           0 :       if ( memcmp( &n->elem.key, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
     163           0 :         continue;
     164           0 :       }
     165           0 :   }
     166             : 
     167           0 :   fd_deserializable_versioned_bank_t * oldbank = &manifest->bank;
     168             : 
     169             :   /* Populate the epoch context, using the already-allocated statically allocated memory */
     170             :   /* Copy stakes */
     171           0 :   epoch_bank->stakes.epoch = oldbank->stakes.epoch;
     172             : 
     173             :   /* Copy stakes->vote_accounts */
     174           0 :   for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
     175           0 :           oldbank->stakes.vote_accounts.vote_accounts_pool,
     176           0 :           oldbank->stakes.vote_accounts.vote_accounts_root );
     177           0 :               n;
     178           0 :               n = fd_vote_accounts_pair_t_map_successor( oldbank->stakes.vote_accounts.vote_accounts_pool, n ) ) {
     179             : 
     180           0 :       const fd_pubkey_t null_pubkey = {{ 0 }};
     181           0 :       if ( memcmp( &n->elem.key, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
     182           0 :         continue;
     183           0 :       }
     184             : 
     185           0 :       FD_TEST( fd_vote_accounts_pair_t_map_free( epoch_bank->stakes.vote_accounts.vote_accounts_pool ) );
     186           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 );
     187           0 :       FD_TEST( new_node );
     188           0 :       fd_memcpy( &new_node->elem, &n->elem, FD_VOTE_ACCOUNTS_PAIR_FOOTPRINT );
     189           0 :       fd_vote_accounts_pair_t_map_insert(
     190           0 :         epoch_bank->stakes.vote_accounts.vote_accounts_pool,
     191           0 :         &epoch_bank->stakes.vote_accounts.vote_accounts_root,
     192           0 :         new_node
     193           0 :       );
     194           0 :   }
     195             : 
     196             :   /* Copy stakes->stake_delegations */
     197           0 :   for ( fd_delegation_pair_t_mapnode_t * n = fd_delegation_pair_t_map_minimum(
     198           0 :           oldbank->stakes.stake_delegations_pool,
     199           0 :           oldbank->stakes.stake_delegations_root );
     200           0 :           n;
     201           0 :           n = fd_delegation_pair_t_map_successor( oldbank->stakes.stake_delegations_pool, n ) ) {
     202             : 
     203           0 :       const fd_pubkey_t null_pubkey = {{ 0 }};
     204           0 :       if ( memcmp( &n->elem.account, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
     205           0 :         continue;
     206           0 :       }
     207             : 
     208           0 :       fd_delegation_pair_t_mapnode_t * new_node = fd_delegation_pair_t_map_acquire( epoch_bank->stakes.stake_delegations_pool );
     209           0 :       FD_TEST( new_node );
     210           0 :       fd_memcpy( &new_node->elem, &n->elem, FD_DELEGATION_PAIR_FOOTPRINT );
     211           0 :       fd_delegation_pair_t_map_insert(
     212           0 :         epoch_bank->stakes.stake_delegations_pool,
     213           0 :         &epoch_bank->stakes.stake_delegations_root,
     214           0 :         new_node
     215           0 :       );
     216           0 :   }
     217             : 
     218             :   /* Copy stakes->stake_history */
     219           0 :   for ( fd_stake_history_treap_fwd_iter_t iter = fd_stake_history_treap_fwd_iter_init(
     220           0 :           oldbank->stakes.stake_history.treap,
     221           0 :           oldbank->stakes.stake_history.pool );
     222           0 :           !fd_stake_history_treap_fwd_iter_done( iter );
     223           0 :           iter = fd_stake_history_treap_fwd_iter_next( iter, oldbank->stakes.stake_history.pool ) ) {
     224             : 
     225           0 :     fd_stake_history_entry_t const * ele = fd_stake_history_treap_fwd_iter_ele_const( iter, oldbank->stakes.stake_history.pool );
     226             : 
     227           0 :     FD_TEST( fd_stake_history_pool_free( epoch_bank->stakes.stake_history.pool ) );
     228           0 :     fd_stake_history_entry_t * new_ele = fd_stake_history_pool_ele_acquire( epoch_bank->stakes.stake_history.pool );
     229             : 
     230           0 :     new_ele->epoch        = ele->epoch;
     231           0 :     new_ele->activating   = ele->activating;
     232           0 :     new_ele->deactivating = ele->deactivating;
     233           0 :     new_ele->effective    = ele->effective;
     234             : 
     235           0 :     epoch_bank->stakes.stake_history.treap = fd_stake_history_treap_ele_insert(
     236           0 :       epoch_bank->stakes.stake_history.treap,
     237           0 :       new_ele,
     238           0 :       epoch_bank->stakes.stake_history.pool
     239           0 :     );
     240           0 :   }
     241             : 
     242           0 :   fd_stakes_destroy( &oldbank->stakes, &destroy );
     243             : 
     244             :   /* Index vote accounts */
     245             : 
     246             :   /* Copy over fields */
     247             : 
     248           0 :   if( oldbank->blockhash_queue.last_hash )
     249           0 :     slot_bank->poh = *oldbank->blockhash_queue.last_hash;
     250           0 :   slot_bank->slot = oldbank->slot;
     251           0 :   slot_bank->prev_slot = oldbank->parent_slot;
     252           0 :   fd_memcpy(&slot_bank->banks_hash, &oldbank->hash, sizeof(oldbank->hash));
     253           0 :   fd_memcpy(&slot_bank->fee_rate_governor, &oldbank->fee_rate_governor, sizeof(oldbank->fee_rate_governor));
     254           0 :   slot_bank->lamports_per_signature = oldbank->fee_calculator.lamports_per_signature;
     255           0 :   slot_ctx->prev_lamports_per_signature = oldbank->fee_calculator.lamports_per_signature;
     256           0 :   if( oldbank->hashes_per_tick )
     257           0 :     epoch_bank->hashes_per_tick = *oldbank->hashes_per_tick;
     258           0 :   else
     259           0 :     epoch_bank->hashes_per_tick = 0;
     260           0 :   epoch_bank->ticks_per_slot = oldbank->ticks_per_slot;
     261           0 :   fd_memcpy(&epoch_bank->ns_per_slot, &oldbank->ns_per_slot, sizeof(oldbank->ns_per_slot));
     262           0 :   epoch_bank->genesis_creation_time = oldbank->genesis_creation_time;
     263           0 :   epoch_bank->slots_per_year = oldbank->slots_per_year;
     264           0 :   slot_bank->max_tick_height = oldbank->max_tick_height;
     265           0 :   fd_memcpy( &epoch_bank->inflation, &oldbank->inflation, FD_INFLATION_FOOTPRINT );
     266           0 :   fd_memcpy( &epoch_bank->epoch_schedule, &oldbank->epoch_schedule, FD_EPOCH_SCHEDULE_FOOTPRINT );
     267           0 :   epoch_bank->rent = oldbank->rent_collector.rent;
     268           0 :   fd_memcpy( &epoch_bank->rent, &oldbank->rent_collector.rent, FD_RENT_FOOTPRINT );
     269           0 :   fd_memcpy( &epoch_bank->rent_epoch_schedule, &oldbank->rent_collector.epoch_schedule, FD_EPOCH_SCHEDULE_FOOTPRINT );
     270             : 
     271           0 :   if( manifest->epoch_account_hash )
     272           0 :     slot_bank->epoch_account_hash = *manifest->epoch_account_hash;
     273             : 
     274           0 :   slot_bank->collected_rent = oldbank->collected_rent;
     275             :   // did they not change the bank?!
     276           0 :   slot_bank->collected_execution_fees = oldbank->collector_fees;
     277           0 :   slot_bank->collected_priority_fees = 0;
     278           0 :   slot_bank->capitalization = oldbank->capitalization;
     279           0 :   slot_bank->block_height = oldbank->block_height;
     280           0 :   slot_bank->transaction_count = oldbank->transaction_count;
     281           0 :   if ( oldbank->blockhash_queue.last_hash ) {
     282           0 :     slot_bank->block_hash_queue.last_hash = fd_valloc_malloc( slot_ctx->valloc, FD_HASH_ALIGN, FD_HASH_FOOTPRINT );
     283           0 :     fd_memcpy( slot_bank->block_hash_queue.last_hash, oldbank->blockhash_queue.last_hash, sizeof(fd_hash_t) );
     284           0 :   } else {
     285           0 :     slot_bank->block_hash_queue.last_hash = NULL;
     286           0 :   }
     287           0 :   slot_bank->block_hash_queue.last_hash_index = oldbank->blockhash_queue.last_hash_index;
     288           0 :   slot_bank->block_hash_queue.max_age = oldbank->blockhash_queue.max_age;
     289           0 :   slot_bank->block_hash_queue.ages_root = NULL;
     290           0 :   slot_bank->block_hash_queue.ages_pool = fd_hash_hash_age_pair_t_map_alloc( slot_ctx->valloc, 400 );
     291           0 :   for ( ulong i = 0; i < oldbank->blockhash_queue.ages_len; i++ ) {
     292           0 :     fd_hash_hash_age_pair_t * elem = &oldbank->blockhash_queue.ages[i];
     293           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 );
     294           0 :     fd_memcpy( &node->elem, elem, FD_HASH_HASH_AGE_PAIR_FOOTPRINT );
     295           0 :     fd_hash_hash_age_pair_t_map_insert( slot_bank->block_hash_queue.ages_pool, &slot_bank->block_hash_queue.ages_root, node );
     296           0 :   }
     297             : 
     298           0 :   recover_clock( slot_ctx );
     299             : 
     300             :   /* Update last restart slot
     301             :      https://github.com/solana-labs/solana/blob/30531d7a5b74f914dde53bfbb0bc2144f2ac92bb/runtime/src/bank.rs#L2152
     302             : 
     303             :      oldbank->hard_forks is sorted ascending by slot number.
     304             :      To find the last restart slot, take the highest hard fork slot
     305             :      number that is less or equal than the current slot number.
     306             :      (There might be some hard forks in the future, ignore these) */
     307           0 :   do {
     308           0 :     slot_bank->last_restart_slot.slot = 0UL;
     309           0 :     if( FD_UNLIKELY( oldbank->hard_forks.hard_forks_len == 0 ) ) {
     310             :       /* SIMD-0047: The first restart slot should be `0` */
     311           0 :       break;
     312           0 :     }
     313             : 
     314           0 :     fd_slot_pair_t const * head = oldbank->hard_forks.hard_forks;
     315           0 :     fd_slot_pair_t const * tail = head + oldbank->hard_forks.hard_forks_len - 1UL;
     316             : 
     317           0 :     for( fd_slot_pair_t const *pair = tail; pair >= head; pair-- ) {
     318           0 :       if( pair->slot <= slot_bank->slot ) {
     319           0 :         slot_bank->last_restart_slot.slot = pair->slot;
     320           0 :         break;
     321           0 :       }
     322           0 :     }
     323           0 :   } while (0);
     324             : 
     325             :   /* Move EpochStakes */
     326           0 :   do {
     327           0 :     ulong epoch = fd_slot_to_epoch( &epoch_bank->epoch_schedule, slot_bank->slot, NULL );
     328             : 
     329             :     /* Find EpochStakes object matching epoch */
     330           0 :     fd_epoch_epoch_stakes_pair_t * epochs  = oldbank->epoch_stakes;
     331           0 :     fd_epoch_stakes_t *            stakes0 = NULL;  /* current */
     332           0 :     fd_epoch_stakes_t *            stakes1 = NULL;  /* next */
     333           0 :     slot_ctx->slot_bank.has_use_preceeding_epoch_stakes = 1;
     334           0 :     slot_ctx->slot_bank.use_preceeding_epoch_stakes     = epoch + 2UL;
     335             : 
     336           0 :     for( ulong i=0UL; i < manifest->bank.epoch_stakes_len; i++ ) {
     337           0 :       if( epochs[i].key == epoch )
     338           0 :         stakes0 = &epochs[i].value;
     339           0 :       if( epochs[i].key == epoch+1UL )
     340           0 :         stakes1 = &epochs[i].value;
     341             : 
     342             :       /* When loading from a snapshot, Agave's stake caches mean that we have to special-case the epoch stakes
     343             :          that are used for the second epoch E+2 after the snapshot epoch E.
     344             : 
     345             :          If the snapshot contains the epoch stakes for E+2, we should use those.
     346             : 
     347             :          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
     348             :          all other epochs. */
     349           0 :       if ( epochs[i].key == epoch+2UL ) {
     350           0 :         slot_ctx->slot_bank.has_use_preceeding_epoch_stakes = 0;
     351           0 :       }
     352           0 :     }
     353           0 :     if( FD_UNLIKELY( (!stakes0) | (!stakes1) ) ) {
     354           0 :       FD_LOG_WARNING(( "snapshot missing EpochStakes for epochs %lu and/or %lu", epoch, epoch+1UL ));
     355           0 :       return 0;
     356           0 :     }
     357             : 
     358             :     /* Move current EpochStakes */
     359           0 :     slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool =
     360           0 :       fd_vote_accounts_pair_t_map_alloc( slot_ctx->valloc, 100000 );  /* FIXME remove magic constant */
     361           0 :     slot_ctx->slot_bank.epoch_stakes.vote_accounts_root = NULL;
     362             : 
     363           0 :     for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
     364           0 :           stakes0->stakes.vote_accounts.vote_accounts_pool,
     365           0 :           stakes0->stakes.vote_accounts.vote_accounts_root );
     366           0 :           n;
     367           0 :           n = fd_vote_accounts_pair_t_map_successor( stakes0->stakes.vote_accounts.vote_accounts_pool, n ) ) {
     368             : 
     369           0 :         fd_vote_accounts_pair_t_mapnode_t * elem = fd_vote_accounts_pair_t_map_acquire(
     370           0 :           slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool );
     371           0 :         FD_TEST( elem );
     372             : 
     373           0 :         fd_memcpy( &elem->elem, &n->elem, sizeof(fd_vote_accounts_pair_t));
     374             : 
     375           0 :         fd_vote_accounts_pair_t_map_insert(
     376           0 :           slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool,
     377           0 :           &slot_ctx->slot_bank.epoch_stakes.vote_accounts_root,
     378           0 :           elem );
     379           0 :     }
     380             : 
     381           0 :     fd_vote_accounts_destroy( &stakes0->stakes.vote_accounts, &destroy );
     382             : 
     383             :     /* Move next EpochStakes
     384             :        TODO Can we derive this instead of trusting the snapshot? */
     385             : 
     386           0 :     fd_vote_accounts_pair_t_mapnode_t * pool = stakes1->stakes.vote_accounts.vote_accounts_pool;
     387           0 :     fd_vote_accounts_pair_t_mapnode_t * root = stakes1->stakes.vote_accounts.vote_accounts_root;
     388             : 
     389           0 :     for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(pool, root);
     390           0 :           n;
     391           0 :           n = fd_vote_accounts_pair_t_map_successor(pool, n) ) {
     392             : 
     393           0 :       fd_vote_accounts_pair_t_mapnode_t * elem = fd_vote_accounts_pair_t_map_acquire(
     394           0 :         epoch_bank->next_epoch_stakes.vote_accounts_pool );
     395           0 :       FD_TEST( elem );
     396             : 
     397           0 :       fd_memcpy( &elem->elem, &n->elem, sizeof(fd_vote_accounts_pair_t));
     398             : 
     399           0 :       fd_vote_accounts_pair_t_map_insert(
     400           0 :         epoch_bank->next_epoch_stakes.vote_accounts_pool,
     401           0 :         &epoch_bank->next_epoch_stakes.vote_accounts_root,
     402           0 :         elem );
     403             : 
     404           0 :     }
     405             : 
     406           0 :     fd_vote_accounts_destroy( &stakes1->stakes.vote_accounts, &destroy );
     407           0 :   } while(0);
     408             : 
     409             :   // TODO Backup to database
     410             :   //int result = fd_runtime_save_epoch_bank(slot_ctx);
     411             :   //if( result != FD_EXECUTOR_INSTR_SUCCESS ) {
     412             :   //  FD_LOG_WARNING(("save epoch bank failed"));
     413             :   //  return result;
     414             :   //}
     415             :   //
     416             :   //return fd_runtime_save_slot_bank(slot_ctx);
     417             : 
     418           0 :   return slot_ctx;
     419           0 : }
     420             : 
     421             : fd_exec_slot_ctx_t *
     422             : fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t *   slot_ctx,
     423           0 :                           fd_solana_manifest_t * manifest ) {
     424             : 
     425           0 :   fd_exec_slot_ctx_t * res = fd_exec_slot_ctx_recover_( slot_ctx, manifest );
     426             : 
     427             :   /* Regardless of result, always destroy manifest */
     428           0 :   fd_bincode_destroy_ctx_t destroy = { .valloc = slot_ctx->valloc };
     429           0 :   fd_solana_manifest_destroy( manifest, &destroy );
     430           0 :   fd_memset( manifest, 0, sizeof(fd_solana_manifest_t) );
     431             : 
     432           0 :   return res;
     433           0 : }
     434             : 
     435             : fd_exec_slot_ctx_t *
     436             : fd_exec_slot_ctx_recover_status_cache( fd_exec_slot_ctx_t *    ctx,
     437           0 :                                        fd_bank_slot_deltas_t * slot_deltas ) {
     438           0 :   fd_txncache_t * status_cache = ctx->status_cache;
     439           0 :   if( !status_cache ) {
     440           0 :     FD_LOG_WARNING(("No status cache in slot ctx"));
     441           0 :     return NULL;
     442           0 :   }
     443             : 
     444           0 :   FD_SCRATCH_SCOPE_BEGIN {
     445           0 :     ulong num_entries = 0;
     446           0 :     for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
     447           0 :       fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[i];
     448           0 :       for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
     449           0 :         num_entries += slot_delta->slot_delta_vec[j].value.statuses_len;
     450           0 :       }
     451           0 :     }
     452           0 :     fd_txncache_insert_t * insert_vals = fd_scratch_alloc( alignof(fd_txncache_insert_t), num_entries * sizeof(fd_txncache_insert_t) );
     453             : 
     454             :     /* Dumb sort for 300 slot entries to insert in order. */
     455           0 :     fd_slot_delta_t ** deltas = fd_scratch_alloc(alignof(fd_slot_delta_t *), slot_deltas->slot_deltas_len * sizeof(fd_slot_delta_t *));
     456             : 
     457           0 :     ulong curr = 0;
     458           0 :     for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
     459           0 :       ulong curr_min = ULONG_MAX;
     460           0 :       ulong curr_min_idx = ULONG_MAX;
     461           0 :       for( ulong j = 0; j < slot_deltas->slot_deltas_len; j++ ) {
     462           0 :         fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[j];
     463           0 :         if( slot_delta->slot <= curr ) continue;
     464             : 
     465           0 :         if( curr_min > slot_delta->slot ) {
     466           0 :           curr_min = slot_delta->slot;
     467           0 :           curr_min_idx = j;
     468           0 :         }
     469           0 :       }
     470           0 :       deltas[i] = &slot_deltas->slot_deltas[curr_min_idx];
     471           0 :       curr = slot_deltas->slot_deltas[curr_min_idx].slot;
     472           0 :     }
     473             : 
     474           0 :     ulong idx = 0;
     475           0 :     for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
     476           0 :       fd_slot_delta_t * slot_delta = deltas[i];
     477           0 :       ulong slot = slot_delta->slot;
     478           0 :       if( slot_delta->is_root ) {
     479           0 :         fd_txncache_register_root_slot( ctx->status_cache, slot );
     480           0 :       }
     481           0 :       for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
     482           0 :         fd_status_pair_t * pair = &slot_delta->slot_delta_vec[j];
     483           0 :         fd_hash_t * blockhash = &pair->hash;
     484             : 
     485           0 :         for( ulong k = 0; k < pair->value.statuses_len; k++ ) {
     486           0 :           fd_cache_status_t * status = &pair->value.statuses[k];
     487           0 :           uchar result = (uchar)status->result.discriminant;
     488           0 :           insert_vals[idx++] = (fd_txncache_insert_t){
     489           0 :             .blockhash = blockhash->uc,
     490           0 :             .slot = slot,
     491           0 :             .txnhash = status->key_slice,
     492           0 :             .result = &result
     493           0 :           };
     494           0 :         }
     495           0 :       }
     496           0 :     }
     497           0 :     fd_txncache_insert_batch( ctx->status_cache, insert_vals, num_entries );
     498             : 
     499           0 :     for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
     500           0 :       fd_slot_delta_t * slot_delta = deltas[i];
     501           0 :       ulong slot = slot_delta->slot;
     502           0 :       for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
     503           0 :         fd_status_pair_t * pair = &slot_delta->slot_delta_vec[j];
     504           0 :         fd_hash_t * blockhash = &pair->hash;
     505           0 :         fd_txncache_set_txnhash_offset( ctx->status_cache, slot, blockhash->uc, pair->value.txn_idx );
     506           0 :       }
     507           0 :     }
     508           0 :   } FD_SCRATCH_SCOPE_END;
     509           0 :   return ctx;
     510           0 : }
     511             : 
     512             : void
     513      108786 : fd_exec_slot_ctx_free( fd_exec_slot_ctx_t * slot_ctx ) {
     514      108786 :   fd_bincode_destroy_ctx_t ctx;
     515      108786 :   ctx.valloc = slot_ctx->valloc;
     516      108786 :   fd_slot_bank_destroy( &slot_ctx->slot_bank, &ctx );
     517             : 
     518             :   /* leader points to a caller-allocated leader schedule */
     519      108786 :   fd_exec_slot_ctx_delete( fd_exec_slot_ctx_leave( slot_ctx ) );
     520      108786 : }

Generated by: LCOV version 1.14