LCOV - code coverage report
Current view: top level - flamenco/stakes - fd_vote_states.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 1 1 100.0 %
Date: 2025-09-19 04:41:14 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_stakes_fd_vote_states_h
       2             : #define HEADER_fd_src_flamenco_stakes_fd_vote_states_h
       3             : 
       4             : #include "../../util/fd_util_base.h"
       5             : #include "../../util/tmpl/fd_map.h"
       6             : #include "../types/fd_types_custom.h"
       7             : 
       8           3 : #define FD_VOTE_STATES_MAGIC (0xF17EDA2CE7601E70UL) /* FIREDANCER VOTER V0 */
       9             : 
      10             : /* fd_vote_states_t is a cache of vote accounts mapping the pubkey of
      11             :    a vote account to various infromation about the vote account
      12             :    including, stake, last vote slot/timestamp, commission, and the
      13             :    epoch credits for the vote account.
      14             : 
      15             :    In the runtime, there are 3 instances of fd_vote_states_t that are
      16             :    maintained and used at different points, notably around epoch reward
      17             :    and leader schedule calculations. The 3 instances are:
      18             :    1. vote_states: This is the vote states for the current epoch. This
      19             :       is updated through the course of an epoch as vote accounts are
      20             :       updated.
      21             :    2. vote_states_prev: This is the vote states as of the end of
      22             :       previous epoch E-1 if we are currently executing epoch E.
      23             :       This gets updated at the end of an epoch when vote_states are
      24             :       copied into vote_states_prev.
      25             :    3. vote_states_prev_prev: This is the vote states as of the end of
      26             :       epoch E-2 if we are currently executing epoch E. This only gets
      27             :       updated at the end of an epoch when vote_states_prev is copied
      28             :       into vote_states_prev_prev.
      29             : 
      30             :    The implementation of fd_vote_states_t is a hash map which is backed
      31             :    by a memory pool. Callers are allowed to insert, replace, and remove
      32             :    entries from the map.
      33             : 
      34             :    In practice, fd_vote_states_t are updated in 3 cases:
      35             :    1. They are initially populated from the versioned vote account
      36             :       stake accounts in the snapshot manifest. These are populated from
      37             :       the raw vote account data. This is done in a single pass over the
      38             :       vote account data.
      39             :    2. The vote states for the current epoch can be updated after
      40             :       transaction execution. This is done for vote accounts that are
      41             :       referenced during a transaction.
      42             :    3. Vote states are updated at the epoch boundary. The stake
      43             :       information for the vote states is refreshed at the boundary.
      44             :       TODO: The total stake delegated to a vote account should be
      45             :       calculated during execution as the stake delegations are updated.
      46             : */
      47             : 
      48             : #define FD_VOTE_STATES_ALIGN (128UL)
      49             : 
      50             : /* Agave defines the max number of epoch credits to store to be 64.
      51             :    https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v2.2.6/vote-interface/src/state/mod.rs#L37 */
      52             : #define EPOCH_CREDITS_MAX (64UL)
      53             : 
      54             : struct fd_vote_state_ele {
      55             :   fd_pubkey_t vote_account;
      56             :   fd_pubkey_t node_account;
      57             :   ulong       next_; /* Internal pool/map use */
      58             :   ulong       stake;
      59             :   ulong       last_vote_slot;
      60             :   long        last_vote_timestamp;
      61             :   uchar       commission;
      62             : 
      63             :   ulong       credits_cnt;
      64             :   ushort      epoch       [ EPOCH_CREDITS_MAX ];
      65             :   ulong       credits     [ EPOCH_CREDITS_MAX ];
      66             :   ulong       prev_credits[ EPOCH_CREDITS_MAX ];
      67             : };
      68             : typedef struct fd_vote_state_ele fd_vote_state_ele_t;
      69             : 
      70             : /* Forward declare map iterator API generated by fd_map_chain.c */
      71             : typedef struct fd_vote_state_map_private fd_vote_state_map_t;
      72             : typedef struct fd_map_chain_iter fd_vote_state_map_iter_t;
      73             : struct fd_vote_states_iter {
      74             :   fd_vote_state_map_t *    map;
      75             :   fd_vote_state_ele_t *    pool;
      76             :   fd_vote_state_map_iter_t iter;
      77             : };
      78             : typedef struct fd_vote_states_iter fd_vote_states_iter_t;
      79             : 
      80             : struct __attribute__((aligned(FD_VOTE_STATES_ALIGN))) fd_vote_states {
      81             :   ulong magic;
      82             :   ulong max_vote_accounts_;
      83             :   ulong pool_offset_;
      84             :   ulong map_offset_;
      85             : };
      86             : typedef struct fd_vote_states fd_vote_states_t;
      87             : 
      88             : /* This guarantees that the pool element alignment is at most 128UL. */
      89             : FD_STATIC_ASSERT(alignof(fd_vote_state_ele_t)<=FD_VOTE_STATES_ALIGN, unexpected pool element alignment);
      90             : 
      91             : /* The static footprint of the vote states assumes that there are
      92             :    FD_RUNTIME_MAX_VOTE_ACCOUNTS. It also assumes worst case alignment
      93             :    for each struct. fd_vote_states_t is laid out as first the
      94             :    fd_vote_states_t struct, followed by a pool of fd_vote_state_ele_t
      95             :    structs, followed by a map of fd_vote_state_map_ele_t structs.
      96             :    The pool has FD_RUNTIME_MAX_VOTE_ACCOUNTS elements, and the map
      97             :    has a chain count deteremined by a call to
      98             :    fd_vote_states_chain_cnt_est.
      99             :    NOTE: the footprint is validated to be at least as large as the
     100             :    actual runtime-determined footprint (see test_vote_states.c) */
     101             : 
     102             : #define FD_VOTE_STATES_CHAIN_CNT_EST (32768UL)
     103             : #define FD_VOTE_STATES_FOOTPRINT                                                      \
     104             :   /* First, layout the struct with alignment */                                       \
     105             :   sizeof(fd_vote_states_t) + alignof(fd_vote_states_t) +                              \
     106             :   /* Now layout the pool's data footprint */                                          \
     107             :   FD_VOTE_STATES_ALIGN + sizeof(fd_vote_state_ele_t) * FD_RUNTIME_MAX_VOTE_ACCOUNTS + \
     108             :   /* Now layout the pool's meta footprint */                                          \
     109             :   FD_VOTE_STATES_ALIGN + 128UL /* POOL_ALIGN */ +                                     \
     110             :   /* Now layout the map.  We must make assumptions about the chain */                 \
     111             :   /* count to be equivalent to chain_cnt_est. */                                      \
     112             :   FD_VOTE_STATES_ALIGN + 128UL /* MAP_ALIGN */ + (FD_VOTE_STATES_CHAIN_CNT_EST * sizeof(ulong))
     113             : 
     114             : FD_PROTOTYPES_BEGIN
     115             : 
     116             : /* fd_vote_states_align returns the minimum alignment required for a
     117             :    vote states struct. */
     118             : 
     119             : FD_FN_CONST ulong
     120             : fd_vote_states_align( void );
     121             : 
     122             : /* fd_vote_states_footprint returns the footprint of the vote states
     123             :    struct for a given amount of max vote accounts. */
     124             : 
     125             : FD_FN_CONST ulong
     126             : fd_vote_states_footprint( ulong max_vote_accounts );
     127             : 
     128             : /* fd_vote_states_new creates a new vote states struct with a given
     129             :    number of max vote accounts and a seed. It formats a memory region
     130             :    which is sized based off of the number of vote accounts. */
     131             : 
     132             : void *
     133             : fd_vote_states_new( void * mem,
     134             :                     ulong  max_vote_accounts,
     135             :                     ulong  seed );
     136             : 
     137             : /* fd_vote_states_join joins a vote states struct from a
     138             :    memory region. There can be multiple valid joins for a given memory
     139             :    region but the caller is responsible for accessing memory in a
     140             :    thread-safe manner. */
     141             : 
     142             : fd_vote_states_t *
     143             : fd_vote_states_join( void * mem );
     144             : 
     145             : /* fd_vote_states_update inserts or updates the vote state corresponding
     146             :    to a given account. The caller is expected to pass in valid arrays of
     147             :    epoch, credits, and prev_credits that corresponds to a length of
     148             :    credits_cnt. */
     149             : 
     150             : void
     151             : fd_vote_states_update( fd_vote_states_t *  vote_states,
     152             :                        fd_pubkey_t const * vote_account,
     153             :                        fd_pubkey_t const * node_account,
     154             :                        uchar               commission,
     155             :                        long                last_vote_timestamp,
     156             :                        ulong               last_vote_slot,
     157             :                        ulong               credits_cnt,
     158             :                        ushort *            epoch,
     159             :                        ulong *             credits,
     160             :                        ulong *             prev_credits );
     161             : 
     162             : /* fd_vote_states_update_from_account inserts or updates the vote state
     163             :    corresponding to a valid vote account. This is the same as
     164             :    fd_vote_states_update but is also responsible for decoding the vote
     165             :    account data into a versioned vote state object and extracing the
     166             :    commission and credits. Kills the client if the vote state cannot
     167             :    be decoded. */
     168             : 
     169             : void
     170             : fd_vote_states_update_from_account( fd_vote_states_t *  vote_states,
     171             :                                     fd_pubkey_t const * vote_account,
     172             :                                     uchar const *       account_data,
     173             :                                     ulong               account_data_len );
     174             : 
     175             : /* fd_vote_states_reset_stakes_t resets the stakes to 0 for each of the
     176             :    vote accounts in fd_vote_states_t. */
     177             : 
     178             : void
     179             : fd_vote_states_reset_stakes( fd_vote_states_t * vote_states );
     180             : 
     181             : /* fd_vote_states_update_stake updates the stake for a given vote
     182             :    account. */
     183             : 
     184             : void
     185             : fd_vote_states_update_stake( fd_vote_states_t *  vote_states,
     186             :                              fd_pubkey_t const * vote_account,
     187             :                              ulong               stake );
     188             : 
     189             : /* fd_vote_states_remove removes the vote state corresponding to a given
     190             :    account. Does nothing if the account does not exist. */
     191             : 
     192             : void
     193             : fd_vote_states_remove( fd_vote_states_t *  vote_states,
     194             :                        fd_pubkey_t const * vote_account );
     195             : 
     196             : /* fd_vote_states_query returns the vote state corresponding to a given
     197             :    account. Returns NULL if the account does not exist. This function is
     198             :    safe for concurrent reads, but the caller needs to synchronize
     199             :    concurrent writers to the fd_vote_state_ele_t. */
     200             : 
     201             : fd_vote_state_ele_t *
     202             : fd_vote_states_query( fd_vote_states_t const * vote_states,
     203             :                       fd_pubkey_t const *      vote_account );
     204             : 
     205             : /* fd_vote_states_query_const is the same as fd_vote_states but instead
     206             :    returns a const pointer. */
     207             : 
     208             : fd_vote_state_ele_t const *
     209             : fd_vote_states_query_const( fd_vote_states_t const * vote_states,
     210             :                             fd_pubkey_t const *      vote_account );
     211             : 
     212             : /* fd_vote_states_max returns the maximum number of vote accounts that
     213             :    the vote states struct can support. */
     214             : 
     215             : ulong
     216             : fd_vote_states_max( fd_vote_states_t const * vote_states );
     217             : 
     218             : /* fd_vote_states_cnt returns the number of vote states in the vote
     219             :    states struct. */
     220             : 
     221             : ulong
     222             : fd_vote_states_cnt( fd_vote_states_t const * vote_states );
     223             : 
     224             : /* Iterator API for vote states. The iterator is initialized with a
     225             :    call to fd_vote_states_iter_init. The caller is responsible for
     226             :    managing the memory for the iterator. It is safe to call
     227             :    fd_vote_states_iter_next if the result of
     228             :    fd_vote_states_iter_done() ==0. It is safe to call
     229             :    fd_vote_states_iter_ele() to get the current vote state. As a note,
     230             :    it is safe to modify the vote state acquired from
     231             :    fd_vote_states_iter_ele() as long as the next_ field is not modified
     232             :    (which the caller should never do). It is unsafe to insert or remove
     233             :    fd_vote_state_ele_t from the vote states struct while iterating.
     234             : 
     235             :    Under the hood, the iterator is just a wrapper over the iterator in
     236             :    fd_map_chain.c.
     237             : 
     238             :    Example use:
     239             : 
     240             :    fd_vote_states_iter_t iter_[1];
     241             :    for( fd_vote_states_iter_t * iter = fd_vote_states_iter_init( vote_states, iter_ ); !fd_vote_states_iter_done( iter ); fd_vote_states_iter_next( iter ) ) {
     242             :      fd_vote_state_ele_t * vote_state = fd_vote_states_iter_ele( iter );
     243             :      // Do something with the vote state ...
     244             :    }
     245             : */
     246             : 
     247             : fd_vote_state_ele_t *
     248             : fd_vote_states_iter_ele( fd_vote_states_iter_t * iter );
     249             : 
     250             : fd_vote_states_iter_t *
     251             : fd_vote_states_iter_init( fd_vote_states_iter_t *  iter,
     252             :                           fd_vote_states_t const * vote_states );
     253             : 
     254             : int
     255             : fd_vote_states_iter_done( fd_vote_states_iter_t * iter );
     256             : 
     257             : void
     258             : fd_vote_states_iter_next( fd_vote_states_iter_t * iter );
     259             : 
     260             : FD_PROTOTYPES_END
     261             : 
     262             : #endif /* HEADER_fd_src_flamenco_stakes_fd_vote_states_h */

Generated by: LCOV version 1.14