LCOV - code coverage report
Current view: top level - flamenco/rewards - fd_epoch_rewards.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 3 6 50.0 %
Date: 2025-11-29 04:46:19 Functions: 0 72 0.0 %

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

Generated by: LCOV version 1.14