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 */
|