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