LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_bank.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 165 210 78.6 %
Date: 2026-01-08 05:16:19 Functions: 46 3726 1.2 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_fd_bank_h
       2             : #define HEADER_fd_src_flamenco_runtime_fd_bank_h
       3             : 
       4             : #include "../types/fd_types.h"
       5             : #include "../leaders/fd_leaders.h"
       6             : #include "../features/fd_features.h"
       7             : #include "../rewards/fd_epoch_rewards.h"
       8             : #include "../stakes/fd_stake_delegations.h"
       9             : #include "../stakes/fd_vote_states.h"
      10             : #include "../fd_rwlock.h"
      11             : #include "fd_blockhashes.h"
      12             : #include "sysvar/fd_sysvar_cache.h"
      13             : #include "../../ballet/lthash/fd_lthash.h"
      14             : #include "fd_txncache_shmem.h"
      15             : 
      16             : FD_PROTOTYPES_BEGIN
      17             : 
      18          15 : #define FD_BANKS_MAGIC (0XF17EDA2C7EBA2450) /* FIREDANCER BANKS V0 */
      19             : 
      20             : /* TODO: Some optimizations, cleanups, future work:
      21             :    1. Simple data types (ulong, int, etc) should be stored as their
      22             :       underlying type instead of a byte array.
      23             :    3. Rename locks to suffix with _query_locking and _query_locking_end
      24             :   */
      25             : 
      26             : /* A fd_bank_t struct is the representation of the bank state on Solana
      27             :    for a given block.  More specifically, the bank state corresponds to
      28             :    all information needed during execution that is not stored on-chain,
      29             :    but is instead cached in a validator's memory.  Each of these bank
      30             :    fields are repesented by a member of the fd_bank_t struct.
      31             : 
      32             :    Management of fd_bank_t structs must be fork-aware: the state of each
      33             :    fd_bank_t must be based on the fd_bank_t of its parent block.  This
      34             :    state is managed by the fd_banks_t struct.
      35             : 
      36             :    In order to support fork-awareness, there are several key features
      37             :    that fd_banks_t and fd_bank_t MUST support:
      38             :    1. Query for any non-rooted block's bank: create a fast lookup
      39             :       from bank index to bank
      40             :    2. Be able to create a new bank for a given block from the bank of
      41             :       that block's parent and maintain some tree-like structure to
      42             :       track the parent-child relationships: copy the contents from a
      43             :       parent bank into a child bank.
      44             :    3. Prune the set of active banks to keep the root updated as the
      45             :       network progresses: free resources of fd_bank_t structs that
      46             :       are are not direct descendants of the root bank (remove parents
      47             :       and any competing lineages).
      48             :    4. Each bank will have field(s) that are concurrently read/write
      49             :       from multiple threads: add read-write locks to the fields that are
      50             :       concurrently written to.
      51             :    5. In practice, a bank state for a given block can be very large and
      52             :       not all of the fields are written to every block.  Therefore, it
      53             :       can be very expensive to copy the entire bank state for a given
      54             :       block each time a bank is created.  In order to avoid large
      55             :       memcpys, we can use a CoW mechanism for certain fields.
      56             :    6. In a similar vein, some fields are very large and are not written
      57             :       to very often, and are only read at the epoch boundary.  The most
      58             :       notable example is the stake delegations cache.  In order to
      59             :       handle this, we can use a delta-based approach where each bank
      60             :       only has a delta of the stake delegations.  The root bank will own
      61             :       the full set of stake delegations.  This means that the deltas are
      62             :       only applied to the root bank as each bank gets rooted.  If the
      63             :       caller needs to access the full set of stake delegations for a
      64             :       given bank, they can assemble the full set of stake delegations by
      65             :       applying all of the deltas from the current bank and all of its
      66             :       ancestors up to the root bank.
      67             : 
      68             :   fd_banks_t is represented by a left-child, right-sibling n-ary tree
      69             :   (inspired by fd_ghost) to keep track of the parent-child fork tree.
      70             :   The underlying data structure is a pool of fd_bank_t structs.  Banks
      71             :   are then accessed via an index into the bank pool (bank index).
      72             : 
      73             :   NOTE: The reason fd_banks_t is keyed by bank index and not by slot is
      74             :   to handle block equivocation: if there are two different blocks for
      75             :   the same slot, we need to be able to differentiate and handle both
      76             :   blocks against different banks.  As mentioned above, the bank index is
      77             :   just an index into the bank pool.  The caller is responsible for
      78             :   establishing a mapping from the bank index (which is managed by
      79             :   fd_banks_t) and runtime state (e.g. slot number).
      80             : 
      81             :   The fields in fd_bank_t can be categorized into two groups:
      82             :   1. Simple fields: these are fields which don't need any special
      83             :      handling and are laid out contiguously in the fd_bank_t struct.
      84             :      These types are also templatized out and are defined in the
      85             :      FD_BANKS_ITER macro.
      86             :   2. Complex fields: these are fields which need special handling
      87             :      (e.g. locking, copy on write semantics, delta-based semantics).
      88             :      These types are not templatized and are manually defined below.
      89             : 
      90             :   Each field that is CoW has its own memory pool. The memory
      91             :   corresponding to the field is not located in the fd_bank_t struct and
      92             :   is instead represented by a pool index and a dirty flag. If the field
      93             :   is modified, then the dirty flag is set, and an element of the pool
      94             :   is acquired and the data is copied over from the parent pool idx.
      95             : 
      96             :   Currently, there is a delta-based field, fd_stake_delegations_t.
      97             :   Each bank stores a delta-based representation in the form of an
      98             :   aligned uchar buffer.  The full state is stored in fd_banks_t also as
      99             :   a uchar buffer which corresponds to the full state of stake
     100             :   delegations for the current root.  fd_banks_t also reserves another
     101             :   buffer which can store the full state of the stake delegations.
     102             : 
     103             :   The cost tracker is allocated from a pool.  The lifetime of a cost
     104             :   tracker element starts when the bank is linked to a parent with a
     105             :   call to fd_banks_clone_from_parent() which makes the bank replayable.
     106             :   The lifetime of a cost tracker element ends when the bank is marked
     107             :   dead or when the bank is frozen.
     108             : 
     109             :   The lthash is a simple field that is laid out contiguously in the
     110             :   fd_bank_t struct, but is not templatized and it has its own lock.
     111             : 
     112             :   So, when a bank is cloned from a parent, the non CoW fields are copied
     113             :   over and the CoW fields just copy over a pool index. The CoW behavior
     114             :   is completely abstracted away from the caller as callers have to
     115             :   query/modify fields using specific APIs.
     116             : 
     117             :   The memory for the banks is based off of two bounds:
     118             :   1. the max number of unrooted blocks at any given time. Most fields
     119             :      can be bounded by this value.
     120             :   2. the max number of forks that execute through any 1 block.  We bound
     121             :      fields that are only written to at the epoch boundary by
     122             :      the max fork width that can execute through the boundary instead of
     123             :      by the max number of banks.  See fd_banks_footprint() for more
     124             :      details.
     125             : 
     126             :   There are also some important states that a bank can be in:
     127             :   - Initialized: This bank has been created and linked to a parent bank
     128             :     index with a call to fd_banks_new_bank().  However, it is not yet
     129             :     replayable.
     130             :   - Replayable: This bank has inherited state from its parent and now
     131             :     transactions can be executed against it.  For a bank to become
     132             :     replayable, it must've been initialized beforehand.
     133             :   - Dead: This bank has been marked as dead.  This means that the block
     134             :     that this bank is associated with is invalid.  A bank can be marked
     135             :     dead before, during, or after it has finished replaying.  A bank
     136             :     can still be executing transactions while it is marked dead, but it
     137             :     shouldn't be dispatched any more work.
     138             :   - Frozen: This bank has been marked as frozen and no other tasks
     139             :     should be dispatched to it.  Any bank-specific resources will be
     140             :     released (e.g. cost tracker element).  A bank can be marked frozen
     141             :     if the bank has finished executing all of its transactions or if the
     142             :     bank is marked as dead and has no outstanding references.  A bank
     143             :     can only be copied from a parent bank (fd_banks_clone_from_parent)
     144             :     if the parent bank has been frozen.  The program will crash if this
     145             :     invariant is violated.
     146             : 
     147             :   The usage pattern is as follows:
     148             : 
     149             :    To create an initial bank:
     150             :    fd_bank_t * bank_init = fd_bank_init_bank( banks );
     151             : 
     152             :    To create a new bank.  This simply provisions the memory for the bank
     153             :    but it should not be used to execute transactions against.
     154             :    ulong bank_index = fd_banks_new_bank( banks, parent_bank_index );
     155             : 
     156             :    To clone bank from parent banks.  This makes a bank replayable by
     157             :    copying over the state from the parent bank into the child.  It
     158             :    assumes that the bank index has been previously provisioned by a call
     159             :    to fd_banks_new_bank and that the parent bank index has been frozen.
     160             :    fd_bank_t * bank_clone = fd_banks_clone_from_parent( banks, bank_index );
     161             : 
     162             :    To ensure that the bank index we want to advance our root to is safe
     163             :    and that there are no outstanding references to the banks that are
     164             :    not descendants of the target bank.
     165             :    fd_banks_advance_root_prepare( banks, target_bank_idx, &advanceable_bank_idx_out );
     166             : 
     167             :    To advance the root bank.  This assumes that the bank index is "safe"
     168             :    to advance to.  This means that none of the ancestors of the bank
     169             :    index have a non-zero reference count.
     170             :    fd_bank_t * root_bank = fd_banks_advance_root( banks, bank_index );
     171             : 
     172             :    To query some arbitrary bank:
     173             :    fd_bank_t * bank_query = fd_banks_bank_query( banks, bank_index );
     174             : 
     175             :   To access the fields in the bank if they are templatized:
     176             : 
     177             :   fd_struct_t const * field = fd_bank_field_query( bank );
     178             :   OR
     179             :   fd_struct field = fd_bank_field_get( bank );
     180             : 
     181             :   fd_struct_t * field = fd_bank_field_modify( bank );
     182             :   OR
     183             :   fd_bank_field_set( bank, value );
     184             : 
     185             :   If the fields are not templatized, their accessor and modifier
     186             :   patterns vary and are documented below.
     187             : */
     188             : 
     189             : #define FD_BANKS_ITER(X)                                                                                                                                                                                             \
     190             :   /* type,                             name,                        footprint,                                 align  */                                                                                             \
     191             :   X(fd_blockhashes_t,                  block_hash_queue,            sizeof(fd_blockhashes_t),                  alignof(fd_blockhashes_t)                  ) /* Block hash queue */                                   \
     192             :   X(fd_fee_rate_governor_t,            fee_rate_governor,           sizeof(fd_fee_rate_governor_t),            alignof(fd_fee_rate_governor_t)            ) /* Fee rate governor */                                  \
     193             :   X(ulong,                             rbh_lamports_per_sig,        sizeof(ulong),                             alignof(ulong)                             ) /* Recent Block Hashes lamports per signature */         \
     194             :   X(ulong,                             slot,                        sizeof(ulong),                             alignof(ulong)                             ) /* Slot */                                               \
     195             :   X(ulong,                             parent_slot,                 sizeof(ulong),                             alignof(ulong)                             ) /* Parent slot */                                        \
     196             :   X(ulong,                             capitalization,              sizeof(ulong),                             alignof(ulong)                             ) /* Capitalization */                                     \
     197             :   X(ulong,                             transaction_count,           sizeof(ulong),                             alignof(ulong)                             ) /* Transaction count */                                  \
     198             :   X(ulong,                             parent_signature_cnt,        sizeof(ulong),                             alignof(ulong)                             ) /* Parent signature count */                             \
     199             :   X(ulong,                             tick_height,                 sizeof(ulong),                             alignof(ulong)                             ) /* Tick height */                                        \
     200             :   X(ulong,                             max_tick_height,             sizeof(ulong),                             alignof(ulong)                             ) /* Max tick height */                                    \
     201             :   X(ulong,                             hashes_per_tick,             sizeof(ulong),                             alignof(ulong)                             ) /* Hashes per tick */                                    \
     202             :   X(fd_w_u128_t,                       ns_per_slot,                 sizeof(fd_w_u128_t),                       alignof(fd_w_u128_t)                       ) /* NS per slot */                                        \
     203             :   X(ulong,                             ticks_per_slot,              sizeof(ulong),                             alignof(ulong)                             ) /* Ticks per slot */                                     \
     204             :   X(ulong,                             genesis_creation_time,       sizeof(ulong),                             alignof(ulong)                             ) /* Genesis creation time */                              \
     205             :   X(double,                            slots_per_year,              sizeof(double),                            alignof(double)                            ) /* Slots per year */                                     \
     206             :   X(fd_inflation_t,                    inflation,                   sizeof(fd_inflation_t),                    alignof(fd_inflation_t)                    ) /* Inflation */                                          \
     207             :   X(ulong,                             cluster_type,                sizeof(ulong),                             alignof(ulong)                             ) /* Cluster type */                                       \
     208             :   X(ulong,                             total_epoch_stake,           sizeof(ulong),                             alignof(ulong)                             ) /* Total epoch stake */                                  \
     209             :                                                                                                                                                             /* This is only used for the get_epoch_stake syscall. */ \
     210             :                                                                                                                                                             /* If we are executing in epoch E, this is the total */  \
     211             :                                                                                                                                                             /* stake at the end of epoch E-1. */                     \
     212             :   X(ulong,                             block_height,                sizeof(ulong),                             alignof(ulong)                             ) /* Block height */                                       \
     213             :   X(ulong,                             execution_fees,              sizeof(ulong),                             alignof(ulong)                             ) /* Execution fees */                                     \
     214             :   X(ulong,                             priority_fees,               sizeof(ulong),                             alignof(ulong)                             ) /* Priority fees */                                      \
     215             :   X(ulong,                             tips,                        sizeof(ulong),                             alignof(ulong)                             ) /* Tips collected */                                     \
     216             :   X(ulong,                             signature_count,             sizeof(ulong),                             alignof(ulong)                             ) /* Signature count */                                    \
     217             :   X(fd_hash_t,                         poh,                         sizeof(fd_hash_t),                         alignof(fd_hash_t)                         ) /* PoH */                                                \
     218             :   X(fd_sol_sysvar_last_restart_slot_t, last_restart_slot,           sizeof(fd_sol_sysvar_last_restart_slot_t), alignof(fd_sol_sysvar_last_restart_slot_t) ) /* Last restart slot */                                  \
     219             :   X(fd_hash_t,                         bank_hash,                   sizeof(fd_hash_t),                         alignof(fd_hash_t)                         ) /* Bank hash */                                          \
     220             :   X(fd_hash_t,                         prev_bank_hash,              sizeof(fd_hash_t),                         alignof(fd_hash_t)                         ) /* Previous bank hash */                                 \
     221             :   X(fd_hash_t,                         genesis_hash,                sizeof(fd_hash_t),                         alignof(fd_hash_t)                         ) /* Genesis hash */                                       \
     222             :   X(fd_epoch_schedule_t,               epoch_schedule,              sizeof(fd_epoch_schedule_t),               alignof(fd_epoch_schedule_t)               ) /* Epoch schedule */                                     \
     223             :   X(fd_rent_t,                         rent,                        sizeof(fd_rent_t),                         alignof(fd_rent_t)                         ) /* Rent */                                               \
     224             :   X(fd_sysvar_cache_t,                 sysvar_cache,                sizeof(fd_sysvar_cache_t),                 alignof(fd_sysvar_cache_t)                 ) /* Sysvar cache */                                       \
     225             :                                                                                                                                                             /* then there can be 100k unique leaders in the worst */ \
     226             :                                                                                                                                                             /* case. We also can assume 432k slots per epoch. */     \
     227             :   X(fd_features_t,                     features,                    sizeof(fd_features_t),                     alignof(fd_features_t)                     ) /* Features */                                           \
     228             :   X(ulong,                             txn_count,                   sizeof(ulong),                             alignof(ulong)                             ) /* Transaction count */                                  \
     229             :   X(ulong,                             nonvote_txn_count,           sizeof(ulong),                             alignof(ulong)                             ) /* Nonvote transaction count */                          \
     230             :   X(ulong,                             failed_txn_count,            sizeof(ulong),                             alignof(ulong)                             ) /* Failed transaction count */                           \
     231             :   X(ulong,                             nonvote_failed_txn_count,    sizeof(ulong),                             alignof(ulong)                             ) /* Nonvote failed transaction count */                   \
     232             :   X(ulong,                             total_compute_units_used,    sizeof(ulong),                             alignof(ulong)                             ) /* Total compute units used */                           \
     233             :   X(ulong,                             slots_per_epoch,             sizeof(ulong),                             alignof(ulong)                             ) /* Slots per epoch */                                    \
     234             :   X(ulong,                             shred_cnt,                   sizeof(ulong),                             alignof(ulong)                             ) /* Shred count */                                        \
     235             :   X(ulong,                             epoch,                       sizeof(ulong),                             alignof(ulong)                             ) /* Epoch */                                              \
     236             :   X(int,                               has_identity_vote,           sizeof(int),                               alignof(int)                               ) /* Has identity vote */
     237             : 
     238             : /* Defining pools for any CoW fields. */
     239             : 
     240             : struct fd_bank_epoch_rewards {
     241             :   ulong next;
     242             :   uchar data[FD_EPOCH_REWARDS_FOOTPRINT] __attribute__((aligned(FD_EPOCH_REWARDS_ALIGN)));
     243             : };
     244             : typedef struct fd_bank_epoch_rewards fd_bank_epoch_rewards_t;
     245             : 
     246             : struct fd_bank_epoch_leaders {
     247             :   ulong next;
     248             :   uchar data[FD_EPOCH_LEADERS_MAX_FOOTPRINT] __attribute__((aligned(FD_EPOCH_LEADERS_ALIGN)));
     249             : };
     250             : typedef struct fd_bank_epoch_leaders fd_bank_epoch_leaders_t;
     251             : 
     252             : struct fd_bank_vote_states {
     253             :   ulong next;
     254             :   uchar data[FD_VOTE_STATES_FOOTPRINT] __attribute__((aligned(FD_VOTE_STATES_ALIGN)));
     255             : };
     256             : typedef struct fd_bank_vote_states fd_bank_vote_states_t;
     257             : 
     258             : struct fd_bank_vote_states_prev {
     259             :   ulong next;
     260             :   uchar data[FD_VOTE_STATES_FOOTPRINT] __attribute__((aligned(FD_VOTE_STATES_ALIGN)));
     261             : };
     262             : typedef struct fd_bank_vote_states_prev fd_bank_vote_states_prev_t;
     263             : 
     264             : struct fd_bank_vote_states_prev_prev {
     265             :   ulong next;
     266             :   uchar data[FD_VOTE_STATES_FOOTPRINT] __attribute__((aligned(FD_VOTE_STATES_ALIGN)));
     267             : };
     268             : typedef struct fd_bank_vote_states_prev_prev fd_bank_vote_states_prev_prev_t;
     269             : 
     270             : struct fd_bank_cost_tracker {
     271             :   ulong next;
     272             :   uchar data[FD_COST_TRACKER_FOOTPRINT] __attribute__((aligned(FD_COST_TRACKER_ALIGN)));
     273             : };
     274             : typedef struct fd_bank_cost_tracker fd_bank_cost_tracker_t;
     275             : 
     276             : #define POOL_NAME fd_bank_epoch_leaders_pool
     277         297 : #define POOL_T    fd_bank_epoch_leaders_t
     278             : #include "../../util/tmpl/fd_pool.c"
     279             : 
     280             : #define POOL_NAME fd_bank_epoch_rewards_pool
     281         333 : #define POOL_T    fd_bank_epoch_rewards_t
     282             : #include "../../util/tmpl/fd_pool.c"
     283             : 
     284             : #define POOL_NAME fd_bank_vote_states_pool
     285         387 : #define POOL_T    fd_bank_vote_states_t
     286             : #include "../../util/tmpl/fd_pool.c"
     287             : 
     288             : #define POOL_NAME fd_bank_vote_states_prev_pool
     289         336 : #define POOL_T    fd_bank_vote_states_prev_t
     290             : #include "../../util/tmpl/fd_pool.c"
     291             : 
     292             : #define POOL_NAME fd_bank_vote_states_prev_prev_pool
     293         312 : #define POOL_T    fd_bank_vote_states_prev_prev_t
     294             : #include "../../util/tmpl/fd_pool.c"
     295             : 
     296             : #define POOL_NAME fd_bank_cost_tracker_pool
     297         669 : #define POOL_T    fd_bank_cost_tracker_t
     298             : #include "../../util/tmpl/fd_pool.c"
     299             : 
     300             : /* Initialized.  Not yet replayable. */
     301         261 : #define FD_BANK_FLAGS_INIT       (0x00000001UL)
     302             : /* Replayable.  Implies that FD_BANK_FLAGS_INIT is also set. */
     303         108 : #define FD_BANK_FLAGS_REPLAYABLE (0x00000002UL)
     304             : /* Frozen.  We finished replaying or because it was a snapshot/genesis
     305             :    loaded bank.  Implies that FD_BANK_FLAGS_REPLAYABLE is also set. */
     306         105 : #define FD_BANK_FLAGS_FROZEN     (0x00000004UL)
     307             : /* Dead.  We stopped replaying it before we could finish it (e.g.
     308             :    invalid block or pruned minority fork).  It is implied that
     309             :    FD_BANK_FLAGS_INIT is set, but not necessarily
     310             :    FD_BANK_FLAGS_REPLAYABLE. */
     311          51 : #define FD_BANK_FLAGS_DEAD       (0x00000008UL)
     312             :  /* Rooted.  Part of the consnensus root fork.  Implies that
     313             :     FD_BANK_FLAGS_FROZEN is also set. */
     314         114 : #define FD_BANK_FLAGS_ROOTED     (0x00000010UL)
     315             : 
     316             : /* As mentioned above, the overall layout of the bank struct:
     317             :    - Fields used for internal pool/bank management
     318             :    - Non-Cow fields
     319             :    - CoW fields
     320             :    - Locks for CoW fields
     321             : 
     322             :    The CoW fields are laid out contiguously in the bank struct.
     323             :    The locks for the CoW fields are laid out contiguously after the
     324             :    CoW fields.
     325             : 
     326             :    (r) Field is owned by the replay tile, and should be updated only by
     327             :        the replay tile.
     328             : */
     329             : 
     330             : struct fd_bank {
     331             : 
     332             :   /* Fields used for internal pool and bank management */
     333             :   ulong idx;         /* current fork idx of the bank (synchronized with the pool index) */
     334             :   ulong next;        /* reserved for internal use by pool and fd_banks_advance_root */
     335             :   ulong parent_idx;  /* index of the parent in the node pool */
     336             :   ulong child_idx;   /* index of the left-child in the node pool */
     337             :   ulong sibling_idx; /* index of the right-sibling in the node pool */
     338             :   ulong flags;       /* (r) keeps track of the state of the bank, as well as some configurations */
     339             :   ulong bank_seq;    /* app-wide bank sequence number */
     340             : 
     341             :   ulong refcnt; /* (r) reference count on the bank, see replay for more details */
     342             : 
     343             :   fd_txncache_fork_id_t txncache_fork_id; /* fork id used by the txn cache */
     344             : 
     345             :   /* Timestamps written and read only by replay */
     346             : 
     347             :   long first_fec_set_received_nanos;
     348             :   long preparation_begin_nanos;
     349             :   long first_transaction_scheduled_nanos;
     350             :   long last_transaction_finished_nanos;
     351             : 
     352             :   /* First, layout all non-CoW fields contiguously. This is done to
     353             :      allow for cloning the bank state with a simple memcpy. Each
     354             :      non-CoW field is just represented as a byte array. */
     355             : 
     356             :   fd_rwlock_t lthash_lock;
     357             : 
     358             :   struct {
     359             :     fd_lthash_value_t lthash;
     360             : 
     361             :     #define X(type, name, footprint, align) uchar name[footprint] __attribute__((aligned(align)));
     362             :     FD_BANKS_ITER(X)
     363             :     #undef X
     364             :   } non_cow;
     365             : 
     366             :   /* Layout all information needed for non-templatized fields. */
     367             : 
     368             :   fd_rwlock_t cost_tracker_lock;
     369             :   ulong       cost_tracker_pool_idx;
     370             :   ulong       cost_tracker_pool_offset;
     371             : 
     372             :   fd_rwlock_t stake_delegations_delta_lock;
     373             :   int         stake_delegations_delta_dirty;
     374             :   uchar       stake_delegations_delta[FD_STAKE_DELEGATIONS_DELTA_FOOTPRINT] __attribute__((aligned(FD_STAKE_DELEGATIONS_ALIGN)));
     375             : 
     376             :   fd_rwlock_t vote_states_lock;
     377             :   int         vote_states_dirty;
     378             :   ulong       vote_states_pool_idx;
     379             :   ulong       vote_states_pool_offset;
     380             :   ulong       vote_states_pool_lock_offset;
     381             : 
     382             :   int   epoch_rewards_dirty;
     383             :   ulong epoch_rewards_pool_idx;
     384             :   ulong epoch_rewards_pool_offset;
     385             :   ulong epoch_rewards_pool_lock_offset;
     386             : 
     387             :   int   epoch_leaders_dirty;
     388             :   ulong epoch_leaders_pool_idx;
     389             :   ulong epoch_leaders_pool_offset;
     390             :   ulong epoch_leaders_pool_lock_offset;
     391             : 
     392             :   int   vote_states_prev_dirty;
     393             :   ulong vote_states_prev_pool_idx;
     394             :   ulong vote_states_prev_pool_offset;
     395             :   ulong vote_states_prev_pool_lock_offset;
     396             : 
     397             :   int   vote_states_prev_prev_dirty;
     398             :   ulong vote_states_prev_prev_pool_idx;
     399             :   ulong vote_states_prev_prev_pool_offset;
     400             :   ulong vote_states_prev_prev_pool_lock_offset;
     401             : };
     402             : typedef struct fd_bank fd_bank_t;
     403             : 
     404             : static inline void
     405         114 : fd_bank_set_epoch_rewards_pool( fd_bank_t * bank, fd_bank_epoch_rewards_t * epoch_rewards_pool ) {
     406         114 :   void * epoch_rewards_pool_mem = fd_bank_epoch_rewards_pool_leave( epoch_rewards_pool );
     407         114 :   if( FD_UNLIKELY( !epoch_rewards_pool_mem ) ) {
     408           0 :     FD_LOG_CRIT(( "Failed to leave epoch rewards pool" ));
     409           0 :   }
     410         114 :   bank->epoch_rewards_pool_offset = (ulong)epoch_rewards_pool_mem - (ulong)bank;
     411         114 : }
     412             : 
     413             : static inline fd_bank_epoch_rewards_t *
     414         138 : fd_bank_get_epoch_rewards_pool( fd_bank_t * bank ) {
     415         138 :   return fd_bank_epoch_rewards_pool_join( (uchar *)bank + bank->epoch_rewards_pool_offset );
     416         138 : }
     417             : 
     418             : static inline void
     419         114 : fd_bank_set_epoch_rewards_pool_lock( fd_bank_t * bank, fd_rwlock_t * rwlock ) {
     420         114 :   bank->epoch_rewards_pool_lock_offset = (ulong)rwlock - (ulong)bank;
     421         114 : }
     422             : 
     423             : static inline fd_rwlock_t *
     424          18 : fd_bank_get_epoch_rewards_pool_lock( fd_bank_t * bank ) {
     425          18 :   return (fd_rwlock_t *)( (uchar *)bank + bank->epoch_rewards_pool_lock_offset );
     426          18 : }
     427             : 
     428             : static inline void
     429         114 : fd_bank_set_epoch_leaders_pool( fd_bank_t * bank, fd_bank_epoch_leaders_t * epoch_leaders_pool ) {
     430         114 :   void * epoch_leaders_pool_mem = fd_bank_epoch_leaders_pool_leave( epoch_leaders_pool );
     431         114 :   if( FD_UNLIKELY( !epoch_leaders_pool_mem ) ) {
     432           0 :     FD_LOG_CRIT(( "Failed to leave epoch leaders pool" ));
     433           0 :   }
     434         114 :   bank->epoch_leaders_pool_offset = (ulong)epoch_leaders_pool_mem - (ulong)bank;
     435         114 : }
     436             : 
     437             : static inline fd_bank_epoch_leaders_t *
     438         102 : fd_bank_get_epoch_leaders_pool( fd_bank_t * bank ) {
     439         102 :   return fd_bank_epoch_leaders_pool_join( (uchar *)bank + bank->epoch_leaders_pool_offset );
     440         102 : }
     441             : 
     442             : static inline void
     443         114 : fd_bank_set_epoch_leaders_pool_lock( fd_bank_t * bank, fd_rwlock_t * rwlock ) {
     444         114 :   bank->epoch_leaders_pool_lock_offset = (ulong)rwlock - (ulong)bank;
     445         114 : }
     446             : 
     447             : static inline fd_rwlock_t *
     448          18 : fd_bank_get_epoch_leaders_pool_lock( fd_bank_t * bank ) {
     449          18 :   return (fd_rwlock_t *)( (uchar *)bank + bank->epoch_leaders_pool_lock_offset );
     450          18 : }
     451             : 
     452             : static inline void
     453         114 : fd_bank_set_vote_states_pool( fd_bank_t * bank, fd_bank_vote_states_t * vote_states_pool ) {
     454         114 :   void * vote_states_pool_mem = fd_bank_vote_states_pool_leave( vote_states_pool );
     455         114 :   if( FD_UNLIKELY( !vote_states_pool_mem ) ) {
     456           0 :     FD_LOG_CRIT(( "Failed to leave vote states pool" ));
     457           0 :   }
     458         114 :   bank->vote_states_pool_offset = (ulong)vote_states_pool_mem - (ulong)bank;
     459         114 : }
     460             : 
     461             : static inline fd_bank_vote_states_t *
     462         177 : fd_bank_get_vote_states_pool( fd_bank_t * bank ) {
     463         177 :   return fd_bank_vote_states_pool_join( (uchar *)bank + bank->vote_states_pool_offset );
     464         177 : }
     465             : 
     466             : static inline void
     467         114 : fd_bank_set_vote_states_pool_lock( fd_bank_t * bank, fd_rwlock_t * rwlock ) {
     468         114 :   bank->vote_states_pool_lock_offset = (ulong)rwlock - (ulong)bank;
     469         114 : }
     470             : 
     471             : static inline fd_rwlock_t *
     472          24 : fd_bank_get_vote_states_pool_lock( fd_bank_t * bank ) {
     473          24 :   return (fd_rwlock_t *)( (uchar *)bank + bank->vote_states_pool_lock_offset );
     474          24 : }
     475             : 
     476             : static inline void
     477         114 : fd_bank_set_vote_states_prev_pool( fd_bank_t * bank, fd_bank_vote_states_prev_t * vote_states_prev_pool ) {
     478         114 :   void * vote_states_prev_pool_mem = fd_bank_vote_states_prev_pool_leave( vote_states_prev_pool );
     479         114 :   if( FD_UNLIKELY( !vote_states_prev_pool_mem ) ) {
     480           0 :     FD_LOG_CRIT(( "Failed to leave vote states prev pool" ));
     481           0 :   }
     482         114 :   bank->vote_states_prev_pool_offset = (ulong)vote_states_prev_pool_mem - (ulong)bank;
     483         114 : }
     484             : 
     485             : static inline fd_bank_vote_states_prev_t *
     486         126 : fd_bank_get_vote_states_prev_pool( fd_bank_t * bank ) {
     487         126 :   return fd_bank_vote_states_prev_pool_join( (uchar *)bank + bank->vote_states_prev_pool_offset );
     488         126 : }
     489             : 
     490             : static inline void
     491         114 : fd_bank_set_vote_states_prev_pool_lock( fd_bank_t * bank, fd_rwlock_t * rwlock ) {
     492         114 :   bank->vote_states_prev_pool_lock_offset = (ulong)rwlock - (ulong)bank;
     493         114 : }
     494             : 
     495             : static inline fd_rwlock_t *
     496          30 : fd_bank_get_vote_states_prev_pool_lock( fd_bank_t * bank ) {
     497          30 :   return (fd_rwlock_t *)( (uchar *)bank + bank->vote_states_prev_pool_lock_offset );
     498          30 : }
     499             : 
     500             : static inline void
     501         114 : fd_bank_set_vote_states_prev_prev_pool( fd_bank_t * bank, fd_bank_vote_states_prev_prev_t * vote_states_prev_prev_pool ) {
     502         114 :   void * vote_states_prev_prev_pool_mem = fd_bank_vote_states_prev_prev_pool_leave( vote_states_prev_prev_pool );
     503         114 :   if( FD_UNLIKELY( !vote_states_prev_prev_pool_mem ) ) {
     504           0 :     FD_LOG_CRIT(( "Failed to leave vote states prev prev pool" ));
     505           0 :   }
     506         114 :   bank->vote_states_prev_prev_pool_offset = (ulong)vote_states_prev_prev_pool_mem - (ulong)bank;
     507         114 : }
     508             : 
     509             : static inline fd_bank_vote_states_prev_prev_t *
     510         102 : fd_bank_get_vote_states_prev_prev_pool( fd_bank_t * bank ) {
     511         102 :   return fd_bank_vote_states_prev_prev_pool_join( (uchar *)bank + bank->vote_states_prev_prev_pool_offset );
     512         102 : }
     513             : 
     514             : static inline void
     515         114 : fd_bank_set_vote_states_prev_prev_pool_lock( fd_bank_t * bank, fd_rwlock_t * rwlock ) {
     516         114 :   bank->vote_states_prev_prev_pool_lock_offset = (ulong)rwlock - (ulong)bank;
     517         114 : }
     518             : 
     519             : static inline fd_rwlock_t *
     520          18 : fd_bank_get_vote_states_prev_prev_pool_lock( fd_bank_t * bank ) {
     521          18 :   return (fd_rwlock_t *)( (uchar *)bank + bank->vote_states_prev_prev_pool_lock_offset );
     522          18 : }
     523             : 
     524             : /* Do the same setup for the cost tracker pool. */
     525             : 
     526             : static inline void
     527         114 : fd_bank_set_cost_tracker_pool( fd_bank_t * bank, fd_bank_cost_tracker_t * cost_tracker_pool ) {
     528         114 :   void * cost_tracker_pool_mem = fd_bank_cost_tracker_pool_leave( cost_tracker_pool );
     529         114 :   if( FD_UNLIKELY( !cost_tracker_pool_mem ) ) {
     530           0 :     FD_LOG_CRIT(( "Failed to leave cost tracker pool" ));
     531           0 :   }
     532         114 :   bank->cost_tracker_pool_offset = (ulong)cost_tracker_pool_mem - (ulong)bank;
     533         114 : }
     534             : 
     535             : static inline fd_bank_cost_tracker_t *
     536         489 : fd_bank_get_cost_tracker_pool( fd_bank_t * bank ) {
     537         489 :   return fd_bank_cost_tracker_pool_join( (uchar *)bank + bank->cost_tracker_pool_offset );
     538         489 : }
     539             : 
     540             : /* fd_bank_t is the alignment for the bank state. */
     541             : 
     542             : ulong
     543             : fd_bank_align( void );
     544             : 
     545             : /* fd_bank_t is the footprint for the bank state. This does NOT
     546             :    include the footprint for the CoW state. */
     547             : 
     548             : ulong
     549             : fd_bank_footprint( void );
     550             : 
     551             : /**********************************************************************/
     552             : /* fd_banks_t is the main struct used to manage the bank state.  It can
     553             :    be used to query/modify/clone/publish the bank state.
     554             : 
     555             :    fd_banks_t contains some metadata to a pool to manage the banks.
     556             :    It also contains pointers to the CoW pools.
     557             : 
     558             :    The data is laid out contiguously in memory starting from fd_banks_t;
     559             :    this can be seen in fd_banks_footprint(). */
     560             : 
     561             : #define POOL_NAME fd_banks_pool
     562         636 : #define POOL_T    fd_bank_t
     563             : #include "../../util/tmpl/fd_pool.c"
     564             : 
     565             : struct fd_banks {
     566             :   ulong       magic;           /* ==FD_BANKS_MAGIC */
     567             :   ulong       max_total_banks; /* Maximum number of banks */
     568             :   ulong       max_fork_width;  /* Maximum fork width executing through
     569             :                                   any given slot. */
     570             :   ulong       root_idx;        /* root idx */
     571             :   ulong       bank_seq;        /* app-wide bank sequence number */
     572             : 
     573             :   /* This lock is only used to serialize banks fork tree reads with
     574             :      respect to fork tree writes.  In other words, tree traversals
     575             :      cannot happen at the same time as a tree pruning operation or a
     576             :      tree insertion operation.  So the public APIs on banks take either
     577             :      a read lock or a write lock depending on what they do on the fork
     578             :      tree.  For example, publishing takes a write lock, and bank lookups
     579             :      take a read lock.  Notably, individual banks can still be
     580             :      concurrently accessed or modified, and this lock does not offer
     581             :      synchronization on individual fields within a bank. */
     582             :   fd_rwlock_t rwlock;
     583             : 
     584             :   ulong       pool_offset;     /* offset of pool from banks */
     585             : 
     586             :   ulong       cost_tracker_pool_offset; /* offset of cost tracker pool from banks */
     587             : 
     588             :   ulong       vote_states_pool_offset_;
     589             : 
     590             :   /* stake_delegations_root will be the full state of stake delegations
     591             :      for the current root. It can get updated in two ways:
     592             :      1. On boot the snapshot will be directly read into the rooted
     593             :         stake delegations because we assume that any and all snapshots
     594             :         are a rooted slot.
     595             :      2. Calls to fd_banks_publish() will apply all of the stake
     596             :         delegation deltas from each of the banks that are about to be
     597             :         published.  */
     598             : 
     599             :   uchar stake_delegations_root[FD_STAKE_DELEGATIONS_FOOTPRINT] __attribute__((aligned(FD_STAKE_DELEGATIONS_ALIGN)));
     600             : 
     601             :   /* stake_delegations_frontier is reserved memory that can represent
     602             :      the full state of stake delegations for the current frontier. This
     603             :      is done by taking the stake_delegations_root and applying all of
     604             :      the deltas from the current bank and all of its ancestors up to the
     605             :      root bank. */
     606             : 
     607             :   uchar stake_delegations_frontier[FD_STAKE_DELEGATIONS_FOOTPRINT] __attribute__((aligned(FD_STAKE_DELEGATIONS_ALIGN)));
     608             : 
     609             :   /* Layout all CoW pools. */
     610             : 
     611             :   ulong epoch_rewards_pool_offset;
     612             :   fd_rwlock_t epoch_rewards_pool_lock;
     613             : 
     614             :   ulong epoch_leaders_pool_offset;
     615             :   fd_rwlock_t epoch_leaders_pool_lock;
     616             : 
     617             :   ulong vote_states_pool_offset;
     618             :   fd_rwlock_t vote_states_pool_lock;
     619             : 
     620             :   ulong vote_states_prev_pool_offset;
     621             :   fd_rwlock_t vote_states_prev_pool_lock;
     622             : 
     623             :   ulong vote_states_prev_prev_pool_offset;
     624             :   fd_rwlock_t vote_states_prev_prev_pool_lock;
     625             : };
     626             : typedef struct fd_banks fd_banks_t;
     627             : 
     628             : /* Bank accesssors and mutators.  Different accessors are emitted for
     629             :    different types depending on if the field has a lock or not. */
     630             : 
     631             : fd_epoch_rewards_t const *
     632             : fd_bank_epoch_rewards_query( fd_bank_t * bank );
     633             : 
     634             : fd_epoch_rewards_t *
     635             : fd_bank_epoch_rewards_modify( fd_bank_t * bank );
     636             : 
     637             : fd_epoch_leaders_t const *
     638             : fd_bank_epoch_leaders_query( fd_bank_t * bank );
     639             : 
     640             : fd_epoch_leaders_t *
     641             : fd_bank_epoch_leaders_modify( fd_bank_t * bank );
     642             : 
     643             : fd_vote_states_t const *
     644             : fd_bank_vote_states_prev_query( fd_bank_t * bank );
     645             : 
     646             : fd_vote_states_t *
     647             : fd_bank_vote_states_prev_modify( fd_bank_t * bank );
     648             : 
     649             : fd_vote_states_t const *
     650             : fd_bank_vote_states_prev_prev_query( fd_bank_t * bank );
     651             : 
     652             : fd_vote_states_t *
     653             : fd_bank_vote_states_prev_prev_modify( fd_bank_t * bank );
     654             : 
     655             : fd_vote_states_t const *
     656             : fd_bank_vote_states_locking_query( fd_bank_t * bank );
     657             : 
     658             : void
     659             : fd_bank_vote_states_end_locking_query( fd_bank_t * bank );
     660             : 
     661             : fd_vote_states_t *
     662             : fd_bank_vote_states_locking_modify( fd_bank_t * bank );
     663             : 
     664             : void
     665             : fd_bank_vote_states_end_locking_modify( fd_bank_t * bank );
     666             : 
     667             : fd_cost_tracker_t *
     668             : fd_bank_cost_tracker_locking_modify( fd_bank_t * bank );
     669             : 
     670             : void
     671             : fd_bank_cost_tracker_end_locking_modify( fd_bank_t * bank );
     672             : 
     673             : fd_cost_tracker_t const *
     674             : fd_bank_cost_tracker_locking_query( fd_bank_t * bank );
     675             : 
     676             : void
     677             : fd_bank_cost_tracker_end_locking_query( fd_bank_t * bank );
     678             : 
     679             : fd_lthash_value_t const *
     680             : fd_bank_lthash_locking_query( fd_bank_t * bank );
     681             : 
     682             : void
     683             : fd_bank_lthash_end_locking_query( fd_bank_t * bank );
     684             : 
     685             : fd_lthash_value_t *
     686             : fd_bank_lthash_locking_modify( fd_bank_t * bank );
     687             : 
     688             : void
     689             : fd_bank_lthash_end_locking_modify( fd_bank_t * bank );
     690             : 
     691             : #define X(type, name, footprint, align)                          \
     692             :   void fd_bank_##name##_set( fd_bank_t * bank, type value );     \
     693             :   type fd_bank_##name##_get( fd_bank_t const * bank );           \
     694             :   type const * fd_bank_##name##_query( fd_bank_t const * bank ); \
     695             :   type * fd_bank_##name##_modify( fd_bank_t * bank );
     696             : FD_BANKS_ITER(X)
     697             : #undef X
     698             : 
     699             : /* Each bank has a fd_stake_delegations_t object which is delta-based.
     700             :    The usage pattern is the same as other bank fields:
     701             :    1. fd_bank_stake_delegations_delta_locking_modify( bank ) will return
     702             :       a mutable pointer to the stake delegations delta object. If the
     703             :       caller has not yet initialized the delta object, then it will
     704             :       be initialized. Because it is a delta it is not copied over from
     705             :       a parent bank.
     706             :    2. fd_bank_stake_delegations_delta_locking_query( bank ) will return
     707             :       a const pointer to the stake delegations delta object. If the
     708             :       delta object has not been initialized, then NULL is returned.
     709             :    3. fd_bank_stake_delegations_delta_locking_end_modify( bank ) will
     710             :       release the write lock on the object.
     711             :    4. fd_bank_stake_delegations_delta_locking_end_query( bank ) will
     712             :       release a read lock on the object.
     713             : */
     714             : 
     715             : static inline fd_stake_delegations_t *
     716          15 : fd_bank_stake_delegations_delta_locking_modify( fd_bank_t * bank ) {
     717          15 :   fd_rwlock_write( &bank->stake_delegations_delta_lock );
     718          15 :   if( !bank->stake_delegations_delta_dirty ) {
     719          15 :     bank->stake_delegations_delta_dirty = 1;
     720          15 :     fd_stake_delegations_init( fd_type_pun( bank->stake_delegations_delta ) );
     721          15 :   }
     722          15 :   return fd_type_pun( bank->stake_delegations_delta );
     723          15 : }
     724             : 
     725             : static inline void
     726          15 : fd_bank_stake_delegations_delta_end_locking_modify( fd_bank_t * bank ) {
     727          15 :   fd_rwlock_unwrite( &bank->stake_delegations_delta_lock );
     728          15 : }
     729             : 
     730             : static inline fd_stake_delegations_t *
     731           0 : fd_bank_stake_delegations_delta_locking_query( fd_bank_t * bank ) {
     732           0 :   fd_rwlock_read( &bank->stake_delegations_delta_lock );
     733           0 :   return bank->stake_delegations_delta_dirty ? fd_stake_delegations_join( bank->stake_delegations_delta ) : NULL;
     734           0 : }
     735             : 
     736             : static inline void
     737           0 : fd_bank_stake_delegations_delta_end_locking_query( fd_bank_t * bank ) {
     738           0 :   fd_rwlock_unread( &bank->stake_delegations_delta_lock );
     739           0 : }
     740             : 
     741             : /* fd_bank_stake_delegations_frontier_query() will return a pointer to
     742             :    the full stake delegations for the current frontier. The caller is
     743             :    responsible that there are no concurrent readers or writers to
     744             :    the stake delegations returned by this function.
     745             : 
     746             :    Under the hood, the function copies the rooted stake delegations and
     747             :    applies all of the deltas for the direct ancestry from the current
     748             :    bank up to the rooted bank to the copy. */
     749             : 
     750             : fd_stake_delegations_t *
     751             : fd_bank_stake_delegations_frontier_query( fd_banks_t * banks,
     752             :                                           fd_bank_t *  bank );
     753             : 
     754             : /* fd_banks_stake_delegations_root_query() will return a pointer to the
     755             :    full stake delegations for the current root. This function should
     756             :    only be called on boot. */
     757             : 
     758             : fd_stake_delegations_t *
     759             : fd_banks_stake_delegations_root_query( fd_banks_t * banks );
     760             : 
     761             : /* Simple getters and setters for the pools/maps in fd_banks_t.  Notably,
     762             :    the pool for the fd_bank_t structs as well as a map and pool pair of
     763             :    the CoW structs in the banks. */
     764             : 
     765             : static inline fd_bank_t *
     766         588 : fd_banks_get_bank_pool( fd_banks_t const * banks ) {
     767         588 :   return fd_banks_pool_join( ((uchar *)banks + banks->pool_offset) );
     768         588 : }
     769             : 
     770             : static inline void
     771             : fd_banks_set_bank_pool( fd_banks_t * banks,
     772          15 :                         fd_bank_t *  bank_pool ) {
     773          15 :   void * bank_pool_mem = fd_banks_pool_leave( bank_pool );
     774          15 :   if( FD_UNLIKELY( !bank_pool_mem ) ) {
     775           0 :     FD_LOG_CRIT(( "Failed to leave bank pool" ));
     776           0 :   }
     777          15 :   banks->pool_offset = (ulong)bank_pool_mem - (ulong)banks;
     778          15 : }
     779             : 
     780             : static inline fd_bank_epoch_rewards_t *
     781         147 : fd_banks_get_epoch_rewards_pool( fd_banks_t * banks ) {
     782         147 :   return fd_bank_epoch_rewards_pool_join( (uchar *)banks + banks->epoch_rewards_pool_offset );
     783         147 : }
     784             : 
     785             : static inline void
     786          15 : fd_banks_set_epoch_rewards_pool( fd_banks_t * banks, fd_bank_epoch_rewards_t * epoch_rewards_pool ) {
     787          15 :   void * epoch_rewards_pool_mem = fd_bank_epoch_rewards_pool_leave( epoch_rewards_pool );
     788          15 :   if( FD_UNLIKELY( !epoch_rewards_pool_mem ) ) {
     789           0 :     FD_LOG_CRIT(( "Failed to leave epoch rewards pool" ));
     790           0 :   }
     791          15 :   banks->epoch_rewards_pool_offset = (ulong)epoch_rewards_pool_mem - (ulong)banks;
     792          15 : }
     793             : 
     794             : static inline fd_bank_epoch_leaders_t *
     795         147 : fd_banks_get_epoch_leaders_pool( fd_banks_t * banks ) {
     796         147 :   return fd_bank_epoch_leaders_pool_join( (uchar *)banks + banks->epoch_leaders_pool_offset );
     797         147 : }
     798             : 
     799             : static inline void
     800          15 : fd_banks_set_epoch_leaders_pool( fd_banks_t * banks, fd_bank_epoch_leaders_t * epoch_leaders_pool ) {
     801          15 :   void * epoch_leaders_pool_mem = fd_bank_epoch_leaders_pool_leave( epoch_leaders_pool );
     802          15 :   if( FD_UNLIKELY( !epoch_leaders_pool_mem ) ) {
     803           0 :     FD_LOG_CRIT(( "Failed to leave epoch leaders pool" ));
     804           0 :   }
     805          15 :   banks->epoch_leaders_pool_offset = (ulong)epoch_leaders_pool_mem - (ulong)banks;
     806          15 : }
     807             : 
     808             : static inline fd_bank_vote_states_t *
     809         162 : fd_banks_get_vote_states_pool( fd_banks_t * banks ) {
     810         162 :   return fd_bank_vote_states_pool_join( (uchar *)banks + banks->vote_states_pool_offset );
     811         162 : }
     812             : 
     813             : static inline void
     814          15 : fd_banks_set_vote_states_pool( fd_banks_t * banks, fd_bank_vote_states_t * vote_states_pool ) {
     815          15 :   void * vote_states_pool_mem = fd_bank_vote_states_pool_leave( vote_states_pool );
     816          15 :   if( FD_UNLIKELY( !vote_states_pool_mem ) ) {
     817           0 :     FD_LOG_CRIT(( "Failed to leave vote states pool" ));
     818           0 :   }
     819          15 :   banks->vote_states_pool_offset = (ulong)vote_states_pool_mem - (ulong)banks;
     820          15 : }
     821             : 
     822             : static inline fd_bank_vote_states_prev_t *
     823         162 : fd_banks_get_vote_states_prev_pool( fd_banks_t * banks ) {
     824         162 :   return fd_bank_vote_states_prev_pool_join( (uchar *)banks + banks->vote_states_prev_pool_offset );
     825         162 : }
     826             : 
     827             : static inline void
     828          15 : fd_banks_set_vote_states_prev_pool( fd_banks_t * banks, fd_bank_vote_states_prev_t * vote_states_prev_pool ) {
     829          15 :   void * vote_states_prev_pool_mem = fd_bank_vote_states_prev_pool_leave( vote_states_prev_pool );
     830          15 :   if( FD_UNLIKELY( !vote_states_prev_pool_mem ) ) {
     831           0 :     FD_LOG_CRIT(( "Failed to leave vote states prev pool" ));
     832           0 :   }
     833          15 :   banks->vote_states_prev_pool_offset = (ulong)vote_states_prev_pool_mem - (ulong)banks;
     834          15 : }
     835             : 
     836             : static inline fd_bank_vote_states_prev_prev_t *
     837         162 : fd_banks_get_vote_states_prev_prev_pool( fd_banks_t * banks ) {
     838         162 :   return fd_bank_vote_states_prev_prev_pool_join( (uchar *)banks + banks->vote_states_prev_prev_pool_offset );
     839         162 : }
     840             : 
     841             : static inline void
     842          15 : fd_banks_set_vote_states_prev_prev_pool( fd_banks_t * banks, fd_bank_vote_states_prev_prev_t * vote_states_prev_prev_pool ) {
     843          15 :   void * vote_states_prev_prev_pool_mem = fd_bank_vote_states_prev_prev_pool_leave( vote_states_prev_prev_pool );
     844          15 :   if( FD_UNLIKELY( !vote_states_prev_prev_pool_mem ) ) {
     845           0 :     FD_LOG_CRIT(( "Failed to leave vote states prev prev pool" ));
     846           0 :   }
     847          15 :   banks->vote_states_prev_prev_pool_offset = (ulong)vote_states_prev_prev_pool_mem - (ulong)banks;
     848          15 : }
     849             : 
     850             : static inline fd_bank_cost_tracker_t *
     851         132 : fd_banks_get_cost_tracker_pool( fd_banks_t * banks ) {
     852         132 :   return fd_bank_cost_tracker_pool_join( (uchar *)banks + banks->cost_tracker_pool_offset );
     853         132 : }
     854             : 
     855             : static inline void
     856             : fd_banks_set_cost_tracker_pool( fd_banks_t *             banks,
     857          15 :                                 fd_bank_cost_tracker_t * cost_tracker_pool ) {
     858          15 :   void * cost_tracker_pool_mem = fd_bank_cost_tracker_pool_leave( cost_tracker_pool );
     859          15 :   if( FD_UNLIKELY( !cost_tracker_pool_mem ) ) {
     860           0 :     FD_LOG_CRIT(( "Failed to leave cost tracker pool" ));
     861           0 :   }
     862          15 :   banks->cost_tracker_pool_offset = (ulong)cost_tracker_pool_mem - (ulong)banks;
     863          15 : }
     864             : 
     865             : /* fd_banks_root() and fd_banks_root_const() returns a non-const and
     866             :    const pointer to the root bank respectively. */
     867             : 
     868             : FD_FN_PURE static inline fd_bank_t const *
     869           0 : fd_banks_root_const( fd_banks_t const * banks ) {
     870           0 :   return fd_banks_pool_ele_const( fd_banks_get_bank_pool( banks ), banks->root_idx );
     871           0 : }
     872             : 
     873             : FD_FN_PURE static inline fd_bank_t *
     874          69 : fd_banks_root( fd_banks_t * banks ) {
     875          69 :   return fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), banks->root_idx );
     876          69 : }
     877             : 
     878             : /* fd_banks_align() returns the alignment of fd_banks_t */
     879             : 
     880             : ulong
     881             : fd_banks_align( void );
     882             : 
     883             : /* fd_banks_footprint() returns the footprint of fd_banks_t.  This
     884             :    includes the struct itself but also the footprint for all of the
     885             :    pools.
     886             : 
     887             :    The footprint of fd_banks_t is determined by the total number
     888             :    of banks that the bank manages.  This is an analog for the max number
     889             :    of unrooted blocks the bank can manage at any given time.
     890             : 
     891             :    We can also further bound the memory footprint of the banks by the
     892             :    max width of forks that can exist at any given time.  The reason for
     893             :    this is that there are several large CoW structs that are only
     894             :    written to during the epoch boundary (e.g. epoch_rewards,
     895             :    epoch_stakes, etc.).  These structs are read-only afterwards. This
     896             :    means if we also bound the max number of forks that can execute
     897             :    through the epoch boundary, we can bound the memory footprint of
     898             :    the banks. */
     899             : 
     900             : ulong
     901             : fd_banks_footprint( ulong max_total_banks,
     902             :                     ulong max_fork_width );
     903             : 
     904             : /* fd_banks_new() creates a new fd_banks_t struct.  This function lays
     905             :    out the memory for all of the constituent fd_bank_t structs and
     906             :    pools depending on the max_total_banks and the max_fork_width for a
     907             :    given block. */
     908             : 
     909             : void *
     910             : fd_banks_new( void * mem,
     911             :               ulong  max_total_banks,
     912             :               ulong  max_fork_width,
     913             :               int    larger_max_cost_per_block,
     914             :               ulong  seed );
     915             : 
     916             : /* fd_banks_join() joins a new fd_banks_t struct. */
     917             : 
     918             : fd_banks_t *
     919             : fd_banks_join( void * mem );
     920             : 
     921             : /* fd_banks_leave() leaves a bank. */
     922             : 
     923             : void *
     924             : fd_banks_leave( fd_banks_t * banks );
     925             : 
     926             : /* fd_banks_delete() deletes a bank. */
     927             : 
     928             : void *
     929             : fd_banks_delete( void * shmem );
     930             : 
     931             : /* fd_banks_init_bank() initializes a new bank in the bank manager.
     932             :    This should only be used during bootup. This returns an initial
     933             :    fd_bank_t with the corresponding bank index set to 0. */
     934             : 
     935             : fd_bank_t *
     936             : fd_banks_init_bank( fd_banks_t * banks );
     937             : 
     938             : /* fd_banks_get_bank_idx returns a bank for a given bank index. */
     939             : 
     940             : static inline fd_bank_t *
     941             : fd_banks_bank_mem_query( fd_banks_t * banks,
     942           0 :                          ulong        bank_idx ) {
     943           0 :   return fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), bank_idx );
     944           0 : }
     945             : 
     946             : static inline fd_bank_t *
     947             : fd_banks_bank_query( fd_banks_t * banks,
     948         153 :                      ulong        bank_idx ) {
     949         153 :   fd_bank_t * bank = fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), bank_idx );
     950         153 :   return (bank->flags&FD_BANK_FLAGS_INIT) ? bank : NULL;
     951         153 : }
     952             : 
     953             : static inline fd_bank_t *
     954             : fd_banks_get_parent( fd_banks_t * banks,
     955           0 :                      fd_bank_t *  bank ) {
     956           0 :   return fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), bank->parent_idx );
     957           0 : }
     958             : 
     959             : /* fd_banks_clone_from_parent() clones a bank from a parent bank.
     960             :    This function links the child bank to its parent bank and copies
     961             :    over the data from the parent bank to the child.  This function
     962             :    assumes that the child and parent banks both have been allocated.
     963             :    The parent bank must be frozen and the child bank must be initialized
     964             :    but not yet used.
     965             : 
     966             :    A more detailed note: not all of the data is copied over and this
     967             :    is a shallow clone.  All of the CoW fields are not copied over and
     968             :    will only be done so if the caller explicitly calls
     969             :    fd_bank_{*}_modify().  This naming was chosen to emulate the
     970             :    semantics of the Agave client. */
     971             : 
     972             : fd_bank_t *
     973             : fd_banks_clone_from_parent( fd_banks_t * banks,
     974             :                             ulong        bank_idx );
     975             : 
     976             : /* fd_banks_advance_root() advances the root bank to the bank manager.
     977             :    This should only be used when a bank is no longer needed and has no
     978             :    active refcnts.  This will prune off the bank from the bank manager.
     979             :    It returns the new root bank.  An invariant of this function is that
     980             :    the new root bank should be a child of the current root bank.
     981             : 
     982             :    All banks that are ancestors or siblings of the new root bank will be
     983             :    cancelled and their resources will be released back to the pool. */
     984             : 
     985             : fd_bank_t const *
     986             : fd_banks_advance_root( fd_banks_t * banks,
     987             :                        ulong        bank_idx );
     988             : 
     989             : /* fd_bank_clear_bank() clears the contents of a bank. This should ONLY
     990             :    be used with banks that have no children and should only be used in
     991             :    testing and fuzzing.
     992             : 
     993             :    This function will memset all non-CoW fields to 0.
     994             : 
     995             :    For all CoW fields, we will reset the indices to its parent. */
     996             : 
     997             : void
     998             : fd_banks_clear_bank( fd_banks_t * banks,
     999             :                      fd_bank_t *  bank,
    1000             :                      ulong        max_vote_accounts );
    1001             : 
    1002             : /* fd_banks_advance_root_prepare returns the highest block that can be
    1003             :    safely advanced between the current root of the fork tree and the
    1004             :    target block.  See the note on safe publishing for more details.  In
    1005             :    general, a node in the fork tree can be pruned if:
    1006             :    (1) the node itself can be pruned, and
    1007             :    (2) all subtrees (except for the one on the rooted fork) forking off
    1008             :        of the node can be pruned.
    1009             :    The highest publishable block is the highest block on the rooted fork
    1010             :    where the above is true, or the rooted child block of such if there
    1011             :    is one.
    1012             : 
    1013             :    This function assumes that the given target block has been rooted by
    1014             :    consensus.  It will mark every block on the rooted fork as rooted, up
    1015             :    to the given target block.  It will also mark minority forks as dead.
    1016             : 
    1017             :    Highest advanceable block is written to the out pointer.  Returns 1
    1018             :    if the advanceable block can be advanced beyond the current root.
    1019             :    Returns 0 if no such block can be found.  We will ONLY advance our
    1020             :    advanceable_bank_idx to a child of the current root.  In order to
    1021             :    advance to the target bank, fd_banks_advance_root_prepare() must be
    1022             :    called repeatedly. */
    1023             : 
    1024             : int
    1025             : fd_banks_advance_root_prepare( fd_banks_t * banks,
    1026             :                                ulong        target_bank_idx,
    1027             :                                ulong *      advanceable_bank_idx_out );
    1028             : 
    1029             : /* fd_banks_mark_bank_dead marks the current bank (and all of its
    1030             :    descendants) as dead.  The caller is still responsible for handling
    1031             :    the behavior of the dead bank correctly. */
    1032             : 
    1033             : void
    1034             : fd_banks_mark_bank_dead( fd_banks_t * banks,
    1035             :                          fd_bank_t *  bank );
    1036             : 
    1037             : /* fd_banks_mark_bank_frozen marks the current bank as frozen.  This
    1038             :    should be done when the bank is no longer being updated: it should be
    1039             :    done at the end of a slot.  This also releases the memory for the
    1040             :    cost tracker which only has to be persisted from the start of a slot
    1041             :    to the end. */
    1042             : 
    1043             : void
    1044             : fd_banks_mark_bank_frozen( fd_banks_t * banks,
    1045             :                            fd_bank_t *  bank );
    1046             : 
    1047             : /* fd_banks_new_bank reserves a bank index for a new bank.  New bank
    1048             :    indicies should always be available.  After this function is called,
    1049             :    the bank will be linked to its parent bank, but not yet replayable.
    1050             :    After a call to fd_banks_clone_from_parent, the bank will be
    1051             :    replayable.  This assumes that there is a parent bank which exists
    1052             :    and the there are available bank indices in the bank pool. */
    1053             : 
    1054             : fd_bank_t *
    1055             : fd_banks_new_bank( fd_banks_t * banks,
    1056             :                    ulong        parent_bank_idx,
    1057             :                    long         now );
    1058             : 
    1059             : 
    1060             : /* fd_banks_is_full returns 1 if the banks are full, 0 otherwise. */
    1061             : 
    1062             : static inline int
    1063           0 : fd_banks_is_full( fd_banks_t * banks ) {
    1064           0 :   return fd_banks_pool_free( fd_banks_get_bank_pool( banks ) )==0UL;
    1065           0 : }
    1066             : 
    1067             : FD_PROTOTYPES_END
    1068             : 
    1069             : #endif /* HEADER_fd_src_flamenco_runtime_fd_bank_h */

Generated by: LCOV version 1.14