LCOV - code coverage report
Current view: top level - flamenco/leaders - fd_multi_epoch_leaders.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 5 15 33.3 %
Date: 2025-08-07 04:53:16 Functions: 1 32 3.1 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_leaders_fd_multi_epoch_leaders_h
       2             : #define HEADER_fd_src_flamenco_leaders_fd_multi_epoch_leaders_h
       3             : 
       4             : #include "fd_leaders.h"
       5             : 
       6             : /* fd_multi_epoch_leaders is a wrapper around multiple fd_epoch_leaders
       7             :    objects.  It simplifies tracking leader schedules for multiple epochs,
       8             :    and querying to find the leader for a given slot.  While maintaining
       9             :    the leader schedule for the current epoch i, you can also prepare the
      10             :    schedule for epoch i+1 and send to the next epoch's leader as you
      11             :    approach the boundary. */
      12             : 
      13             : typedef uchar __attribute__((aligned(FD_EPOCH_LEADERS_ALIGN)))
      14             :     _lsched_t[FD_EPOCH_LEADERS_FOOTPRINT(MAX_STAKED_LEADERS, MAX_SLOTS_PER_EPOCH)];
      15             : 
      16         192 : #define MULTI_EPOCH_LEADERS_EPOCH_CNT (2UL)
      17             : FD_STATIC_ASSERT(MULTI_EPOCH_LEADERS_EPOCH_CNT == 2UL, "This implementation depends on epoch_cnt==2");
      18             : 
      19             : struct fd_multi_epoch_leaders_priv {
      20             :   fd_epoch_leaders_t * lsched       [ MULTI_EPOCH_LEADERS_EPOCH_CNT ];
      21             :   fd_vote_stake_weight_t vote_stake_weight [ MAX_STAKED_LEADERS ];
      22             : 
      23             :   /* has that epoch's mem experienced a stake_msg_fini? */
      24             :   int                  init_done    [ MULTI_EPOCH_LEADERS_EPOCH_CNT ];
      25             :   struct {
      26             :     ulong epoch;
      27             :     ulong start_slot;
      28             :     ulong slot_cnt;
      29             :     ulong staked_cnt;
      30             :     ulong excluded_stake;
      31             :     ulong vote_keyed_lsched;
      32             :   } scratch[1];
      33             : 
      34             :   _lsched_t _lsched[MULTI_EPOCH_LEADERS_EPOCH_CNT];
      35             : };
      36             : typedef struct fd_multi_epoch_leaders_priv fd_multi_epoch_leaders_priv_t;
      37             : 
      38             : typedef fd_multi_epoch_leaders_priv_t fd_multi_epoch_leaders_t;
      39             : 
      40             : 
      41             : FD_PROTOTYPES_BEGIN
      42             : 
      43             : /* ********    OBJECT LIFECYCLE FUNCTIONS    ******** */
      44             : 
      45             : /* fd_epoch_leaders_{align,footprint} describe the required footprint
      46             :    and alignment of the leader schedule object. They have compile friendly
      47             :    versions for static allocation of underlying mem */
      48             : 
      49             : #define FD_MULTI_EPOCH_LEADERS_ALIGN \
      50          24 :   FD_ULONG_MAX( FD_EPOCH_LEADERS_ALIGN, alignof(fd_multi_epoch_leaders_t) )
      51             : 
      52             : #define FD_MULTI_EPOCH_LEADERS_FOOTPRINT \
      53           0 :   sizeof(fd_multi_epoch_leaders_t)
      54             : 
      55             : FD_FN_CONST static inline ulong
      56          24 : fd_multi_epoch_leaders_align( void ) {
      57          24 :   return FD_MULTI_EPOCH_LEADERS_ALIGN;
      58          24 : }
      59             : 
      60             : FD_FN_CONST static inline ulong
      61           0 : fd_multi_epoch_leaders_footprint( void ) {
      62           0 :   return FD_MULTI_EPOCH_LEADERS_FOOTPRINT;
      63           0 : }
      64             : 
      65             : /* fd_multi_epoch_leaders_new formats a memory region for use as a multi-epoch
      66             :    leader schedule object.  shmem points to the first byte of a memory
      67             :    region with matching alignment and footprint requirements. Returns NULL
      68             :    if shmem is NULL or misaligned. Else returns pointer to formatted memory.
      69             :    Does not join. */
      70             : 
      71             : void *
      72             : fd_multi_epoch_leaders_new( void  * shmem );
      73             : 
      74             : /* fd_multi_epoch_leaders_join joins the caller to the leader schedule object.
      75             :    fd_multi_epoch_leaders_leave undoes an existing join. */
      76             : 
      77             : fd_multi_epoch_leaders_t *
      78             : fd_multi_epoch_leaders_join( void * shleaders );
      79             : 
      80             : void *
      81             : fd_multi_epoch_leaders_leave( fd_multi_epoch_leaders_t * mleaders );
      82             : 
      83             : /* fd_multi_epoch_leaders_delete unformats a memory region and returns owner-
      84             :    ship back to the caller. */
      85             : 
      86             : void *
      87             : fd_multi_epoch_leaders_delete( void * shleaders );
      88             : 
      89             : /* ********    LEADER INFO GETTER FUNCTIONS    ******** */
      90             : 
      91             : /* fd_multi_epoch_leaders_get_stake_{weights,cnt} returns a pointer to
      92             :    the stake weights and count for the latest epoch. Returns null if never
      93             :    initialized. The pointer lifetime is until the next leave on mleaders.
      94             :    However, cnt is the valid length for stake_weights only until the next
      95             :    call to stake_msg_init. */
      96             : FD_FN_PURE static inline fd_vote_stake_weight_t const *
      97           0 : fd_multi_epoch_leaders_get_stake_weights( fd_multi_epoch_leaders_t const * mleaders ) {
      98           0 :    return fd_ptr_if( mleaders->init_done[0] | mleaders->init_done[1], (fd_vote_stake_weight_t const *)mleaders->vote_stake_weight, NULL );
      99           0 : }
     100             : FD_FN_PURE static inline ulong
     101           0 : fd_multi_epoch_leaders_get_stake_cnt( fd_multi_epoch_leaders_t const * mleaders ) {
     102           0 :    return mleaders->scratch->staked_cnt;
     103           0 : }
     104             : 
     105             : /* fd_multi_epoch_leaders_get_leader_for_slot returns a pointer to the selected
     106             :    public key given a slot.  Returns NULL if slot is not in epochs tracked
     107             :    by multi-epoch leader object. If the leader for slot is part of the
     108             :    excluded_stake for that epoch, instead of returning the correct value
     109             :    (which is not known), returns a pointer to a pubkey with value
     110             :    FD_INDETERMINATE_LEADER. */
     111             : 
     112             : FD_FN_PURE fd_pubkey_t const *
     113             : fd_multi_epoch_leaders_get_leader_for_slot( fd_multi_epoch_leaders_t const * mleaders,
     114             :                                             ulong                            slot );
     115             : 
     116             : /* fd_multi_epoch_leaders_get_lsched_for_{epoch,slot} return the leader
     117             :    schedule for epoch or epoch containing slot, respectively.  Returns
     118             :    NULL if not tracked by mleaders. */
     119             : 
     120             : FD_FN_PURE fd_epoch_leaders_t const *
     121             : fd_multi_epoch_leaders_get_lsched_for_epoch( fd_multi_epoch_leaders_t const * mleaders,
     122             :                                              ulong                            epoch );
     123             : FD_FN_PURE fd_epoch_leaders_t const *
     124             : fd_multi_epoch_leaders_get_lsched_for_slot( fd_multi_epoch_leaders_t const * mleaders,
     125             :                                              ulong                           slot   );
     126             : 
     127             : /* fd_multi_epoch_leaders_get_sorted_lscheds returns up to two lscheds,
     128             :    sorted in increasing epoch order. If we only have data for one epoch,
     129             :    the first element will be the corresponding lsched. If no lsched data,
     130             :    both will be null. Lifetime of returned pointers is until next call to
     131             :    fd_multi_epoch_leaders_stake_msg_fini. */
     132             : typedef struct {
     133             :   fd_epoch_leaders_t const * lscheds[2];
     134             : } fd_multi_epoch_leaders_lsched_sorted_t;
     135             : 
     136             : FD_FN_PURE fd_multi_epoch_leaders_lsched_sorted_t
     137             : fd_multi_epoch_leaders_get_sorted_lscheds( fd_multi_epoch_leaders_t const * mleaders );
     138             : 
     139             : 
     140             : /* fd_multi_epoch_leaders_get_next_slot returns the first slot on or after
     141             :    start_slot that 'leader' will be leader. If it can't find one, returns ULONG_MAX.
     142             : 
     143             :    Failures cases include:
     144             :       - mleaders does not track the epoch containing start_slot
     145             :         - It was either never initialized with that epoch information, or
     146             :         - It was overwritten by another epoch with the same parity
     147             :       - leader_q does not have a leader slot in the epochs tracked
     148             :       - leader_q was part of the excluded_stake for that epoch, and the lsched
     149             :         returns FD_INDETERMINATE_LEADER as the leader for leader_q's slots.
     150             : */
     151             : 
     152             : FD_FN_PURE ulong
     153             : fd_multi_epoch_leaders_get_next_slot( fd_multi_epoch_leaders_t const * mleaders,
     154             :                                       ulong                            start_slot,
     155             :                                       fd_pubkey_t const *              leader_q );
     156             : 
     157             : /* ********    STAKE INFO UPDATE METHODS    ******** */
     158             : 
     159             : /* fd_stake_ci_stake_msg_{init, fini} are used to handle messages
     160             :    containing stake weight updates from the Rust side of the splice,.
     161             :    Since these messages arrive on a dcache and can get overrun, both
     162             :    expose a init/fini model. Calling init multiple times without calling
     163             :    fini will not leak any resources.
     164             : 
     165             :    msg should be a pointer to the first byte of the dcache entry
     166             :    containing the stakes update.  msg will be accessed
     167             :    msg->weights[i] for i in [0, msg->staked_cnt).  msg->weights
     168             :    must contain at least one staked pubkey, and the pubkeys must be
     169             :    sorted in the usual way (by stake descending, ties broken by pubkey
     170             :    ascending). multi_epoch_leaders will only use the staked node.
     171             : 
     172             :    init does not maintain a read interest in msg after returning. */
     173             : 
     174             : void
     175             : fd_multi_epoch_leaders_stake_msg_init( fd_multi_epoch_leaders_t    * mleaders,
     176             :                                        fd_stake_weight_msg_t const * msg );
     177             : 
     178             : void
     179             : fd_multi_epoch_leaders_stake_msg_fini( fd_multi_epoch_leaders_t * mleaders );
     180             : 
     181             : 
     182             : FD_PROTOTYPES_END
     183             : 
     184             : #endif /* HEADER_fd_src_flamenco_leaders_fd_multi_epoch_leaders_h */

Generated by: LCOV version 1.14