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