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

Generated by: LCOV version 1.14