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