LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_bank.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 351 770 45.6 %
Date: 2026-11-11 12:40:43 Functions: 33 50 66.0 %

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

Generated by: LCOV version 1.14