LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_runtime_stack.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 62 71 87.3 %
Date: 2026-04-10 06:33:15 Functions: 16 100 16.0 %

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

Generated by: LCOV version 1.14