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-05-26 08:02:49 Functions: 16 96 16.7 %

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

Generated by: LCOV version 1.14