LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_bank.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 119 166 71.7 %
Date: 2026-03-19 18:19:27 Functions: 43 3315 1.3 %

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

Generated by: LCOV version 1.14