LCOV - code coverage report
Current view: top level - flamenco/stakes - fd_vote_stakes.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 6 8 75.0 %
Date: 2026-10-22 18:10:43 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_stakes_fd_vote_stakes_h
       2             : #define HEADER_fd_src_flamenco_stakes_fd_vote_stakes_h
       3             : 
       4             : #include "../../util/fd_util_base.h"
       5             : #include "../fd_flamenco_base.h"
       6             : #include "../accdb/fd_accdb_base.h"
       7             : #include "../runtime/program/vote/fd_vote_codec.h"
       8             : 
       9          24 : #define FD_VOTE_STAKES_FD                   (123454)
      10         360 : #define FD_VOTE_STAKES_ALIGN                (128UL)
      11        2345 : #define FD_VOTE_STAKES_ALPENGLOW_RANK_NULL  USHORT_MAX
      12             : 
      13             : /* fd_vote_stakes is the Firedancer equivalent of the Agave epoch stakes
      14             :    data structure.  It is a fork aware data structure that maintains the
      15             :    vote account state that is used for clock and VM syscall calculations
      16             :    during execution.
      17             : 
      18             :    The underlying data structure is a tiered set of caches:
      19             :    - t-2..t-5: these are caches used for the vote account states at
      20             :      the end of the t-2 through t-5 epochs assuming you are currently
      21             :      in the t epoch.  These caches are shared across all forks.
      22             :    - t-1: computed at the most recent epoch boundary.  These sets are
      23             :      ref-counted and fork specific, up to max_live_slots of them;
      24             :      cache_cnt are kept in memory and the rest spill to disk.
      25             :    - state: each bank has its own view of the t-2 state of vote
      26             :      accounts.  This is what is actually used for clock calculations
      27             :      which is a stake weighted median of the last vote slot and
      28             :      timestamp.
      29             : 
      30             :    fd_vote_stakes also handles the creation of new vote stakes caches.
      31             :    The creation of new vote stakes caches happens at the epoch boundary
      32             :    and follows the rules defined in the validator_admission_ticket
      33             :    feature where every vote account must be in the top 2000 by stake.
      34             :    Under the hood, this is managed by a stake-sorted heap that is shared
      35             :    across all forks.
      36             : 
      37             :    NOTE:
      38             :    This system assumes that multiple forks can cross an epoch boundary
      39             :    but only one epoch boundary can be crossed at a time.  This means
      40             :    that there can be multiple t-1 forks after an epoch boundary, but
      41             :    only one will be active when the first fork crosses into an epoch
      42             :    boundary.  Similarly, this means that live forks address 5 epoch
      43             :    sets during an epoch boundary crossing and 4 most of the time:
      44             :    crossing into t+1 evicts the t-6 set, which no live fork addresses. */
      45             : 
      46             : struct fd_vote_stakes;
      47             : typedef struct fd_vote_stakes fd_vote_stakes_t;
      48             : 
      49             : /* fd_vote_stakes_ele_t is a copy of one vote account in a vote stakes
      50             :    set. */
      51             : 
      52             : struct fd_vote_stakes_ele {
      53             :   fd_pubkey_t pubkey;
      54             :   fd_pubkey_t node_account;
      55             :   ulong       stake;
      56             :   ushort      commission;                   /* inflation rewards, basis points */
      57             :   ushort      block_revenue_commission_bps; /* SIMD-0123 */
      58             :   ulong       pending_delegator_rewards;    /* SIMD-0123 */
      59             :   fd_pubkey_t inflation_collector;          /* SIMD-0232 */
      60             :   fd_pubkey_t block_collector;              /* SIMD-0232 */
      61             :   ushort      rank;
      62             :   uchar       bls_key[ FD_BLS_PUBKEY_COMPRESSED_SZ ];
      63             :   uchar       bls_key_uncompressed[ FD_BLS_PUBKEY_UNCOMPRESSED_SZ ];
      64             : 
      65             :   /* The fork's vote state, only set for t-2 (zero otherwise). */
      66             :   ulong       last_vote_slot;
      67             :   long        last_vote_ts;
      68             :   uchar       is_valid;
      69             : };
      70             : typedef struct fd_vote_stakes_ele fd_vote_stakes_ele_t;
      71             : 
      72             : FD_PROTOTYPES_BEGIN
      73             : 
      74             : ulong
      75             : fd_vote_stakes_align( void );
      76             : 
      77             : ulong
      78             : fd_vote_stakes_footprint( ulong max_live_slots,
      79             :                           ulong cache_cnt );
      80             : 
      81             : void *
      82             : fd_vote_stakes_new( void * mem,
      83             :                     int    disk_fd,
      84             :                     ulong  max_live_slots,
      85             :                     ulong  cache_cnt,
      86             :                     ulong  seed );
      87             : 
      88             : fd_vote_stakes_t *
      89             : fd_vote_stakes_join( void * mem,
      90             :                      int    disk_fd );
      91             : 
      92             : /* fd_vote_stakes_fork_epoch returns the epoch of the fork. */
      93             : 
      94             : ulong
      95             : fd_vote_stakes_fork_epoch( ulong fork_id );
      96             : 
      97             : /* fd_vote_stakes_init initializes the vote stakes data structure for a
      98             :    given epoch. */
      99             : 
     100             : ulong
     101             : fd_vote_stakes_init( fd_vote_stakes_t * vote_stakes,
     102             :                      ulong              epoch );
     103             : 
     104             : /* fd_vote_stakes_reset resets the vote stakes data structure. */
     105             : 
     106             : void
     107             : fd_vote_stakes_reset( fd_vote_stakes_t * vote_stakes );
     108             : 
     109             : /* fd_vote_stakes_snap_insert_t_1 inserts a new vote account into the
     110             :    t-1 set.  This skips over any vote account validation and should
     111             :    only be used when loading in vote accounts from a snapshot. */
     112             : 
     113             : void
     114             : fd_vote_stakes_snap_insert_t_1( fd_vote_stakes_t *  vote_stakes,
     115             :                                 ulong               fork_id,
     116             :                                 fd_pubkey_t const * pubkey,
     117             :                                 fd_pubkey_t const * node_account,
     118             :                                 ulong               stake,
     119             :                                 ushort              commission,
     120             :                                 uchar const         bls_key[ static FD_BLS_PUBKEY_COMPRESSED_SZ ],
     121             :                                 ushort              block_revenue_commission_bps,
     122             :                                 ulong               pending_delegator_rewards,
     123             :                                 fd_pubkey_t const * inflation_collector_opt,
     124             :                                 fd_pubkey_t const * block_collector_opt );
     125             : 
     126             : /* fd_vote_stakes_snap_insert_t_2 inserts a new vote account into the
     127             :    t-2 set.  This skips over any vote account validation and should
     128             :    only be used when loading in vote accounts from a snapshot. */
     129             : 
     130             : void
     131             : fd_vote_stakes_snap_insert_t_2( fd_vote_stakes_t *  vote_stakes,
     132             :                                 ulong               fork_id,
     133             :                                 fd_pubkey_t const * pubkey,
     134             :                                 fd_pubkey_t const * node_account,
     135             :                                 ulong               stake,
     136             :                                 ushort              commission,
     137             :                                 uchar const         bls_key[ static FD_BLS_PUBKEY_COMPRESSED_SZ ],
     138             :                                 ushort              block_revenue_commission_bps,
     139             :                                 ulong               pending_delegator_rewards,
     140             :                                 fd_pubkey_t const * inflation_collector_opt,
     141             :                                 fd_pubkey_t const * block_collector_opt );
     142             : 
     143             : /* fd_vote_stakes_snap_insert_t_n inserts a new vote account into the
     144             :    t-n set, n in 3..5, and marks that set resident.  This skips over
     145             :    any vote account validation and should only be used when loading in
     146             :    vote accounts from a snapshot. */
     147             : 
     148             : void
     149             : fd_vote_stakes_snap_insert_t_n( fd_vote_stakes_t *  vote_stakes,
     150             :                                 ulong               fork_id,
     151             :                                 ulong               n,
     152             :                                 fd_pubkey_t const * pubkey,
     153             :                                 fd_pubkey_t const * node_account,
     154             :                                 ulong               stake,
     155             :                                 ushort              commission,
     156             :                                 uchar const         bls_key[ static FD_BLS_PUBKEY_COMPRESSED_SZ ],
     157             :                                 ushort              block_revenue_commission_bps,
     158             :                                 ulong               pending_delegator_rewards,
     159             :                                 fd_pubkey_t const * inflation_collector_opt,
     160             :                                 fd_pubkey_t const * block_collector_opt );
     161             : 
     162             : /* fd_vote_stakes_insert inserts a new vote account into the t-1 set.
     163             :    This can be called repeatedly after a boundary-crossing
     164             :    fd_vote_stakes_new_fork.  An account will only be inserted if it
     165             :    matches the semantics of the validator_admission_ticket feature.
     166             :    The top 2000 vote accounts by stake are inserted into the t-1 set. */
     167             : 
     168             : void
     169             : fd_vote_stakes_insert( fd_vote_stakes_t *  vote_stakes,
     170             :                        ulong               fork_id,
     171             :                        fd_pubkey_t const * pubkey,
     172             :                        fd_pubkey_t const * node_account,
     173             :                        ulong               stake,
     174             :                        ushort              commission,
     175             :                        uchar const         bls_key[ static FD_BLS_PUBKEY_COMPRESSED_SZ ],
     176             :                        ushort              block_revenue_commission_bps,
     177             :                        ulong               pending_delegator_rewards,
     178             :                        fd_pubkey_t const * inflation_collector_opt,
     179             :                        fd_pubkey_t const * block_collector_opt );
     180             : 
     181             : /* fd_vote_stakes_finalize assigns Alpenglow ranks to the set that
     182             :    iter_kind addresses for fork_id.  Accounts with invalid or infinity
     183             :    BLS keys or duplicate BLS/identity keys retain
     184             :    FD_VOTE_STAKES_ALPENGLOW_RANK_NULL but remain in the set.  This is a
     185             :    no-op if the set is not resident. */
     186             : 
     187             : void
     188             : fd_vote_stakes_finalize( fd_vote_stakes_t * vote_stakes,
     189             :                          ulong              fork_id,
     190             :                          int                iter_kind );
     191             : 
     192             : /* fd_vote_stakes_purge_fork removes a t-1 set.  This should be called
     193             :    when the banks are evicting a bank or during root advancement. */
     194             : 
     195             : void
     196             : fd_vote_stakes_purge_fork( fd_vote_stakes_t * vote_stakes,
     197             :                            ulong              fork_id );
     198             : 
     199             : /* fd_vote_stakes_new_fork creates a child of the given parent fork.
     200             :    Within an epoch, the child shares the parent's t-1 set and receives a
     201             :    copy of its t-2 state.  At an epoch boundary, it rotates t-1 into
     202             :    t-2 and acquires fresh t-1 and t-2 state. */
     203             : 
     204             : ulong
     205             : fd_vote_stakes_new_fork( fd_vote_stakes_t * vote_stakes,
     206             :                          ulong              parent_fork_id,
     207             :                          ulong              epoch );
     208             : 
     209             : /* fd_vote_stakes_update updates the vote account state for a given
     210             :    fork id.  It is a no-op if the pubkey corresponds to an account not
     211             :    in the t-2 set.  If is_valid==0, the last vote arguments will be
     212             :    ignored. */
     213             : 
     214             : void
     215             : fd_vote_stakes_update_state( fd_vote_stakes_t *  vote_stakes,
     216             :                              ulong               fork_id,
     217             :                              fd_pubkey_t const * pubkey,
     218             :                              ulong               last_vote_slot,
     219             :                              long                last_vote_ts,
     220             :                              uchar               is_valid );
     221             : 
     222             : void
     223             : fd_vote_stakes_refresh( fd_vote_stakes_t * vote_stakes,
     224             :                         ulong              fork_id,
     225             :                         fd_accdb_t *        accdb,
     226             :                         fd_accdb_fork_id_t  accdb_fork_id );
     227             : 
     228             : /* fd_vote_stakes_query_t_{1,2,3} look up pubkey in the fork's t-1,
     229             :    t-2 or t-3 set and, if ele_out_opt is non-NULL, copy the entry to
     230             :    it.  Only query_t_2 sets the vote state fields.  Returns 1 if the
     231             :    account is in the set, 0 otherwise. */
     232             : 
     233             : int
     234             : fd_vote_stakes_query_t_1( fd_vote_stakes_t *     vote_stakes,
     235             :                           ulong                  fork_id,
     236             :                           fd_pubkey_t const *    pubkey,
     237             :                           fd_vote_stakes_ele_t * ele_out_opt );
     238             : 
     239             : int
     240             : fd_vote_stakes_query_t_2( fd_vote_stakes_t const * vote_stakes,
     241             :                           ulong                    fork_id,
     242             :                           fd_pubkey_t const *      pubkey,
     243             :                           fd_vote_stakes_ele_t *   ele_out_opt );
     244             : 
     245             : int
     246             : fd_vote_stakes_query_t_3( fd_vote_stakes_t const * vote_stakes,
     247             :                           ulong                    fork_id,
     248             :                           fd_pubkey_t const *      pubkey,
     249             :                           fd_vote_stakes_ele_t *   ele_out_opt );
     250             : 
     251             : /* fd_vote_stakes_cnt_t_{1,2} returns the number of vote accounts in the
     252             :    t-1 and t-2 sets respectively. */
     253             : 
     254             : ulong
     255             : fd_vote_stakes_cnt_t_1( fd_vote_stakes_t * vote_stakes,
     256             :                         ulong              fork_id );
     257             : 
     258             : ulong
     259             : fd_vote_stakes_cnt_t_2( fd_vote_stakes_t const * vote_stakes,
     260             :                         ulong                    fork_id );
     261             : 
     262             : ulong
     263             : fd_vote_stakes_t_2_votes( fd_vote_stakes_t const * vote_stakes,
     264             :                           ulong                    fork_id,
     265             :                           ulong *                  stake,
     266             :                           ulong *                  last_vote_slot,
     267             :                           long *                   last_vote_ts );
     268             : 
     269             : /* fd_vote_stakes_total_stake returns the total stake of the epoch
     270             :    stakes set for epoch.
     271             :    epoch must be one of the t-2 through t-5 sets; returns 0 if that
     272             :    epoch's set is not resident. */
     273             : 
     274             : ulong
     275             : fd_vote_stakes_total_stake( fd_vote_stakes_t const * vote_stakes,
     276             :                             ulong                    epoch );
     277             : 
     278             : /* The iterator will NOT skip over invalid vote accounts
     279             :    intentionally.  The reason being is that invalid vote accounts are
     280             :    still considered for stake and leader calculations: the caller is
     281             :    expected to handle the state of each account correctly. */
     282             : 
     283             : #define FD_VOTE_STAKES_ITER_FOOTPRINT     (16UL)
     284             : #define FD_VOTE_STAKES_ITER_ALIGN         (8UL)
     285         419 : #define FD_VOTE_STAKES_ITER_T_1           (1)
     286       18934 : #define FD_VOTE_STAKES_ITER_T_2           (2)
     287         185 : #define FD_VOTE_STAKES_ITER_T_3           (3)
     288           0 : #define FD_VOTE_STAKES_ITER_T_4           (4)
     289           0 : #define FD_VOTE_STAKES_ITER_T_5           (5)
     290             : 
     291             : struct vacc_map_iter;
     292             : typedef struct vacc_map_iter fd_vote_stakes_iter_t;
     293             : 
     294             : /* The iterator walks the fork's set selected by iter_kind.  The vote
     295             :    state fields of the element are only set for T_2. */
     296             : 
     297             : fd_vote_stakes_iter_t *
     298             : fd_vote_stakes_iter_init( fd_vote_stakes_t * vote_stakes,
     299             :                           ulong              fork_id,
     300             :                           int                iter_kind,
     301             :                           uchar              iter_mem[ static FD_VOTE_STAKES_ITER_FOOTPRINT ] );
     302             : 
     303             : int
     304             : fd_vote_stakes_iter_done( fd_vote_stakes_t *      vote_stakes,
     305             :                           ulong                   fork_id,
     306             :                           int                     iter_kind,
     307             :                           fd_vote_stakes_iter_t * iter );
     308             : 
     309             : void
     310             : fd_vote_stakes_iter_next( fd_vote_stakes_t *      vote_stakes,
     311             :                           ulong                   fork_id,
     312             :                           int                     iter_kind,
     313             :                           fd_vote_stakes_iter_t * iter );
     314             : 
     315             : void
     316             : fd_vote_stakes_iter_ele( fd_vote_stakes_t *      vote_stakes,
     317             :                          ulong                   fork_id,
     318             :                          int                     iter_kind,
     319             :                          fd_vote_stakes_iter_t * iter,
     320             :                          fd_vote_stakes_ele_t *  ele_out );
     321             : 
     322             : FD_PROTOTYPES_END
     323             : 
     324             : #endif /* HEADER_fd_src_flamenco_stakes_fd_vote_stakes_h */

Generated by: LCOV version 1.14