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 "sysvar/fd_sysvar_clock.h" 6 : #include "program/fd_builtin_programs.h" 7 : #include "fd_runtime_const.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_epoch_credits { 31 : ulong cnt; 32 : ushort epoch [ FD_EPOCH_CREDITS_MAX ]; 33 : ulong credits [ FD_EPOCH_CREDITS_MAX ]; 34 : ulong prev_credits[ FD_EPOCH_CREDITS_MAX ]; 35 : }; 36 : typedef struct fd_epoch_credits fd_epoch_credits_t; 37 : 38 : struct fd_vote_rewards { 39 : fd_pubkey_t pubkey; 40 : ulong vote_rewards; 41 : uint next; 42 : uchar commission; 43 : }; 44 : typedef struct fd_vote_rewards fd_vote_rewards_t; 45 : 46 : #define MAP_NAME fd_vote_rewards_map 47 : #define MAP_KEY_T fd_pubkey_t 48 : #define MAP_ELE_T fd_vote_rewards_t 49 301 : #define MAP_KEY pubkey 50 6 : #define MAP_KEY_EQ(k0,k1) (!memcmp( k0, k1, sizeof(fd_pubkey_t) )) 51 307 : #define MAP_KEY_HASH(key,seed) (fd_hash( seed, key, sizeof(fd_pubkey_t) )) 52 303 : #define MAP_NEXT next 53 630 : #define MAP_IDX_T uint 54 : #include "../../util/tmpl/fd_map_chain.c" 55 : 56 : #define FD_VOTE_ELE_MAP_ALIGN (128UL) 57 : 58 : FD_FN_PURE static inline ulong 59 36 : fd_vote_ele_map_footprint( ulong max_vote_accounts ) { 60 36 : return sizeof(fd_vote_rewards_map_t) + max_vote_accounts * sizeof(uint); 61 36 : } 62 : 63 : /* fd_runtime_stack_t serves as stack memory to store temporary data 64 : for the runtime. This object should only be used and owned by the 65 : replay tile and is used for short-lived allocations for the runtime, 66 : more specifically, for slot level calculations. */ 67 : struct fd_runtime_stack { 68 : 69 : ulong max_vote_accounts; 70 : ulong expected_vote_accounts; 71 : ulong expected_stake_accounts; 72 : 73 : struct { 74 : /* Staging memory to sort vote accounts by last vote timestamp for 75 : clock sysvar calculation. */ 76 : ts_est_ele_t * staked_ts; 77 : } clock_ts; 78 : 79 : struct { 80 : /* Staging memory for bpf migration. This is used to store and 81 : stage various accounts which is required for deploying a new BPF 82 : program at the epoch boundary. */ 83 : fd_tmp_account_t source; 84 : fd_tmp_account_t program_account; 85 : fd_tmp_account_t new_target_program; 86 : fd_tmp_account_t new_target_program_data; 87 : fd_tmp_account_t empty; 88 : } bpf_migration; 89 : 90 : struct { 91 : fd_calculated_stake_points_t * stake_points_result; 92 : 93 : fd_calculated_stake_rewards_t * stake_rewards_result; 94 : 95 : ulong total_rewards; 96 : ulong distributed_rewards; 97 : fd_w_u128_t total_points; 98 : 99 : ulong stake_rewards_cnt; 100 : 101 : /* Staging memory used for calculating and sorting vote account 102 : stake weights for the leader schedule calculation. */ 103 : fd_vote_stake_weight_t * stake_weights; 104 : 105 : fd_vote_rewards_t * vote_ele; 106 : void * vote_map_mem; 107 : 108 : fd_epoch_credits_t * epoch_credits; 109 : 110 : } stakes; 111 : }; 112 : typedef struct fd_runtime_stack fd_runtime_stack_t; 113 : 114 : FD_FN_CONST static inline ulong 115 84 : fd_runtime_stack_align( void ) { 116 84 : return 128UL; 117 84 : } 118 : 119 : FD_FN_PURE static inline ulong 120 : fd_runtime_stack_footprint( ulong max_vote_accounts, 121 : ulong expected_vote_accounts, 122 24 : ulong expected_stake_accounts ) { 123 24 : ulong chain_cnt = fd_vote_rewards_map_chain_cnt_est( expected_vote_accounts ); 124 24 : ulong l = FD_LAYOUT_INIT; 125 24 : l = FD_LAYOUT_APPEND( l, alignof(fd_runtime_stack_t), sizeof(fd_runtime_stack_t) ); 126 24 : l = FD_LAYOUT_APPEND( l, alignof(ts_est_ele_t), sizeof(ts_est_ele_t) * max_vote_accounts ); 127 24 : l = FD_LAYOUT_APPEND( l, alignof(fd_vote_stake_weight_t), sizeof(fd_vote_stake_weight_t) * max_vote_accounts ); 128 24 : l = FD_LAYOUT_APPEND( l, 128UL, sizeof(fd_vote_rewards_t) * max_vote_accounts ); 129 24 : l = FD_LAYOUT_APPEND( l, FD_VOTE_ELE_MAP_ALIGN, fd_vote_ele_map_footprint( chain_cnt ) ); 130 24 : l = FD_LAYOUT_APPEND( l, alignof(fd_epoch_credits_t), sizeof(fd_epoch_credits_t) * expected_vote_accounts ); 131 24 : l = FD_LAYOUT_APPEND( l, alignof(fd_calculated_stake_points_t), sizeof(fd_calculated_stake_points_t) * expected_stake_accounts ); 132 24 : l = FD_LAYOUT_APPEND( l, alignof(fd_calculated_stake_rewards_t),sizeof(fd_calculated_stake_rewards_t) * expected_stake_accounts ); 133 24 : return FD_LAYOUT_FINI( l, fd_runtime_stack_align() ); 134 24 : } 135 : 136 : static inline void * 137 : fd_runtime_stack_new( void * shmem, 138 : ulong max_vote_accounts, 139 : ulong expected_vote_accounts, 140 : ulong expected_stake_accounts, 141 12 : ulong seed ) { 142 12 : if( FD_UNLIKELY( !shmem ) ) return NULL; 143 12 : ulong chain_cnt = fd_vote_rewards_map_chain_cnt_est( expected_vote_accounts ); 144 12 : FD_SCRATCH_ALLOC_INIT( l, shmem ); 145 12 : fd_runtime_stack_t * runtime_stack = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_runtime_stack_t), sizeof(fd_runtime_stack_t) ); 146 12 : ts_est_ele_t * staked_ts = FD_SCRATCH_ALLOC_APPEND( l, alignof(ts_est_ele_t), sizeof(ts_est_ele_t) * max_vote_accounts ); 147 12 : 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 ); 148 12 : fd_vote_rewards_t * vote_ele = FD_SCRATCH_ALLOC_APPEND( l, 128UL, sizeof(fd_vote_rewards_t) * max_vote_accounts ); 149 12 : void * vote_map_mem = FD_SCRATCH_ALLOC_APPEND( l, FD_VOTE_ELE_MAP_ALIGN, fd_vote_ele_map_footprint( chain_cnt ) ); 150 12 : fd_epoch_credits_t * epoch_credits = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_epoch_credits_t), sizeof(fd_epoch_credits_t) * expected_vote_accounts ); 151 12 : 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 ); 152 12 : 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 ); 153 12 : 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 ) ) ) { 154 0 : FD_LOG_WARNING(( "fd_runtime_stack_new: bad layout" )); 155 0 : return NULL; 156 0 : } 157 : 158 12 : runtime_stack->max_vote_accounts = max_vote_accounts; 159 12 : runtime_stack->expected_vote_accounts = expected_vote_accounts; 160 12 : runtime_stack->expected_stake_accounts = expected_stake_accounts; 161 12 : runtime_stack->clock_ts.staked_ts = staked_ts; 162 12 : runtime_stack->stakes.stake_weights = stake_weights; 163 12 : runtime_stack->stakes.vote_ele = vote_ele; 164 12 : runtime_stack->stakes.vote_map_mem = vote_map_mem; 165 12 : runtime_stack->stakes.epoch_credits = epoch_credits; 166 12 : runtime_stack->stakes.stake_points_result = stake_points_result; 167 12 : runtime_stack->stakes.stake_rewards_result = stake_rewards_result; 168 : 169 12 : if( FD_UNLIKELY( !fd_vote_rewards_map_join( fd_vote_rewards_map_new( runtime_stack->stakes.vote_map_mem, chain_cnt, seed ) ) ) ) { 170 0 : FD_LOG_WARNING(( "fd_runtime_stack_new: bad map" )); 171 0 : return NULL; 172 0 : } 173 12 : return shmem; 174 12 : } 175 : 176 : FD_FN_CONST static inline fd_runtime_stack_t * 177 12 : fd_runtime_stack_join( void * shruntime_stack ) { 178 12 : return (fd_runtime_stack_t *)shruntime_stack; 179 12 : } 180 : 181 : #endif /* HEADER_fd_src_flamenco_runtime_fd_runtime_stack_h */