Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_rewards_fd_epoch_rewards_h 2 : #define HEADER_fd_src_flamenco_rewards_fd_epoch_rewards_h 3 : 4 : #include "../runtime/fd_runtime_const.h" 5 : #include "fd_rewards_base.h" 6 : 7 : FD_PROTOTYPES_BEGIN 8 : 9 : /* fd_epoch_rewards_t is the main struct that stores the epoch rewards 10 : data. Specifically, the struct manages storing the stake account 11 : rewards which are distributed over many slots. The number of 12 : partitions are determined by a simple function on the number of stake 13 : accounts. The rewards distribution starts on the first block after 14 : an epoch boundary and the rewards for each partition is distributed 15 : during a single slot. The partitions and reward schedule are 16 : calculated during the epoch boundary and distributed after. 17 : 18 : fd_epoch_rewards_t is usually managed by the banks. It is only 19 : written to during the epoch boundary and is read-only after that. */ 20 : 21 : /* Some useful bounds to size out the epoch rewards struct. */ 22 : 23 : /* The max number of partitions is bounded by the the slots_per_epoch 24 : divided by the MAX_FACTOR_OF_REWARD_BLOCKS_IN_EPOCH. 25 : See hash_rewards_into_partitions() and 26 : Bank::get_reward_distribution_num_blocks(). 27 : 28 : We can find a loose bound by assuming FD_BANKS_SLOTS_PER_EPOCH is the 29 : number of slots in an epoch, there can be: 30 : FD_BANKS_SLOTS_PER_EPOCH / MAX_FACTOR_OF_REWARD_BLOCKS_IN_EPOCH 31 : == 43200UL partitions. 32 : 33 : However, it is possible to find a tighter bound. If we assume that 34 : the max number of stake accounts is FD_BANKS_MAX_STAKE_ACCOUNTS, 35 : then the max number of partiitions is 36 : (FD_BANKS_MAX_STAKE_ACCOUNTS / (STAKE_ACCOUNT_STORES_PER_BLOCK + (FD_BANKS_MAX_STAKE_ACCOUNTS % STAKE_ACCOUNT_STORES_PER_BLOCK))) 37 : == 515UL partitions. 38 : */ 39 13215 : #define FD_REWARDS_MAX_PARTITIONS ((FD_RUNTIME_MAX_STAKE_ACCOUNTS / STAKE_ACCOUNT_STORES_PER_BLOCK) + (FD_RUNTIME_MAX_STAKE_ACCOUNTS % STAKE_ACCOUNT_STORES_PER_BLOCK != 0)) 40 : FD_STATIC_ASSERT( FD_REWARDS_MAX_PARTITIONS == 733, "incorrect FD_REWARDS_MAX_PARTITIONS" ); 41 : FD_STATIC_ASSERT( FD_REWARDS_MAX_PARTITIONS <= FD_RUNTIME_SLOTS_PER_EPOCH / MAX_FACTOR_OF_REWARD_BLOCKS_IN_EPOCH, "incorrect FD_REWARDS_MAX_PARTITIONS" ); 42 : 43 : /* The max of footprint of fd_epoch_stakes is variable depending on the 44 : number of stake accounts that are supported. However, the size can be 45 : bounded out assuming worst case with 3M stake accounts. The total 46 : struct contains the top level header struct, the pool, and the dlists 47 : 48 : fd_epoch_stake_reward_t: 4192 bytes + 64 bytes align = 4224 bytes 49 : 50 : pool's private meta: 32 bytes + 96 bytes align = 128 bytes 51 : each pool member: 72 bytes + 56 bytes align = 128 bytes 52 : all pool members: 128 bytes * 3M = 384 MB 53 : 54 : each dlist: 24 bytes for sizeof(DLIST_T) = 24 bytes 55 : all dlists: 24 bytes * 733 max partitions = 17592 bytes 56 : 57 : total footprint: 4224 bytes + 384 MB + 17592 bytes = 384021816 bytes 58 : */ 59 : #define FD_EPOCH_REWARDS_FOOTPRINT (384021816UL) 60 : 61 855 : #define FD_EPOCH_REWARDS_ALIGN (128UL) 62 : 63 6 : #define FD_EPOCH_REWARDS_MAGIC (0x122400081001UL) 64 : 65 : struct fd_epoch_stake_reward { 66 : ulong prev; 67 : ulong next; 68 : ulong parent; 69 : fd_pubkey_t stake_pubkey; 70 : ulong credits_observed; 71 : ulong lamports; 72 : }; 73 : typedef struct fd_epoch_stake_reward fd_epoch_stake_reward_t; 74 : 75 : #define POOL_NAME fd_epoch_stake_reward_pool 76 30 : #define POOL_T fd_epoch_stake_reward_t 77 : #include "../../util/tmpl/fd_pool.c" 78 : 79 : #define DLIST_NAME fd_epoch_stake_reward_dlist 80 : #define DLIST_ELE_T fd_epoch_stake_reward_t 81 : #include "../../util/tmpl/fd_dlist.c" 82 : 83 : struct fd_epoch_rewards { 84 : ulong magic; 85 : 86 : /* Data representing the partitioned stake rewards */ 87 : int is_active_; 88 : ulong stake_account_max_; 89 : ulong starting_block_height_; 90 : ulong num_partitions_; 91 : ulong partitions_lengths_[FD_REWARDS_MAX_PARTITIONS]; 92 : 93 : /* Result of total rewards distribution */ 94 : 95 : /* Total rewards for the epoch (including both vote rewards and stake 96 : rewards) */ 97 : ulong total_rewards_; 98 : /* total rewards points calculated for the current epoch, where points 99 : equals the sum of (delegated stake * credits observed) for all 100 : delegations */ 101 : ulong distributed_rewards_; 102 : /* Stake rewards that still need to be distributed, grouped by 103 : partition */ 104 : uint128 total_points_; 105 : 106 : /* This will be followed by a pool of fd_epoch_stake_reward_t. This 107 : pool will be sized out to FD_BANKS_MAX_STAKE_ACCOUNTS. */ 108 : 109 : /* The pool will be followed by up to FD_REWARDS_MAX_PARTITIONS 110 : that will all need to be joined. */ 111 : 112 : }; 113 : typedef struct fd_epoch_rewards fd_epoch_rewards_t; 114 : 115 : 116 : /* fd_epoch_rewards_align returns the alignment of the epoch rewards 117 : struct. */ 118 : 119 : ulong 120 : fd_epoch_rewards_align( void ); 121 : 122 : /* fd_epoch_rewards_footprint returns the footprint of the epoch rewards 123 : struct. */ 124 : 125 : ulong 126 : fd_epoch_rewards_footprint( ulong stake_account_max ); 127 : 128 : /* fd_epoch_rewards_new initializes the epoch_rewards struct. */ 129 : void * 130 : fd_epoch_rewards_new( void * shmem, ulong stake_account_max ); 131 : 132 : /* fd_epoch_rewards_join returns a pointer to the epoch rewards struct 133 : that is stored in the shared memory. */ 134 : 135 : fd_epoch_rewards_t * 136 : fd_epoch_rewards_join( void * shmem ); 137 : 138 : /* fd_epoch_rewards_leave returns a pointer to the epoch rewards struct 139 : that is stored in the shared memory. */ 140 : 141 : void * 142 : fd_epoch_rewards_leave( fd_epoch_rewards_t const * epoch_rewards ); 143 : 144 : /* fd_epoch_rewards_delete unformats the epoch rewards struct and the 145 : memory that the struct manages. */ 146 : 147 : void * 148 : fd_epoch_rewards_delete( void * epoch_rewards ); 149 : 150 : /* fd_epoch_rewards_get_partition_index returns a pointer to the dlist 151 : of stake rewards for the given partition index. */ 152 : 153 : fd_epoch_stake_reward_dlist_t * 154 : fd_epoch_rewards_get_partition_index( fd_epoch_rewards_t const * epoch_rewards, ulong idx ); 155 : 156 : /* fd_epoch_rewards_get_stake_reward_pool returns a pointer to the pool 157 : of stake rewards. */ 158 : 159 : fd_epoch_stake_reward_t * 160 : fd_epoch_rewards_get_stake_reward_pool( fd_epoch_rewards_t const * epoch_rewards ); 161 : 162 : /* fd_epoch_rewards_hash_and_insert determines the hash partition that 163 : the stake pubkey belongs in and stores the pubkey along with the 164 : total amount of credits and lamports. */ 165 : 166 : int 167 : fd_epoch_rewards_hash_and_insert( fd_epoch_rewards_t * epoch_rewards, 168 : fd_hash_t const * parent_blockhash, 169 : fd_pubkey_t const * pubkey, 170 : ulong credits, 171 : ulong lamports ); 172 : 173 : /* fd_epoch_rewards_get_distribution_partition_index determines the 174 : hash partition that the current block belongs in. */ 175 : 176 : ulong 177 : fd_epoch_rewards_get_distribution_partition_index( fd_epoch_rewards_t const * epoch_rewards, ulong curr_block_height ); 178 : 179 : /* Simple inline mutator functions */ 180 : 181 : static void FD_FN_UNUSED 182 3 : fd_epoch_rewards_set_active( fd_epoch_rewards_t * epoch_rewards, int is_active ) { 183 3 : epoch_rewards->is_active_ = is_active; 184 3 : } 185 : 186 : static void FD_FN_UNUSED 187 3 : fd_epoch_rewards_set_starting_block_height( fd_epoch_rewards_t * epoch_rewards, ulong block_height ) { 188 3 : epoch_rewards->starting_block_height_ = block_height; 189 3 : } 190 : 191 : static void FD_FN_UNUSED 192 6 : fd_epoch_rewards_set_num_partitions( fd_epoch_rewards_t * epoch_rewards, ulong num_partitions ) { 193 6 : if( FD_UNLIKELY( num_partitions>FD_REWARDS_MAX_PARTITIONS ) ) { 194 3 : FD_LOG_WARNING(( "num_partitions: %lu is greater than FD_REWARDS_MAX_PARTITIONS: %lu", num_partitions, FD_REWARDS_MAX_PARTITIONS )); 195 3 : return; 196 3 : } 197 3 : epoch_rewards->num_partitions_ = num_partitions; 198 3 : } 199 : 200 : static void FD_FN_UNUSED 201 3 : fd_epoch_rewards_set_distributed_rewards( fd_epoch_rewards_t * epoch_rewards, ulong distributed_rewards ) { 202 3 : epoch_rewards->distributed_rewards_ = distributed_rewards; 203 3 : } 204 : 205 : static void FD_FN_UNUSED 206 3 : fd_epoch_rewards_set_total_rewards( fd_epoch_rewards_t * epoch_rewards, ulong total_rewards ) { 207 3 : epoch_rewards->total_rewards_ = total_rewards; 208 3 : } 209 : 210 : static void FD_FN_UNUSED 211 3 : fd_epoch_rewards_set_total_points( fd_epoch_rewards_t * epoch_rewards, uint128 total_points ) { 212 3 : epoch_rewards->total_points_ = total_points; 213 3 : } 214 : 215 : /* Simple inline accessor functions */ 216 : 217 : static int FD_FN_UNUSED 218 9 : fd_epoch_rewards_is_active( fd_epoch_rewards_t const * epoch_rewards ) { 219 9 : return epoch_rewards->is_active_; 220 9 : } 221 : 222 : static ulong FD_FN_UNUSED 223 312 : fd_epoch_rewards_get_num_partitions( fd_epoch_rewards_t const * epoch_rewards ) { 224 312 : return epoch_rewards->num_partitions_; 225 312 : } 226 : 227 : static ulong FD_FN_UNUSED 228 9 : fd_epoch_rewards_get_starting_block_height( fd_epoch_rewards_t const * epoch_rewards ) { 229 9 : return epoch_rewards->starting_block_height_; 230 9 : } 231 : 232 : static ulong FD_FN_UNUSED 233 6 : fd_epoch_rewards_get_exclusive_ending_block_height( fd_epoch_rewards_t const * epoch_rewards ) { 234 6 : return epoch_rewards->starting_block_height_ + epoch_rewards->num_partitions_; 235 6 : } 236 : 237 : static ulong FD_FN_UNUSED 238 9 : fd_epoch_rewards_get_distributed_rewards( fd_epoch_rewards_t const * epoch_rewards ) { 239 9 : return epoch_rewards->distributed_rewards_; 240 9 : } 241 : 242 : static uint128 FD_FN_UNUSED 243 9 : fd_epoch_rewards_get_total_points( fd_epoch_rewards_t const * epoch_rewards ) { 244 9 : return epoch_rewards->total_points_; 245 9 : } 246 : 247 : static ulong FD_FN_UNUSED 248 9 : fd_epoch_rewards_get_total_rewards( fd_epoch_rewards_t const * epoch_rewards ) { 249 9 : return epoch_rewards->total_rewards_; 250 9 : } 251 : 252 : FD_PROTOTYPES_END 253 : 254 : #endif /* HEADER_fd_src_flamenco_rewards_fd_epoch_rewards_h */