Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_leaders_fd_leaders_base_h 2 : #define HEADER_fd_src_flamenco_leaders_fd_leaders_base_h 3 : 4 : #include "../stakes/fd_stake_weight.h" 5 : #include "../runtime/sysvar/fd_sysvar_base.h" 6 : #include "../features/fd_features.h" 7 : 8 592023 : #define MAX_SHRED_DESTS 40200UL /* 200 * 201 - 1 (exclude self) */ 9 30 : #define MAX_SLOTS_PER_EPOCH 432000UL 10 30 : #define MAX_STAKE_WEIGHTS 2000UL /* validator_admission_ticket limit */ 11 : 12 : /* Follows message structure in fd_stake_ci_stake_msg_init. 13 : Frankendancer only */ 14 : struct fd_stake_weight_msg_t { 15 : ulong epoch; /* Epoch for which the stake weights are valid */ 16 : ulong staked_vote_cnt; /* Number of staked nodes */ 17 : ulong staked_id_cnt; /* Number of staked nodes */ 18 : ulong start_slot; /* Start slot of the epoch */ 19 : ulong slot_cnt; /* Number of slots in the epoch */ 20 : ulong ns_per_slot; /* Slot time duration */ 21 : }; 22 : typedef struct fd_stake_weight_msg_t fd_stake_weight_msg_t; 23 : 24 603 : #define FD_STAKE_CI_STAKE_MSG_HEADER_SZ (sizeof(fd_stake_weight_msg_t)) 25 267 : #define FD_STAKE_CI_STAKE_MSG_RECORD_SZ (sizeof(fd_vote_stake_weight_t)) 26 0 : #define FD_STAKE_CI_ID_WEIGHT_RECORD_SZ (sizeof(fd_stake_weight_t)) 27 0 : #define FD_STAKE_CI_STAKE_MSG_SZ (FD_STAKE_CI_STAKE_MSG_HEADER_SZ + MAX_STAKE_WEIGHTS * (FD_STAKE_CI_STAKE_MSG_RECORD_SZ + FD_STAKE_CI_ID_WEIGHT_RECORD_SZ)) 28 : 29 0 : #define FD_STAKE_OUT_MTU FD_STAKE_CI_STAKE_MSG_SZ 30 : 31 : static inline ulong fd_stake_weight_msg_sz( ulong staked_vote_cnt, 32 0 : ulong staked_id_cnt ) { 33 0 : return FD_STAKE_CI_STAKE_MSG_HEADER_SZ + staked_vote_cnt * FD_STAKE_CI_STAKE_MSG_RECORD_SZ + staked_id_cnt * FD_STAKE_CI_ID_WEIGHT_RECORD_SZ; 34 0 : } 35 : 36 : static inline fd_vote_stake_weight_t * 37 336 : fd_stake_weight_msg_stake_weights( fd_stake_weight_msg_t const * stake_weight_msg ) { 38 336 : return (fd_vote_stake_weight_t *)fd_type_pun( (uchar *)stake_weight_msg + FD_STAKE_CI_STAKE_MSG_HEADER_SZ ); 39 336 : } 40 : 41 : static inline fd_stake_weight_t * 42 267 : fd_stake_weight_msg_id_weights( fd_stake_weight_msg_t const * stake_weight_msg ) { 43 267 : return (fd_stake_weight_t *)fd_type_pun( (uchar *)stake_weight_msg + FD_STAKE_CI_STAKE_MSG_HEADER_SZ + stake_weight_msg->staked_vote_cnt * FD_STAKE_CI_STAKE_MSG_RECORD_SZ ); 44 267 : } 45 : 46 : /* Firedancer only */ 47 : struct fd_epoch_info_msg_t { 48 : ulong epoch; /* Epoch for which the info is valid */ 49 : ulong staked_vote_cnt; /* Number of staked nodes */ 50 : ulong staked_id_cnt; /* Number of staked nodes */ 51 : ulong start_slot; /* Start slot of the epoch */ 52 : ulong slot_cnt; /* Number of slots in the epoch */ 53 : ulong ns_per_slot; /* Slot time duration */ 54 : fd_epoch_schedule_t epoch_schedule; /* Epoch schedule */ 55 : fd_features_t features; /* Feature activation slots */ 56 : }; 57 : typedef struct fd_epoch_info_msg_t fd_epoch_info_msg_t; 58 : 59 348 : #define FD_EPOCH_INFO_MSG_HEADER_SZ (sizeof(fd_epoch_info_msg_t)) 60 0 : #define FD_EPOCH_INFO_MAX_MSG_SZ (FD_EPOCH_INFO_MSG_HEADER_SZ + MAX_STAKE_WEIGHTS * (sizeof(fd_vote_stake_weight_t) + sizeof(fd_stake_weight_t))) 61 0 : #define FD_EPOCH_OUT_MTU FD_EPOCH_INFO_MAX_MSG_SZ 62 : 63 : static inline ulong fd_epoch_info_msg_sz( ulong vote_cnt, 64 0 : ulong id_weight_cnt ) { 65 0 : return FD_EPOCH_INFO_MSG_HEADER_SZ + 66 0 : (vote_cnt * sizeof(fd_vote_stake_weight_t)) + 67 0 : (id_weight_cnt * sizeof(fd_stake_weight_t)); 68 0 : } 69 : 70 : static inline fd_vote_stake_weight_t * 71 174 : fd_epoch_info_msg_stake_weights( fd_epoch_info_msg_t const * epoch_info_msg ) { 72 174 : return (fd_vote_stake_weight_t *)fd_type_pun( (uchar *)epoch_info_msg + FD_EPOCH_INFO_MSG_HEADER_SZ ); 73 174 : } 74 : 75 : static inline fd_stake_weight_t * 76 174 : fd_epoch_info_msg_id_weights( fd_epoch_info_msg_t const * epoch_info_msg ) { 77 174 : return (fd_stake_weight_t *)fd_type_pun( (uchar *)epoch_info_msg + FD_EPOCH_INFO_MSG_HEADER_SZ + epoch_info_msg->staked_vote_cnt * sizeof(fd_vote_stake_weight_t) ); 78 174 : } 79 : 80 : /* compute_id_weights_from_vote_weights() translates vote-based 81 : stake weights into (older) identity-based stake weights. 82 : 83 : Before SIMD-0180, the leader schedule was generated starting from 84 : a list [(id, stake)] where `id` is the validator identity and 85 : `stake` its aggregated stake, and the same list was used to build 86 : the Turbine tree. 87 : 88 : After SIMD-0180, the leader schedule is generated by vote 89 : accounts, i.e. starting from a list [(vote, id, stake)] instead. 90 : This makes it easier to send rewards to the expected vote account. 91 : Notably, turbine tree doesn't change with SIMD-0180, so the old 92 : list [(id, stake)] is still necessary. 93 : 94 : Realistically, there should be a 1:1 relationship between id and 95 : vote, but unfortunately the on chain state allows for a 1:N 96 : relationship (1 id could be associated to N vote accounts). 97 : At the time of writing, testnet has one such example. 98 : id: DtSguGSHVrXdqZU1mKWKocsAjrXMhaC7YJic5xxN1Uom 99 : votes: 100 : - https://solscan.io/account/BbtyLT1ntMFbbXtsJRCZnYjpe7d7TUtyZeGKzod3eNsN?cluster=testnet 101 : - https://solscan.io/account/FFr8Gyjy3Wjeqv6oD4RjbwqD1mVfKycAFxQdASYAfR75?cluster=testnet 102 : 103 : Even when there is a 1:1 relationship, the order of the 2 lists 104 : can be different because validators with the same stake could 105 : be ordered differently by vote vs id. 106 : 107 : Last consideration, this operation is done only once per epoch, twice 108 : at startup. 109 : 110 : The current implementation uses sort in place to avoid extra memory 111 : for a map or tree. */ 112 : ulong 113 : compute_id_weights_from_vote_weights( fd_stake_weight_t * stake_weight, 114 : fd_vote_stake_weight_t const * vote_stake_weight, 115 : ulong staked_cnt ); 116 : 117 : #endif /* HEADER_fd_src_flamenco_leaders_fd_leaders_base_h */