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 13212 : #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 180 : #define FD_EPOCH_REWARDS_ALIGN (128UL) 62 : 63 6 : #define FD_EPOCH_REWARDS_MAGIC (0x122400081001UL) 64 : 65 : struct fd_epoch_stake_reward { 66 : fd_pubkey_t stake_pubkey; 67 : ulong credits_observed; 68 : ulong lamports; 69 : /* Internal pointers for pool, dlist, and map. */ 70 : ulong prev; 71 : ulong next; 72 : ulong parent; 73 : ulong next_map; 74 : }; 75 : typedef struct fd_epoch_stake_reward fd_epoch_stake_reward_t; 76 : 77 : /* TODO: Need to move the dlist into the .c file. There needs to be a 78 : way to forward declare the iterator (see fd_map.h). */ 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_iter { 85 : fd_epoch_stake_reward_t * pool; 86 : void * dlist; 87 : fd_epoch_stake_reward_dlist_iter_t iter; 88 : }; 89 : typedef struct fd_epoch_rewards_iter fd_epoch_rewards_iter_t; 90 : 91 : struct fd_epoch_rewards { 92 : ulong magic; 93 : 94 : /* Data representing the partitioned stake rewards */ 95 : ulong stake_account_max; 96 : ulong starting_block_height; 97 : ulong num_partitions; 98 : ulong partitions_lengths[FD_REWARDS_MAX_PARTITIONS]; 99 : 100 : /* Result of total rewards distribution */ 101 : 102 : /* Total rewards for the epoch (including both vote rewards and stake 103 : rewards) */ 104 : ulong total_rewards; 105 : 106 : /* total rewards points calculated for the current epoch, where points 107 : equals the sum of (delegated stake * credits observed) for all 108 : delegations */ 109 : ulong distributed_rewards; 110 : 111 : /* Stake rewards that still need to be distributed, grouped by 112 : partition */ 113 : fd_w_u128_t total_points; 114 : 115 : /* Total stake rewards to distribute as calculated during the epoch 116 : boundary */ 117 : ulong total_stake_rewards; 118 : 119 : /* Total number of stake accounts that have rewards to distribute */ 120 : ulong stake_rewards_cnt; 121 : 122 : /* Internal pointers for pool, dlist, and map. */ 123 : ulong pool_offset; 124 : ulong map_offset; 125 : ulong dlists_offset; 126 : 127 : /* This will be followed by a pool of fd_epoch_stake_reward_t. This 128 : pool will be sized out to FD_BANKS_MAX_STAKE_ACCOUNTS. */ 129 : 130 : /* The pool will be followed by up to FD_REWARDS_MAX_PARTITIONS 131 : that will all need to be joined. */ 132 : 133 : }; 134 : typedef struct fd_epoch_rewards fd_epoch_rewards_t; 135 : 136 : 137 : /* fd_epoch_rewards_align returns the alignment of the epoch rewards 138 : struct. */ 139 : 140 : ulong 141 : fd_epoch_rewards_align( void ); 142 : 143 : /* fd_epoch_rewards_footprint returns the footprint of the epoch rewards 144 : struct. */ 145 : 146 : ulong 147 : fd_epoch_rewards_footprint( ulong stake_account_max ); 148 : 149 : /* fd_epoch_rewards_new initializes the epoch_rewards struct. */ 150 : void * 151 : fd_epoch_rewards_new( void * shmem, ulong stake_account_max ); 152 : 153 : /* fd_epoch_rewards_join returns a pointer to the epoch rewards struct 154 : that is stored in the shared memory. */ 155 : 156 : fd_epoch_rewards_t * 157 : fd_epoch_rewards_join( void * shmem ); 158 : 159 : /* fd_epoch_rewards_leave returns a pointer to the epoch rewards struct 160 : that is stored in the shared memory. */ 161 : 162 : void * 163 : fd_epoch_rewards_leave( fd_epoch_rewards_t const * epoch_rewards ); 164 : 165 : /* fd_epoch_rewards_delete unformats the epoch rewards struct and the 166 : memory that the struct manages. */ 167 : 168 : void * 169 : fd_epoch_rewards_delete( void * epoch_rewards ); 170 : 171 : /* fd_epoch_rewards_insert stores the rewards for a given stake account 172 : into the data structure. */ 173 : 174 : void 175 : fd_epoch_rewards_insert( fd_epoch_rewards_t * epoch_rewards, 176 : fd_pubkey_t const * pubkey, 177 : ulong credits, 178 : ulong lamports ); 179 : 180 : /* fd_epoch_rewards_hash_into_partitions hashes all of the stake 181 : accounts into the appropriate partitions. */ 182 : 183 : void 184 : fd_epoch_rewards_hash_into_partitions( fd_epoch_rewards_t * epoch_rewards, 185 : fd_hash_t const * parent_blockhash, 186 : ulong num_partitions ); 187 : 188 : /* fd_epoch_rewards_get_distribution_partition_index determines the 189 : hash partition that the current block belongs in. */ 190 : 191 : ulong 192 : fd_epoch_rewards_get_distribution_partition_index( fd_epoch_rewards_t const * epoch_rewards, 193 : ulong curr_block_height ); 194 : 195 : /* fd_epoch_rewards_get_exclusive_ending_block_height returns the 196 : block height that the last partition ends at. */ 197 : 198 : static inline ulong 199 0 : fd_epoch_rewards_get_exclusive_ending_block_height( fd_epoch_rewards_t const * epoch_rewards ) { 200 0 : return epoch_rewards->starting_block_height + epoch_rewards->num_partitions; 201 0 : } 202 : 203 : /* Iterator API for epoch rewards. The iterator is initialized with a 204 : call to fd_epoch_rewards_iter_init. The caller is responsible for 205 : managing the memory for the iterator. It is safe to call 206 : fd_epoch_rewards_iter_next if the result of 207 : fd_epoch_rewards_iter_done() ==0. It is safe to call 208 : fd_epoch_rewards_iter_ele() to get the current epoch reward. 209 : Elements that are iterated over are not safe to modify. 210 : 211 : Under the hood, the iterator is just a wrapper over the iterator used 212 : by the underlying dlist. 213 : */ 214 : 215 : fd_epoch_stake_reward_t * 216 : fd_epoch_rewards_iter_ele( fd_epoch_rewards_iter_t * iter ); 217 : 218 : fd_epoch_rewards_iter_t * 219 : fd_epoch_rewards_iter_init( fd_epoch_rewards_iter_t * iter, 220 : fd_epoch_rewards_t const * epoch_rewards, 221 : ulong partition_idx ); 222 : 223 : int 224 : fd_epoch_rewards_iter_done( fd_epoch_rewards_iter_t * iter ); 225 : 226 : void 227 : fd_epoch_rewards_iter_next( fd_epoch_rewards_iter_t * iter ); 228 : 229 : FD_PROTOTYPES_END 230 : 231 : #endif /* HEADER_fd_src_flamenco_rewards_fd_epoch_rewards_h */