LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_bank.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 691 803 86.1 %
Date: 2026-07-11 05:27:41 Functions: 58 63 92.1 %

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

Generated by: LCOV version 1.14