Line data Source code
1 : #include "fd_exec_slot_ctx.h"
2 : #include "../sysvar/fd_sysvar_epoch_schedule.h"
3 : #include "../program/fd_vote_program.h"
4 : #include "../../../ballet/lthash/fd_lthash.h"
5 :
6 : #include <assert.h>
7 : #include <time.h>
8 :
9 : void *
10 3 : fd_exec_slot_ctx_new( void * mem ) {
11 :
12 3 : if( FD_UNLIKELY( !mem ) ) {
13 0 : FD_LOG_WARNING(( "NULL mem" ));
14 0 : return NULL;
15 0 : }
16 :
17 3 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_SLOT_CTX_ALIGN ) ) ) {
18 0 : FD_LOG_WARNING(( "misaligned mem" ));
19 0 : return NULL;
20 0 : }
21 :
22 3 : fd_memset( mem, 0, sizeof(fd_exec_slot_ctx_t) );
23 :
24 3 : fd_exec_slot_ctx_t * self = (fd_exec_slot_ctx_t *)mem;
25 :
26 3 : FD_COMPILER_MFENCE();
27 3 : self->magic = FD_EXEC_SLOT_CTX_MAGIC;
28 3 : FD_COMPILER_MFENCE();
29 :
30 3 : return mem;
31 3 : }
32 :
33 : fd_exec_slot_ctx_t *
34 3 : fd_exec_slot_ctx_join( void * mem ) {
35 3 : if( FD_UNLIKELY( !mem ) ) {
36 0 : FD_LOG_WARNING(( "NULL block" ));
37 0 : return NULL;
38 0 : }
39 :
40 3 : fd_exec_slot_ctx_t * ctx = (fd_exec_slot_ctx_t *) mem;
41 :
42 3 : if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
43 0 : FD_LOG_WARNING(( "bad magic" ));
44 0 : return NULL;
45 0 : }
46 :
47 3 : return ctx;
48 3 : }
49 :
50 : void *
51 3 : fd_exec_slot_ctx_leave( fd_exec_slot_ctx_t * ctx) {
52 3 : if( FD_UNLIKELY( !ctx ) ) {
53 0 : FD_LOG_WARNING(( "NULL block" ));
54 0 : return NULL;
55 0 : }
56 :
57 3 : if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
58 0 : FD_LOG_WARNING(( "bad magic" ));
59 0 : return NULL;
60 0 : }
61 :
62 3 : return (void *) ctx;
63 3 : }
64 :
65 : void *
66 0 : fd_exec_slot_ctx_delete( void * mem ) {
67 0 : if( FD_UNLIKELY( !mem ) ) {
68 0 : FD_LOG_WARNING(( "NULL mem" ));
69 0 : return NULL;
70 0 : }
71 :
72 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_SLOT_CTX_ALIGN) ) ) {
73 0 : FD_LOG_WARNING(( "misaligned mem" ));
74 0 : return NULL;
75 0 : }
76 :
77 0 : fd_exec_slot_ctx_t * hdr = (fd_exec_slot_ctx_t *)mem;
78 0 : if( FD_UNLIKELY( hdr->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
79 0 : FD_LOG_WARNING(( "bad magic" ));
80 0 : return NULL;
81 0 : }
82 :
83 0 : FD_COMPILER_MFENCE();
84 0 : FD_VOLATILE( hdr->magic ) = 0UL;
85 0 : FD_COMPILER_MFENCE();
86 :
87 0 : return mem;
88 0 : }
89 :
90 : /* recover_clock recovers PoH/wallclock synchronization. Walks all vote
91 : accounts in current epoch stakes. */
92 :
93 : static int
94 0 : recover_clock( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
95 :
96 0 : fd_stakes_global_t const * stakes = fd_bank_stakes_locking_query( slot_ctx->bank );
97 0 : if( FD_UNLIKELY( stakes==NULL ) ) {
98 0 : FD_LOG_WARNING(( "stakes is NULL" ));
99 0 : fd_bank_stakes_end_locking_query( slot_ctx->bank );
100 0 : return 0;
101 0 : }
102 :
103 0 : fd_vote_accounts_global_t const * vote_accounts = &stakes->vote_accounts;
104 0 : fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_pool = fd_vote_accounts_vote_accounts_pool_join( vote_accounts );
105 0 : fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_root = fd_vote_accounts_vote_accounts_root_join( vote_accounts );
106 :
107 0 : if( FD_UNLIKELY( !vote_accounts_pool ) ) {
108 0 : FD_LOG_CRIT(( "vote_accounts_pool is NULL" ));
109 0 : }
110 0 : if( FD_UNLIKELY( !vote_accounts_root ) ) {
111 0 : FD_LOG_CRIT(( "vote_accounts_root is NULL" ));
112 0 : }
113 :
114 0 : for( fd_vote_accounts_pair_global_t_mapnode_t * n = fd_vote_accounts_pair_global_t_map_minimum(vote_accounts_pool, vote_accounts_root);
115 0 : n;
116 0 : n = fd_vote_accounts_pair_global_t_map_successor( vote_accounts_pool, n ) ) {
117 :
118 0 : FD_SPAD_FRAME_BEGIN( runtime_spad ) {
119 :
120 : /* Extract vote timestamp of account */
121 0 : int err;
122 :
123 0 : uchar * data = fd_solana_account_data_join( &n->elem.value );
124 0 : ulong data_len = n->elem.value.data_len;
125 :
126 0 : fd_vote_state_versioned_t * vsv = fd_bincode_decode_spad(
127 0 : vote_state_versioned, runtime_spad,
128 0 : data,
129 0 : data_len,
130 0 : &err );
131 0 : if( FD_UNLIKELY( err ) ) {
132 0 : FD_LOG_WARNING(( "vote state decode failed" ));
133 0 : fd_bank_stakes_end_locking_query( slot_ctx->bank );
134 0 : return 0;
135 0 : }
136 :
137 0 : long timestamp = 0;
138 0 : ulong slot = 0;
139 0 : switch( vsv->discriminant ) {
140 0 : case fd_vote_state_versioned_enum_v0_23_5:
141 0 : timestamp = vsv->inner.v0_23_5.last_timestamp.timestamp;
142 0 : slot = vsv->inner.v0_23_5.last_timestamp.slot;
143 0 : break;
144 0 : case fd_vote_state_versioned_enum_v1_14_11:
145 0 : timestamp = vsv->inner.v1_14_11.last_timestamp.timestamp;
146 0 : slot = vsv->inner.v1_14_11.last_timestamp.slot;
147 0 : break;
148 0 : case fd_vote_state_versioned_enum_current:
149 0 : timestamp = vsv->inner.current.last_timestamp.timestamp;
150 0 : slot = vsv->inner.current.last_timestamp.slot;
151 0 : break;
152 0 : default:
153 0 : __builtin_unreachable();
154 0 : }
155 :
156 : /* Record timestamp */
157 0 : if( slot != 0 || n->elem.stake != 0 ) {
158 0 : fd_vote_record_timestamp_vote_with_slot( &n->elem.key, timestamp, slot, slot_ctx->bank );
159 0 : }
160 0 : } FD_SPAD_FRAME_END;
161 0 : }
162 :
163 0 : fd_bank_stakes_end_locking_query( slot_ctx->bank );
164 0 : return 1;
165 0 : }
166 :
167 : fd_exec_slot_ctx_t *
168 : fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t * slot_ctx,
169 : fd_solana_manifest_global_t const * manifest,
170 0 : fd_spad_t * runtime_spad ) {
171 :
172 0 : slot_ctx->bank = fd_banks_clone_from_parent( slot_ctx->banks, manifest->bank.slot, 0UL );
173 0 : if( FD_UNLIKELY( !slot_ctx->bank ) ) {
174 0 : FD_LOG_CRIT(( "fd_banks_clone_from_parent failed" ));
175 0 : }
176 :
177 0 : fd_versioned_bank_global_t const * old_bank = &manifest->bank;
178 :
179 0 : ulong stakes_sz = fd_stakes_size_global( &manifest->bank.stakes );
180 0 : fd_stakes_global_t * stakes = fd_bank_stakes_locking_modify( slot_ctx->bank );
181 0 : fd_memcpy( stakes, &manifest->bank.stakes, stakes_sz );
182 : /* Verify stakes */
183 :
184 0 : fd_bank_stakes_end_locking_modify( slot_ctx->bank );
185 :
186 : /* Index vote accounts */
187 :
188 : /* Block Hash Queue */
189 :
190 0 : fd_block_hash_queue_global_t * bhq = (fd_block_hash_queue_global_t *)&slot_ctx->bank->block_hash_queue[0];
191 0 : uchar * last_hash_mem = (uchar *)fd_ulong_align_up( (ulong)bhq + sizeof(fd_block_hash_queue_global_t), alignof(fd_hash_t) );
192 0 : uchar * ages_pool_mem = (uchar *)fd_ulong_align_up( (ulong)last_hash_mem + sizeof(fd_hash_t), fd_hash_hash_age_pair_t_map_align() );
193 :
194 0 : fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_hash_hash_age_pair_t_map_join( fd_hash_hash_age_pair_t_map_new( ages_pool_mem, 301 ) );
195 0 : fd_hash_hash_age_pair_t_mapnode_t * ages_root = NULL;
196 :
197 0 : bhq->last_hash_index = old_bank->blockhash_queue.last_hash_index;
198 :
199 0 : fd_hash_t const * last_hash = fd_block_hash_vec_last_hash_join( &old_bank->blockhash_queue );
200 :
201 0 : if( last_hash ) {
202 0 : fd_memcpy( last_hash_mem, last_hash, sizeof(fd_hash_t) );
203 0 : } else {
204 0 : fd_memset( last_hash_mem, 0, sizeof(fd_hash_t) );
205 0 : }
206 0 : bhq->last_hash_offset = (ulong)last_hash_mem - (ulong)bhq;
207 :
208 0 : fd_hash_hash_age_pair_t const * ages = fd_block_hash_vec_ages_join( &old_bank->blockhash_queue );
209 :
210 0 : for( ulong i=0UL; i<old_bank->blockhash_queue.ages_len; i++ ) {
211 0 : fd_hash_hash_age_pair_t const * elem = &ages[i];
212 0 : fd_hash_hash_age_pair_t_mapnode_t * node = fd_hash_hash_age_pair_t_map_acquire( ages_pool );
213 0 : node->elem = *elem;
214 0 : fd_hash_hash_age_pair_t_map_insert( ages_pool, &ages_root, node );
215 0 : }
216 :
217 0 : fd_block_hash_queue_ages_pool_update( bhq, ages_pool );
218 0 : fd_block_hash_queue_ages_root_update( bhq, ages_root );
219 :
220 0 : bhq->max_age = old_bank->blockhash_queue.max_age;
221 :
222 : /* Bank Hash */
223 :
224 0 : fd_bank_bank_hash_set( slot_ctx->bank, old_bank->hash );
225 :
226 : /* Slot */
227 :
228 0 : slot_ctx->slot = old_bank->slot;
229 :
230 : /* Fee Rate Governor */
231 :
232 0 : fd_fee_rate_governor_t * fee_rate_governor = fd_bank_fee_rate_governor_modify( slot_ctx->bank );
233 0 : fd_memcpy( fee_rate_governor, &old_bank->fee_rate_governor, sizeof(fd_fee_rate_governor_t) );
234 :
235 : /* Capitalization */
236 :
237 0 : fd_bank_capitalization_set( slot_ctx->bank, old_bank->capitalization );
238 :
239 : /* Lamports Per Signature */
240 :
241 0 : fd_bank_lamports_per_signature_set( slot_ctx->bank, manifest->lamports_per_signature );
242 :
243 : /* Previous Lamports Per Signature */
244 :
245 0 : fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, manifest->lamports_per_signature );
246 :
247 : /* Transaction Count */
248 :
249 0 : fd_bank_transaction_count_set( slot_ctx->bank, old_bank->transaction_count );
250 :
251 : /* Parent Signature Count */
252 :
253 0 : fd_bank_parent_signature_cnt_set( slot_ctx->bank, old_bank->signature_count );
254 :
255 : /* Tick Height */
256 :
257 0 : fd_bank_tick_height_set( slot_ctx->bank, old_bank->tick_height );
258 :
259 : /* Max Tick Height */
260 :
261 0 : fd_bank_max_tick_height_set( slot_ctx->bank, old_bank->max_tick_height );
262 :
263 : /* Hashes Per Tick */
264 :
265 0 : ulong * hashes_per_tick = fd_versioned_bank_hashes_per_tick_join( old_bank );
266 0 : fd_bank_hashes_per_tick_set( slot_ctx->bank, !!hashes_per_tick ? *hashes_per_tick : 0UL );
267 :
268 : /* NS Per Slot */
269 :
270 0 : fd_bank_ns_per_slot_set( slot_ctx->bank, old_bank->ns_per_slot );
271 :
272 : /* Ticks Per Slot */
273 :
274 0 : fd_bank_ticks_per_slot_set( slot_ctx->bank, old_bank->ticks_per_slot );
275 :
276 : /* Genesis Creation Time */
277 :
278 0 : fd_bank_genesis_creation_time_set( slot_ctx->bank, old_bank->genesis_creation_time );
279 :
280 : /* Slots Per Year */
281 :
282 0 : fd_bank_slots_per_year_set( slot_ctx->bank, old_bank->slots_per_year );
283 :
284 : /* Inflation */
285 :
286 0 : fd_bank_inflation_set( slot_ctx->bank, old_bank->inflation );
287 :
288 : /* Block Height */
289 :
290 0 : fd_bank_block_height_set( slot_ctx->bank, old_bank->block_height );
291 :
292 : /* Epoch Account Hash */
293 :
294 0 : fd_hash_t * epoch_account_hash = fd_solana_manifest_epoch_account_hash_join( manifest );
295 0 : if( !!epoch_account_hash ) {
296 0 : fd_bank_epoch_account_hash_set( slot_ctx->bank, *epoch_account_hash );
297 0 : } else {
298 0 : fd_bank_epoch_account_hash_set( slot_ctx->bank, (fd_hash_t){0} );
299 0 : }
300 :
301 : /* Prev Slot */
302 :
303 0 : fd_bank_prev_slot_set( slot_ctx->bank, old_bank->parent_slot );
304 :
305 : /* Execution Fees */
306 :
307 0 : fd_bank_execution_fees_set( slot_ctx->bank, old_bank->collector_fees );
308 :
309 : /* Priority Fees */
310 :
311 0 : fd_bank_priority_fees_set( slot_ctx->bank, 0UL );
312 :
313 : /* PoH */
314 :
315 0 : if( last_hash ) {
316 0 : fd_bank_poh_set( slot_ctx->bank, *last_hash );
317 0 : }
318 :
319 : /* Prev Bank Hash */
320 :
321 0 : fd_bank_prev_bank_hash_set( slot_ctx->bank, old_bank->parent_hash );
322 :
323 : /* Epoch Schedule */
324 :
325 0 : fd_bank_epoch_schedule_set( slot_ctx->bank, old_bank->epoch_schedule );
326 :
327 : /* Rent */
328 :
329 0 : fd_bank_rent_set( slot_ctx->bank, old_bank->rent_collector.rent );
330 :
331 : /* Last Restart Slot */
332 :
333 : /* Update last restart slot
334 : https://github.com/solana-labs/solana/blob/30531d7a5b74f914dde53bfbb0bc2144f2ac92bb/runtime/src/bank.rs#L2152
335 :
336 : old_bank->hard_forks is sorted ascending by slot number.
337 : To find the last restart slot, take the highest hard fork slot
338 : number that is less or equal than the current slot number.
339 : (There might be some hard forks in the future, ignore these) */
340 0 : do {
341 0 : fd_sol_sysvar_last_restart_slot_t * last_restart_slot = fd_bank_last_restart_slot_modify( slot_ctx->bank );
342 0 : last_restart_slot->slot = 0UL;
343 :
344 0 : if( FD_UNLIKELY( old_bank->hard_forks.hard_forks_len == 0 ) ) {
345 : /* SIMD-0047: The first restart slot should be `0` */
346 0 : break;
347 0 : }
348 :
349 0 : fd_slot_pair_t const * head = fd_hard_forks_hard_forks_join( &old_bank->hard_forks );
350 0 : fd_slot_pair_t const * tail = head + old_bank->hard_forks.hard_forks_len - 1UL;
351 :
352 0 : for( fd_slot_pair_t const *pair = tail; pair >= head; pair-- ) {
353 0 : if( pair->slot <= slot_ctx->slot ) {
354 0 : fd_sol_sysvar_last_restart_slot_t * last_restart_slot = fd_bank_last_restart_slot_modify( slot_ctx->bank );
355 0 : last_restart_slot->slot = pair->slot;
356 0 : break;
357 0 : }
358 0 : }
359 0 : } while (0);
360 :
361 : /* FIXME: Remove the magic number here. */
362 0 : fd_clock_timestamp_votes_global_t * clock_timestamp_votes = fd_bank_clock_timestamp_votes_locking_modify( slot_ctx->bank );
363 0 : uchar * clock_pool_mem = (uchar *)fd_ulong_align_up( (ulong)clock_timestamp_votes + sizeof(fd_clock_timestamp_votes_global_t), fd_clock_timestamp_vote_t_map_align() );
364 0 : fd_clock_timestamp_vote_t_mapnode_t * clock_pool = fd_clock_timestamp_vote_t_map_join( fd_clock_timestamp_vote_t_map_new(clock_pool_mem, 30000UL ) );
365 0 : clock_timestamp_votes->votes_pool_offset = (ulong)fd_clock_timestamp_vote_t_map_leave( clock_pool) - (ulong)clock_timestamp_votes;
366 0 : clock_timestamp_votes->votes_root_offset = 0UL;
367 0 : fd_bank_clock_timestamp_votes_end_locking_modify( slot_ctx->bank );
368 :
369 0 : recover_clock( slot_ctx, runtime_spad );
370 :
371 :
372 : /* Move EpochStakes */
373 0 : do {
374 :
375 0 : fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank );
376 0 : ulong epoch = fd_slot_to_epoch( epoch_schedule, slot_ctx->slot, NULL );
377 :
378 : /* We need to save the vote accounts for the current epoch and the next
379 : epoch as it is used to calculate the leader schedule at the epoch
380 : boundary. */
381 :
382 0 : fd_vote_accounts_global_t * vote_accounts_curr_stakes = NULL;
383 0 : fd_vote_accounts_global_t * vote_accounts_next_stakes = NULL;
384 :
385 0 : fd_epoch_epoch_stakes_pair_global_t * versioned_bank_epoch_stakes = fd_versioned_bank_epoch_stakes_join( &manifest->bank );
386 0 : for( ulong i=0UL; i<manifest->bank.epoch_stakes_len; i++ ) {
387 0 : if( versioned_bank_epoch_stakes[i].key == epoch ) {
388 0 : vote_accounts_curr_stakes = &versioned_bank_epoch_stakes[i].value.stakes.vote_accounts;
389 0 : }
390 0 : if( versioned_bank_epoch_stakes[i].key == epoch+1UL ) {
391 0 : vote_accounts_next_stakes = &versioned_bank_epoch_stakes[i].value.stakes.vote_accounts;
392 0 : }
393 :
394 : /* When loading from a snapshot, Agave's stake caches mean that we have to special-case the epoch stakes
395 : that are used for the second epoch E+2 after the snapshot epoch E.
396 :
397 : If the snapshot contains the epoch stakes for E+2, we should use those.
398 :
399 : If the snapshot does not, we should use the stakes at the end of the E-1 epoch, instead of E-2 as we do for
400 : all other epochs. */
401 0 : }
402 :
403 0 : fd_versioned_epoch_stakes_pair_global_t * versioned_epoch_stakes = fd_solana_manifest_versioned_epoch_stakes_join( manifest );
404 0 : for( ulong i=0UL; i<manifest->versioned_epoch_stakes_len; i++ ) {
405 :
406 0 : if( versioned_epoch_stakes[i].epoch == epoch ) {
407 0 : vote_accounts_curr_stakes = &versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts;
408 0 : }
409 0 : if( versioned_epoch_stakes[i].epoch == epoch+1UL ) {
410 0 : vote_accounts_next_stakes = &versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts;
411 :
412 : /* Save the initial value to be used for the get_epoch_stake
413 : syscall.
414 :
415 : A note on Agave's indexing scheme for their epoch_stakes
416 : structure:
417 :
418 : https://github.com/anza-xyz/agave/blob/v2.2.14/runtime/src/bank.rs#L6175
419 :
420 : If we are loading a snapshot and replaying in the middle of
421 : epoch 7, the syscall is supposed to return the total stake at
422 : the end of epoch 6. The epoch_stakes structure is indexed in
423 : Agave by the epoch number of the leader schedule that the
424 : stakes are meant to determine. For instance, to get the
425 : stakes at the end of epoch 6, we should query by 8, because
426 : the leader schedule for epoch 8 is determined based on the
427 : stakes at the end of epoch 6. Therefore, we save the total
428 : epoch stake by querying for epoch+1. */
429 0 : fd_bank_total_epoch_stake_set( slot_ctx->bank, versioned_epoch_stakes[i].val.inner.Current.total_stake );
430 0 : }
431 0 : }
432 :
433 0 : fd_bank_use_prev_epoch_stake_set( slot_ctx->bank, epoch + 2UL );
434 :
435 0 : fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_curr_stakes_pool = fd_vote_accounts_vote_accounts_pool_join( vote_accounts_curr_stakes );
436 0 : fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_curr_stakes_root = fd_vote_accounts_vote_accounts_root_join( vote_accounts_curr_stakes );
437 :
438 0 : fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_next_stakes_pool = fd_vote_accounts_vote_accounts_pool_join( vote_accounts_next_stakes );
439 0 : fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_next_stakes_root = fd_vote_accounts_vote_accounts_root_join( vote_accounts_next_stakes );
440 :
441 0 : if( FD_UNLIKELY( (!vote_accounts_curr_stakes_pool) | (!vote_accounts_next_stakes_pool) ) ) {
442 0 : FD_LOG_WARNING(( "snapshot missing EpochStakes for epochs %lu and/or %lu", epoch, epoch+1UL ));
443 0 : return 0;
444 0 : }
445 :
446 : /* Move current EpochStakes */
447 :
448 0 : fd_vote_accounts_global_t * epoch_stakes = fd_bank_epoch_stakes_locking_modify( slot_ctx->bank );
449 0 : uchar * epoch_stakes_pool_mem = (uchar *)fd_ulong_align_up( (ulong)epoch_stakes + sizeof(fd_vote_accounts_global_t), fd_vote_accounts_pair_global_t_map_align() );
450 0 : fd_vote_accounts_pair_global_t_mapnode_t * epoch_stakes_pool = fd_vote_accounts_pair_global_t_map_join( fd_vote_accounts_pair_global_t_map_new( epoch_stakes_pool_mem, 50000UL ) );
451 0 : fd_vote_accounts_pair_global_t_mapnode_t * epoch_stakes_root = NULL;
452 :
453 0 : uchar * acc_region_curr = (uchar *)fd_ulong_align_up( (ulong)epoch_stakes_pool + fd_vote_accounts_pair_global_t_map_footprint( 50000UL ), 8UL );
454 :
455 0 : for( fd_vote_accounts_pair_global_t_mapnode_t * n = fd_vote_accounts_pair_global_t_map_minimum(
456 0 : vote_accounts_curr_stakes_pool,
457 0 : vote_accounts_curr_stakes_root );
458 0 : n;
459 0 : n = fd_vote_accounts_pair_global_t_map_successor( vote_accounts_curr_stakes_pool, n ) ) {
460 :
461 0 : fd_vote_accounts_pair_global_t_mapnode_t * elem = fd_vote_accounts_pair_global_t_map_acquire(
462 0 : epoch_stakes_pool );
463 0 : FD_TEST( elem );
464 :
465 0 : elem->elem.stake = n->elem.stake;
466 0 : elem->elem.key = n->elem.key;
467 :
468 0 : elem->elem.value.lamports = n->elem.value.lamports;
469 0 : elem->elem.value.data_len = 0UL;
470 0 : elem->elem.value.data_offset = 0UL;
471 0 : elem->elem.value.owner = n->elem.value.owner;
472 0 : elem->elem.value.executable = n->elem.value.executable;
473 0 : elem->elem.value.rent_epoch = n->elem.value.rent_epoch;
474 :
475 0 : elem->elem.value.data_offset = (ulong)(acc_region_curr - (uchar *)&elem->elem.value);
476 0 : elem->elem.value.data_len = n->elem.value.data_len;
477 :
478 0 : uchar * manifest_data = fd_solana_account_data_join( &n->elem.value );
479 0 : memcpy( acc_region_curr, manifest_data, n->elem.value.data_len );
480 0 : acc_region_curr += n->elem.value.data_len;
481 :
482 0 : fd_vote_accounts_pair_global_t_map_insert(
483 0 : epoch_stakes_pool,
484 0 : &epoch_stakes_root,
485 0 : elem );
486 0 : }
487 :
488 0 : fd_vote_accounts_vote_accounts_pool_update( epoch_stakes, epoch_stakes_pool );
489 0 : fd_vote_accounts_vote_accounts_root_update( epoch_stakes, epoch_stakes_root );
490 0 : fd_bank_epoch_stakes_end_locking_modify( slot_ctx->bank );
491 :
492 : /* Move next EpochStakes */
493 :
494 0 : fd_vote_accounts_global_t * next_epoch_stakes = fd_bank_next_epoch_stakes_locking_modify( slot_ctx->bank );
495 0 : uchar * next_epoch_stakes_pool_mem = (uchar *)fd_ulong_align_up( (ulong)next_epoch_stakes + sizeof(fd_vote_accounts_global_t), fd_vote_accounts_pair_global_t_map_align() );
496 0 : fd_vote_accounts_pair_global_t_mapnode_t * next_epoch_stakes_pool = fd_vote_accounts_pair_global_t_map_join( fd_vote_accounts_pair_global_t_map_new( next_epoch_stakes_pool_mem, 50000UL ) );
497 0 : fd_vote_accounts_pair_global_t_mapnode_t * next_epoch_stakes_root = NULL;
498 :
499 0 : fd_vote_accounts_pair_global_t_mapnode_t * pool = vote_accounts_next_stakes_pool;
500 0 : fd_vote_accounts_pair_global_t_mapnode_t * root = vote_accounts_next_stakes_root;
501 :
502 0 : acc_region_curr = (uchar *)fd_ulong_align_up( (ulong)next_epoch_stakes_pool + fd_vote_accounts_pair_global_t_map_footprint( 50000UL ), 8UL );
503 :
504 0 : for( fd_vote_accounts_pair_global_t_mapnode_t * n = fd_vote_accounts_pair_global_t_map_minimum( pool, root );
505 0 : n;
506 0 : n = fd_vote_accounts_pair_global_t_map_successor( pool, n ) ) {
507 :
508 0 : fd_vote_accounts_pair_global_t_mapnode_t * elem = fd_vote_accounts_pair_global_t_map_acquire( next_epoch_stakes_pool );
509 0 : FD_TEST( elem );
510 :
511 0 : elem->elem.stake = n->elem.stake;
512 0 : elem->elem.key = n->elem.key;
513 :
514 0 : elem->elem.value.lamports = n->elem.value.lamports;
515 0 : elem->elem.value.data_len = 0UL;
516 0 : elem->elem.value.data_offset = 0UL;
517 0 : elem->elem.value.owner = n->elem.value.owner;
518 0 : elem->elem.value.executable = n->elem.value.executable;
519 0 : elem->elem.value.rent_epoch = n->elem.value.rent_epoch;
520 :
521 0 : elem->elem.value.data_offset = (ulong)(acc_region_curr - (uchar *)&elem->elem.value);;
522 0 : elem->elem.value.data_len = n->elem.value.data_len;
523 :
524 0 : uchar * manifest_data = fd_solana_account_data_join( &n->elem.value );
525 0 : memcpy( acc_region_curr, manifest_data, n->elem.value.data_len );
526 0 : acc_region_curr += n->elem.value.data_len;
527 :
528 0 : fd_vote_accounts_pair_global_t_map_insert(
529 0 : next_epoch_stakes_pool,
530 0 : &next_epoch_stakes_root,
531 0 : elem );
532 :
533 0 : }
534 0 : fd_vote_accounts_vote_accounts_pool_update( next_epoch_stakes, next_epoch_stakes_pool );
535 0 : fd_vote_accounts_vote_accounts_root_update( next_epoch_stakes, next_epoch_stakes_root );
536 0 : fd_bank_next_epoch_stakes_end_locking_modify( slot_ctx->bank );
537 :
538 0 : } while(0);
539 :
540 0 : fd_slot_lthash_t * lthash = fd_bank_lthash_modify( slot_ctx->bank );
541 :
542 0 : fd_slot_lthash_t * lthash_value = fd_solana_manifest_lthash_join( manifest );
543 0 : if( !!lthash_value ) {
544 0 : *lthash = *lthash_value;
545 0 : } else {
546 0 : fd_lthash_zero( (fd_lthash_value_t *)lthash->lthash );
547 0 : }
548 : /* Setup next epoch stakes */
549 :
550 0 : return slot_ctx;
551 0 : }
552 :
553 : fd_exec_slot_ctx_t *
554 : fd_exec_slot_ctx_recover_status_cache( fd_exec_slot_ctx_t * ctx,
555 : fd_bank_slot_deltas_t * slot_deltas,
556 0 : fd_spad_t * runtime_spad ) {
557 :
558 0 : fd_txncache_t * status_cache = ctx->status_cache;
559 0 : if( !status_cache ) {
560 0 : FD_LOG_WARNING(("No status cache in slot ctx"));
561 0 : return NULL;
562 0 : }
563 :
564 0 : FD_SPAD_FRAME_BEGIN( runtime_spad ) {
565 :
566 0 : ulong num_entries = 0;
567 0 : for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
568 0 : fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[i];
569 0 : for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
570 0 : num_entries += slot_delta->slot_delta_vec[j].value.statuses_len;
571 0 : }
572 0 : }
573 0 : fd_txncache_insert_t * insert_vals = fd_spad_alloc_check( runtime_spad, alignof(fd_txncache_insert_t), num_entries * sizeof(fd_txncache_insert_t) );
574 :
575 : /* Dumb sort for 300 slot entries to insert in order. */
576 0 : fd_slot_delta_t ** deltas = fd_spad_alloc_check( runtime_spad, alignof(fd_slot_delta_t*), slot_deltas->slot_deltas_len * sizeof(fd_slot_delta_t*) );
577 :
578 0 : long curr = -1;
579 0 : for( ulong i = 0UL; i < slot_deltas->slot_deltas_len; i++ ) {
580 0 : ulong curr_min = ULONG_MAX;
581 0 : ulong curr_min_idx = ULONG_MAX;
582 0 : for( ulong j = 0; j < slot_deltas->slot_deltas_len; j++ ) {
583 0 : fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[j];
584 0 : if( (long)slot_delta->slot <= curr ) continue;
585 :
586 0 : if( curr_min > slot_delta->slot ) {
587 0 : curr_min = slot_delta->slot;
588 0 : curr_min_idx = j;
589 0 : }
590 0 : }
591 0 : deltas[i] = &slot_deltas->slot_deltas[curr_min_idx];
592 0 : curr = (long)slot_deltas->slot_deltas[curr_min_idx].slot;
593 0 : }
594 :
595 0 : ulong idx = 0;
596 0 : for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
597 0 : fd_slot_delta_t * slot_delta = deltas[i];
598 0 : ulong slot = slot_delta->slot;
599 0 : if( slot_delta->is_root ) {
600 0 : fd_txncache_register_root_slot( ctx->status_cache, slot );
601 0 : }
602 0 : for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
603 0 : fd_status_pair_t * pair = &slot_delta->slot_delta_vec[j];
604 0 : fd_hash_t * blockhash = &pair->hash;
605 0 : uchar * results = fd_spad_alloc( runtime_spad, FD_SPAD_ALIGN, pair->value.statuses_len );
606 0 : for( ulong k = 0; k < pair->value.statuses_len; k++ ) {
607 0 : fd_cache_status_t * status = &pair->value.statuses[k];
608 0 : uchar * result = results + k;
609 0 : *result = (uchar)status->result.discriminant;
610 0 : insert_vals[idx++] = (fd_txncache_insert_t){
611 0 : .blockhash = blockhash->uc,
612 0 : .slot = slot,
613 0 : .txnhash = status->key_slice,
614 0 : .result = result
615 0 : };
616 0 : }
617 0 : }
618 0 : }
619 0 : fd_txncache_insert_batch( ctx->status_cache, insert_vals, num_entries );
620 :
621 0 : for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
622 0 : fd_slot_delta_t * slot_delta = deltas[i];
623 0 : ulong slot = slot_delta->slot;
624 0 : for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
625 0 : fd_status_pair_t * pair = &slot_delta->slot_delta_vec[j];
626 0 : fd_hash_t * blockhash = &pair->hash;
627 0 : fd_txncache_set_txnhash_offset( ctx->status_cache, slot, blockhash->uc, pair->value.txn_idx );
628 0 : }
629 0 : }
630 :
631 0 : } FD_SPAD_FRAME_END;
632 0 : return ctx;
633 0 : }
|