LCOV - code coverage report
Current view: top level - flamenco/leaders - fd_leaders.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 30 31 96.8 %
Date: 2026-04-23 06:43:46 Functions: 10 382 2.6 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_leaders_fd_leaders_h
       2             : #define HEADER_fd_src_flamenco_leaders_fd_leaders_h
       3             : 
       4             : /* fd_leaders provides APIs for the Solana leader schedule.
       5             :    Logic is compatible with Solana mainnet as of 2023-Jul.
       6             : 
       7             :    Every slot is assigned a leader (identified by a "node identity"
       8             :    public key).  The sequence of leaders for all slots in an epoch is
       9             :    called the "leader schedule".  The main responsibility of the leader
      10             :    is to produce a block for the slot.
      11             : 
      12             :    The leader schedule is divided into sched_cnt rotations.  Each
      13             :    rotation spans one or more slots, such that
      14             : 
      15             :      slots_per_epoch = sched_cnt * slots_per_rotation
      16             : 
      17             :    The leader can only change between rotations.  An example leader
      18             :    schedule looks as follows (where A, B, C are node identities and each
      19             :    column is a slot, with 4 slots per rotation)
      20             : 
      21             :      A  A  A  A  B  B  B  B  B  B  B  B  C  C  C  C  A  A  A  A
      22             :      ^           ^           ^           ^           ^
      23             :      rotation    rotation    rotation    rotation    rotation
      24             : 
      25             :    The mainnet epoch duration is quite long (currently 432000 slots, for
      26             :    more information see fd_sysvar_epoch_schedule.h).  To save space, we
      27             :    dedup pubkeys into a lookup table and only store an index for each
      28             :    rotation. */
      29             : 
      30             : #include "fd_leaders_base.h"
      31             : #include "../../ballet/wsample/fd_wsample.h"
      32             : 
      33          45 : #define FD_ULONG_MAX(  a, b ) (__builtin_choose_expr( __builtin_constant_p( a ) & __builtin_constant_p( b ),        \
      34          45 :                                                       ((ulong )(a))>=((ulong )(b)) ? ((ulong )(a)) : ((ulong )(b)), \
      35          45 :                                                       fd_ulong_max( (a), (b) ) ))
      36             : 
      37             : /* FD_EPOCH_LEADERS_{ALIGN,FOOTPRINT} are compile-time-friendly versions
      38             :    of the fd_epoch_leaders_{align,footprint} functions. */
      39             : 
      40           0 : #define FD_EPOCH_LEADERS_ALIGN (64UL)
      41        7092 : #define FD_EPOCH_LEADERS_BITSET_WORD_CNT( pub_cnt ) (((pub_cnt)+1UL+63UL)/64UL)
      42             : #define FD_EPOCH_LEADERS_BITSET_FOOTPRINT( pub_cnt ) (FD_EPOCH_LEADERS_BITSET_WORD_CNT( pub_cnt )*sizeof(ulong))
      43             : #define FD_EPOCH_LEADERS_FOOTPRINT( pub_cnt, slot_cnt )                                                     \
      44       15219 :   ( FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND(                                                     \
      45       15219 :     FD_LAYOUT_INIT,                                                                                         \
      46       15219 :       alignof(fd_epoch_leaders_t), sizeof(fd_epoch_leaders_t)                            ),                 \
      47       15219 :       alignof(uint),               (                                                                        \
      48       15219 :         (slot_cnt+FD_EPOCH_SLOTS_PER_ROTATION-1UL)/FD_EPOCH_SLOTS_PER_ROTATION*sizeof(uint)                 \
      49       15219 :         )                                                                                ),                 \
      50       15219 :       FD_EPOCH_LEADERS_ALIGN                                                             )  +               \
      51       15219 :       FD_ULONG_ALIGN_UP( FD_ULONG_MAX( 32UL*((pub_cnt)+1UL) + FD_EPOCH_LEADERS_BITSET_FOOTPRINT( pub_cnt ), \
      52       15219 :                                        FD_WSAMPLE_FOOTPRINT( pub_cnt, 0 ) ), 64UL ) )
      53             : 
      54     4328607 : #define FD_EPOCH_SLOTS_PER_ROTATION (4UL)
      55             : 
      56             : /* fd_epoch_leaders_t contains the leader schedule of a Solana epoch. */
      57             : 
      58             : struct fd_epoch_leaders {
      59             :   /* This struct contains the schedule for epoch `epoch` which spans
      60             :      slots [slot0, slot0+slot_cnt). */
      61             :   ulong epoch;
      62             :   ulong slot0;
      63             :   ulong slot_cnt;
      64             : 
      65             :   /* pub is a lookup table for node public keys with length pub_cnt */
      66             :   fd_pubkey_t * pub;
      67             :   ulong         pub_cnt;
      68             : 
      69             :   /* sched contains the leader schedule in the form of indexes into
      70             :      the pub array.  For sched_cnt, refer to below. */
      71             :   uint *        sched;
      72             :   ulong         sched_cnt;
      73             : 
      74             :   /* leader_bits stores whether pub[idx] appears at least once in sched.
      75             :      Includes one extra index for the indeterminate leader at idx==pub_cnt. */
      76             :   ulong *       leader_bits;
      77             :   ulong         leader_bits_word_cnt;
      78             : };
      79             : typedef struct fd_epoch_leaders fd_epoch_leaders_t;
      80             : 
      81             : FD_PROTOTYPES_BEGIN
      82             : 
      83             : /* fd_epoch_leaders_{align,footprint} describe the required footprint
      84             :    and alignment of the leader schedule object.  pub_cnt is the number
      85             :    of unique public keys.  slot_cnt is the number of slots in the
      86             :    epoch. */
      87             : 
      88             : FD_FN_CONST ulong
      89             : fd_epoch_leaders_align( void );
      90             : 
      91             : FD_FN_CONST ulong
      92             : fd_epoch_leaders_footprint( ulong pub_cnt,
      93             :                             ulong slot_cnt );
      94             : 
      95             : /* fd_epoch_leaders_new formats a memory region for use as a leader
      96             :    schedule object.  shmem points to the first byte of a memory region
      97             :    with matching alignment and footprint requirements.  The leader
      98             :    schedule object will contain the leader schedule for epoch `epoch`
      99             :    which spans slots [slot0, slot0+slot_cnt).  `slot0` must be the first
     100             :    slot in the epoch, but slot_cnt can be less than the length of the
     101             :    epoch to derive only the first portion of the leader schedule.
     102             :    pub_cnt is the number of unique public keys in this schedule.
     103             :    `stakes` points to the first entry of pub_cnt entries of stake
     104             :    weights sorted by tuple (stake, pubkey) in descending order.
     105             : 
     106             :    If `stakes` does not include all staked nodes, e.g. in the case of an
     107             :    attack that swamps the network with fake validators, `stakes` should
     108             :    contain the first `pub_cnt` of them in the normal sort order, and the
     109             :    sum of the remaining stake must be provided in excluded_stake,
     110             :    measured in lamports.
     111             : 
     112             :    Does NOT retain a read interest in stakes upon return.
     113             :    The caller is not joined to the object on return. */
     114             : void *
     115             : fd_epoch_leaders_new( void  *                  shmem,
     116             :                       ulong                    epoch,
     117             :                       ulong                    slot0,
     118             :                       ulong                    slot_cnt,
     119             :                       ulong                    pub_cnt,
     120             :                       fd_vote_stake_weight_t * stakes, /* indexed [0, pub_cnt) */
     121             :                       ulong                    excluded_stake );
     122             : 
     123             : /* fd_epoch_leaders_join joins the caller to the leader schedule object.
     124             :    fd_epoch_leaders_leave undoes an existing join. */
     125             : 
     126             : fd_epoch_leaders_t *
     127             : fd_epoch_leaders_join( void * shleaders );
     128             : 
     129             : void *
     130             : fd_epoch_leaders_leave( fd_epoch_leaders_t * leaders );
     131             : 
     132             : /* fd_epoch_leaders_delete unformats a memory region and returns owner-
     133             :    ship back to the caller. */
     134             : 
     135             : void *
     136             : fd_epoch_leaders_delete( void * shleaders );
     137             : 
     138             : /* FD_INDETERMINATE_LEADER has base58 encoding
     139             :    1111111111indeterminateLeader9QSxFYNqsXA.  In hex, this pubkey ends
     140             :    with 0x0badf00d0badf00d. */
     141        7095 : #define FD_INDETERMINATE_LEADER 0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x99U,0xf6U,0x0fU,0x96U,0x2cU,0xddU,\
     142        7095 :                                 0x38U,0x21U,0xf3U,0x0cU,0x16U,0x1dU,0xe3U,0x0aU,0x0bU,0xadU,0xf0U,0x0dU,0x0bU,0xadU,0xf0U,0x0dU
     143             : 
     144             : /* fd_epoch_leaders_get returns a pointer to the selected public key
     145             :    given a slot.  Returns NULL if slot is not in [slot0, slot0+slot_cnt)
     146             :    given the values supplied in fd_epoch_leaders_new.
     147             : 
     148             :    If a non-zero value was provided for excluded_stake in
     149             :    fd_epoch_leaders_new and a validator included in the excluded_stake
     150             :    is the leader for the requested slot, instead of returning the
     151             :    correct value (which is not known), fd_epoch_leaders_get will return
     152             :    a pointer to a pubkey with value FD_INDETERMINATE_LEADER. */
     153             : 
     154             : FD_FN_PURE static inline fd_pubkey_t const *
     155             : fd_epoch_leaders_get( fd_epoch_leaders_t const * leaders,
     156     4315359 :                       ulong                      slot ) {
     157     4315359 :   if( FD_UNLIKELY( leaders==NULL ) ) return NULL;
     158     4315359 :   ulong slot_delta = slot - leaders->slot0;
     159     4315359 :   if( FD_UNLIKELY( slot      < leaders->slot0    ) ) return NULL;
     160     4315131 :   if( FD_UNLIKELY( slot_delta>=leaders->slot_cnt ) ) return NULL;
     161     4314423 :   return (fd_pubkey_t const *)( leaders->pub + leaders->sched[ slot_delta/FD_EPOCH_SLOTS_PER_ROTATION ] );
     162     4315131 : }
     163             : 
     164             : FD_FN_PURE static inline int
     165             : fd_epoch_leaders_is_leader_idx( fd_epoch_leaders_t const * leaders,
     166       15189 :                                 ulong                      idx ) {
     167       15189 :   if( FD_UNLIKELY( leaders==NULL ) ) return 0;
     168       15189 :   if( FD_UNLIKELY( idx>leaders->pub_cnt ) ) return 0;
     169       15183 :   ulong word_idx = idx>>6;
     170       15183 :   if( FD_UNLIKELY( word_idx>=leaders->leader_bits_word_cnt ) ) return 0;
     171       15183 :   return !!( leaders->leader_bits[ word_idx ] & (1UL<<(idx&63UL)) );
     172       15183 : }
     173             : 
     174             : FD_PROTOTYPES_END
     175             : 
     176             : #endif /* HEADER_fd_src_flamenco_leaders_fd_leaders_h */

Generated by: LCOV version 1.14