LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_runtime_stack.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 64 73 87.7 %
Date: 2026-08-28 06:53:58 Functions: 8 340 2.4 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_fd_runtime_stack_h
       2             : #define HEADER_fd_src_flamenco_runtime_fd_runtime_stack_h
       3             : 
       4             : #include "sysvar/fd_sysvar_clock.h"
       5             : #include "program/fd_builtin_programs.h"
       6             : #include "../leaders/fd_leaders_base.h"
       7             : #include "../../ballet/sbpf/fd_sbpf_loader.h"
       8             : 
       9             : /* https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/programs/stake/src/points.rs#L27 */
      10             : struct fd_calculated_stake_points {
      11             :   fd_w_u128_t points;
      12             :   ulong       new_credits_observed;
      13             :   uint        vote_idx; /* Caches this delegation's vote_rewards_map index.  UINT_MAX if the
      14             :                            vote account is not in the rewards map.  Not populated during
      15             :                            recalculation due to lack of the points phase. */
      16             :   uchar       force_credits_update_with_skipped_reward;
      17             : };
      18             : typedef struct fd_calculated_stake_points fd_calculated_stake_points_t;
      19             : 
      20             : /* https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/programs/stake/src/rewards.rs#L24 */
      21             : struct fd_calculated_stake_rewards {
      22             :   ulong staker_rewards;
      23             :   ulong voter_rewards;
      24             :   ulong new_credits_observed;
      25             :   uchar success;
      26             : };
      27             : typedef struct fd_calculated_stake_rewards fd_calculated_stake_rewards_t;
      28             : 
      29             : /* fd_vote_ele and fd_vote_ele_map are used to temporarily cache
      30             :    computed fields for vote accounts during epoch boundary stake
      31             :    and rewards calculations. */
      32             : 
      33             : struct fd_vote_rewards {
      34             :   fd_pubkey_t pubkey;
      35             :   ulong       vote_rewards;
      36             :   uint        next;
      37             :   ushort      commission;
      38             : };
      39             : typedef struct fd_vote_rewards fd_vote_rewards_t;
      40             : 
      41             : #define MAP_NAME               fd_vote_rewards_map
      42             : #define MAP_KEY_T              fd_pubkey_t
      43             : #define MAP_ELE_T              fd_vote_rewards_t
      44         336 : #define MAP_KEY                pubkey
      45         474 : #define MAP_KEY_EQ(k0,k1)      (!memcmp( k0, k1, sizeof(fd_pubkey_t) ))
      46         732 : #define MAP_KEY_HASH(key,seed) (fd_ulong_hash( (seed)^FD_LOAD( ulong, ((uchar const *)(key))+24UL ) ))
      47         933 : #define MAP_NEXT               next
      48        2025 : #define MAP_IDX_T              uint
      49             : #include "../../util/tmpl/fd_map_chain.c"
      50             : 
      51             : struct fd_stake_accum {
      52             :   fd_pubkey_t pubkey;
      53             :   ulong       stake;        /* effective stake in the current epoch */
      54             :   ulong       reward_stake; /* effective stake in the rewarded epoch */
      55             :   uint        next;
      56             : };
      57             : typedef struct fd_stake_accum fd_stake_accum_t;
      58             : 
      59             : #define MAP_NAME               fd_stake_accum_map
      60             : #define MAP_KEY_T              fd_pubkey_t
      61             : #define MAP_ELE_T              fd_stake_accum_t
      62         390 : #define MAP_KEY                pubkey
      63         105 : #define MAP_KEY_EQ(k0,k1)      (!memcmp( k0, k1, sizeof(fd_pubkey_t) ))
      64         804 : #define MAP_KEY_HASH(key,seed) (fd_ulong_hash( (seed)^FD_LOAD( ulong, ((uchar const *)(key))+24UL ) ))
      65         855 : #define MAP_NEXT               next
      66        2250 : #define MAP_IDX_T              uint
      67             : #include "../../util/tmpl/fd_map_chain.c"
      68             : 
      69             : /* fd_runtime_stack_t serves as stack memory to store temporary data
      70             :    for the runtime.  This object should only be used and owned by the
      71             :    replay tile and is used for short-lived allocations for the runtime,
      72             :    more specifically, for slot level calculations. */
      73             : struct fd_runtime_stack {
      74             : 
      75             :   ulong max_vote_accounts;
      76             :   ulong max_staked_vote_accounts;
      77             :   ulong max_stake_accounts;
      78             : 
      79             :   struct {
      80             :     /* Staging memory to sort vote accounts by last vote timestamp for
      81             :        clock sysvar calculation. */
      82             :     ts_est_ele_t * staked_ts;
      83             :   } clock_ts;
      84             : 
      85             :   struct {
      86             :     /* Staging memory for bpf migration.  This is used to store and
      87             :        stage various accounts which is required for deploying a new BPF
      88             :        program at the epoch boundary.
      89             : 
      90             :        TODO: These are only used by the replay tile on epoch boundaries
      91             :        and don't need to be in the per-exec stacks.  Additionally, we
      92             :        could just acquire these buffers out of the account database
      93             :        directly to share them across tiles using the existing flexible
      94             :        buffer management. */
      95             :     fd_tmp_account_t source;
      96             :     fd_tmp_account_t program_account;
      97             :     fd_tmp_account_t new_target_program;
      98             :     fd_tmp_account_t new_target_program_data;
      99             :     fd_tmp_account_t empty;
     100             : 
     101             :     /* Staging memory for ELF validation during BPF program
     102             :        migrations. */
     103             :     struct {
     104             :       uchar rodata        [ FD_RUNTIME_ACC_SZ_MAX     ] __attribute__((aligned(FD_SBPF_PROG_RODATA_ALIGN)));
     105             :       uchar sbpf_footprint[ FD_SBPF_PROGRAM_FOOTPRINT ] __attribute__((aligned(alignof(fd_sbpf_program_t))));
     106             :       uchar programdata   [ FD_RUNTIME_ACC_SZ_MAX     ] __attribute__((aligned(FD_ACCOUNT_REC_ALIGN)));
     107             :     } progcache_validate;
     108             :   } bpf_migration;
     109             : 
     110             :   struct {
     111             :     fd_calculated_stake_points_t *  stake_points_result;
     112             : 
     113             :     fd_calculated_stake_rewards_t * stake_rewards_result;
     114             : 
     115             :     fd_stake_accum_t *     stake_accum;
     116             :     fd_stake_accum_map_t * stake_accum_map;
     117             : 
     118             :     fd_vote_rewards_t *     vote_ele;
     119             :     fd_vote_rewards_map_t * vote_map;
     120             : 
     121             :     ulong       total_rewards;
     122             :     ulong       distributed_rewards;
     123             :     fd_w_u128_t total_points;
     124             : 
     125             :     ulong stake_rewards_cnt;
     126             : 
     127             :     /* Staging memory used for calculating and sorting vote account
     128             :        stake weights for the leader schedule calculation. */
     129             :     fd_vote_stake_weight_t * stake_weights;
     130             :     fd_stake_weight_t *      id_weights;
     131             : 
     132             :   } stakes;
     133             : 
     134             :   struct {
     135             :     fd_vote_stake_weight_t stake_weights[ MAX_STAKE_WEIGHTS ];
     136             :     ulong                  stake_weights_cnt;
     137             : 
     138             :     fd_stake_weight_t      id_weights[ MAX_STAKE_WEIGHTS ];
     139             :     ulong                  id_weights_cnt;
     140             : 
     141             :     fd_vote_stake_weight_t next_stake_weights[ MAX_STAKE_WEIGHTS ];
     142             :     ulong                  next_stake_weights_cnt;
     143             : 
     144             :     fd_stake_weight_t      next_id_weights[ MAX_STAKE_WEIGHTS ];
     145             :     ulong                  next_id_weights_cnt;
     146             :   } epoch_weights;
     147             : };
     148             : typedef struct fd_runtime_stack fd_runtime_stack_t;
     149             : 
     150             : FD_FN_CONST static inline ulong
     151         633 : fd_runtime_stack_align( void ) {
     152         633 :   return 128UL;
     153         633 : }
     154             : 
     155             : FD_FN_PURE static inline ulong
     156             : fd_runtime_stack_footprint( ulong max_vote_accounts,
     157             :                             ulong max_staked_vote_accounts,
     158         189 :                             ulong max_stake_accounts ) {
     159         189 :   ulong vote_chain_cnt  = fd_vote_rewards_map_chain_cnt_est( max_vote_accounts );
     160         189 :   ulong stake_chain_cnt = fd_stake_accum_map_chain_cnt_est( max_staked_vote_accounts );
     161         189 :   ulong l = FD_LAYOUT_INIT;
     162         189 :   l = FD_LAYOUT_APPEND( l, alignof(fd_runtime_stack_t),           sizeof(fd_runtime_stack_t) );
     163         189 :   l = FD_LAYOUT_APPEND( l, alignof(ts_est_ele_t),                 sizeof(ts_est_ele_t) * max_vote_accounts );
     164         189 :   l = FD_LAYOUT_APPEND( l, alignof(fd_vote_stake_weight_t),       sizeof(fd_vote_stake_weight_t) * max_vote_accounts );
     165         189 :   l = FD_LAYOUT_APPEND( l, alignof(fd_stake_weight_t),            sizeof(fd_stake_weight_t) * max_vote_accounts );
     166         189 :   l = FD_LAYOUT_APPEND( l, 128UL,                                 sizeof(fd_vote_rewards_t) * max_vote_accounts );
     167         189 :   l = FD_LAYOUT_APPEND( l, fd_vote_rewards_map_align(),           fd_vote_rewards_map_footprint( vote_chain_cnt ) );
     168         189 :   l = FD_LAYOUT_APPEND( l, 128UL,                                 sizeof(fd_stake_accum_t) * max_staked_vote_accounts );
     169         189 :   l = FD_LAYOUT_APPEND( l, fd_stake_accum_map_align(),            fd_stake_accum_map_footprint( stake_chain_cnt ) );
     170         189 :   l = FD_LAYOUT_APPEND( l, alignof(fd_calculated_stake_points_t), sizeof(fd_calculated_stake_points_t) * max_stake_accounts );
     171         189 :   l = FD_LAYOUT_APPEND( l, alignof(fd_calculated_stake_rewards_t),sizeof(fd_calculated_stake_rewards_t) * max_stake_accounts );
     172         189 :   return FD_LAYOUT_FINI( l, fd_runtime_stack_align() );
     173         189 : }
     174             : 
     175             : static inline void *
     176             : fd_runtime_stack_new( void * shmem,
     177             :                       ulong  max_vote_accounts,
     178             :                       ulong  max_staked_vote_accounts,
     179             :                       ulong  max_stake_accounts,
     180          66 :                       ulong  seed ) {
     181          66 :   if( FD_UNLIKELY( !shmem ) ) return NULL;
     182          66 :   ulong vote_chain_cnt  = fd_vote_rewards_map_chain_cnt_est( max_vote_accounts );
     183          66 :   ulong stake_chain_cnt = fd_stake_accum_map_chain_cnt_est( max_staked_vote_accounts );
     184          66 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
     185          66 :   fd_runtime_stack_t *            runtime_stack        = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_runtime_stack_t),            sizeof(fd_runtime_stack_t) );
     186          66 :   ts_est_ele_t *                  staked_ts            = FD_SCRATCH_ALLOC_APPEND( l, alignof(ts_est_ele_t),                  sizeof(ts_est_ele_t) * max_vote_accounts );
     187          66 :   fd_vote_stake_weight_t *        stake_weights        = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_vote_stake_weight_t),        sizeof(fd_vote_stake_weight_t) * max_vote_accounts );
     188          66 :   fd_stake_weight_t *             id_weights           = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_stake_weight_t),             sizeof(fd_stake_weight_t) * max_vote_accounts );
     189          66 :   fd_vote_rewards_t *             vote_ele             = FD_SCRATCH_ALLOC_APPEND( l, 128UL,                                  sizeof(fd_vote_rewards_t) * max_vote_accounts );
     190          66 :   void *                          vote_map_mem         = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_rewards_map_align(),            fd_vote_rewards_map_footprint( vote_chain_cnt ) );
     191          66 :   fd_stake_accum_t *              stake_accum          = FD_SCRATCH_ALLOC_APPEND( l, 128UL,                                  sizeof(fd_stake_accum_t) * max_staked_vote_accounts );
     192          66 :   void *                          stake_accum_map_mem  = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_accum_map_align(),             fd_stake_accum_map_footprint( stake_chain_cnt ) );
     193          66 :   fd_calculated_stake_points_t *  stake_points_result  = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_calculated_stake_points_t),  sizeof(fd_calculated_stake_points_t) * max_stake_accounts );
     194          66 :   fd_calculated_stake_rewards_t * stake_rewards_result = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_calculated_stake_rewards_t), sizeof(fd_calculated_stake_rewards_t) * max_stake_accounts );
     195          66 :   if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_runtime_stack_align() )!=(ulong)shmem + fd_runtime_stack_footprint( max_vote_accounts, max_staked_vote_accounts, max_stake_accounts ) ) ) {
     196           0 :     FD_LOG_WARNING(( "fd_runtime_stack_new: bad layout" ));
     197           0 :     return NULL;
     198           0 :   }
     199             : 
     200          66 :   runtime_stack->max_vote_accounts           = max_vote_accounts;
     201          66 :   runtime_stack->max_staked_vote_accounts    = max_staked_vote_accounts;
     202          66 :   runtime_stack->max_stake_accounts          = max_stake_accounts;
     203          66 :   runtime_stack->clock_ts.staked_ts          = staked_ts;
     204          66 :   runtime_stack->stakes.stake_weights        = stake_weights;
     205          66 :   runtime_stack->stakes.id_weights           = id_weights;
     206          66 :   runtime_stack->stakes.vote_ele             = vote_ele;
     207          66 :   runtime_stack->stakes.stake_points_result  = stake_points_result;
     208          66 :   runtime_stack->stakes.stake_rewards_result = stake_rewards_result;
     209          66 :   runtime_stack->stakes.stake_accum          = stake_accum;
     210             : 
     211          66 :   runtime_stack->stakes.stake_accum_map = fd_stake_accum_map_join( fd_stake_accum_map_new( stake_accum_map_mem, stake_chain_cnt, seed ) );
     212          66 :   if( FD_UNLIKELY( !runtime_stack->stakes.stake_accum_map ) ) {
     213           0 :     FD_LOG_WARNING(( "fd_runtime_stack_new: bad map" ));
     214           0 :     return NULL;
     215           0 :   }
     216             : 
     217          66 :   runtime_stack->stakes.vote_map = fd_vote_rewards_map_join( fd_vote_rewards_map_new( vote_map_mem, vote_chain_cnt, seed ) );
     218          66 :   if( FD_UNLIKELY( !runtime_stack->stakes.vote_map ) ) {
     219           0 :     FD_LOG_WARNING(( "fd_runtime_stack_new: bad map" ));
     220           0 :     return NULL;
     221           0 :   }
     222             : 
     223          66 :   return shmem;
     224          66 : }
     225             : 
     226             : FD_FN_CONST static inline fd_runtime_stack_t *
     227          66 : fd_runtime_stack_join( void * shruntime_stack ) {
     228          66 :   return (fd_runtime_stack_t *)shruntime_stack;
     229          66 : }
     230             : 
     231             : #endif /* HEADER_fd_src_flamenco_runtime_fd_runtime_stack_h */

Generated by: LCOV version 1.14