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 9291 : #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))) 40 : FD_STATIC_ASSERT( FD_REWARDS_MAX_PARTITIONS == 515UL, "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 * 515 max partitions = 12360 bytes 56 : 57 : total footprint: 4224 bytes + 384 MB + 12360 bytes = 384016584 bytes 58 : */ 59 : #define FD_EPOCH_REWARDS_FOOTPRINT (384016584UL) 60 : /* TODO: Add some static asserts to validate this calculation*/ 61 : 62 843 : #define FD_EPOCH_REWARDS_ALIGN (128UL) 63 : 64 6 : #define FD_EPOCH_REWARDS_MAGIC (0x122400081001UL) 65 : 66 : struct fd_epoch_stake_reward { 67 : ulong prev; 68 : ulong next; 69 : ulong parent; 70 : fd_pubkey_t stake_pubkey; 71 : ulong credits_observed; 72 : ulong lamports; 73 : }; 74 : typedef struct fd_epoch_stake_reward fd_epoch_stake_reward_t; 75 : 76 : #define POOL_NAME fd_epoch_stake_reward_pool 77 30 : #define POOL_T fd_epoch_stake_reward_t 78 : #include "../../util/tmpl/fd_pool.c" 79 : 80 : #define DLIST_NAME fd_epoch_stake_reward_dlist 81 : #define DLIST_ELE_T fd_epoch_stake_reward_t 82 : #include "../../util/tmpl/fd_dlist.c" 83 : 84 : struct fd_epoch_rewards { 85 : ulong magic; 86 : 87 : /* Data representing the partitioned stake rewards */ 88 : int is_active_; 89 : ulong stake_account_max_; 90 : ulong starting_block_height_; 91 : ulong num_partitions_; 92 : ulong partitions_lengths_[FD_REWARDS_MAX_PARTITIONS]; 93 : 94 : /* Result of total rewards distribution */ 95 : 96 : /* Total rewards for the epoch (including both vote rewards and stake 97 : rewards) */ 98 : ulong total_rewards_; 99 : /* total rewards points calculated for the current epoch, where points 100 : equals the sum of (delegated stake * credits observed) for all 101 : delegations */ 102 : ulong distributed_rewards_; 103 : /* Stake rewards that still need to be distributed, grouped by 104 : partition */ 105 : uint128 total_points_; 106 : 107 : /* This will be followed by a pool of fd_epoch_stake_reward_t. This 108 : pool will be sized out to FD_BANKS_MAX_STAKE_ACCOUNTS. */ 109 : 110 : /* The pool will be followed by up to FD_REWARDS_MAX_PARTITIONS 111 : that will all need to be joined. */ 112 : 113 : }; 114 : typedef struct fd_epoch_rewards fd_epoch_rewards_t; 115 : 116 : 117 : /* fd_epoch_rewards_align returns the alignment of the epoch rewards 118 : struct. */ 119 : 120 : ulong 121 : fd_epoch_rewards_align( void ); 122 : 123 : /* fd_epoch_rewards_footprint returns the footprint of the epoch rewards 124 : struct. */ 125 : 126 : ulong 127 : fd_epoch_rewards_footprint( ulong stake_account_max ); 128 : 129 : /* fd_epoch_rewards_new initializes the epoch_rewards struct. */ 130 : void * 131 : fd_epoch_rewards_new( void * shmem, ulong stake_account_max ); 132 : 133 : /* fd_epoch_rewards_join returns a pointer to the epoch rewards struct 134 : that is stored in the shared memory. */ 135 : 136 : fd_epoch_rewards_t * 137 : fd_epoch_rewards_join( void * shmem ); 138 : 139 : /* fd_epoch_rewards_leave returns a pointer to the epoch rewards struct 140 : that is stored in the shared memory. */ 141 : 142 : void * 143 : fd_epoch_rewards_leave( fd_epoch_rewards_t const * epoch_rewards ); 144 : 145 : /* fd_epoch_rewards_delete unformats the epoch rewards struct and the 146 : memory that the struct manages. */ 147 : 148 : void * 149 : fd_epoch_rewards_delete( void * epoch_rewards ); 150 : 151 : /* fd_epoch_rewards_get_partition_index returns a pointer to the dlist 152 : of stake rewards for the given partition index. */ 153 : 154 : fd_epoch_stake_reward_dlist_t * 155 : fd_epoch_rewards_get_partition_index( fd_epoch_rewards_t const * epoch_rewards, ulong idx ); 156 : 157 : /* fd_epoch_rewards_get_stake_reward_pool returns a pointer to the pool 158 : of stake rewards. */ 159 : 160 : fd_epoch_stake_reward_t * 161 : fd_epoch_rewards_get_stake_reward_pool( fd_epoch_rewards_t const * epoch_rewards ); 162 : 163 : /* fd_epoch_rewards_hash_and_insert determines the hash partition that 164 : the stake pubkey belongs in and stores the pubkey along with the 165 : total amount of credits and lamports. */ 166 : 167 : int 168 : fd_epoch_rewards_hash_and_insert( fd_epoch_rewards_t * epoch_rewards, 169 : fd_hash_t const * parent_blockhash, 170 : fd_pubkey_t const * pubkey, 171 : ulong credits, 172 : ulong lamports ); 173 : 174 : /* fd_epoch_rewards_get_distribution_partition_index determines the 175 : hash partition that the current block belongs in. */ 176 : 177 : ulong 178 : fd_epoch_rewards_get_distribution_partition_index( fd_epoch_rewards_t const * epoch_rewards, ulong curr_block_height ); 179 : 180 : /* Simple inline mutator functions */ 181 : 182 : static void FD_FN_UNUSED 183 3 : fd_epoch_rewards_set_active( fd_epoch_rewards_t * epoch_rewards, int is_active ) { 184 3 : epoch_rewards->is_active_ = is_active; 185 3 : } 186 : 187 : static void FD_FN_UNUSED 188 3 : fd_epoch_rewards_set_starting_block_height( fd_epoch_rewards_t * epoch_rewards, ulong block_height ) { 189 3 : epoch_rewards->starting_block_height_ = block_height; 190 3 : } 191 : 192 : static void FD_FN_UNUSED 193 6 : fd_epoch_rewards_set_num_partitions( fd_epoch_rewards_t * epoch_rewards, ulong num_partitions ) { 194 6 : if( FD_UNLIKELY( num_partitions>FD_REWARDS_MAX_PARTITIONS ) ) { 195 3 : FD_LOG_WARNING(( "num_partitions: %lu is greater than FD_REWARDS_MAX_PARTITIONS: %lu", num_partitions, FD_REWARDS_MAX_PARTITIONS )); 196 3 : return; 197 3 : } 198 3 : epoch_rewards->num_partitions_ = num_partitions; 199 3 : } 200 : 201 : static void FD_FN_UNUSED 202 3 : fd_epoch_rewards_set_distributed_rewards( fd_epoch_rewards_t * epoch_rewards, ulong distributed_rewards ) { 203 3 : epoch_rewards->distributed_rewards_ = distributed_rewards; 204 3 : } 205 : 206 : static void FD_FN_UNUSED 207 3 : fd_epoch_rewards_set_total_rewards( fd_epoch_rewards_t * epoch_rewards, ulong total_rewards ) { 208 3 : epoch_rewards->total_rewards_ = total_rewards; 209 3 : } 210 : 211 : static void FD_FN_UNUSED 212 3 : fd_epoch_rewards_set_total_points( fd_epoch_rewards_t * epoch_rewards, uint128 total_points ) { 213 3 : epoch_rewards->total_points_ = total_points; 214 3 : } 215 : 216 : /* Simple inline accessor functions */ 217 : 218 : static int FD_FN_UNUSED 219 9 : fd_epoch_rewards_is_active( fd_epoch_rewards_t const * epoch_rewards ) { 220 9 : return epoch_rewards->is_active_; 221 9 : } 222 : 223 : static ulong FD_FN_UNUSED 224 312 : fd_epoch_rewards_get_num_partitions( fd_epoch_rewards_t const * epoch_rewards ) { 225 312 : return epoch_rewards->num_partitions_; 226 312 : } 227 : 228 : static ulong FD_FN_UNUSED 229 9 : fd_epoch_rewards_get_starting_block_height( fd_epoch_rewards_t const * epoch_rewards ) { 230 9 : return epoch_rewards->starting_block_height_; 231 9 : } 232 : 233 : static ulong FD_FN_UNUSED 234 6 : fd_epoch_rewards_get_exclusive_ending_block_height( fd_epoch_rewards_t const * epoch_rewards ) { 235 6 : return epoch_rewards->starting_block_height_ + epoch_rewards->num_partitions_; 236 6 : } 237 : 238 : static ulong FD_FN_UNUSED 239 9 : fd_epoch_rewards_get_distributed_rewards( fd_epoch_rewards_t const * epoch_rewards ) { 240 9 : return epoch_rewards->distributed_rewards_; 241 9 : } 242 : 243 : static uint128 FD_FN_UNUSED 244 9 : fd_epoch_rewards_get_total_points( fd_epoch_rewards_t const * epoch_rewards ) { 245 9 : return epoch_rewards->total_points_; 246 9 : } 247 : 248 : static ulong FD_FN_UNUSED 249 9 : fd_epoch_rewards_get_total_rewards( fd_epoch_rewards_t const * epoch_rewards ) { 250 9 : return epoch_rewards->total_rewards_; 251 9 : } 252 : 253 : FD_PROTOTYPES_END 254 : 255 : #endif /* HEADER_fd_src_flamenco_rewards_fd_epoch_rewards_h */