LCOV - code coverage report
Current view: top level - flamenco/rewards - fd_epoch_rewards.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 47 47 100.0 %
Date: 2025-09-19 04:41:14 Functions: 13 975 1.3 %

          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 */

Generated by: LCOV version 1.14