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