LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_bank.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 667 791 84.3 %
Date: 2026-05-26 08:02:49 Functions: 55 63 87.3 %

          Line data    Source code
       1             : #include "fd_bank.h"
       2             : #include "fd_runtime_const.h"
       3             : #include "../rewards/fd_stake_rewards.h"
       4             : #include "sysvar/fd_sysvar_cache.h"
       5             : 
       6             : fd_lthash_value_t const *
       7          78 : fd_bank_lthash_locking_query( fd_bank_t * bank ) {
       8          78 :   fd_rwlock_read( &bank->lthash_lock );
       9          78 :   return &bank->f.lthash;
      10          78 : }
      11             : 
      12             : void
      13          78 : fd_bank_lthash_end_locking_query( fd_bank_t * bank ) {
      14          78 :   fd_rwlock_unread( &bank->lthash_lock );
      15          78 : }
      16             : 
      17             : fd_lthash_value_t *
      18       15516 : fd_bank_lthash_locking_modify( fd_bank_t * bank ) {
      19       15516 :   fd_rwlock_write( &bank->lthash_lock );
      20       15516 :   return &bank->f.lthash;
      21       15516 : }
      22             : 
      23             : void
      24       15516 : fd_bank_lthash_end_locking_modify( fd_bank_t * bank ) {
      25       15516 :   fd_rwlock_unwrite( &bank->lthash_lock );
      26       15516 : }
      27             : 
      28             : ulong
      29       10074 : fd_banks_align( void ) {
      30       10074 :   return FD_BANKS_ALIGN;
      31       10074 : }
      32             : 
      33             : static fd_bank_t *
      34      120285 : fd_banks_get_bank_pool( fd_banks_t * banks_data ) {
      35      120285 :   return fd_type_pun( (uchar *)banks_data + banks_data->pool_offset );
      36      120285 : }
      37             : 
      38             : static fd_bank_idx_seq_t *
      39        3522 : fd_banks_get_dead_banks_deque( fd_banks_t * banks_data ) {
      40        3522 :   return fd_type_pun( (uchar *)banks_data + banks_data->dead_banks_deque_offset );
      41        3522 : }
      42             : 
      43             : static fd_epoch_leaders_t *
      44        4170 : fd_banks_get_epoch_leaders( fd_banks_t * banks_data ) {
      45        4170 :   return fd_type_pun( (uchar *)banks_data + banks_data->epoch_leaders_offset );
      46        4170 : }
      47             : 
      48             : static fd_stake_delegations_t *
      49       11763 : fd_banks_get_stake_delegations( fd_banks_t * banks_data ) {
      50       11763 :   return fd_type_pun( (uchar *)banks_data + banks_data->stake_delegations_offset );
      51       11763 : }
      52             : 
      53             : static fd_bank_cost_tracker_t *
      54       16161 : fd_banks_get_cost_tracker_pool( fd_banks_t * banks_data ) {
      55       16161 :   return fd_type_pun( (uchar *)banks_data + banks_data->cost_tracker_pool_offset );
      56       16161 : }
      57             : 
      58             : static fd_stake_rewards_t *
      59        4053 : fd_banks_get_stake_rewards( fd_banks_t * banks_data ) {
      60        4053 :   return fd_type_pun( (uchar *)banks_data + banks_data->stake_rewards_offset );
      61        4053 : }
      62             : 
      63             : static fd_vote_stakes_t *
      64       14838 : fd_banks_get_vote_stakes( fd_banks_t * banks_data ) {
      65       14838 :   return fd_type_pun( (uchar *)banks_data + banks_data->vote_stakes_pool_offset );
      66       14838 : }
      67             : 
      68             : static fd_new_votes_t *
      69        7467 : fd_banks_get_new_votes( fd_banks_t * banks_data ) {
      70        7467 :   return fd_type_pun( (uchar *)banks_data + banks_data->new_votes_offset );
      71        7467 : }
      72             : 
      73             : static fd_epoch_credits_t *
      74         270 : fd_banks_get_epoch_credits( fd_banks_t * banks_data ) {
      75         270 :   return fd_type_pun( (uchar *)banks_data + banks_data->epoch_credits_offset );
      76         270 : }
      77             : 
      78             : static fd_stashed_commission_t *
      79           0 : fd_banks_get_snapshot_commission_t_3( fd_banks_t * banks_data ) {
      80           0 :   return fd_type_pun( (uchar *)banks_data + banks_data->snapshot_commission_t_3_offset );
      81           0 : }
      82             : 
      83             : fd_epoch_credits_t *
      84         270 : fd_bank_epoch_credits( fd_bank_t * bank ) {
      85         270 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
      86         270 :   return fd_banks_get_epoch_credits( banks_data );
      87         270 : }
      88             : 
      89             : ulong *
      90         129 : fd_bank_epoch_credits_len( fd_bank_t * bank ) {
      91         129 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
      92         129 :   return &banks_data->epoch_credits_len;
      93         129 : }
      94             : 
      95             : fd_stashed_commission_t *
      96           0 : fd_bank_snapshot_commission_t_3( fd_bank_t * bank ) {
      97           0 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
      98           0 :   return fd_banks_get_snapshot_commission_t_3( banks_data );
      99           0 : }
     100             : 
     101             : ulong *
     102           0 : fd_bank_snapshot_commission_t_3_len( fd_bank_t * bank ) {
     103           0 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     104           0 :   return &banks_data->snapshot_commission_t_3_len;
     105           0 : }
     106             : 
     107             : fd_vote_stakes_t *
     108        7323 : fd_bank_vote_stakes( fd_bank_t const * bank ) {
     109        7323 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     110        7323 :   return fd_banks_get_vote_stakes( banks_data );
     111        7323 : }
     112             : 
     113             : fd_new_votes_t *
     114         150 : fd_bank_new_votes( fd_bank_t const * bank ) {
     115         150 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     116         150 :   return fd_banks_get_new_votes( banks_data );
     117         150 : }
     118             : 
     119             : fd_stake_delegations_t *
     120          93 : fd_bank_stake_delegations_modify( fd_bank_t * bank ) {
     121          93 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     122          93 :   return fd_banks_get_stake_delegations( banks_data );
     123          93 : }
     124             : 
     125             : fd_stake_rewards_t const *
     126         129 : fd_bank_stake_rewards_query( fd_bank_t * bank ) {
     127         129 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     128         129 :   return fd_type_pun_const( fd_banks_get_stake_rewards( banks_data ) );
     129         129 : }
     130             : 
     131             : fd_stake_rewards_t *
     132         486 : fd_bank_stake_rewards_modify( fd_bank_t * bank ) {
     133         486 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     134         486 :   return fd_banks_get_stake_rewards( banks_data );
     135         486 : }
     136             : 
     137             : fd_epoch_leaders_t const *
     138             : fd_bank_epoch_leaders_query( fd_bank_t const * bank,
     139          18 :                              ulong             epoch ) {
     140          18 :   FD_TEST( bank->f.epoch==epoch || bank->f.epoch==epoch-1UL );
     141          18 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     142          18 :   return (fd_epoch_leaders_t const *)fd_type_pun( (uchar *)fd_banks_get_epoch_leaders( banks_data ) + (epoch % 2UL) * banks_data->epoch_leaders_footprint );
     143          18 : }
     144             : 
     145             : fd_epoch_leaders_t *
     146             : fd_bank_epoch_leaders_modify( fd_bank_t * bank,
     147        3561 :                               ulong       epoch ) {
     148        3561 :   FD_TEST( bank->f.epoch==epoch || bank->f.epoch==epoch-1UL );
     149        3561 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     150        3561 :   return (fd_epoch_leaders_t *)fd_type_pun( (uchar *)fd_banks_get_epoch_leaders( banks_data ) + (epoch % 2UL) * banks_data->epoch_leaders_footprint );
     151        3561 : }
     152             : 
     153             : fd_top_votes_t const *
     154           0 : fd_bank_top_votes_t_1_query( fd_bank_t const * bank ) {
     155           0 :   return fd_type_pun_const( bank->top_votes_t_1_mem );
     156           0 : }
     157             : 
     158             : fd_top_votes_t *
     159        3546 : fd_bank_top_votes_t_1_modify( fd_bank_t * bank ) {
     160        3546 :   return fd_type_pun( bank->top_votes_t_1_mem );
     161        3546 : }
     162             : 
     163             : fd_top_votes_t const *
     164        3657 : fd_bank_top_votes_t_2_query( fd_bank_t const * bank ) {
     165        3657 :   return fd_type_pun_const( bank->top_votes_t_2_mem );
     166        3657 : }
     167             : 
     168             : fd_top_votes_t *
     169        3621 : fd_bank_top_votes_t_2_modify( fd_bank_t * bank ) {
     170        3621 :   return fd_type_pun( bank->top_votes_t_2_mem );
     171        3621 : }
     172             : 
     173             : fd_cost_tracker_t *
     174        3585 : fd_bank_cost_tracker_modify( fd_bank_t * bank ) {
     175        3585 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     176        3585 :   fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks_data );
     177        3585 :   FD_TEST( bank->cost_tracker_pool_idx!=fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool ) );
     178        3585 :   uchar * cost_tracker_mem = fd_bank_cost_tracker_pool_ele( cost_tracker_pool, bank->cost_tracker_pool_idx )->data;
     179        3585 :   return fd_type_pun( cost_tracker_mem );
     180        3585 : }
     181             : 
     182             : fd_cost_tracker_t const *
     183           0 : fd_bank_cost_tracker_query( fd_bank_t * bank ) {
     184           0 :   fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     185           0 :   fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks_data );
     186           0 :   FD_TEST( bank->cost_tracker_pool_idx!=fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool ) );
     187           0 :   uchar * cost_tracker_mem = fd_bank_cost_tracker_pool_ele( cost_tracker_pool, bank->cost_tracker_pool_idx )->data;
     188           0 :   return fd_type_pun_const( cost_tracker_mem );
     189           0 : }
     190             : 
     191             : fd_bank_t *
     192       86619 : fd_banks_root( fd_banks_t * banks ) {
     193       86619 :   return fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), banks->root_idx );
     194       86619 : }
     195             : 
     196             : fd_bank_t *
     197             : fd_banks_bank_query( fd_banks_t * banks,
     198       10707 :                      ulong        bank_idx ) {
     199       10707 :   fd_bank_t * bank = fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), bank_idx );
     200       10707 :   if( FD_UNLIKELY( bank->state==FD_BANK_STATE_INACTIVE ) ) return NULL;
     201       10650 :   return bank;
     202       10707 : }
     203             : 
     204             : fd_bank_t *
     205             : fd_banks_get_parent( fd_banks_t * banks,
     206           0 :                      fd_bank_t *  bank ) {
     207           0 :   if( FD_UNLIKELY( bank->parent_idx==ULONG_MAX ) ) return NULL;
     208           0 :   return fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), bank->parent_idx );
     209           0 : }
     210             : 
     211             : int
     212           0 : fd_banks_is_full( fd_banks_t * banks ) {
     213           0 :   return fd_banks_pool_free( fd_banks_get_bank_pool( banks ) )==0UL ||
     214           0 :          fd_bank_cost_tracker_pool_free( fd_banks_get_cost_tracker_pool( banks ) )==0UL;
     215           0 : }
     216             : 
     217             : ulong
     218           9 : fd_banks_pool_used_cnt( fd_banks_t * banks ) {
     219           9 :   return fd_banks_pool_used( fd_banks_get_bank_pool( banks ) );
     220           9 : }
     221             : 
     222             : ulong
     223        6807 : fd_banks_pool_max_cnt( fd_banks_t * banks ) {
     224        6807 :   return fd_banks_pool_max( fd_banks_get_bank_pool( banks ) );
     225        6807 : }
     226             : 
     227             : void
     228             : fd_banks_stake_delegations_evict_bank_fork( fd_banks_t * banks,
     229           0 :                                             fd_bank_t *  bank ) {
     230           0 :   if( bank->stake_delegations_fork_id!=USHORT_MAX ) {
     231           0 :     fd_stake_delegations_t * sd = fd_banks_get_stake_delegations( banks );
     232           0 :     fd_stake_delegations_evict_fork( sd, bank->stake_delegations_fork_id );
     233           0 :     bank->stake_delegations_fork_id = USHORT_MAX;
     234           0 :   }
     235           0 : }
     236             : 
     237             : ulong
     238             : fd_banks_footprint( ulong max_total_banks,
     239             :                     ulong max_fork_width,
     240             :                     ulong max_stake_accounts,
     241        1188 :                     ulong max_vote_accounts ) {
     242             : 
     243             :   /* max_fork_width is used in the macro below. */
     244             : 
     245        1188 :   ulong epoch_leaders_footprint = FD_EPOCH_LEADERS_FOOTPRINT( max_vote_accounts, FD_RUNTIME_SLOTS_PER_EPOCH );
     246        1188 :   ulong expected_stake_accounts = fd_ulong_min( max_stake_accounts, FD_RUNTIME_EXPECTED_STAKE_ACCOUNTS );
     247        1188 :   ulong expected_vote_accounts  = fd_ulong_min( max_vote_accounts, FD_RUNTIME_EXPECTED_VOTE_ACCOUNTS );
     248             : 
     249        1188 :   ulong l = FD_LAYOUT_INIT;
     250        1188 :   l = FD_LAYOUT_APPEND( l, fd_banks_align(),                  sizeof(fd_banks_t) );
     251        1188 :   l = FD_LAYOUT_APPEND( l, fd_stake_delegations_align(),      fd_stake_delegations_footprint( max_stake_accounts, expected_stake_accounts, max_total_banks ) );
     252        1188 :   l = FD_LAYOUT_APPEND( l, FD_EPOCH_LEADERS_ALIGN,            2UL * epoch_leaders_footprint );
     253        1188 :   l = FD_LAYOUT_APPEND( l, fd_banks_pool_align(),             fd_banks_pool_footprint( max_total_banks ) );
     254        1188 :   l = FD_LAYOUT_APPEND( l, fd_banks_dead_align(),             fd_banks_dead_footprint() );
     255        1188 :   l = FD_LAYOUT_APPEND( l, fd_bank_cost_tracker_pool_align(), fd_bank_cost_tracker_pool_footprint( max_fork_width ) );
     256        1188 :   l = FD_LAYOUT_APPEND( l, fd_stake_rewards_align(),          fd_stake_rewards_footprint( max_stake_accounts, expected_stake_accounts, max_fork_width ) );
     257        1188 :   l = FD_LAYOUT_APPEND( l, fd_vote_stakes_align(),            fd_vote_stakes_footprint( max_vote_accounts, fd_ulong_min( max_vote_accounts, expected_vote_accounts ), max_fork_width ) );
     258        1188 :   l = FD_LAYOUT_APPEND( l, fd_new_votes_align(),              fd_new_votes_footprint( max_vote_accounts, expected_vote_accounts, max_total_banks ) );
     259        1188 :   l = FD_LAYOUT_APPEND( l, alignof(fd_epoch_credits_t),       sizeof(fd_epoch_credits_t) * max_vote_accounts );
     260        1188 :   l = FD_LAYOUT_APPEND( l, alignof(fd_stashed_commission_t),  sizeof(fd_stashed_commission_t) * max_vote_accounts );
     261        1188 :   return FD_LAYOUT_FINI( l, fd_banks_align() );
     262        1188 : }
     263             : 
     264             : void *
     265             : fd_banks_new( void * shmem,
     266             :               ulong  max_total_banks,
     267             :               ulong  max_fork_width,
     268             :               ulong  max_stake_accounts,
     269             :               ulong  max_vote_accounts,
     270             :               int    larger_max_cost_per_block,
     271         591 :               ulong  seed ) {
     272         591 :   if( FD_UNLIKELY( !shmem ) ) {
     273           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     274           0 :     return NULL;
     275           0 :   }
     276             : 
     277         591 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_banks_align() ) ) ) {
     278           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     279           0 :     return NULL;
     280           0 :   }
     281             : 
     282         591 :   if( FD_UNLIKELY( max_total_banks>FD_BANKS_MAX_BANKS ) ) {
     283           0 :     FD_LOG_WARNING(( "max_total_banks is too large" ));
     284           0 :     return NULL;
     285           0 :   }
     286         591 :   if( FD_UNLIKELY( max_fork_width>FD_BANKS_MAX_BANKS ) ) {
     287           0 :     FD_LOG_WARNING(( "max_fork_width is too large" ));
     288           0 :     return NULL;
     289           0 :   }
     290             : 
     291         591 :   ulong epoch_leaders_footprint = FD_EPOCH_LEADERS_FOOTPRINT( max_vote_accounts, FD_RUNTIME_SLOTS_PER_EPOCH );
     292         591 :   ulong expected_stake_accounts = fd_ulong_min( max_stake_accounts, FD_RUNTIME_EXPECTED_STAKE_ACCOUNTS );
     293         591 :   ulong expected_vote_accounts  = fd_ulong_min( max_vote_accounts, FD_RUNTIME_EXPECTED_VOTE_ACCOUNTS );
     294             : 
     295         591 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
     296         591 :   fd_banks_t * banks_data              = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_align(),                  sizeof(fd_banks_t) );
     297         591 :   void *       stake_delegations_mem   = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegations_align(),      fd_stake_delegations_footprint( max_stake_accounts, expected_stake_accounts, max_total_banks ) );
     298         591 :   void *       epoch_leaders_mem       = FD_SCRATCH_ALLOC_APPEND( l, FD_EPOCH_LEADERS_ALIGN,            2UL * epoch_leaders_footprint );
     299         591 :   void *       pool_mem                = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_pool_align(),             fd_banks_pool_footprint( max_total_banks ) );
     300         591 :   void *       dead_banks_deque_mem    = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_dead_align(),             fd_banks_dead_footprint() );
     301         591 :   void *       cost_tracker_pool_mem   = FD_SCRATCH_ALLOC_APPEND( l, fd_bank_cost_tracker_pool_align(), fd_bank_cost_tracker_pool_footprint( max_fork_width ) );
     302         591 :   void *       stake_rewards_pool_mem  = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_rewards_align(),          fd_stake_rewards_footprint( max_stake_accounts, expected_stake_accounts, max_fork_width ) );
     303         591 :   void *       vote_stakes_mem         = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_stakes_align(),            fd_vote_stakes_footprint( max_vote_accounts, expected_vote_accounts, max_fork_width ) );
     304         591 :   void *       new_votes_mem           = FD_SCRATCH_ALLOC_APPEND( l, fd_new_votes_align(),              fd_new_votes_footprint( max_vote_accounts, expected_vote_accounts, max_total_banks ) );
     305         591 :   void *       epoch_credits_mem       = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_epoch_credits_t),       sizeof(fd_epoch_credits_t) * max_vote_accounts );
     306         591 :   void *       snapshot_commission_t_3 = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_stashed_commission_t),  sizeof(fd_stashed_commission_t) * max_vote_accounts );
     307             : 
     308         591 :   if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_banks_align() ) != (ulong)banks_data + fd_banks_footprint( max_total_banks, max_fork_width, max_stake_accounts, max_vote_accounts ) ) ) {
     309           0 :     FD_LOG_WARNING(( "fd_banks_new: bad layout" ));
     310           0 :     return NULL;
     311           0 :   }
     312             : 
     313         591 :   void * pool = fd_banks_pool_new( pool_mem, max_total_banks );
     314         591 :   if( FD_UNLIKELY( !pool ) ) {
     315           0 :     FD_LOG_WARNING(( "Failed to create bank pool" ));
     316           0 :     return NULL;
     317           0 :   }
     318             : 
     319         591 :   fd_bank_t * bank_pool = fd_banks_pool_join( pool );
     320         591 :   if( FD_UNLIKELY( !bank_pool ) ) {
     321           0 :     FD_LOG_WARNING(( "Failed to join bank pool" ));
     322           0 :     return NULL;
     323           0 :   }
     324             : 
     325         591 :   fd_bank_idx_seq_t * banks_dead_deque = fd_banks_dead_join( fd_banks_dead_new( dead_banks_deque_mem ) );
     326         591 :   if( FD_UNLIKELY( !banks_dead_deque ) ) {
     327           0 :     FD_LOG_WARNING(( "Failed to create banks dead deque" ));
     328           0 :     return NULL;
     329           0 :   }
     330         591 :   banks_data->dead_banks_deque_offset = (ulong)banks_dead_deque - (ulong)banks_data;
     331             : 
     332         591 :   banks_data->epoch_leaders_offset           = (ulong)epoch_leaders_mem - (ulong)banks_data;
     333         591 :   banks_data->epoch_leaders_footprint        = epoch_leaders_footprint;
     334         591 :   banks_data->pool_offset                    = (ulong)bank_pool - (ulong)banks_data;
     335         591 :   banks_data->epoch_credits_offset           = (ulong)epoch_credits_mem - (ulong)banks_data;
     336         591 :   banks_data->snapshot_commission_t_3_offset = (ulong)snapshot_commission_t_3 - (ulong)banks_data;
     337             : 
     338             :   /* Create the pools for the non-inlined fields.  Also new() and join()
     339             :      each of the elements in the pool as well as set up the lock for
     340             :      each of the pools. */
     341             : 
     342         591 :   fd_stake_delegations_t * stake_delegations = fd_stake_delegations_join( fd_stake_delegations_new( stake_delegations_mem, seed, max_stake_accounts, expected_stake_accounts, max_total_banks ) );
     343         591 :   if( FD_UNLIKELY( !stake_delegations ) ) {
     344           0 :     FD_LOG_WARNING(( "Unable to create stake delegations root" ));
     345           0 :     return NULL;
     346           0 :   }
     347         591 :   banks_data->stake_delegations_offset = (ulong)stake_delegations - (ulong)banks_data;
     348             : 
     349         591 :   fd_bank_cost_tracker_t * cost_tracker_pool = fd_bank_cost_tracker_pool_join( fd_bank_cost_tracker_pool_new( cost_tracker_pool_mem, max_fork_width ) );
     350         591 :   if( FD_UNLIKELY( !cost_tracker_pool ) ) {
     351           0 :     FD_LOG_WARNING(( "Failed to create cost tracker pool" ));
     352           0 :     return NULL;
     353           0 :   }
     354         591 :   banks_data->cost_tracker_pool_offset = (ulong)cost_tracker_pool - (ulong)banks_data;
     355             : 
     356        1380 :   for( ulong i=0UL; i<max_fork_width; i++ ) {
     357         789 :     fd_bank_cost_tracker_t * cost_tracker = fd_bank_cost_tracker_pool_ele( cost_tracker_pool, i );
     358         789 :     if( FD_UNLIKELY( !fd_cost_tracker_join( fd_cost_tracker_new( cost_tracker->data, larger_max_cost_per_block, seed ) ) ) ) {
     359           0 :       FD_LOG_WARNING(( "Failed to create cost tracker" ));
     360           0 :       return NULL;
     361           0 :     }
     362         789 :   }
     363             : 
     364         591 :   fd_stake_rewards_t * stake_rewards = fd_stake_rewards_join( fd_stake_rewards_new( stake_rewards_pool_mem, max_stake_accounts, fd_ulong_min( max_stake_accounts, FD_RUNTIME_EXPECTED_STAKE_ACCOUNTS ), max_fork_width, seed ) );
     365         591 :   if( FD_UNLIKELY( !stake_rewards ) ) {
     366           0 :     FD_LOG_WARNING(( "Failed to create stake rewards" ));
     367           0 :     return NULL;
     368           0 :   }
     369         591 :   banks_data->stake_rewards_offset = (ulong)stake_rewards - (ulong)banks_data;
     370             : 
     371             : 
     372         591 :   fd_vote_stakes_t * vote_stakes = fd_vote_stakes_join( fd_vote_stakes_new( vote_stakes_mem, max_vote_accounts, fd_ulong_min( max_vote_accounts, FD_RUNTIME_EXPECTED_VOTE_ACCOUNTS ), max_fork_width, seed ) );
     373         591 :   if( FD_UNLIKELY( !vote_stakes ) ) {
     374           0 :     FD_LOG_WARNING(( "Failed to create vote stakes" ));
     375           0 :     return NULL;
     376           0 :   }
     377         591 :   banks_data->vote_stakes_pool_offset = (ulong)vote_stakes - (ulong)banks_data;
     378             : 
     379         591 :   fd_new_votes_t * new_votes = fd_new_votes_join( fd_new_votes_new( new_votes_mem, seed, max_vote_accounts, expected_vote_accounts, max_total_banks ) );
     380         591 :   if( FD_UNLIKELY( !new_votes ) ) {
     381           0 :     FD_LOG_WARNING(( "Failed to create new votes" ));
     382           0 :     return NULL;
     383           0 :   }
     384         591 :   banks_data->new_votes_offset = (ulong)new_votes - (ulong)banks_data;
     385             : 
     386             :   /* For each bank, set the offset back to banks_data and initialize
     387             :      per-bank state. */
     388             : 
     389         591 :   fd_bank_cost_tracker_t * cost_tracker_pool_init = fd_banks_get_cost_tracker_pool( banks_data );
     390             : 
     391        2016 :   for( ulong i=0UL; i<max_total_banks; i++ ) {
     392             : 
     393        1425 :     fd_bank_t * bank = fd_banks_pool_ele( bank_pool, i );
     394             : 
     395        1425 :     fd_rwlock_new( &bank->lthash_lock );
     396             : 
     397        1425 :     bank->idx               = i;
     398        1425 :     bank->state             = FD_BANK_STATE_INACTIVE;
     399        1425 :     bank->banks_data_offset = (ulong)bank - (ulong)banks_data;
     400             : 
     401        1425 :     if( i==0UL ) {
     402         591 :       FD_TEST( fd_top_votes_join( fd_top_votes_new( bank->top_votes_t_1_mem, FD_RUNTIME_MAX_VOTE_ACCOUNTS_VAT, seed ) ) );
     403         591 :       FD_TEST( fd_top_votes_join( fd_top_votes_new( bank->top_votes_t_2_mem, FD_RUNTIME_MAX_VOTE_ACCOUNTS_VAT, seed ) ) );
     404         591 :     }
     405             : 
     406        1425 :     bank->cost_tracker_pool_idx = fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool_init );
     407        1425 :   }
     408             : 
     409         591 :   banks_data->max_total_banks    = max_total_banks;
     410         591 :   banks_data->max_fork_width     = max_fork_width;
     411         591 :   banks_data->max_stake_accounts = max_stake_accounts;
     412         591 :   banks_data->max_vote_accounts  = max_vote_accounts;
     413         591 :   banks_data->root_idx           = ULONG_MAX;
     414         591 :   banks_data->bank_seq           = 0UL;
     415             : 
     416         591 :   FD_COMPILER_MFENCE();
     417         591 :   FD_VOLATILE( banks_data->magic ) = FD_BANKS_MAGIC;
     418         591 :   FD_COMPILER_MFENCE();
     419             : 
     420         591 :   return shmem;
     421         591 : }
     422             : 
     423             : fd_banks_t *
     424         591 : fd_banks_join( void * banks_data_mem ) {
     425         591 :   fd_banks_t * banks_data  = (fd_banks_t *)banks_data_mem;
     426             : 
     427         591 :   if( FD_UNLIKELY( !banks_data ) ) {
     428           0 :     FD_LOG_WARNING(( "NULL banks data" ));
     429           0 :     return NULL;
     430           0 :   }
     431             : 
     432         591 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)banks_data, fd_banks_align() ) ) ) {
     433           0 :     FD_LOG_WARNING(( "misaligned banks" ));
     434           0 :     return NULL;
     435           0 :   }
     436             : 
     437         591 :   if( FD_UNLIKELY( banks_data->magic!=FD_BANKS_MAGIC ) ) {
     438           0 :     FD_LOG_WARNING(( "Invalid banks magic" ));
     439           0 :     return NULL;
     440           0 :   }
     441             : 
     442         591 :   ulong expected_stake_accounts = fd_ulong_min( banks_data->max_stake_accounts, FD_RUNTIME_EXPECTED_STAKE_ACCOUNTS );
     443         591 :   ulong expected_vote_accounts  = fd_ulong_min( banks_data->max_vote_accounts, FD_RUNTIME_EXPECTED_VOTE_ACCOUNTS );
     444             : 
     445         591 :   FD_SCRATCH_ALLOC_INIT( l, banks_data );
     446         591 :   banks_data                   = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_align(),                  sizeof(fd_banks_t) );
     447         591 :   void * stake_delegations_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegations_align(),      fd_stake_delegations_footprint( banks_data->max_stake_accounts, expected_stake_accounts, banks_data->max_total_banks ) );
     448         591 :   void * epoch_leaders_mem     = FD_SCRATCH_ALLOC_APPEND( l, FD_EPOCH_LEADERS_ALIGN,            2UL * banks_data->epoch_leaders_footprint );
     449         591 :   void * pool_mem              = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_pool_align(),             fd_banks_pool_footprint( banks_data->max_total_banks ) );
     450         591 :   void * dead_banks_deque_mem  = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_dead_align(),             fd_banks_dead_footprint() );
     451         591 :   void * cost_tracker_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_bank_cost_tracker_pool_align(), fd_bank_cost_tracker_pool_footprint( banks_data->max_fork_width ) );
     452         591 :   void * stake_rewards_mem     = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_rewards_align(),          fd_stake_rewards_footprint( banks_data->max_stake_accounts, expected_stake_accounts, banks_data->max_fork_width ) );
     453         591 :   void * vote_stakes_mem       = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_stakes_align(),            fd_vote_stakes_footprint( banks_data->max_vote_accounts, expected_vote_accounts, banks_data->max_fork_width ) );
     454         591 :   void * new_votes_mem         = FD_SCRATCH_ALLOC_APPEND( l, fd_new_votes_align(),              fd_new_votes_footprint( banks_data->max_vote_accounts, expected_vote_accounts, banks_data->max_total_banks ) );
     455         591 :   void * epoch_credits_mem     = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_epoch_credits_t),       sizeof(fd_epoch_credits_t) * banks_data->max_vote_accounts );
     456         591 :   void * snapshot_commission   = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_stashed_commission_t),  sizeof(fd_stashed_commission_t) * banks_data->max_vote_accounts );
     457           0 :   (void)new_votes_mem;
     458         591 :   (void)epoch_credits_mem;
     459         591 :   (void)snapshot_commission;
     460             : 
     461         591 :   FD_SCRATCH_ALLOC_FINI( l, fd_banks_align() );
     462             : 
     463         591 :   fd_bank_t * banks_pool = fd_banks_get_bank_pool( banks_data );
     464         591 :   if( FD_UNLIKELY( !banks_pool ) ) {
     465           0 :     FD_LOG_WARNING(( "Failed to join bank pool" ));
     466           0 :     return NULL;
     467           0 :   }
     468             : 
     469         591 :   if( FD_UNLIKELY( banks_pool!=fd_banks_pool_join( pool_mem ) ) ) {
     470           0 :     FD_LOG_WARNING(( "Failed to join bank pool" ));
     471           0 :     return NULL;
     472           0 :   }
     473             : 
     474         591 :   fd_bank_idx_seq_t * banks_dead_deque = fd_banks_dead_join( dead_banks_deque_mem );
     475         591 :   if( FD_UNLIKELY( !banks_dead_deque ) ) {
     476           0 :     FD_LOG_WARNING(( "Failed to join banks dead deque" ));
     477           0 :     return NULL;
     478           0 :   }
     479             : 
     480         591 :   if( FD_UNLIKELY( epoch_leaders_mem!=fd_banks_get_epoch_leaders( banks_data ) ) ) {
     481           0 :     FD_LOG_WARNING(( "Failed to join epoch leaders mem" ));
     482           0 :     return NULL;
     483           0 :   }
     484             : 
     485         591 :   if( FD_UNLIKELY( stake_delegations_mem!=fd_banks_get_stake_delegations( banks_data ) ) ) {
     486           0 :     FD_LOG_WARNING(( "Failed to join stake delegations root mem" ));
     487           0 :     return NULL;
     488           0 :   }
     489             : 
     490         591 :   fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks_data );
     491         591 :   if( FD_UNLIKELY( !cost_tracker_pool ) ) {
     492           0 :     FD_LOG_WARNING(( "Failed to join cost tracker pool" ));
     493           0 :     return NULL;
     494           0 :   }
     495             : 
     496         591 :   if( FD_UNLIKELY( cost_tracker_pool!=fd_bank_cost_tracker_pool_join( cost_tracker_pool_mem ) ) ) {
     497           0 :     FD_LOG_WARNING(( "Failed to join cost tracker pool" ));
     498           0 :     return NULL;
     499           0 :   }
     500             : 
     501         591 :   if( FD_UNLIKELY( !fd_stake_rewards_join( stake_rewards_mem ) ) ) {
     502           0 :     FD_LOG_WARNING(( "Failed to join stake rewards" ));
     503           0 :     return NULL;
     504           0 :   }
     505             : 
     506         591 :   if( FD_UNLIKELY( !fd_vote_stakes_join( vote_stakes_mem ) ) ) {
     507           0 :     FD_LOG_WARNING(( "Failed to join vote stakes" ));
     508           0 :     return NULL;
     509           0 :   }
     510             : 
     511         591 :   return banks_data;
     512         591 : }
     513             : 
     514             : fd_bank_t *
     515        3990 : fd_banks_init_bank( fd_banks_t * banks ) {
     516             : 
     517        3990 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     518        3990 :   FD_CRIT( fd_banks_pool_free( bank_pool )!=0UL, "invariant violation: no free bank pool elements" );
     519             : 
     520        3990 :   fd_bank_t * bank = fd_banks_pool_ele_acquire( bank_pool );
     521        3990 :   bank->bank_seq = FD_ATOMIC_FETCH_AND_ADD( &banks->bank_seq, 1UL );
     522             : 
     523        3990 :   ulong null_idx    = fd_banks_pool_idx_null( bank_pool );
     524        3990 :   bank->idx         = fd_banks_pool_idx( bank_pool, bank );
     525        3990 :   bank->next        = null_idx;
     526        3990 :   bank->parent_idx  = null_idx;
     527        3990 :   bank->child_idx   = null_idx;
     528        3990 :   bank->sibling_idx = null_idx;
     529             : 
     530        3990 :   fd_memset( &bank->f, 0, sizeof(bank->f) );
     531        3990 :   bank->stake_rewards_fork_id             = UCHAR_MAX;
     532        3990 :   bank->stake_delegations_fork_id         = USHORT_MAX;
     533        3990 :   bank->new_votes_fork_id                 = USHORT_MAX;
     534        3990 :   bank->cost_tracker_pool_idx             = fd_bank_cost_tracker_pool_idx_null( fd_banks_get_cost_tracker_pool( banks ) );
     535        3990 :   bank->first_fec_set_received_nanos      = fd_log_wallclock();
     536        3990 :   bank->preparation_begin_nanos           = 0L;
     537        3990 :   bank->first_transaction_scheduled_nanos = 0L;
     538        3990 :   bank->last_transaction_finished_nanos   = 0L;
     539        3990 :   bank->block_completed_nanos             = 0L;
     540             : 
     541        3990 :   fd_vote_stakes_t * vote_stakes = fd_banks_get_vote_stakes( banks );
     542        3990 :   bank->vote_stakes_fork_id      = fd_vote_stakes_get_root_idx( vote_stakes );
     543             : 
     544        3990 :   bank->state  = FD_BANK_STATE_FROZEN;
     545        3990 :   bank->refcnt = 0UL;
     546             : 
     547        3990 :   banks->root_idx = bank->idx;
     548             : 
     549        3990 :   FD_LOG_DEBUG(( "init bank (idx=%lu, vote_stakes_idx=%u, stake_rewards_idx=%u, stake_delegations_idx=%u, new_votes_idx=%u)",
     550        3990 :                  bank->idx,
     551        3990 :                  bank->vote_stakes_fork_id,
     552        3990 :                  bank->stake_rewards_fork_id,
     553        3990 :                  bank->stake_delegations_fork_id,
     554        3990 :                  bank->new_votes_fork_id ));
     555             : 
     556        3990 :   return bank;
     557        3990 : }
     558             : 
     559             : fd_bank_t *
     560             : fd_banks_clone_from_parent( fd_banks_t * banks,
     561        3681 :                             ulong        child_bank_idx ) {
     562             : 
     563        3681 :   fd_bank_t * bank_pool  = fd_banks_get_bank_pool( banks );
     564        3681 :   fd_bank_t * child_bank = fd_banks_pool_ele( bank_pool, child_bank_idx );
     565        3681 :   FD_CRIT( child_bank->state==FD_BANK_STATE_INIT, "invariant violation: bank is not initialized" );
     566             : 
     567        3681 :   fd_bank_t * parent_bank = fd_banks_pool_ele( bank_pool, child_bank->parent_idx );
     568        3681 :   FD_CRIT( parent_bank->state==FD_BANK_STATE_FROZEN, "invariant violation: parent bank is not frozen" );
     569             : 
     570        3681 :   fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks );
     571        3681 :   FD_CRIT( fd_bank_cost_tracker_pool_free( cost_tracker_pool )!=0UL, "invariant violation: no free cost tracker pool elements" );
     572        3681 :   child_bank->cost_tracker_pool_idx = fd_bank_cost_tracker_pool_idx_acquire( cost_tracker_pool );
     573             : 
     574        3681 :   fd_memcpy( child_bank->top_votes_t_1_mem, parent_bank->top_votes_t_1_mem, FD_TOP_VOTES_MAX_FOOTPRINT );
     575        3681 :   fd_memcpy( child_bank->top_votes_t_2_mem, parent_bank->top_votes_t_2_mem, FD_TOP_VOTES_MAX_FOOTPRINT );
     576             : 
     577        3681 :   child_bank->f                          = parent_bank->f;
     578        3681 :   child_bank->vote_stakes_fork_id        = parent_bank->vote_stakes_fork_id;
     579        3681 :   child_bank->stake_rewards_fork_id      = parent_bank->stake_rewards_fork_id;
     580        3681 :   child_bank->stake_delegations_fork_id  = fd_stake_delegations_new_fork( fd_banks_get_stake_delegations( banks ) );
     581        3681 :   child_bank->new_votes_fork_id          = fd_new_votes_new_fork( fd_banks_get_new_votes( banks ) );
     582        3681 :   child_bank->f.block_height             = parent_bank->f.block_height + 1UL;
     583        3681 :   child_bank->f.tick_height              = parent_bank->f.max_tick_height;
     584        3681 :   child_bank->f.parent_slot              = parent_bank->f.slot;
     585        3681 :   child_bank->f.parent_signature_cnt     = parent_bank->f.signature_count;
     586        3681 :   child_bank->f.prev_bank_hash           = parent_bank->f.bank_hash;
     587        3681 :   child_bank->f.execution_fees           = 0UL;
     588        3681 :   child_bank->f.priority_fees            = 0UL;
     589        3681 :   child_bank->f.tips                     = 0UL;
     590        3681 :   child_bank->f.signature_count          = 0UL;
     591        3681 :   child_bank->f.total_compute_units_used = 0UL;
     592        3681 :   child_bank->f.shred_cnt                = 0UL;
     593        3681 :   child_bank->f.txn_count                = 0UL;
     594        3681 :   child_bank->f.nonvote_txn_count        = 0UL;
     595        3681 :   child_bank->f.failed_txn_count         = 0UL;
     596        3681 :   child_bank->f.nonvote_failed_txn_count = 0UL;
     597        3681 :   child_bank->f.identity_vote_idx        = ULONG_MAX;
     598             : 
     599        3681 :   child_bank->state = FD_BANK_STATE_REPLAYABLE;
     600             : 
     601        3681 :   FD_LOG_DEBUG(( "cloning bank (idx=%lu, parent_idx=%lu, vote_stakes_idx=%u, stake_rewards_idx=%u, stake_delegations_idx=%u, new_votes_idx=%u)",
     602        3681 :                  child_bank_idx,
     603        3681 :                  parent_bank->idx,
     604        3681 :                  child_bank->vote_stakes_fork_id,
     605        3681 :                  child_bank->stake_rewards_fork_id,
     606        3681 :                  child_bank->stake_delegations_fork_id,
     607        3681 :                  child_bank->new_votes_fork_id ));
     608             : 
     609        3681 :   return child_bank;
     610        3681 : }
     611             : 
     612             : /* fd_bank_stake_delegation_apply_deltas applies all of the stake
     613             :    delegations for the entire direct ancestry from the bank to the
     614             :    root into a full fd_stake_delegations_t object. */
     615             : 
     616             : static inline void
     617             : fd_bank_apply_deltas( fd_banks_t * banks,
     618          84 :                       fd_bank_t *  bank ) {
     619             : 
     620          84 :   fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
     621          84 :   fd_new_votes_t *         new_votes         = fd_banks_get_new_votes( banks );
     622             : 
     623             :   /* The stake_delegations root has crossed an epoch boundary.  The
     624             :      stake totals for the current root need to be updated. */
     625          84 :   fd_bank_t * old_root = fd_banks_root( banks );
     626          84 :   if( old_root->f.epoch!=bank->f.epoch ) {
     627          12 :     stake_delegations->effective_stake    = bank->f.total_effective_stake;
     628          12 :     stake_delegations->activating_stake   = bank->f.total_activating_stake;
     629          12 :     stake_delegations->deactivating_stake = bank->f.total_deactivating_stake;
     630          12 :     fd_new_votes_reset_root( new_votes );
     631          12 :   }
     632             : 
     633             :   /* Naively what we want to do is iterate from the old root to the new
     634             :      root and apply the delta to the full state iteratively. */
     635             : 
     636             :   /* First, gather all of the pool indicies that we want to apply deltas
     637             :      for in reverse order starting from the new root. We want to exclude
     638             :      the old root since its delta has been applied previously. */
     639          84 :   ushort sd_pool_indices[ banks->max_total_banks ];
     640          84 :   ushort nv_pool_indices[ banks->max_total_banks ];
     641          84 :   ulong  pool_indices_len = 0UL;
     642             : 
     643          84 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     644             : 
     645          84 :   fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, bank->idx );
     646         252 :   while( !!curr_bank ) {
     647         168 :     FD_LOG_DEBUG(( "applying bank delta (bank_idx=%lu, sd_fork_idx=%u, nv_fork_idx=%u)", curr_bank->idx, curr_bank->stake_delegations_fork_id, curr_bank->new_votes_fork_id ));
     648         168 :     if( curr_bank->stake_delegations_fork_id!=USHORT_MAX ) {
     649          90 :       sd_pool_indices[pool_indices_len] = curr_bank->stake_delegations_fork_id;
     650          90 :       nv_pool_indices[pool_indices_len] = curr_bank->new_votes_fork_id;
     651          90 :       pool_indices_len++;
     652          90 :     }
     653         168 :     curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->parent_idx );
     654         168 :   }
     655             : 
     656             :   /* We have populated all of the indicies that we need to apply deltas
     657             :      from in reverse order. */
     658             : 
     659          84 :   fd_stake_history_t stake_history_[1];
     660          84 :   fd_stake_history_t const * stake_history = fd_sysvar_cache_stake_history_view( &bank->f.sysvar_cache, stake_history_ );
     661             :   /* stake_history may be NULL */
     662         174 :   for( ulong i=pool_indices_len; i>0; i-- ) {
     663          90 :     ushort sd_idx = sd_pool_indices[i-1UL];
     664          90 :     ushort nv_idx = nv_pool_indices[i-1UL];
     665          90 :     fd_stake_delegations_apply_fork_delta( bank->f.epoch, stake_history, &bank->f.warmup_cooldown_rate_epoch, stake_delegations, sd_idx );
     666          90 :     fd_new_votes_apply_delta( new_votes, nv_idx );
     667          90 :   }
     668          84 : }
     669             : 
     670             : static inline void
     671             : fd_bank_stake_delegation_mark_deltas( fd_banks_t *             banks,
     672             :                                       fd_bank_t *              bank,
     673         165 :                                       fd_stake_delegations_t * stake_delegations ) {
     674             : 
     675         165 :   ushort pool_indices[ banks->max_total_banks ];
     676         165 :   ulong  pool_indices_len = 0UL;
     677             : 
     678         165 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     679             : 
     680         165 :   fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, bank->idx );
     681         507 :   while( !!curr_bank ) {
     682         342 :     if( curr_bank->stake_delegations_fork_id!=USHORT_MAX ) {
     683         198 :       pool_indices[pool_indices_len++] = curr_bank->stake_delegations_fork_id;
     684         198 :     }
     685         342 :     curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->parent_idx );
     686         342 :   }
     687             : 
     688         165 :   fd_stake_history_t stake_history[1];
     689         165 :   fd_sysvar_cache_stake_history_view( &bank->f.sysvar_cache, stake_history );
     690             : 
     691         363 :   for( ulong i=pool_indices_len; i>0; i-- ) {
     692         198 :     ushort idx = pool_indices[i-1UL];
     693         198 :     fd_stake_delegations_mark_delta( stake_delegations, bank->f.epoch, stake_history, &bank->f.warmup_cooldown_rate_epoch, idx );
     694         198 :   }
     695         165 : }
     696             : 
     697             : static inline void
     698             : fd_bank_stake_delegation_unmark_deltas( fd_banks_t *             banks,
     699             :                                         fd_bank_t *              bank,
     700         165 :                                         fd_stake_delegations_t * stake_delegations ) {
     701             : 
     702         165 :   ushort pool_indices[ banks->max_total_banks ];
     703         165 :   ulong  pool_indices_len = 0UL;
     704             : 
     705         165 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     706             : 
     707         165 :   fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, bank->idx );
     708         507 :   while( !!curr_bank ) {
     709         342 :     if( curr_bank->stake_delegations_fork_id!=USHORT_MAX ) {
     710         198 :       pool_indices[pool_indices_len++] = curr_bank->stake_delegations_fork_id;
     711         198 :     }
     712         342 :     curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->parent_idx );
     713         342 :   }
     714             : 
     715         165 :   fd_stake_history_t stake_history_[1];
     716         165 :   fd_stake_history_t * stake_history = fd_sysvar_cache_stake_history_view( &bank->f.sysvar_cache, stake_history_ );
     717             : 
     718         363 :   for( ulong i=pool_indices_len; i>0; i-- ) {
     719         198 :     ushort idx = pool_indices[i-1UL];
     720         198 :     fd_stake_delegations_unmark_delta( stake_delegations, bank->f.epoch-1UL, stake_history, &bank->f.warmup_cooldown_rate_epoch, idx );
     721         198 :   }
     722         165 : }
     723             : 
     724             : 
     725             : fd_stake_delegations_t *
     726             : fd_bank_stake_delegations_frontier_query( fd_banks_t * banks,
     727         165 :                                           fd_bank_t *  bank ) {
     728         165 :   fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
     729         165 :   fd_bank_stake_delegation_mark_deltas( banks, bank, stake_delegations );
     730             : 
     731         165 :   return stake_delegations;
     732         165 : }
     733             : 
     734             : void
     735             : fd_bank_stake_delegations_end_frontier_query( fd_banks_t * banks,
     736         165 :                                               fd_bank_t *  bank ) {
     737         165 :   fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
     738         165 :   fd_bank_stake_delegation_unmark_deltas( banks, bank, stake_delegations );
     739         165 : }
     740             : 
     741             : 
     742             : fd_stake_delegations_t *
     743        3435 : fd_banks_stake_delegations_root_query( fd_banks_t * banks ) {
     744        3435 :   return fd_banks_get_stake_delegations( banks );
     745        3435 : }
     746             : 
     747             : ulong
     748             : fd_banks_new_votes_fork_indices( fd_bank_t * bank,
     749         141 :                                  ushort *    fork_indices_out ) {
     750         141 :   fd_banks_t * banks     = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
     751         141 :   fd_bank_t *  bank_pool = fd_banks_get_bank_pool( banks );
     752         141 :   ulong cnt = 0UL;
     753             : 
     754         141 :   fd_bank_t * curr = fd_banks_pool_ele( bank_pool, bank->idx );
     755         429 :   while( !!curr ) {
     756         288 :     if( curr->new_votes_fork_id!=USHORT_MAX ) {
     757         147 :       fork_indices_out[cnt++] = curr->new_votes_fork_id;
     758         147 :     }
     759         288 :     curr = fd_banks_pool_ele( bank_pool, curr->parent_idx );
     760         288 :   }
     761         141 :   return cnt;
     762         141 : }
     763             : 
     764             : void
     765             : fd_banks_advance_root( fd_banks_t * banks,
     766          84 :                        ulong        root_bank_idx ) {
     767             : 
     768          84 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     769             : 
     770             :   /* We want to replace the old root with the new root. This means we
     771             :      have to remove banks that aren't descendants of the new root. */
     772             : 
     773          84 :   fd_bank_t * old_root = fd_banks_root( banks );
     774          84 :   FD_CRIT( old_root->refcnt==0UL, "refcnt for old root bank is nonzero" );
     775             : 
     776          84 :   fd_bank_t * new_root = fd_banks_pool_ele( bank_pool, root_bank_idx );
     777             : 
     778          84 :   fd_bank_apply_deltas( banks, new_root );
     779             : 
     780          84 :   fd_new_votes_t * new_votes = fd_banks_get_new_votes( banks );
     781          84 :   fd_new_votes_evict_fork( new_votes, new_root->new_votes_fork_id );
     782          84 :   new_root->new_votes_fork_id = USHORT_MAX;
     783             : 
     784          84 :   fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
     785          84 :   fd_stake_delegations_evict_fork( stake_delegations, new_root->stake_delegations_fork_id );
     786          84 :   new_root->stake_delegations_fork_id = USHORT_MAX;
     787             : 
     788             :   /* Now that the deltas have been applied, we can remove all nodes
     789             :      that are not direct descendants of the new root. */
     790          84 :   fd_bank_t * head = fd_banks_pool_ele( bank_pool, old_root->idx );
     791          84 :   head->next       = ULONG_MAX;
     792          84 :   fd_bank_t * tail = head;
     793             : 
     794         219 :   while( head ) {
     795         135 :     fd_bank_t * child = fd_banks_pool_ele( bank_pool, head->child_idx );
     796             : 
     797         270 :     while( FD_LIKELY( child ) ) {
     798             : 
     799         135 :       if( FD_LIKELY( child!=new_root ) ) {
     800          51 :         if( FD_UNLIKELY( child->refcnt!=0UL ) ) {
     801           0 :           FD_LOG_CRIT(( "refcnt for child bank at index %lu is %lu", child->idx, child->refcnt ));
     802           0 :         }
     803             : 
     804             :         /* Update tail pointers */
     805          51 :         tail->next = child->idx;
     806          51 :         tail       = fd_banks_pool_ele( bank_pool, tail->next );
     807          51 :         tail->next = fd_banks_pool_idx_null( bank_pool );
     808          51 :       }
     809             : 
     810         135 :       child = fd_banks_pool_ele( bank_pool, child->sibling_idx );
     811         135 :     }
     812             : 
     813         135 :     fd_bank_t * next = fd_banks_pool_ele( bank_pool, head->next );
     814             : 
     815             :     /* It is possible for a bank that never finished replaying to be
     816             :        pruned away.  If the bank was never frozen, then it's possible
     817             :        that the bank still owns a cost tracker pool element.  If this
     818             :        is the case, we need to release the pool element. */
     819         135 :     fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks );
     820         135 :     if( head->cost_tracker_pool_idx!=fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool ) ) {
     821           9 :       FD_LOG_DEBUG(( "releasing cost tracker pool element for bank at index %lu", head->idx ));
     822           9 :       fd_bank_cost_tracker_pool_idx_release( cost_tracker_pool, head->cost_tracker_pool_idx );
     823           9 :       head->cost_tracker_pool_idx = fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool );
     824           9 :     }
     825             : 
     826         135 :     head->stake_rewards_fork_id = UCHAR_MAX;
     827         135 :     head->vote_stakes_fork_id = USHORT_MAX;
     828             : 
     829         135 :     if( head->new_votes_fork_id!=USHORT_MAX ) {
     830          48 :       FD_LOG_DEBUG(( "evicting new votes fork (bank_idx=%lu, fork_idx=%u)", head->idx, head->new_votes_fork_id ));
     831          48 :       fd_new_votes_evict_fork( new_votes, head->new_votes_fork_id );
     832          48 :       head->new_votes_fork_id = USHORT_MAX;
     833          48 :     }
     834             : 
     835         135 :     if( head->stake_delegations_fork_id!=USHORT_MAX ) {
     836          51 :       FD_LOG_DEBUG(( "evicting stake delegation fork (bank_idx=%lu, fork_idx=%u)", head->idx, head->stake_delegations_fork_id ));
     837          51 :       fd_stake_delegations_evict_fork( stake_delegations, head->stake_delegations_fork_id );
     838          51 :       head->stake_delegations_fork_id = USHORT_MAX;
     839          51 :     }
     840             : 
     841         135 :     head->state = FD_BANK_STATE_INACTIVE;
     842         135 :     fd_banks_pool_ele_release( bank_pool, head );
     843         135 :     head = next;
     844         135 :   }
     845             : 
     846             :   /* new_root is detached from old_root and becomes the only root.
     847             :      Clear sibling_idx too so traversals cannot follow a stale link to
     848             :      a bank index that was just pruned and later reused. */
     849          84 :   new_root->parent_idx  = ULONG_MAX;
     850          84 :   new_root->sibling_idx = ULONG_MAX;
     851          84 :   banks->root_idx       = new_root->idx;
     852             : 
     853          84 :   fd_vote_stakes_t * vote_stakes = fd_banks_get_vote_stakes( banks );
     854          84 :   fd_vote_stakes_advance_root( vote_stakes, new_root->vote_stakes_fork_id );
     855          84 : }
     856             : 
     857             : /* Is the fork tree starting at the given bank entirely eligible for
     858             :    pruning?  Returns 1 for yes, 0 for no.
     859             : 
     860             :    See comment in fd_replay_tile.c for more details on safe pruning. */
     861             : static int
     862             : fd_banks_subtree_can_be_pruned( fd_bank_t * bank_pool,
     863          27 :                                 fd_bank_t * bank ) {
     864             : 
     865          27 :   if( bank->refcnt!=0UL ) return 0;
     866             : 
     867             :   /* Recursively check all children. */
     868          24 :   ulong child_idx = bank->child_idx;
     869          33 :   while( child_idx!=fd_banks_pool_idx_null( bank_pool ) ) {
     870           9 :     fd_bank_t * child = fd_banks_pool_ele( bank_pool, child_idx );
     871           9 :     if( !fd_banks_subtree_can_be_pruned( bank_pool, child ) ) return 0;
     872           9 :     child_idx = child->sibling_idx;
     873           9 :   }
     874             : 
     875          24 :   return 1;
     876          24 : }
     877             : 
     878             : int
     879             : fd_banks_advance_root_prepare( fd_banks_t * banks,
     880             :                                ulong        target_bank_idx,
     881          15 :                                ulong *      advanceable_bank_idx_out ) {
     882             :   /* TODO: An optimization here is to do a single traversal of the tree
     883             :      that would mark minority forks as dead while accumulating
     884             :      refcnts to determine which bank is the highest advanceable. */
     885             : 
     886          15 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     887             : 
     888          15 :   fd_bank_t * root = fd_banks_root( banks );
     889             : 
     890             :   /* Early exit if target is the same as the old root. */
     891          15 :   if( FD_UNLIKELY( root->idx==target_bank_idx ) ) {
     892           0 :     FD_LOG_WARNING(( "target bank_idx %lu is the same as the old root's bank index %lu", target_bank_idx, root->idx ));
     893           0 :     return 0;
     894           0 :   }
     895             : 
     896             :   /* Early exit if the root bank still has a reference to it, we can't
     897             :      advance from it unti it's released. */
     898          15 :   if( FD_UNLIKELY( root->refcnt!=0UL ) ) {
     899           0 :     return 0;
     900           0 :   }
     901             : 
     902          15 :   fd_bank_t * target_bank = fd_banks_pool_ele( bank_pool, target_bank_idx );
     903             : 
     904             :   /* Walk from target_bank up to root, recording the direct child of
     905             :      root on the path (prev).  We only advance root by one level. */
     906             : 
     907          15 :   fd_bank_t * curr = target_bank;
     908          15 :   fd_bank_t * prev = NULL;
     909          57 :   while( curr && curr!=root ) {
     910          42 :     prev = curr;
     911          42 :     curr = fd_banks_pool_ele( bank_pool, curr->parent_idx );
     912          42 :   }
     913             : 
     914             :   /* If we didn't reach the old root or there is no parent, target is
     915             :      not a descendant. */
     916          15 :   if( FD_UNLIKELY( !curr || prev->parent_idx!=root->idx ) ) {
     917           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 ));
     918           0 :   }
     919             : 
     920             :   /* We will at most advance our root bank by one.  This means we can
     921             :      advance our root bank by one if each of the siblings of the
     922             :      potential new root are eligible for pruning.  Each of the sibling
     923             :      subtrees can be pruned if the subtrees have no active references on
     924             :      their bank. */
     925          15 :   ulong advance_candidate_idx = prev->idx;
     926          15 :   ulong child_idx = root->child_idx;
     927          42 :   while( child_idx!=fd_banks_pool_idx_null( bank_pool ) ) {
     928          30 :     fd_bank_t * child_bank = fd_banks_pool_ele( bank_pool, child_idx );
     929          30 :     if( child_idx!=advance_candidate_idx ) {
     930          18 :       if( !fd_banks_subtree_can_be_pruned( bank_pool, child_bank ) ) {
     931           3 :         return 0;
     932           3 :       }
     933          18 :     }
     934          27 :     child_idx = child_bank->sibling_idx;
     935          27 :   }
     936             : 
     937          12 :   *advanceable_bank_idx_out = advance_candidate_idx;
     938          12 :   return 1;
     939          15 : }
     940             : 
     941             : fd_bank_t *
     942             : fd_banks_new_bank( fd_banks_t * banks,
     943             :                    ulong        parent_bank_idx,
     944        3705 :                    long         now ) {
     945             : 
     946        3705 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
     947        3705 :   FD_CRIT( fd_banks_pool_free( bank_pool )!=0UL, "invariant violation: no free bank indices available" );
     948             : 
     949        3705 :   ulong       child_bank_idx = fd_banks_pool_idx_acquire( bank_pool );
     950        3705 :   fd_bank_t * child_bank     = fd_banks_pool_ele( bank_pool, child_bank_idx );
     951        3705 :   FD_CRIT( child_bank->state==FD_BANK_STATE_INACTIVE, "invariant violation: bank for bank index is already initialized" );
     952             : 
     953        3705 :   ulong null_idx = fd_banks_pool_idx_null( bank_pool );
     954             : 
     955        3705 :   child_bank->bank_seq    = FD_ATOMIC_FETCH_AND_ADD( &banks->bank_seq, 1UL );
     956        3705 :   child_bank->parent_idx  = null_idx;
     957        3705 :   child_bank->child_idx   = null_idx;
     958        3705 :   child_bank->sibling_idx = null_idx;
     959        3705 :   child_bank->next        = null_idx;
     960        3705 :   child_bank->state       = FD_BANK_STATE_INIT;
     961        3705 :   child_bank->refcnt      = 0UL;
     962             : 
     963        3705 :   child_bank->stake_delegations_fork_id = USHORT_MAX;
     964        3705 :   child_bank->new_votes_fork_id         = USHORT_MAX;
     965             : 
     966             :   /* Then make sure that the parent bank is valid and frozen. */
     967             : 
     968        3705 :   fd_bank_t * parent_bank = fd_banks_pool_ele( bank_pool, parent_bank_idx );
     969        3705 :   FD_CRIT( parent_bank->state!=FD_BANK_STATE_INACTIVE && parent_bank->state!=FD_BANK_STATE_DEAD, "invariant violation: parent bank is dead or inactive" );
     970             : 
     971             :   /* Link node->parent */
     972        3705 :   child_bank->parent_idx = parent_bank_idx;
     973             :   /* Link parent->node and sibling->node */
     974        3705 :   if( FD_LIKELY( parent_bank->child_idx==null_idx ) ) {
     975             :     /* This is the first child so set as left-most child */
     976        3627 :     parent_bank->child_idx = child_bank_idx;
     977             : 
     978        3627 :   } else {
     979             :     /* Already have children so iterate to right-most sibling. */
     980          78 :     fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, parent_bank->child_idx );
     981         105 :     while( curr_bank->sibling_idx != null_idx ) curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->sibling_idx );
     982             :     /* Link to right-most sibling. */
     983          78 :     curr_bank->sibling_idx = child_bank_idx;
     984          78 :   }
     985             : 
     986        3705 :   child_bank->first_fec_set_received_nanos      = now;
     987        3705 :   child_bank->first_transaction_scheduled_nanos = 0L;
     988        3705 :   child_bank->last_transaction_finished_nanos   = 0L;
     989             : 
     990        3705 :   return child_bank;
     991        3705 : }
     992             : 
     993             : /* Mark everything in the fork tree starting at the given bank dead. */
     994             : 
     995             : static ulong
     996             : fd_banks_subtree_mark_dead( fd_banks_t * banks,
     997             :                             fd_bank_t *  bank_pool,
     998             :                             fd_bank_t *  bank,
     999          33 :                             ulong *      opt_idxs ) {
    1000          33 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_CRIT(( "invariant violation: bank is NULL" ));
    1001             : 
    1002          33 :   ulong idxs_cnt = 0UL;
    1003          33 :   bank->state = FD_BANK_STATE_DEAD;
    1004          33 :   fd_banks_dead_push_head( fd_banks_get_dead_banks_deque( banks ), (fd_bank_idx_seq_t){ .idx = bank->idx, .seq = bank->bank_seq } );
    1005          33 :   if( opt_idxs ) opt_idxs[ idxs_cnt ] = bank->idx;
    1006          33 :   idxs_cnt++;
    1007             : 
    1008             :   /* Recursively mark all children as dead. */
    1009          33 :   ulong child_idx = bank->child_idx;
    1010          42 :   while( child_idx!=fd_banks_pool_idx_null( bank_pool ) ) {
    1011           9 :     fd_bank_t * child      = fd_banks_pool_ele( bank_pool, child_idx );
    1012           9 :     ulong *     child_idxs = opt_idxs ? opt_idxs+idxs_cnt : NULL;
    1013           9 :     idxs_cnt += fd_banks_subtree_mark_dead( banks, bank_pool, child, child_idxs );
    1014           9 :     child_idx = child->sibling_idx;
    1015           9 :   }
    1016             : 
    1017          33 :   return idxs_cnt;
    1018          33 : }
    1019             : 
    1020             : void
    1021             : fd_banks_mark_bank_dead( fd_banks_t * banks,
    1022             :                          ulong        bank_idx,
    1023             :                          ulong *      opt_idxs,
    1024          24 :                          ulong *      opt_idxs_cnt ) {
    1025          24 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
    1026          24 :   fd_bank_t * bank      = fd_banks_pool_ele( bank_pool, bank_idx );
    1027             : 
    1028          24 :   ulong idxs_cnt = fd_banks_subtree_mark_dead( banks, bank_pool, bank, opt_idxs );
    1029          24 :   if( opt_idxs_cnt ) *opt_idxs_cnt = idxs_cnt;
    1030          24 : }
    1031             : 
    1032             : int
    1033             : fd_banks_prune_one_dead_bank( fd_banks_t *                   banks,
    1034          51 :                               fd_banks_prune_cancel_info_t * cancel ) {
    1035          51 :   fd_bank_idx_seq_t * dead_banks_queue = fd_banks_get_dead_banks_deque( banks );
    1036          51 :   fd_bank_t *         bank_pool        = fd_banks_get_bank_pool( banks );
    1037          51 :   ulong               null_idx         = fd_banks_pool_idx_null( bank_pool );
    1038          54 :   while( !fd_banks_dead_empty( dead_banks_queue ) ) {
    1039          33 :     fd_bank_idx_seq_t * head = fd_banks_dead_peek_head( dead_banks_queue );
    1040          33 :     fd_bank_t *         bank = fd_banks_pool_ele( bank_pool, head->idx );
    1041          33 :     if( bank->state==FD_BANK_STATE_INACTIVE || bank->bank_seq!=head->seq ) {
    1042           3 :       fd_banks_dead_pop_head( dead_banks_queue );
    1043           3 :       continue;
    1044          30 :     } else if( bank->refcnt!=0UL ) {
    1045           3 :       break;
    1046           3 :     }
    1047             : 
    1048          27 :     FD_LOG_DEBUG(( "pruning dead bank (idx=%lu)", bank->idx ));
    1049             : 
    1050          27 :     int started_replaying = bank->stake_delegations_fork_id!=USHORT_MAX;
    1051             : 
    1052             :     /* There are a few cases to consider:
    1053             :        1. The to-be-pruned bank is the left-most child of the parent.
    1054             :           This means that the parent bank's child idx is the
    1055             :           to-be-pruned bank.  In this case, we can simply make the
    1056             :           left-most sibling of the to-be-pruned bank the new left-most
    1057             :           child (set parent's banks child idx to the sibling).  The
    1058             :           sibling pointer can be null if the to-be-pruned bank is an
    1059             :           only child of the parent.
    1060             :        2. The to-be-pruned bank is some right child of the parent.  In
    1061             :           this case, the child bank which has a sibling pointer to the
    1062             :           to-be-pruned bank needs to be updated to point to the sibling
    1063             :           of the to-be-pruned bank.  The sibling can even be null if the
    1064             :           to-be-pruned bank is the right-most child of the parent.
    1065             :     */
    1066             : 
    1067          27 :     FD_TEST( bank->child_idx==null_idx );
    1068          27 :     fd_bank_t * parent_bank = fd_banks_pool_ele( bank_pool, bank->parent_idx );
    1069          27 :     if( parent_bank->child_idx==bank->idx ) {
    1070             :       /* Case 1: left-most child */
    1071          12 :       parent_bank->child_idx = bank->sibling_idx;
    1072          15 :     } else {
    1073             :       /* Case 2: some right child */
    1074          15 :       fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, parent_bank->child_idx );
    1075          21 :       while( curr_bank->sibling_idx!=bank->idx ) curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->sibling_idx );
    1076          15 :       curr_bank->sibling_idx = bank->sibling_idx;
    1077          15 :     }
    1078          27 :     bank->parent_idx  = null_idx;
    1079          27 :     bank->sibling_idx = null_idx;
    1080             : 
    1081          27 :     if( FD_UNLIKELY( bank->cost_tracker_pool_idx!=null_idx ) ) {
    1082          15 :       fd_bank_cost_tracker_pool_idx_release( fd_banks_get_cost_tracker_pool( banks ), bank->cost_tracker_pool_idx );
    1083          15 :       bank->cost_tracker_pool_idx = null_idx;
    1084          15 :     }
    1085             : 
    1086          27 :     fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
    1087          27 :     fd_stake_delegations_evict_fork( stake_delegations, bank->stake_delegations_fork_id );
    1088          27 :     bank->stake_delegations_fork_id = USHORT_MAX;
    1089             : 
    1090          27 :     fd_new_votes_t * new_votes = fd_banks_get_new_votes( banks );
    1091          27 :     fd_new_votes_evict_fork( new_votes, bank->new_votes_fork_id );
    1092          27 :     bank->new_votes_fork_id = USHORT_MAX;
    1093             : 
    1094          27 :     bank->stake_rewards_fork_id = UCHAR_MAX;
    1095             : 
    1096          27 :     if( FD_LIKELY( started_replaying ) ) {
    1097          18 :       cancel->txncache_fork_id = bank->txncache_fork_id;
    1098          18 :       cancel->slot             = bank->f.slot;
    1099          18 :       cancel->bank_seq         = bank->bank_seq;
    1100          18 :       cancel->bank_idx         = bank->idx;
    1101          18 :     }
    1102             : 
    1103          27 :     bank->state = FD_BANK_STATE_INACTIVE;
    1104             : 
    1105          27 :     fd_banks_pool_ele_release( bank_pool, bank );
    1106          27 :     fd_banks_dead_pop_head( dead_banks_queue );
    1107          27 :     return 1+started_replaying;
    1108          27 :   }
    1109          24 :   return 0;
    1110          51 : }
    1111             : 
    1112             : void
    1113         132 : fd_banks_mark_bank_frozen( fd_bank_t * bank ) {
    1114         132 :   fd_banks_t * banks = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
    1115             : 
    1116         132 :   FD_CRIT( bank->state==FD_BANK_STATE_REPLAYABLE, "invariant violation: bank is not replayable" );
    1117         132 :   bank->state = FD_BANK_STATE_FROZEN;
    1118             : 
    1119         132 :   FD_CRIT( bank->cost_tracker_pool_idx!=ULONG_MAX, "invariant violation: cost tracker pool index is null" );
    1120         132 :   fd_bank_cost_tracker_pool_idx_release( fd_banks_get_cost_tracker_pool( banks ), bank->cost_tracker_pool_idx );
    1121         132 :   bank->cost_tracker_pool_idx = ULONG_MAX;
    1122         132 : }
    1123             : 
    1124             : static void
    1125             : fd_banks_get_frontier_private( fd_bank_t * bank_pool,
    1126             :                                ulong       bank_idx,
    1127             :                                ulong *     frontier_indices_out,
    1128         144 :                                ulong *     frontier_cnt_out ) {
    1129         144 :   if( bank_idx==fd_banks_pool_idx_null( bank_pool ) ) return;
    1130             : 
    1131          90 :   fd_bank_t * bank = fd_banks_pool_ele( bank_pool, bank_idx );
    1132             : 
    1133          90 :   if( bank->child_idx==fd_banks_pool_idx_null( bank_pool ) ) {
    1134          45 :     if( bank->state!=FD_BANK_STATE_FROZEN && bank->state!=FD_BANK_STATE_DEAD ) {
    1135          36 :       frontier_indices_out[*frontier_cnt_out] = bank->idx;
    1136          36 :       (*frontier_cnt_out)++;
    1137          36 :     }
    1138          45 :   } else {
    1139          45 :     fd_banks_get_frontier_private( bank_pool, bank->child_idx, frontier_indices_out, frontier_cnt_out );
    1140          45 :   }
    1141          90 :   fd_banks_get_frontier_private( bank_pool, bank->sibling_idx, frontier_indices_out, frontier_cnt_out );
    1142          90 : }
    1143             : 
    1144             : void
    1145             : fd_banks_get_frontier( fd_banks_t * banks,
    1146             :                        ulong *      frontier_indices_out,
    1147           9 :                        ulong *      frontier_cnt_out ) {
    1148           9 :   *frontier_cnt_out = 0UL;
    1149           9 :   fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
    1150           9 :   fd_banks_get_frontier_private( bank_pool, banks->root_idx, frontier_indices_out, frontier_cnt_out );
    1151           9 : }
    1152             : 
    1153             : void
    1154             : fd_banks_clear_bank( fd_banks_t * banks,
    1155             :                      fd_bank_t *  bank,
    1156           3 :                      ulong        max_vote_accounts ) {
    1157             : 
    1158           3 :   fd_memset( &bank->f, 0, sizeof(bank->f) );
    1159             : 
    1160           3 :   fd_top_votes_init( fd_type_pun( bank->top_votes_t_1_mem ) );
    1161           3 :   fd_top_votes_init( fd_type_pun( bank->top_votes_t_2_mem ) );
    1162             : 
    1163             :   /* We need to acquire a cost tracker element. */
    1164           3 :   fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks );
    1165           3 :   if( FD_UNLIKELY( bank->cost_tracker_pool_idx!=fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool ) ) ) {
    1166           3 :     fd_bank_cost_tracker_pool_idx_release( cost_tracker_pool, bank->cost_tracker_pool_idx );
    1167           3 :   }
    1168           3 :   bank->cost_tracker_pool_idx = fd_bank_cost_tracker_pool_idx_acquire( cost_tracker_pool );
    1169             : 
    1170           3 :   if( FD_UNLIKELY( bank->new_votes_fork_id!=USHORT_MAX ) ) {
    1171           3 :     fd_new_votes_evict_fork( fd_banks_get_new_votes( banks ), bank->new_votes_fork_id );
    1172           3 :     bank->new_votes_fork_id = USHORT_MAX;
    1173           3 :   }
    1174             : 
    1175           3 :   fd_vote_stakes_t * vote_stakes = fd_banks_get_vote_stakes( banks );
    1176           3 :   fd_vote_stakes_new( vote_stakes, max_vote_accounts, max_vote_accounts, banks->max_fork_width, 999UL );
    1177           3 : }
    1178             : 
    1179             : void
    1180        3438 : fd_banks_clear( fd_banks_t * banks ) {
    1181             : 
    1182        3438 :   fd_bank_t *              bank_pool         = fd_banks_get_bank_pool( banks );
    1183        3438 :   fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks );
    1184             : 
    1185       58446 :   for( ulong i=0UL; i<banks->max_total_banks; i++ ) {
    1186       55008 :     fd_bank_t * bank = fd_banks_pool_ele( bank_pool, i );
    1187       55008 :     bank->state                 = FD_BANK_STATE_INACTIVE;
    1188       55008 :     bank->cost_tracker_pool_idx = fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool );
    1189       55008 :     bank->new_votes_fork_id     = USHORT_MAX;
    1190       55008 :   }
    1191             : 
    1192        3438 :   fd_banks_pool_reset( bank_pool );
    1193        3438 :   fd_bank_cost_tracker_pool_reset( cost_tracker_pool );
    1194        3438 :   fd_banks_dead_remove_all( fd_banks_get_dead_banks_deque( banks ) );
    1195             : 
    1196        3438 :   fd_vote_stakes_reset( fd_banks_get_vote_stakes( banks ) );
    1197        3438 :   fd_new_votes_reset( fd_banks_get_new_votes( banks ) );
    1198        3438 :   fd_stake_delegations_reset( fd_banks_get_stake_delegations( banks ) );
    1199             : 
    1200        3438 :   fd_stake_rewards_clear( fd_banks_get_stake_rewards( banks ) );
    1201             : 
    1202             :   banks->root_idx = ULONG_MAX;
    1203        3438 :   banks->bank_seq = 0UL;
    1204        3438 : }

Generated by: LCOV version 1.14