LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_bank.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 345 763 45.2 %
Date: 2026-10-22 18:10:43 Functions: 33 49 67.3 %

          Line data    Source code
       1             : #include "fd_bank.h"
       2             : #include "../events/fd_event_runtime.h"
       3             : #include "fd_runtime_const.h"
       4             : #include "../rewards/fd_stake_rewards.h"
       5             : #include "sysvar/fd_sysvar_cache.h"
       6             : #include "sysvar/fd_sysvar_epoch_schedule.h"
       7             : 
       8             : #define POOL_NAME fd_banks_pool
       9          36 : #define POOL_T    fd_bank_t
      10             : #include "../../util/tmpl/fd_pool.c"
      11             : 
      12             : #define DLIST_NAME  fd_banks_dead
      13             : #define DLIST_ELE_T fd_bank_t
      14           0 : #define DLIST_PREV  dead_prev
      15           0 : #define DLIST_NEXT  dead_next
      16             : #include "../../util/tmpl/fd_dlist.c"
      17             : 
      18          12 : #define FD_BANKS_STAKE_REWARDS_CACHE_CNT (2UL)
      19             : 
      20             : FD_STATIC_ASSERT( FD_BANKS_MAX_BANKS<USHORT_MAX, epoch_credits_fork_id_width );
      21             : 
      22             : fd_lthash_value_t const *
      23         615 : fd_bank_lthash_locking_query( fd_bank_t * bank ) {
      24         615 :   fd_rwlock_read( &bank->lthash_lock );
      25         615 :   return &bank->f.lthash;
      26         615 : }
      27             : 
      28             : void
      29         615 : fd_bank_lthash_end_locking_query( fd_bank_t * bank ) {
      30         615 :   fd_rwlock_unread( &bank->lthash_lock );
      31         615 : }
      32             : 
      33             : fd_lthash_value_t *
      34        6687 : fd_bank_lthash_locking_modify( fd_bank_t * bank ) {
      35        6687 :   fd_rwlock_write( &bank->lthash_lock );
      36        6687 :   return &bank->f.lthash;
      37        6687 : }
      38             : 
      39             : void
      40        6684 : fd_bank_lthash_end_locking_modify( fd_bank_t * bank ) {
      41        6684 :   fd_rwlock_unwrite( &bank->lthash_lock );
      42        6684 : }
      43             : 
      44             : ulong
      45         204 : fd_banks_align( void ) {
      46         204 :   return FD_BANKS_ALIGN;
      47         204 : }
      48             : 
      49             : static fd_bank_t *
      50        1278 : fd_banks_get_bank_pool( fd_banks_t * banks_data ) {
      51        1278 :   return fd_type_pun( (uchar *)banks_data + banks_data->pool_offset );
      52        1278 : }
      53             : 
      54             : static fd_banks_dead_t *
      55          12 : fd_banks_get_dead_banks( fd_banks_t * banks_data ) {
      56          12 :   return fd_type_pun( (uchar *)banks_data + banks_data->dead_banks_offset );
      57          12 : }
      58             : 
      59             : static fd_epoch_leaders_t *
      60        1668 : fd_banks_get_epoch_leaders( fd_banks_t * banks_data ) {
      61        1668 :   return fd_type_pun( (uchar *)banks_data + banks_data->epoch_leaders_offset );
      62        1668 : }
      63             : 
      64             : static fd_stake_delegations_t *
      65        2089 : fd_banks_get_stake_delegations( fd_banks_t * banks_data ) {
      66        2089 :   return fd_type_pun( (uchar *)banks_data + banks_data->stake_delegations_offset );
      67        2089 : }
      68             : 
      69             : static fd_vote_stakes_t *
      70      132690 : fd_banks_get_vote_stakes( fd_banks_t * banks_data ) {
      71      132690 :   return fd_type_pun( (uchar *)banks_data + banks_data->vote_stakes_offset );
      72      132690 : }
      73             : 
      74             : static fd_cost_tracker_store_t *
      75       66830 : fd_banks_get_cost_tracker( fd_banks_t * banks_data ) {
      76       66830 :   return fd_type_pun( (uchar *)banks_data + banks_data->cost_tracker_offset );
      77       66830 : }
      78             : 
      79             : static fd_epoch_credits_store_t *
      80       66015 : fd_banks_get_epoch_credits( fd_banks_t * banks_data ) {
      81       66015 :   return fd_type_pun( (uchar *)banks_data + banks_data->epoch_credits_offset );
      82       66015 : }
      83             : 
      84             : static fd_stake_rewards_t *
      85         896 : fd_banks_get_stake_rewards( fd_banks_t * banks_data ) {
      86         896 :   return fd_type_pun( (uchar *)banks_data + banks_data->stake_rewards_offset );
      87         896 : }
      88             : 
      89             : fd_epoch_credits_store_t *
      90         891 : fd_bank_epoch_credits( fd_bank_t const * bank ) {
      91         891 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
      92         891 :   return fd_banks_get_epoch_credits( banks_data );
      93         891 : }
      94             : 
      95             : fd_stake_delegations_t *
      96         824 : fd_bank_stake_delegations_modify( fd_bank_t * bank ) {
      97         824 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
      98         824 :   return fd_banks_get_stake_delegations( banks_data );
      99         824 : }
     100             : 
     101             : fd_stake_rewards_t const *
     102          32 : fd_bank_stake_rewards_query( fd_bank_t * bank ) {
     103          32 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     104          32 :   return fd_type_pun_const( fd_banks_get_stake_rewards( banks_data ) );
     105          32 : }
     106             : 
     107             : fd_stake_rewards_t *
     108         864 : fd_bank_stake_rewards_modify( fd_bank_t * bank ) {
     109         864 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     110         864 :   return fd_banks_get_stake_rewards( banks_data );
     111         864 : }
     112             : 
     113             : fd_epoch_leaders_t const *
     114             : fd_bank_epoch_leaders_query( fd_bank_t const * bank,
     115        1009 :                              ulong             epoch ) {
     116        1009 :   FD_TEST( bank->f.epoch==epoch || bank->f.epoch==epoch-1UL );
     117        1009 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     118        1009 :   return (fd_epoch_leaders_t const *)fd_type_pun( (uchar *)fd_banks_get_epoch_leaders( banks_data ) + (epoch % 2UL) * banks_data->epoch_leaders_footprint );
     119        1009 : }
     120             : 
     121             : fd_epoch_leaders_t *
     122             : fd_bank_epoch_leaders_modify( fd_bank_t * bank,
     123         647 :                               ulong       epoch ) {
     124         647 :   FD_TEST( bank->f.epoch==epoch || bank->f.epoch==epoch-1UL );
     125         647 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     126         647 :   return (fd_epoch_leaders_t *)fd_type_pun( (uchar *)fd_banks_get_epoch_leaders( banks_data ) + (epoch % 2UL) * banks_data->epoch_leaders_footprint );
     127         647 : }
     128             : 
     129             : fd_vote_stakes_t *
     130        2398 : fd_bank_vote_stakes( fd_bank_t const * bank ) {
     131        2398 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     132        2398 :   return fd_banks_get_vote_stakes( banks_data );
     133        2398 : }
     134             : 
     135             : fd_cost_tracker_store_t *
     136        1688 : fd_bank_cost_tracker( fd_bank_t const * bank ) {
     137        1688 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     138        1688 :   return fd_banks_get_cost_tracker( banks_data );
     139        1688 : }
     140             : 
     141             : fd_bank_t *
     142           0 : fd_banks_root( fd_banks_t * banks ) {
     143           0 :   return fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), banks->root_idx );
     144           0 : }
     145             : 
     146             : fd_bank_t *
     147             : fd_banks_bank_query( fd_banks_t * banks,
     148         615 :                      ulong        bank_idx ) {
     149         615 :   fd_bank_t * bank = fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), bank_idx );
     150         615 :   if( FD_UNLIKELY( bank->state==FD_BANK_STATE_INACTIVE ) ) return NULL;
     151         615 :   return bank;
     152         615 : }
     153             : 
     154             : fd_bank_t *
     155             : fd_banks_get_parent( fd_banks_t * banks,
     156         615 :                      fd_bank_t *  bank ) {
     157         615 :   if( FD_UNLIKELY( bank->parent_idx==ULONG_MAX ) ) return NULL;
     158         615 :   return fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), bank->parent_idx );
     159         615 : }
     160             : 
     161             : int
     162           0 : fd_banks_can_start_bank( fd_banks_t * banks ) {
     163           0 :   if( FD_UNLIKELY( fd_banks_pool_free( fd_banks_get_bank_pool( banks ) )==0UL ) ) return 0;
     164           0 :   return 1;
     165           0 : }
     166             : 
     167             : ulong
     168           0 : fd_banks_pool_used_cnt( fd_banks_t * banks ) {
     169           0 :   return fd_banks_pool_used( fd_banks_get_bank_pool( banks ) );
     170           0 : }
     171             : 
     172             : ulong
     173           0 : fd_banks_pool_max_cnt( fd_banks_t * banks ) {
     174           0 :   return fd_banks_pool_max( fd_banks_get_bank_pool( banks ) );
     175           0 : }
     176             : 
     177             : void
     178             : fd_banks_stake_delegations_evict_bank_fork( fd_banks_t * banks,
     179         614 :                                             fd_bank_t *  bank ) {
     180         614 :   if( bank->stake_delegations_fork_id!=USHORT_MAX ) {
     181         614 :     fd_stake_delegations_t * sd = fd_banks_get_stake_delegations( banks );
     182         614 :     fd_stake_delegations_evict_fork( sd, bank->stake_delegations_fork_id );
     183         614 :     bank->stake_delegations_fork_id = USHORT_MAX;
     184         614 :   }
     185         614 : }
     186             : 
     187             : static void
     188             : fd_banks_vote_stakes_evict_bank_fork( fd_banks_t * banks,
     189       65135 :                                       fd_bank_t *  bank ) {
     190       65135 :   if( bank->vote_stakes_fork_id!=ULONG_MAX ) {
     191       65133 :     fd_vote_stakes_purge_fork( fd_banks_get_vote_stakes( banks ), bank->vote_stakes_fork_id );
     192       65133 :     bank->vote_stakes_fork_id = ULONG_MAX;
     193       65133 :   }
     194       65135 : }
     195             : 
     196             : ulong
     197             : fd_banks_footprint( ulong max_total_banks,
     198             :                     ulong cache_cnt,
     199             :                     ulong max_stake_accounts,
     200          24 :                     ulong max_vote_accounts ) {
     201             : 
     202          24 :   if( FD_UNLIKELY( !cache_cnt ) ) return 0UL;
     203             : 
     204          24 :   ulong epoch_leaders_footprint = FD_EPOCH_LEADERS_FOOTPRINT( max_vote_accounts, FD_RUNTIME_SLOTS_PER_EPOCH );;
     205             : 
     206          24 :   ulong l = FD_LAYOUT_INIT;
     207          24 :   l = FD_LAYOUT_APPEND( l, fd_banks_align(),               sizeof(fd_banks_t) );
     208          24 :   l = FD_LAYOUT_APPEND( l, fd_stake_delegations_align(),   fd_stake_delegations_footprint( max_stake_accounts, max_total_banks ) );
     209          24 :   l = FD_LAYOUT_APPEND( l, fd_vote_stakes_align(),         fd_vote_stakes_footprint( max_total_banks, cache_cnt ) );
     210          24 :   l = FD_LAYOUT_APPEND( l, FD_EPOCH_LEADERS_ALIGN,         2UL * epoch_leaders_footprint );
     211          24 :   l = FD_LAYOUT_APPEND( l, fd_banks_pool_align(),          fd_banks_pool_footprint( max_total_banks ) );
     212          24 :   l = FD_LAYOUT_APPEND( l, fd_banks_dead_align(),          fd_banks_dead_footprint() );
     213          24 :   l = FD_LAYOUT_APPEND( l, fd_cost_tracker_store_align(),  fd_cost_tracker_store_footprint( max_total_banks, cache_cnt ) );
     214          24 :   l = FD_LAYOUT_APPEND( l, fd_stake_rewards_align(),       fd_stake_rewards_footprint( max_stake_accounts, max_total_banks, FD_BANKS_STAKE_REWARDS_CACHE_CNT ) );
     215          24 :   l = FD_LAYOUT_APPEND( l, fd_epoch_credits_store_align(), fd_epoch_credits_store_footprint( max_total_banks, cache_cnt ) );
     216          24 :   return FD_LAYOUT_FINI( l, fd_banks_align() );
     217          24 : }
     218             : 
     219             : void *
     220             : fd_banks_new( void * shmem,
     221             :               int    stake_delegations_fd,
     222             :               ulong  max_total_banks,
     223             :               ulong  cache_cnt,
     224             :               ulong  max_stake_accounts,
     225             :               ulong  max_disk_records,
     226             :               ulong  max_vote_accounts,
     227             :               ulong  bench_max_cost_per_block,
     228          12 :               ulong  seed ) {
     229          12 :   if( FD_UNLIKELY( !shmem ) ) {
     230           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     231           0 :     return NULL;
     232           0 :   }
     233             : 
     234          12 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_banks_align() ) ) ) {
     235           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     236           0 :     return NULL;
     237           0 :   }
     238             : 
     239          12 :   if( FD_UNLIKELY( max_total_banks>FD_BANKS_MAX_BANKS ) ) {
     240           0 :     FD_LOG_WARNING(( "max_total_banks is too large" ));
     241           0 :     return NULL;
     242           0 :   }
     243             : 
     244          12 :   if( FD_UNLIKELY( !cache_cnt ) ) {
     245           0 :     FD_LOG_WARNING(( "cache_cnt must be non-zero" ));
     246           0 :     return NULL;
     247           0 :   }
     248          12 :   ulong epoch_leaders_footprint = FD_EPOCH_LEADERS_FOOTPRINT( max_vote_accounts, FD_RUNTIME_SLOTS_PER_EPOCH );
     249             : 
     250          12 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
     251          12 :   fd_banks_t * banks_data              = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_align(),               sizeof(fd_banks_t) );
     252          12 :   void *       stake_delegations_mem   = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegations_align(),   fd_stake_delegations_footprint( max_stake_accounts, max_total_banks ) );
     253          12 :   void *       vote_stakes_mem         = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_stakes_align(),         fd_vote_stakes_footprint( max_total_banks, cache_cnt ) );
     254          12 :   void *       epoch_leaders_mem       = FD_SCRATCH_ALLOC_APPEND( l, FD_EPOCH_LEADERS_ALIGN,         2UL * epoch_leaders_footprint );
     255          12 :   void *       pool_mem                = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_pool_align(),          fd_banks_pool_footprint( max_total_banks ) );
     256          12 :   void *       dead_banks_mem          = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_dead_align(),          fd_banks_dead_footprint() );
     257          12 :   void *       cost_tracker_mem        = FD_SCRATCH_ALLOC_APPEND( l, fd_cost_tracker_store_align(),  fd_cost_tracker_store_footprint( max_total_banks, cache_cnt ) );
     258          12 :   void *       stake_rewards_pool_mem  = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_rewards_align(),       fd_stake_rewards_footprint( max_stake_accounts, max_total_banks, FD_BANKS_STAKE_REWARDS_CACHE_CNT ) );
     259          12 :   void *       epoch_credits_mem       = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_credits_store_align(), fd_epoch_credits_store_footprint( max_total_banks, cache_cnt ) );
     260             : 
     261          12 :   if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_banks_align() ) != (ulong)banks_data + fd_banks_footprint( max_total_banks, cache_cnt, max_stake_accounts, max_vote_accounts ) ) ) {
     262           0 :     FD_LOG_WARNING(( "fd_banks_new: bad layout" ));
     263           0 :     return NULL;
     264           0 :   }
     265             : 
     266          12 :   void * pool = fd_banks_pool_new( pool_mem, max_total_banks );
     267          12 :   if( FD_UNLIKELY( !pool ) ) {
     268           0 :     FD_LOG_WARNING(( "Failed to create bank pool" ));
     269           0 :     return NULL;
     270           0 :   }
     271             : 
     272          12 :   fd_bank_t * bank_pool = fd_banks_pool_join( pool );
     273          12 :   if( FD_UNLIKELY( !bank_pool ) ) {
     274           0 :     FD_LOG_WARNING(( "Failed to join bank pool" ));
     275           0 :     return NULL;
     276           0 :   }
     277             : 
     278          12 :   fd_banks_dead_t * dead_banks = fd_banks_dead_join( fd_banks_dead_new( dead_banks_mem ) );
     279          12 :   if( FD_UNLIKELY( !dead_banks ) ) {
     280           0 :     FD_LOG_WARNING(( "Failed to create dead banks list" ));
     281           0 :     return NULL;
     282           0 :   }
     283          12 :   banks_data->dead_banks_offset = (ulong)dead_banks - (ulong)banks_data;
     284             : 
     285          12 :   banks_data->epoch_leaders_offset           = (ulong)epoch_leaders_mem - (ulong)banks_data;
     286          12 :   banks_data->epoch_leaders_footprint        = epoch_leaders_footprint;
     287          12 :   banks_data->pool_offset                    = (ulong)bank_pool - (ulong)banks_data;
     288             : 
     289             :   /* Create the pools for the non-inlined fields.  Also new() and join()
     290             :      each of the elements in the pool as well as set up the lock for
     291             :      each of the pools. */
     292             : 
     293          12 :   fd_stake_delegations_t * stake_delegations = fd_stake_delegations_join(
     294          12 :       fd_stake_delegations_new( stake_delegations_mem, stake_delegations_fd, seed, max_stake_accounts, max_disk_records, max_total_banks ),
     295          12 :       stake_delegations_fd );
     296          12 :   if( FD_UNLIKELY( !stake_delegations ) ) {
     297           0 :     FD_LOG_WARNING(( "Unable to create stake delegations root" ));
     298           0 :     return NULL;
     299           0 :   }
     300          12 :   banks_data->stake_delegations_offset = (ulong)stake_delegations - (ulong)banks_data;
     301             : 
     302          12 :   fd_vote_stakes_t * vote_stakes = fd_vote_stakes_join( fd_vote_stakes_new( vote_stakes_mem, FD_VOTE_STAKES_FD, max_total_banks, cache_cnt, seed ), FD_VOTE_STAKES_FD );
     303          12 :   if( FD_UNLIKELY( !vote_stakes ) ) {
     304           0 :     FD_LOG_WARNING(( "Unable to create vote stakes" ));
     305           0 :     return NULL;
     306           0 :   }
     307          12 :   banks_data->vote_stakes_offset = (ulong)vote_stakes - (ulong)banks_data;
     308             : 
     309          12 :   fd_cost_tracker_store_t * cost_tracker_store = fd_cost_tracker_store_join( fd_cost_tracker_store_new( cost_tracker_mem, FD_COST_TRACKER_FD, max_total_banks, cache_cnt, bench_max_cost_per_block, seed ), FD_COST_TRACKER_FD );
     310          12 :   if( FD_UNLIKELY( !cost_tracker_store ) ) {
     311           0 :     FD_LOG_WARNING(( "Failed to create cost tracker pool" ));
     312           0 :     return NULL;
     313           0 :   }
     314          12 :   banks_data->cost_tracker_offset = (ulong)cost_tracker_store - (ulong)banks_data;
     315             : 
     316          12 :   fd_stake_rewards_t * stake_rewards = fd_stake_rewards_join( fd_stake_rewards_new( stake_rewards_pool_mem, max_stake_accounts, max_total_banks, FD_BANKS_STAKE_REWARDS_CACHE_CNT ) );
     317          12 :   if( FD_UNLIKELY( !stake_rewards ) ) {
     318           0 :     FD_LOG_WARNING(( "Failed to create stake rewards" ));
     319           0 :     return NULL;
     320           0 :   }
     321          12 :   banks_data->stake_rewards_offset = (ulong)stake_rewards - (ulong)banks_data;
     322             : 
     323          12 :   fd_epoch_credits_store_t * epoch_credits = fd_epoch_credits_store_join( fd_epoch_credits_store_new( epoch_credits_mem, FD_EPOCH_CREDITS_FD, max_total_banks, cache_cnt ), FD_EPOCH_CREDITS_FD );
     324          12 :   if( FD_UNLIKELY( !epoch_credits ) ) {
     325           0 :     FD_LOG_WARNING(( "Failed to create epoch credits" ));
     326           0 :     return NULL;
     327           0 :   }
     328          12 :   banks_data->epoch_credits_offset = (ulong)epoch_credits - (ulong)banks_data;
     329             : 
     330             :   /* For each bank, set the offset back to banks_data and initialize
     331             :      per-bank state. */
     332             : 
     333          36 :   for( ulong i=0UL; i<max_total_banks; i++ ) {
     334             : 
     335          24 :     fd_bank_t * bank = fd_banks_pool_ele( bank_pool, i );
     336             : 
     337          24 :     fd_rwlock_new( &bank->lthash_lock );
     338             : 
     339          24 :     bank->idx               = i;
     340          24 :     bank->state             = FD_BANK_STATE_INACTIVE;
     341          24 :     bank->banks_data_offset = (ulong)bank - (ulong)banks_data;
     342             : 
     343          24 :     bank->cost_tracker_fork_id = USHORT_MAX;
     344          24 :     bank->vote_stakes_fork_id  = ULONG_MAX;
     345          24 :   }
     346             : 
     347          12 :   banks_data->report_runtime_diffs = 0;
     348          12 :   banks_data->max_total_banks    = max_total_banks;
     349          12 :   banks_data->cache_cnt          = cache_cnt;
     350          12 :   banks_data->max_stake_accounts = max_stake_accounts;
     351          12 :   banks_data->max_vote_accounts  = max_vote_accounts;
     352          12 :   banks_data->root_idx           = ULONG_MAX;
     353          12 :   banks_data->evict_rr_idx       = seed;
     354          12 :   banks_data->prunable_idx       = ULONG_MAX;
     355          12 :   banks_data->curr_fork_width    = 0UL;
     356          12 :   banks_data->bank_seq           = 1UL;
     357             : 
     358          12 :   FD_COMPILER_MFENCE();
     359          12 :   FD_VOLATILE( banks_data->magic ) = FD_BANKS_MAGIC;
     360          12 :   FD_COMPILER_MFENCE();
     361             : 
     362          12 :   return shmem;
     363          12 : }
     364             : 
     365             : fd_banks_t *
     366          12 : fd_banks_join( void * banks_data_mem ) {
     367          12 :   fd_banks_t * banks_data  = (fd_banks_t *)banks_data_mem;
     368             : 
     369          12 :   if( FD_UNLIKELY( !banks_data ) ) {
     370           0 :     FD_LOG_WARNING(( "NULL banks data" ));
     371           0 :     return NULL;
     372           0 :   }
     373             : 
     374          12 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)banks_data, fd_banks_align() ) ) ) {
     375           0 :     FD_LOG_WARNING(( "misaligned banks" ));
     376           0 :     return NULL;
     377           0 :   }
     378             : 
     379          12 :   if( FD_UNLIKELY( banks_data->magic!=FD_BANKS_MAGIC ) ) {
     380           0 :     FD_LOG_WARNING(( "Invalid banks magic" ));
     381           0 :     return NULL;
     382           0 :   }
     383             : 
     384          12 :   FD_SCRATCH_ALLOC_INIT( l, banks_data );
     385          12 :   banks_data                     = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_align(),               sizeof(fd_banks_t) );
     386          12 :   void * stake_delegations_mem   = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegations_align(),   fd_stake_delegations_footprint( banks_data->max_stake_accounts, banks_data->max_total_banks ) );
     387          12 :   void * vote_stakes_mem         = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_stakes_align(),         fd_vote_stakes_footprint( banks_data->max_total_banks, banks_data->cache_cnt ) );
     388          12 :   void * epoch_leaders_mem       = FD_SCRATCH_ALLOC_APPEND( l, FD_EPOCH_LEADERS_ALIGN,         2UL * banks_data->epoch_leaders_footprint );
     389          12 :   void * pool_mem                = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_pool_align(),          fd_banks_pool_footprint( banks_data->max_total_banks ) );
     390          12 :   void * dead_banks_mem          = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_dead_align(),          fd_banks_dead_footprint() );
     391          12 :   void * cost_tracker_mem        = FD_SCRATCH_ALLOC_APPEND( l, fd_cost_tracker_store_align(),  fd_cost_tracker_store_footprint( banks_data->max_total_banks, banks_data->cache_cnt ) );
     392          12 :   void * stake_rewards_mem       = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_rewards_align(),       fd_stake_rewards_footprint( banks_data->max_stake_accounts, banks_data->max_total_banks, FD_BANKS_STAKE_REWARDS_CACHE_CNT ) );
     393          12 :   void * epoch_credits_mem       = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_credits_store_align(), fd_epoch_credits_store_footprint( banks_data->max_total_banks, banks_data->cache_cnt ) );
     394             : 
     395          12 :   FD_SCRATCH_ALLOC_FINI( l, fd_banks_align() );
     396             : 
     397          12 :   fd_bank_t * banks_pool = fd_banks_get_bank_pool( banks_data );
     398          12 :   if( FD_UNLIKELY( !banks_pool ) ) {
     399           0 :     FD_LOG_WARNING(( "Failed to join bank pool" ));
     400           0 :     return NULL;
     401           0 :   }
     402             : 
     403          12 :   if( FD_UNLIKELY( banks_pool!=fd_banks_pool_join( pool_mem ) ) ) {
     404           0 :     FD_LOG_WARNING(( "Failed to join bank pool" ));
     405           0 :     return NULL;
     406           0 :   }
     407             : 
     408          12 :   if( FD_UNLIKELY( fd_banks_dead_join( dead_banks_mem )!=fd_banks_get_dead_banks( banks_data ) ) ) {
     409           0 :     FD_LOG_WARNING(( "Failed to join dead banks list" ));
     410           0 :     return NULL;
     411           0 :   }
     412             : 
     413          12 :   if( FD_UNLIKELY( epoch_leaders_mem!=fd_banks_get_epoch_leaders( banks_data ) ) ) {
     414           0 :     FD_LOG_WARNING(( "Failed to join epoch leaders mem" ));
     415           0 :     return NULL;
     416           0 :   }
     417             : 
     418          12 :   if( FD_UNLIKELY( stake_delegations_mem!=fd_banks_get_stake_delegations( banks_data ) ) ) {
     419           0 :     FD_LOG_WARNING(( "Failed to join stake delegations root mem" ));
     420           0 :     return NULL;
     421           0 :   }
     422          12 :   if( FD_UNLIKELY( vote_stakes_mem!=(void *)fd_banks_get_vote_stakes( banks_data ) ) ) {
     423           0 :     FD_LOG_WARNING(( "Failed to join vote stakes" ));
     424           0 :     return NULL;
     425           0 :   }
     426          12 :   if( FD_UNLIKELY( !fd_vote_stakes_join( vote_stakes_mem, FD_VOTE_STAKES_FD ) ) ) {
     427           0 :     FD_LOG_WARNING(( "Failed to join vote stakes" ));
     428           0 :     return NULL;
     429           0 :   }
     430             : 
     431          12 :   if( FD_UNLIKELY( cost_tracker_mem!=(void *)fd_banks_get_cost_tracker( banks_data ) ||
     432          12 :                    !fd_cost_tracker_store_join( cost_tracker_mem, FD_COST_TRACKER_FD ) ) ) {
     433           0 :     FD_LOG_WARNING(( "Failed to join cost tracker pool" ));
     434           0 :     return NULL;
     435           0 :   }
     436             : 
     437          12 :   if( FD_UNLIKELY( epoch_credits_mem!=(void *)fd_banks_get_epoch_credits( banks_data ) ||
     438          12 :                    !fd_epoch_credits_store_join( epoch_credits_mem, FD_EPOCH_CREDITS_FD ) ) ) {
     439           0 :     FD_LOG_WARNING(( "Failed to join epoch credits" ));
     440           0 :     return NULL;
     441           0 :   }
     442             : 
     443          12 :   if( FD_UNLIKELY( !fd_stake_rewards_join( stake_rewards_mem ) ) ) {
     444           0 :     FD_LOG_WARNING(( "Failed to join stake rewards" ));
     445           0 :     return NULL;
     446           0 :   }
     447             : 
     448          12 :   return banks_data;
     449          12 : }
     450             : 
     451             : fd_bank_t *
     452          12 : fd_banks_init_bank( fd_banks_t * banks ) {
     453             : 
     454          12 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     455          12 :   FD_CHECK_CRIT( fd_banks_pool_free( bank_pool )!=0UL, "invariant violation: no free bank pool elements" );
     456             : 
     457          12 :   fd_bank_t * bank = fd_banks_pool_ele_acquire( bank_pool );
     458          12 :   bank->bank_seq = FD_ATOMIC_FETCH_AND_ADD( &banks->bank_seq, 1UL );
     459             : 
     460          12 :   ulong null_idx    = fd_banks_pool_idx_null( bank_pool );
     461          12 :   bank->idx         = fd_banks_pool_idx( bank_pool, bank );
     462          12 :   bank->next        = null_idx;
     463          12 :   bank->parent_idx  = null_idx;
     464          12 :   bank->child_idx   = null_idx;
     465          12 :   bank->sibling_idx = null_idx;
     466             : 
     467          12 :   fd_memset( &bank->f, 0, sizeof(bank->f) );
     468          12 :   bank->f.alpenglow_migration_slot        = ULONG_MAX;
     469          12 :   fd_event_runtime_slot_diffs_reset( bank->idx );
     470          12 :   bank->stake_rewards_fork_id             = USHORT_MAX;
     471          12 :   bank->epoch_credits_fork_id             = fd_epoch_credits_store_new_fork( fd_banks_get_epoch_credits( banks ), USHORT_MAX );
     472          12 :   bank->stake_delegations_fork_id         = USHORT_MAX;
     473          12 :   bank->parent_accdb_fork_id.val          = USHORT_MAX;
     474          12 :   bank->cost_tracker_fork_id              = USHORT_MAX;
     475          12 :   bank->first_fec_set_received_nanos      = fd_log_wallclock();
     476          12 :   bank->preparation_begin_nanos           = 0L;
     477          12 :   bank->first_transaction_scheduled_nanos = 0L;
     478          12 :   bank->last_transaction_finished_nanos   = 0L;
     479          12 :   bank->block_completed_nanos             = 0L;
     480             : 
     481          12 :   fd_vote_stakes_t * vote_stakes = fd_banks_get_vote_stakes( banks );
     482          12 :   fd_vote_stakes_reset( vote_stakes );
     483          12 :   bank->vote_stakes_fork_id = fd_vote_stakes_init( vote_stakes, 0UL );
     484             : 
     485          12 :   bank->state     = FD_BANK_STATE_FROZEN;
     486          12 :   bank->refcnt        = 0UL;
     487          12 :   bank->cert_task_cnt = 0UL;
     488          12 :   bank->is_leader     = 0;
     489             : 
     490          12 :   banks->root_idx = bank->idx;
     491          12 :   banks->curr_fork_width = 1UL;
     492          12 :   banks->prunable_idx    = null_idx;
     493             : 
     494          12 :   FD_LOG_DEBUG(( "init bank (idx=%lu, stake_rewards_idx=%u, stake_delegations_idx=%u)",
     495          12 :                  bank->idx,
     496          12 :                  bank->stake_rewards_fork_id,
     497          12 :                  bank->stake_delegations_fork_id ));
     498             : 
     499          12 :   return bank;
     500          12 : }
     501             : 
     502             : fd_bank_t *
     503             : fd_banks_clone_from_parent( fd_banks_t * banks,
     504          12 :                             ulong        child_bank_idx ) {
     505             : 
     506          12 :   fd_bank_t * bank_pool  = fd_banks_get_bank_pool( banks );
     507          12 :   fd_bank_t * child_bank = fd_banks_pool_ele( bank_pool, child_bank_idx );
     508          12 :   FD_CHECK_CRIT( child_bank->state==FD_BANK_STATE_INIT, "invariant violation: bank is not initialized" );
     509             : 
     510          12 :   fd_bank_t * parent_bank = fd_banks_pool_ele( bank_pool, child_bank->parent_idx );
     511          12 :   FD_CHECK_CRIT( parent_bank->state==FD_BANK_STATE_FROZEN || parent_bank->state==FD_BANK_STATE_PRUNABLE, "invariant violation: parent bank is not frozen or prunable" );
     512             : 
     513          12 :   child_bank->cost_tracker_fork_id = fd_cost_tracker_store_new_fork( fd_banks_get_cost_tracker( banks ), USHORT_MAX );
     514             : 
     515          12 :   child_bank->f                           = parent_bank->f;
     516          12 :   child_bank->vote_stakes_fork_id         = fd_vote_stakes_new_fork( fd_banks_get_vote_stakes( banks ), parent_bank->vote_stakes_fork_id, parent_bank->f.epoch );
     517          12 :   child_bank->stake_rewards_fork_id       = parent_bank->stake_rewards_fork_id;
     518          12 :   child_bank->epoch_credits_fork_id       = parent_bank->epoch_credits_fork_id;
     519          12 :   if( FD_UNLIKELY( child_bank->stake_rewards_fork_id!=USHORT_MAX ) ) {
     520           0 :     fd_stake_rewards_acquire( fd_banks_get_stake_rewards( banks ), child_bank->stake_rewards_fork_id );
     521           0 :   }
     522          12 :   fd_epoch_credits_store_acquire( fd_banks_get_epoch_credits( banks ), child_bank->epoch_credits_fork_id );
     523          12 :   child_bank->stake_delegations_fork_id   = fd_stake_delegations_new_fork( fd_banks_get_stake_delegations( banks ), parent_bank->stake_delegations_fork_id );
     524          12 :   child_bank->f.block_height              = parent_bank->f.block_height + 1UL;
     525          12 :   child_bank->f.tick_height               = parent_bank->f.max_tick_height;
     526          12 :   child_bank->f.parent_slot               = parent_bank->f.slot;
     527          12 :   child_bank->f.parent_signature_cnt      = parent_bank->f.signature_count;
     528          12 :   child_bank->f.parent_txn_count          = parent_bank->f.parent_txn_count + parent_bank->f.txn_count;
     529          12 :   child_bank->f.prev_bank_hash            = parent_bank->f.bank_hash;
     530          12 :   child_bank->f.execution_fees            = 0UL;
     531          12 :   child_bank->f.priority_fees             = 0UL;
     532          12 :   child_bank->f.tips                      = 0UL;
     533          12 :   child_bank->f.signature_count           = 0UL;
     534          12 :   child_bank->f.total_compute_units_used  = 0UL;
     535          12 :   child_bank->f.shred_cnt                 = 0UL;
     536          12 :   child_bank->f.txn_count                 = 0UL;
     537          12 :   child_bank->f.nonvote_txn_count         = 0UL;
     538          12 :   child_bank->f.failed_txn_count          = 0UL;
     539          12 :   child_bank->f.nonvote_failed_txn_count  = 0UL;
     540          12 :   child_bank->f.identity_vote_idx         = ULONG_MAX;
     541             : 
     542          12 :   child_bank->state = FD_BANK_STATE_REPLAYABLE;
     543             : 
     544          12 :   FD_LOG_DEBUG(( "cloning bank (idx=%lu, parent_idx=%lu, stake_rewards_idx=%u, stake_delegations_idx=%u)",
     545          12 :                  child_bank_idx,
     546          12 :                  parent_bank->idx,
     547          12 :                  child_bank->stake_rewards_fork_id,
     548          12 :                  child_bank->stake_delegations_fork_id ));
     549             : 
     550          12 :   return child_bank;
     551          12 : }
     552             : 
     553             : /* fd_bank_stake_delegation_apply_deltas applies all of the stake
     554             :    delegations for the entire direct ancestry from the bank to the
     555             :    root into a full fd_stake_delegations_t object. */
     556             : 
     557             : static inline void
     558             : fd_bank_apply_deltas( fd_banks_t *                         banks,
     559             :                       fd_bank_t *                          bank,
     560           0 :                       fd_stake_delegations_delta_stats_t * stake_delegations_delta_stats ) {
     561             : 
     562           0 :   fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
     563             : 
     564             :   /* The stake_delegations root has crossed an epoch boundary.  The
     565             :      stake totals for the current root need to be updated. */
     566           0 :   fd_bank_t * old_root = fd_banks_root( banks );
     567           0 :   if( old_root->f.epoch!=bank->f.epoch ) {
     568           0 :     fd_stake_delegations_set_totals( stake_delegations, bank->f.total_effective_stake,
     569           0 :                                      bank->f.total_activating_stake, bank->f.total_deactivating_stake );
     570           0 :   }
     571             : 
     572           0 :   fd_stake_history_t stake_history_[1];
     573           0 :   fd_stake_history_t const * stake_history = fd_sysvar_cache_stake_history_view( &bank->f.sysvar_cache, stake_history_ );
     574             :   /* stake_history may be NULL */
     575           0 :   fd_stake_delegations_advance_root( bank->f.epoch,
     576           0 :                                      stake_history,
     577           0 :                                      &bank->f.warmup_cooldown_rate_epoch,
     578           0 :                                      FD_FEATURE_ACTIVE_BANK( bank, upgrade_bpf_stake_program_to_v5_1 ),
     579           0 :                                      0,
     580           0 :                                      stake_delegations,
     581           0 :                                      bank->stake_delegations_fork_id,
     582           0 :                                      stake_delegations_delta_stats );
     583           0 : }
     584             : 
     585             : fd_stake_delegations_t *
     586         627 : fd_banks_stake_delegations_root_query( fd_banks_t * banks ) {
     587         627 :   return fd_banks_get_stake_delegations( banks );
     588         627 : }
     589             : 
     590             : void
     591             : fd_banks_advance_root( fd_banks_t * banks,
     592           0 :                        ulong        root_bank_idx ) {
     593             : 
     594           0 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     595             : 
     596             :   /* We want to replace the old root with the new root. This means we
     597             :      have to remove banks that aren't descendants of the new root. */
     598             : 
     599           0 :   fd_bank_t * old_root = fd_banks_root( banks );
     600           0 :   FD_CHECK_CRIT( old_root->refcnt==0UL, "refcnt for old root bank is nonzero" );
     601             : 
     602           0 :   fd_bank_t * new_root = fd_banks_pool_ele( bank_pool, root_bank_idx );
     603             : 
     604           0 :   fd_stake_delegations_delta_stats_t stake_delegations_delta_stats = {0};
     605           0 :   fd_bank_apply_deltas( banks, new_root, &stake_delegations_delta_stats );
     606             : 
     607           0 :   fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
     608           0 :   ulong                    stake_delegations_prunes = 0UL;
     609           0 :   if( FD_UNLIKELY( old_root->f.epoch!=new_root->f.epoch && FD_FEATURE_ACTIVE_BANK( new_root, remove_inactive_stakes ) ) ) {
     610           0 :     fd_stake_history_t         stake_history_[1];
     611           0 :     fd_stake_history_t const * stake_history = fd_sysvar_cache_stake_history_view( &new_root->f.sysvar_cache, stake_history_ );
     612           0 :     stake_delegations_prunes = fd_stake_delegations_prune_inactive_root( stake_delegations, new_root->f.epoch, stake_history, &new_root->f.warmup_cooldown_rate_epoch,
     613           0 :                                                                          FD_FEATURE_ACTIVE_BANK( new_root, upgrade_bpf_stake_program_to_v5_1 ),
     614           0 :                                                                          banks->report_runtime_diffs ? new_root : NULL );
     615           0 :   }
     616             : 
     617           0 :   fd_stake_delegations_evict_fork( stake_delegations, new_root->stake_delegations_fork_id );
     618           0 :   new_root->stake_delegations_fork_id = USHORT_MAX;
     619             : 
     620           0 :   if( FD_UNLIKELY( banks->report_runtime_diffs ) ) {
     621             :     /* Epoch-boundary prunes are emitted as remove-kind rows, so fold
     622             :        them into the rooted removal count. */
     623           0 :     stake_delegations_delta_stats.removes = fd_ulong_sat_add( stake_delegations_delta_stats.removes, stake_delegations_prunes );
     624           0 :     stake_delegations_delta_stats.root_cnt = fd_ulong_sat_sub( stake_delegations_delta_stats.root_cnt, stake_delegations_prunes );
     625           0 :     fd_event_runtime_rooted_emit( new_root, old_root->f.slot, stake_delegations,
     626           0 :                                   &stake_delegations_delta_stats );
     627           0 :   }
     628             : 
     629             :   /* Now that the deltas have been applied, we can remove all nodes
     630             :      that are not direct descendants of the new root. */
     631           0 :   fd_bank_t * head = fd_banks_pool_ele( bank_pool, old_root->idx );
     632           0 :   head->next       = ULONG_MAX;
     633           0 :   fd_bank_t * tail = head;
     634           0 :   ulong pruned_leaf_cnt = 0UL;
     635             : 
     636           0 :   while( head ) {
     637           0 :     fd_bank_t * child = fd_banks_pool_ele( bank_pool, head->child_idx );
     638             : 
     639           0 :     while( FD_LIKELY( child ) ) {
     640             : 
     641           0 :       if( FD_LIKELY( child!=new_root ) ) {
     642           0 :         if( FD_UNLIKELY( child->refcnt!=0UL ) ) {
     643           0 :           FD_LOG_CRIT(( "refcnt for child bank at index %lu is %lu", child->idx, child->refcnt ));
     644           0 :         }
     645             : 
     646             :         /* Update tail pointers */
     647           0 :         tail->next = child->idx;
     648           0 :         tail       = fd_banks_pool_ele( bank_pool, tail->next );
     649           0 :         tail->next = fd_banks_pool_idx_null( bank_pool );
     650           0 :       }
     651             : 
     652           0 :       child = fd_banks_pool_ele( bank_pool, child->sibling_idx );
     653           0 :     }
     654             : 
     655           0 :     fd_bank_t * next = fd_banks_pool_ele( bank_pool, head->next );
     656           0 :     if( head->child_idx==fd_banks_pool_idx_null( bank_pool ) ) pruned_leaf_cnt++;
     657             : 
     658             :     /* It is possible for a bank that never finished replaying to be
     659             :        pruned away.  If the bank was never frozen, then it's possible
     660             :        that the bank still owns a cost tracker pool element.  If this
     661             :        is the case, we need to release the pool element. */
     662           0 :     if( head->cost_tracker_fork_id!=USHORT_MAX ) {
     663           0 :       FD_LOG_DEBUG(( "releasing cost tracker pool element for bank at index %lu", head->idx ));
     664           0 :       fd_cost_tracker_store_release( fd_banks_get_cost_tracker( banks ), head->cost_tracker_fork_id );
     665           0 :       head->cost_tracker_fork_id = USHORT_MAX;
     666           0 :     }
     667             : 
     668           0 :     if( FD_LIKELY( head->stake_rewards_fork_id!=USHORT_MAX ) ) {
     669           0 :       fd_stake_rewards_release( fd_banks_get_stake_rewards( banks ), head->stake_rewards_fork_id );
     670           0 :     }
     671           0 :     if( FD_LIKELY( head->epoch_credits_fork_id!=USHORT_MAX ) ) {
     672           0 :       fd_epoch_credits_store_release( fd_banks_get_epoch_credits( banks ), head->epoch_credits_fork_id );
     673           0 :       head->epoch_credits_fork_id = USHORT_MAX;
     674           0 :     }
     675           0 :     head->stake_rewards_fork_id       = USHORT_MAX;
     676             : 
     677           0 :     if( head->stake_delegations_fork_id!=USHORT_MAX ) {
     678           0 :       FD_LOG_DEBUG(( "evicting stake delegation fork (bank_idx=%lu, fork_idx=%u)", head->idx, head->stake_delegations_fork_id ));
     679           0 :       fd_stake_delegations_evict_fork( stake_delegations, head->stake_delegations_fork_id );
     680           0 :       head->stake_delegations_fork_id = USHORT_MAX;
     681           0 :     }
     682             : 
     683           0 :     fd_banks_vote_stakes_evict_bank_fork( banks, head );
     684             : 
     685           0 :     if( FD_UNLIKELY( head->state==FD_BANK_STATE_PRUNABLE ) ) {
     686           0 :       FD_TEST( banks->prunable_idx==head->idx );
     687           0 :       banks->prunable_idx = fd_banks_pool_idx_null( bank_pool );
     688           0 :     }
     689           0 :     if( FD_UNLIKELY( head->state==FD_BANK_STATE_DEAD ) ) fd_banks_dead_ele_remove( fd_banks_get_dead_banks( banks ), head, bank_pool );
     690           0 :     head->state = FD_BANK_STATE_INACTIVE;
     691           0 :     fd_banks_pool_ele_release( bank_pool, head );
     692           0 :     head = next;
     693           0 :   }
     694             : 
     695             :   /* new_root is detached from old_root and becomes the only root.
     696             :      Clear sibling_idx too so traversals cannot follow a stale link to
     697             :      a bank index that was just pruned and later reused. */
     698           0 :   new_root->parent_idx  = ULONG_MAX;
     699           0 :   new_root->sibling_idx = ULONG_MAX;
     700           0 :   banks->root_idx       = new_root->idx;
     701           0 :   FD_TEST( banks->curr_fork_width>pruned_leaf_cnt );
     702           0 :   banks->curr_fork_width -= pruned_leaf_cnt;
     703           0 : }
     704             : 
     705             : /* Is the fork tree starting at the given bank entirely eligible for
     706             :    pruning?  Returns 1 for yes, 0 for no.
     707             : 
     708             :    See comment in fd_replay_tile.c for more details on safe pruning. */
     709             : static int
     710             : fd_banks_subtree_can_be_pruned( fd_bank_t * bank_pool,
     711           0 :                                 fd_bank_t * bank ) {
     712             : 
     713           0 :   if( bank->refcnt!=0UL ) return 0;
     714             : 
     715             :   /* Recursively check all children. */
     716           0 :   ulong child_idx = bank->child_idx;
     717           0 :   while( child_idx!=fd_banks_pool_idx_null( bank_pool ) ) {
     718           0 :     fd_bank_t * child = fd_banks_pool_ele( bank_pool, child_idx );
     719           0 :     if( !fd_banks_subtree_can_be_pruned( bank_pool, child ) ) return 0;
     720           0 :     child_idx = child->sibling_idx;
     721           0 :   }
     722             : 
     723           0 :   return 1;
     724           0 : }
     725             : 
     726             : int
     727             : fd_banks_advance_root_prepare( fd_banks_t * banks,
     728             :                                ulong        target_bank_idx,
     729           0 :                                ulong *      advanceable_bank_idx_out ) {
     730             :   /* TODO: An optimization here is to do a single traversal of the tree
     731             :      that would mark minority forks as dead while accumulating
     732             :      refcnts to determine which bank is the highest advanceable. */
     733             : 
     734           0 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     735             : 
     736           0 :   fd_bank_t * root = fd_banks_root( banks );
     737             : 
     738             :   /* Early exit if target is the same as the old root. */
     739           0 :   if( FD_UNLIKELY( root->idx==target_bank_idx ) ) {
     740           0 :     FD_LOG_WARNING(( "target bank_idx %lu is the same as the old root's bank index %lu", target_bank_idx, root->idx ));
     741           0 :     return 0;
     742           0 :   }
     743             : 
     744             :   /* Early exit if the root bank still has a reference to it, we can't
     745             :      advance from it unti it's released. */
     746           0 :   if( FD_UNLIKELY( root->refcnt!=0UL ) ) {
     747           0 :     return 0;
     748           0 :   }
     749             : 
     750           0 :   fd_bank_t * target_bank = fd_banks_pool_ele( bank_pool, target_bank_idx );
     751             : 
     752             :   /* Walk from target_bank up to root, recording the direct child of
     753             :      root on the path (prev).  We only advance root by one level. */
     754             : 
     755           0 :   fd_bank_t * curr = target_bank;
     756           0 :   fd_bank_t * prev = NULL;
     757           0 :   while( curr && curr!=root ) {
     758           0 :     prev = curr;
     759           0 :     curr = fd_banks_pool_ele( bank_pool, curr->parent_idx );
     760           0 :   }
     761             : 
     762             :   /* If we didn't reach the old root or there is no parent, target is
     763             :      not a descendant. */
     764           0 :   if( FD_UNLIKELY( !curr || prev->parent_idx!=root->idx ) ) {
     765           0 :     FD_LOG_CRIT(( "invariant violation: target bank_idx %lu is not a direct descendant of root bank_idx %lu %lu %lu", target_bank_idx, root->idx, prev->idx, prev->parent_idx ));
     766           0 :   }
     767             : 
     768             :   /* We will at most advance our root bank by one.  This means we can
     769             :      advance our root bank by one if each of the siblings of the
     770             :      potential new root are eligible for pruning.  Each of the sibling
     771             :      subtrees can be pruned if the subtrees have no active references on
     772             :      their bank. */
     773           0 :   ulong advance_candidate_idx = prev->idx;
     774           0 :   ulong child_idx = root->child_idx;
     775           0 :   while( child_idx!=fd_banks_pool_idx_null( bank_pool ) ) {
     776           0 :     fd_bank_t * child_bank = fd_banks_pool_ele( bank_pool, child_idx );
     777           0 :     if( child_idx!=advance_candidate_idx ) {
     778           0 :       if( !fd_banks_subtree_can_be_pruned( bank_pool, child_bank ) ) {
     779           0 :         return 0;
     780           0 :       }
     781           0 :     }
     782           0 :     child_idx = child_bank->sibling_idx;
     783           0 :   }
     784             : 
     785           0 :   fd_bank_t * cand = fd_banks_pool_ele( bank_pool, advance_candidate_idx );
     786           0 :   FD_CHECK_CRIT( cand->state==FD_BANK_STATE_FROZEN, "advancing root to non-frozen bank" );
     787             : 
     788           0 :   *advanceable_bank_idx_out = advance_candidate_idx;
     789           0 :   return 1;
     790           0 : }
     791             : 
     792             : fd_bank_t *
     793             : fd_banks_new_bank( fd_banks_t * banks,
     794             :                    ulong        parent_bank_idx,
     795             :                    long         now,
     796          12 :                    uchar        is_leader ) {
     797             : 
     798          12 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     799          12 :   FD_CHECK_CRIT( fd_banks_pool_free( bank_pool )!=0UL, "invariant violation: no free bank indices available" );
     800             : 
     801          12 :   ulong       child_bank_idx = fd_banks_pool_idx_acquire( bank_pool );
     802          12 :   fd_bank_t * child_bank     = fd_banks_pool_ele( bank_pool, child_bank_idx );
     803          12 :   FD_CHECK_CRIT( child_bank->state==FD_BANK_STATE_INACTIVE, "invariant violation: bank for bank index is already initialized" );
     804             : 
     805          12 :   ulong null_idx = fd_banks_pool_idx_null( bank_pool );
     806             : 
     807          12 :   child_bank->bank_seq    = FD_ATOMIC_FETCH_AND_ADD( &banks->bank_seq, 1UL );
     808          12 :   child_bank->parent_idx  = null_idx;
     809          12 :   child_bank->child_idx   = null_idx;
     810          12 :   child_bank->sibling_idx = null_idx;
     811          12 :   child_bank->next        = null_idx;
     812          12 :   child_bank->state       = FD_BANK_STATE_INIT;
     813          12 :   child_bank->refcnt      = 0UL;
     814          12 :   child_bank->cert_task_cnt = 0UL;
     815          12 :   child_bank->is_leader   = is_leader;
     816          12 :   fd_event_runtime_slot_diffs_reset( child_bank->idx );
     817          12 :   child_bank->f.block_id  = (fd_hash_t){0};
     818             : 
     819          12 :   child_bank->stake_rewards_fork_id       = USHORT_MAX;
     820          12 :   child_bank->epoch_credits_fork_id       = USHORT_MAX;
     821          12 :   child_bank->stake_delegations_fork_id   = USHORT_MAX;
     822          12 :   child_bank->vote_stakes_fork_id         = ULONG_MAX;
     823          12 :   child_bank->parent_accdb_fork_id.val    = USHORT_MAX;
     824             : 
     825             :   /* Then make sure that the parent bank is valid.  PRUNABLE parents are
     826             :      rejected so eviction victims remain leaves until pruned. */
     827             : 
     828          12 :   fd_bank_t * parent_bank = fd_banks_pool_ele( bank_pool, parent_bank_idx );
     829          12 :   FD_CHECK_CRIT( parent_bank->state!=FD_BANK_STATE_INACTIVE &&
     830          12 :                  parent_bank->state!=FD_BANK_STATE_DEAD &&
     831          12 :                  parent_bank->state!=FD_BANK_STATE_PRUNABLE,
     832          12 :                  "invariant violation: parent bank is dead, inactive, or prunable" );
     833             : 
     834             :   /* Link node->parent */
     835          12 :   child_bank->parent_idx = parent_bank_idx;
     836             :   /* Link parent->node and sibling->node */
     837          12 :   if( FD_LIKELY( parent_bank->child_idx==null_idx ) ) {
     838             :     /* This is the first child so set as left-most child */
     839          12 :     parent_bank->child_idx = child_bank_idx;
     840             : 
     841          12 :   } else {
     842             :     /* Already have children so iterate to right-most sibling. */
     843           0 :     fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, parent_bank->child_idx );
     844           0 :     while( curr_bank->sibling_idx != null_idx ) curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->sibling_idx );
     845             :     /* Link to right-most sibling. */
     846           0 :     curr_bank->sibling_idx = child_bank_idx;
     847           0 :     banks->curr_fork_width++;
     848           0 :   }
     849             : 
     850          12 :   child_bank->first_fec_set_received_nanos      = now;
     851          12 :   child_bank->preparation_begin_nanos           = 0L;
     852          12 :   child_bank->first_transaction_scheduled_nanos = 0L;
     853          12 :   child_bank->last_transaction_finished_nanos   = 0L;
     854          12 :   child_bank->block_completed_nanos             = 0L;
     855             : 
     856          12 :   return child_bank;
     857          12 : }
     858             : 
     859             : /* Mark everything in the fork tree starting at the given bank dead. */
     860             : 
     861             : static ulong
     862             : fd_banks_subtree_mark_dead( fd_banks_t * banks,
     863             :                             fd_bank_t *  bank_pool,
     864             :                             fd_bank_t *  bank,
     865           0 :                             ulong *      opt_idxs ) {
     866           0 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_CRIT(( "invariant violation: bank is NULL" ));
     867             : 
     868             :   /* If a bank is already on the dead bank list and we need to insert
     869             :      its parent, we need to remove it from the list first and reinsert
     870             :      it ahead of its parent. */
     871           0 :   int newly_dead = bank->state!=FD_BANK_STATE_DEAD;
     872             : 
     873           0 :   ulong idxs_cnt = 0UL;
     874           0 :   if( FD_UNLIKELY( bank->state==FD_BANK_STATE_PRUNABLE ) ) {
     875           0 :     FD_TEST( banks->prunable_idx==bank->idx );
     876           0 :     banks->prunable_idx = fd_banks_pool_idx_null( bank_pool );
     877           0 :   }
     878           0 :   bank->state = FD_BANK_STATE_DEAD;
     879           0 :   fd_banks_dead_t * dead_banks = fd_banks_get_dead_banks( banks );
     880           0 :   if( FD_UNLIKELY( !newly_dead ) ) fd_banks_dead_ele_remove( dead_banks, bank, bank_pool );
     881           0 :   fd_banks_dead_ele_push_head( dead_banks, bank, bank_pool );
     882           0 :   if( newly_dead ) {
     883           0 :     if( opt_idxs ) opt_idxs[ idxs_cnt ] = bank->idx;
     884           0 :     idxs_cnt++;
     885           0 :   }
     886             : 
     887             :   /* Recursively mark all children as dead. */
     888           0 :   ulong child_idx = bank->child_idx;
     889           0 :   while( child_idx!=fd_banks_pool_idx_null( bank_pool ) ) {
     890           0 :     fd_bank_t * child      = fd_banks_pool_ele( bank_pool, child_idx );
     891           0 :     ulong *     child_idxs = opt_idxs ? opt_idxs+idxs_cnt : NULL;
     892           0 :     idxs_cnt += fd_banks_subtree_mark_dead( banks, bank_pool, child, child_idxs );
     893           0 :     child_idx = child->sibling_idx;
     894           0 :   }
     895             : 
     896           0 :   return idxs_cnt;
     897           0 : }
     898             : 
     899             : void
     900             : fd_banks_mark_bank_dead( fd_banks_t * banks,
     901             :                          ulong        bank_idx,
     902             :                          ulong *      opt_idxs,
     903           0 :                          ulong *      opt_idxs_cnt ) {
     904           0 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     905           0 :   fd_bank_t * bank      = fd_banks_pool_ele( bank_pool, bank_idx );
     906             : 
     907           0 :   ulong idxs_cnt = fd_banks_subtree_mark_dead( banks, bank_pool, bank, opt_idxs );
     908           0 :   if( opt_idxs_cnt ) *opt_idxs_cnt = idxs_cnt;
     909           0 : }
     910             : 
     911             : static int
     912             : fd_banks_prune_one_leaf( fd_banks_t *                   banks,
     913             :                          fd_bank_t *                    bank_pool,
     914             :                          fd_bank_t *                    bank,
     915           0 :                          fd_banks_prune_cancel_info_t * cancel ) {
     916           0 :   ulong       null_idx    = fd_banks_pool_idx_null( bank_pool );
     917           0 :   fd_bank_t * parent_bank = fd_banks_pool_ele( bank_pool, bank->parent_idx );
     918           0 :   FD_TEST( bank->child_idx==null_idx );
     919           0 :   int started_replaying = bank->stake_delegations_fork_id!=USHORT_MAX;
     920           0 :   int is_new_fork       = parent_bank->child_idx!=bank->idx || bank->sibling_idx!=null_idx;
     921             : 
     922           0 :   if( parent_bank->child_idx==bank->idx ) {
     923           0 :     parent_bank->child_idx = bank->sibling_idx;
     924           0 :   } else {
     925           0 :     fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, parent_bank->child_idx );
     926           0 :     while( curr_bank->sibling_idx!=bank->idx ) curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->sibling_idx );
     927           0 :     curr_bank->sibling_idx = bank->sibling_idx;
     928           0 :   }
     929           0 :   bank->parent_idx  = null_idx;
     930           0 :   bank->sibling_idx = null_idx;
     931           0 :   if( FD_LIKELY( is_new_fork ) ) {
     932           0 :     FD_TEST( banks->curr_fork_width>1UL );
     933           0 :     banks->curr_fork_width--;
     934           0 :   }
     935             : 
     936           0 :   if( FD_UNLIKELY( bank->cost_tracker_fork_id!=USHORT_MAX ) ) {
     937           0 :     fd_cost_tracker_store_release( fd_banks_get_cost_tracker( banks ), bank->cost_tracker_fork_id );
     938           0 :     bank->cost_tracker_fork_id = USHORT_MAX;
     939           0 :   }
     940             : 
     941           0 :   fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
     942           0 :   fd_stake_delegations_evict_fork( stake_delegations, bank->stake_delegations_fork_id );
     943           0 :   bank->stake_delegations_fork_id = USHORT_MAX;
     944           0 :   fd_banks_vote_stakes_evict_bank_fork( banks, bank );
     945             : 
     946           0 :   if( FD_LIKELY( bank->stake_rewards_fork_id!=USHORT_MAX ) ) {
     947           0 :     fd_stake_rewards_release( fd_banks_get_stake_rewards( banks ), bank->stake_rewards_fork_id );
     948           0 :   }
     949           0 :   if( FD_LIKELY( bank->epoch_credits_fork_id!=USHORT_MAX ) ) {
     950           0 :     fd_epoch_credits_store_release( fd_banks_get_epoch_credits( banks ), bank->epoch_credits_fork_id );
     951           0 :     bank->epoch_credits_fork_id = USHORT_MAX;
     952           0 :   }
     953           0 :   bank->stake_rewards_fork_id       = USHORT_MAX;
     954             : 
     955           0 :   if( FD_LIKELY( cancel ) ) {
     956           0 :     cancel->bank_idx = bank->idx;
     957           0 :     if( FD_LIKELY( started_replaying ) ) {
     958           0 :       cancel->txncache_fork_id  = bank->txncache_fork_id;
     959           0 :       cancel->progcache_fork_id = bank->progcache_fork_id;
     960           0 :       cancel->accdb_fork_id     = bank->accdb_fork_id;
     961           0 :       cancel->slot              = bank->f.slot;
     962           0 :       cancel->bank_seq          = bank->bank_seq;
     963           0 :     }
     964           0 :   }
     965             : 
     966           0 :   if( FD_UNLIKELY( bank->state==FD_BANK_STATE_PRUNABLE ) ) {
     967           0 :     FD_TEST( banks->prunable_idx==bank->idx );
     968           0 :     banks->prunable_idx = null_idx;
     969           0 :   }
     970           0 :   bank->state = FD_BANK_STATE_INACTIVE;
     971             : 
     972           0 :   fd_banks_pool_ele_release( bank_pool, bank );
     973           0 :   return 1+started_replaying;
     974           0 : }
     975             : 
     976             : int
     977             : fd_banks_prune_one_bank( fd_banks_t *                   banks,
     978           0 :                          fd_banks_prune_cancel_info_t * cancel ) {
     979           0 :   fd_banks_dead_t * dead_banks = fd_banks_get_dead_banks( banks );
     980           0 :   fd_bank_t *       bank_pool  = fd_banks_get_bank_pool( banks );
     981           0 :   ulong             null_idx   = fd_banks_pool_idx_null( bank_pool );
     982           0 :   if( !fd_banks_dead_is_empty( dead_banks, bank_pool ) ) {
     983           0 :     fd_bank_t * bank = fd_banks_dead_ele_peek_head( dead_banks, bank_pool );
     984           0 :     FD_TEST( bank->state==FD_BANK_STATE_DEAD );
     985           0 :     if( bank->refcnt==0UL ) {
     986           0 :       FD_LOG_DEBUG(( "pruning dead bank (idx=%lu)", bank->idx ));
     987             : 
     988           0 :       fd_banks_dead_ele_pop_head( dead_banks, bank_pool );
     989           0 :       return fd_banks_prune_one_leaf( banks, bank_pool, bank, cancel );
     990           0 :     }
     991           0 :   }
     992             : 
     993           0 :   if( FD_LIKELY( banks->prunable_idx==null_idx ) ) return 0;
     994             : 
     995           0 :   fd_bank_t * bank = fd_banks_pool_ele( bank_pool, banks->prunable_idx );
     996           0 :   FD_TEST( bank->state==FD_BANK_STATE_PRUNABLE );
     997           0 :   if( FD_UNLIKELY( bank->refcnt!=0UL ) ) return 0;
     998             : 
     999           0 :   FD_LOG_DEBUG(( "pruning evictable bank (idx=%lu)", bank->idx ));
    1000           0 :   return fd_banks_prune_one_leaf( banks, bank_pool, bank, cancel );
    1001           0 : }
    1002             : 
    1003             : void
    1004           0 : fd_banks_mark_bank_frozen( fd_bank_t * bank ) {
    1005           0 :   fd_banks_t * banks = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
    1006             : 
    1007           0 :   FD_CHECK_CRIT( bank->state==FD_BANK_STATE_REPLAYABLE, "invariant violation: bank is not replayable" );
    1008           0 :   bank->state = FD_BANK_STATE_FROZEN;
    1009             : 
    1010           0 :   FD_CHECK_CRIT( bank->cost_tracker_fork_id!=USHORT_MAX, "invariant violation: cost tracker fork id is null" );
    1011           0 :   fd_cost_tracker_store_release( fd_banks_get_cost_tracker( banks ), bank->cost_tracker_fork_id );
    1012           0 :   bank->cost_tracker_fork_id = USHORT_MAX;
    1013           0 : }
    1014             : 
    1015             : static fd_bank_t *
    1016             : fd_banks_get_evictable_private( fd_banks_t *      banks,
    1017             :                                 fd_bank_t *       bank_pool,
    1018             :                                 ulong             bank_idx,
    1019             :                                 fd_bank_t const * protected_bank,
    1020             :                                 ulong *           evictable_cnt,
    1021           0 :                                 ulong *           target ) {
    1022             :   /* Return any leaf node that is eligible for eviction.  We consider
    1023             :      a bank to be eligibile iff:
    1024             :      - it is a leaf
    1025             :      - it's not the root,
    1026             :      - it's not the leader
    1027             :      - the state is INIT, REPLAYABLE, or FROZEN */
    1028             : 
    1029           0 :   ulong null_idx = fd_banks_pool_idx_null( bank_pool );
    1030           0 :   if( bank_idx==null_idx ) return NULL;
    1031             : 
    1032           0 :   fd_bank_t * bank = fd_banks_pool_ele( bank_pool, bank_idx );
    1033             : 
    1034           0 :   ulong child_idx = bank->child_idx;
    1035           0 :   while( child_idx!=null_idx ) {
    1036           0 :     fd_bank_t * evictable = fd_banks_get_evictable_private( banks, bank_pool, child_idx, protected_bank, evictable_cnt, target );
    1037           0 :     if( FD_LIKELY( evictable ) ) return evictable;
    1038           0 :     fd_bank_t * child = fd_banks_pool_ele( bank_pool, child_idx );
    1039           0 :     child_idx = child->sibling_idx;
    1040           0 :   }
    1041             : 
    1042           0 :   if( bank->child_idx!=null_idx ) return NULL;
    1043           0 :   if( bank->idx==banks->root_idx ) return NULL;
    1044           0 :   if( bank==protected_bank ) return NULL;
    1045           0 :   if( bank->is_leader ) return NULL;
    1046           0 :   if( bank->state==FD_BANK_STATE_INACTIVE || bank->state==FD_BANK_STATE_DEAD || bank->state==FD_BANK_STATE_PRUNABLE ) return NULL;
    1047             : 
    1048           0 :   if( FD_LIKELY( evictable_cnt ) ) {
    1049           0 :     (*evictable_cnt)++;
    1050           0 :     return NULL;
    1051           0 :   }
    1052             : 
    1053           0 :   if( FD_LIKELY( (*target)-- ) ) return NULL;
    1054           0 :   return bank;
    1055           0 : }
    1056             : 
    1057             : ulong
    1058             : fd_banks_get_evictable_bank( fd_banks_t *      banks,
    1059           0 :                              fd_bank_t const * protected_bank ) {
    1060           0 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
    1061           0 :   ulong       null_idx  = fd_banks_pool_idx_null( bank_pool );
    1062             : 
    1063           0 :   if( FD_UNLIKELY( banks->prunable_idx!=null_idx ) ) return ULONG_MAX;
    1064             : 
    1065           0 :   fd_bank_t * root = fd_banks_root( banks );
    1066           0 :   if( FD_UNLIKELY( root->child_idx==null_idx ) ) return ULONG_MAX;
    1067             : 
    1068           0 :   ulong evictable_cnt = 0UL;
    1069           0 :   fd_banks_get_evictable_private( banks, bank_pool, banks->root_idx, protected_bank, &evictable_cnt, NULL );
    1070           0 :   if( FD_UNLIKELY( !evictable_cnt ) ) return ULONG_MAX;
    1071             : 
    1072           0 :   ulong target = banks->evict_rr_idx++ % evictable_cnt;
    1073           0 :   fd_bank_t * evictable = fd_banks_get_evictable_private( banks, bank_pool, banks->root_idx, protected_bank, NULL, &target );
    1074           0 :   if( FD_UNLIKELY( !evictable ) ) FD_LOG_CRIT(( "invariant violation: evictable bank not found" ));
    1075             : 
    1076             :   /* Eviction only selects leaves, and prunable_idx is a single pending
    1077             :      victim.  Non-leaf prunables would break both invariants. */
    1078           0 :   FD_TEST( evictable->child_idx==null_idx );
    1079           0 :   evictable->state = FD_BANK_STATE_PRUNABLE;
    1080           0 :   banks->prunable_idx = evictable->idx;
    1081           0 :   return evictable->idx;
    1082           0 : }
    1083             : 
    1084             : void
    1085             : fd_banks_clear_bank( fd_banks_t * banks,
    1086       64964 :                      fd_bank_t *  bank ) {
    1087             : 
    1088       64964 :   fd_memset( &bank->f, 0, sizeof(bank->f) );
    1089       64964 :   bank->f.alpenglow_migration_slot = ULONG_MAX;
    1090       64964 :   fd_event_runtime_slot_diffs_reset( bank->idx );
    1091             : 
    1092       64964 :   fd_vote_stakes_t * vote_stakes = fd_banks_get_vote_stakes( banks );
    1093       64964 :   fd_banks_vote_stakes_evict_bank_fork( banks, bank );
    1094       64964 :   bank->vote_stakes_fork_id = fd_vote_stakes_init( vote_stakes, 0UL );
    1095             : 
    1096             :   /* We need to acquire a cost tracker element. */
    1097       64964 :   bank->cost_tracker_fork_id = fd_cost_tracker_store_new_fork( fd_banks_get_cost_tracker( banks ), bank->cost_tracker_fork_id );
    1098             : 
    1099       64964 :   if( FD_UNLIKELY( bank->stake_rewards_fork_id!=USHORT_MAX ) ) {
    1100           0 :     fd_stake_rewards_release( fd_banks_get_stake_rewards( banks ), bank->stake_rewards_fork_id );
    1101           0 :     bank->stake_rewards_fork_id = USHORT_MAX;
    1102           0 :   }
    1103             : 
    1104       64964 :   bank->epoch_credits_fork_id = fd_epoch_credits_store_new_fork( fd_banks_get_epoch_credits( banks ), bank->epoch_credits_fork_id );
    1105       64964 : }
    1106             : 
    1107             : void
    1108           0 : fd_banks_clear( fd_banks_t * banks ) {
    1109             : 
    1110           0 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
    1111             : 
    1112           0 :   for( ulong i=0UL; i<banks->max_total_banks; i++ ) {
    1113           0 :     fd_bank_t * bank = fd_banks_pool_ele( bank_pool, i );
    1114           0 :     bank->state                 = FD_BANK_STATE_INACTIVE;
    1115           0 :     bank->cost_tracker_fork_id = USHORT_MAX;
    1116           0 :     bank->vote_stakes_fork_id   = ULONG_MAX;
    1117           0 :     bank->epoch_credits_fork_id = USHORT_MAX;
    1118           0 :   }
    1119             : 
    1120           0 :   fd_banks_pool_reset( bank_pool );
    1121           0 :   fd_cost_tracker_store_reset( fd_banks_get_cost_tracker( banks ) );
    1122           0 :   fd_banks_dead_remove_all( fd_banks_get_dead_banks( banks ), bank_pool );
    1123           0 :   banks->evict_rr_idx = 0UL;
    1124           0 :   banks->prunable_idx = fd_banks_pool_idx_null( bank_pool );
    1125             : 
    1126           0 :   fd_stake_delegations_reset( fd_banks_get_stake_delegations( banks ) );
    1127           0 :   fd_vote_stakes_reset( fd_banks_get_vote_stakes( banks ) );
    1128             : 
    1129           0 :   fd_stake_rewards_clear( fd_banks_get_stake_rewards( banks ) );
    1130             : 
    1131           0 :   fd_epoch_credits_store_reset( fd_banks_get_epoch_credits( banks ) );
    1132             : 
    1133           0 :   banks->root_idx        = ULONG_MAX;
    1134           0 :   banks->curr_fork_width = 0UL;
    1135           0 :   banks->bank_seq        = 1UL; /* start at 1 so 0 is reserved as an invalid bank_seq sentinel */
    1136           0 : }

Generated by: LCOV version 1.14