Line data Source code
1 : #include "fd_exec_slot_ctx.h"
2 : #include "fd_exec_epoch_ctx.h"
3 : #include "../sysvar/fd_sysvar_epoch_schedule.h"
4 : #include "../program/fd_vote_program.h"
5 :
6 : #include <assert.h>
7 : #include <time.h>
8 :
9 : void *
10 : fd_exec_slot_ctx_new( void * mem,
11 108786 : fd_valloc_t valloc ) {
12 108786 : if( FD_UNLIKELY( !mem ) ) {
13 0 : FD_LOG_WARNING(( "NULL mem" ));
14 0 : return NULL;
15 0 : }
16 :
17 108786 : 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 108786 : fd_memset( mem, 0, sizeof(fd_exec_slot_ctx_t) );
23 :
24 108786 : fd_exec_slot_ctx_t * self = (fd_exec_slot_ctx_t *) mem;
25 108786 : self->valloc = valloc;
26 108786 : fd_slot_bank_new(&self->slot_bank);
27 :
28 108786 : self->sysvar_cache = fd_sysvar_cache_new( fd_valloc_malloc( valloc, fd_sysvar_cache_align(), fd_sysvar_cache_footprint() ), valloc );
29 108786 : self->account_compute_table = fd_account_compute_table_join( fd_account_compute_table_new( fd_valloc_malloc( valloc, fd_account_compute_table_align(), fd_account_compute_table_footprint( 10000 ) ), 10000, 0 ) );
30 :
31 : /* This is inactive by default */
32 108786 : self->epoch_reward_status.discriminant = fd_epoch_reward_status_enum_Inactive;
33 :
34 108786 : FD_COMPILER_MFENCE();
35 108786 : self->magic = FD_EXEC_SLOT_CTX_MAGIC;
36 108786 : FD_COMPILER_MFENCE();
37 :
38 108786 : return mem;
39 108786 : }
40 :
41 : fd_exec_slot_ctx_t *
42 108786 : fd_exec_slot_ctx_join( void * mem ) {
43 108786 : if( FD_UNLIKELY( !mem ) ) {
44 0 : FD_LOG_WARNING(( "NULL block" ));
45 0 : return NULL;
46 0 : }
47 :
48 108786 : fd_exec_slot_ctx_t * ctx = (fd_exec_slot_ctx_t *) mem;
49 :
50 108786 : if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
51 0 : FD_LOG_WARNING(( "bad magic" ));
52 0 : return NULL;
53 0 : }
54 :
55 108786 : return ctx;
56 108786 : }
57 :
58 : void *
59 108786 : fd_exec_slot_ctx_leave( fd_exec_slot_ctx_t * ctx) {
60 108786 : if( FD_UNLIKELY( !ctx ) ) {
61 0 : FD_LOG_WARNING(( "NULL block" ));
62 0 : return NULL;
63 0 : }
64 :
65 108786 : if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
66 0 : FD_LOG_WARNING(( "bad magic" ));
67 0 : return NULL;
68 0 : }
69 :
70 108786 : return (void *) ctx;
71 108786 : }
72 :
73 : void *
74 108786 : fd_exec_slot_ctx_delete( void * mem ) {
75 108786 : if( FD_UNLIKELY( !mem ) ) {
76 0 : FD_LOG_WARNING(( "NULL mem" ));
77 0 : return NULL;
78 0 : }
79 :
80 108786 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_SLOT_CTX_ALIGN) ) ) {
81 0 : FD_LOG_WARNING(( "misaligned mem" ));
82 0 : return NULL;
83 0 : }
84 :
85 108786 : fd_exec_slot_ctx_t * hdr = (fd_exec_slot_ctx_t *)mem;
86 108786 : if( FD_UNLIKELY( hdr->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
87 0 : FD_LOG_WARNING(( "bad magic" ));
88 0 : return NULL;
89 0 : }
90 :
91 108786 : fd_bincode_destroy_ctx_t ctx = { .valloc = hdr->valloc };
92 108786 : fd_slot_bank_destroy(&hdr->slot_bank, &ctx);
93 :
94 108786 : fd_valloc_free( hdr->valloc, fd_sysvar_cache_delete( hdr->sysvar_cache ) );
95 108786 : hdr->sysvar_cache = NULL;
96 108786 : fd_valloc_free( hdr->valloc, fd_account_compute_table_delete( fd_account_compute_table_leave( hdr->account_compute_table ) ) );
97 108786 : hdr->account_compute_table = NULL;
98 :
99 108786 : FD_COMPILER_MFENCE();
100 108786 : FD_VOLATILE( hdr->magic ) = 0UL;
101 108786 : FD_COMPILER_MFENCE();
102 :
103 108786 : return mem;
104 108786 : }
105 :
106 : /* recover_clock recovers PoH/wallclock synchronization. Walks all vote
107 : accounts in current epoch stakes. */
108 :
109 : static int
110 0 : recover_clock( fd_exec_slot_ctx_t * slot_ctx ) {
111 :
112 0 : fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
113 0 : fd_vote_accounts_t const * vote_accounts = &epoch_bank->stakes.vote_accounts;
114 :
115 0 : fd_vote_accounts_pair_t_mapnode_t * vote_accounts_pool = vote_accounts->vote_accounts_pool;
116 0 : fd_vote_accounts_pair_t_mapnode_t * vote_accounts_root = vote_accounts->vote_accounts_root;
117 :
118 0 : for( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(vote_accounts_pool, vote_accounts_root);
119 0 : n;
120 0 : n = fd_vote_accounts_pair_t_map_successor( vote_accounts_pool, n ) ) {
121 : /* Extract vote timestamp of account */
122 :
123 0 : fd_vote_block_timestamp_t vote_state_timestamp = {
124 0 : .timestamp = n->elem.value.last_timestamp_ts,
125 0 : .slot = n->elem.value.last_timestamp_slot
126 0 : };
127 :
128 : /* Record timestamp */
129 0 : if( vote_state_timestamp.slot != 0 || n->elem.stake != 0 ) {
130 0 : fd_vote_record_timestamp_vote_with_slot(slot_ctx, &n->elem.key, vote_state_timestamp.timestamp, vote_state_timestamp.slot);
131 0 : }
132 0 : }
133 :
134 0 : return 1;
135 0 : }
136 :
137 : /* Implementation note: fd_exec_slot_ctx_recover moves objects from
138 : manifest to slot_ctx. This function must not share pointers between
139 : slot_ctx and manifest. Otherwise, would cause a use-after-free. */
140 :
141 : static fd_exec_slot_ctx_t *
142 : fd_exec_slot_ctx_recover_( fd_exec_slot_ctx_t * slot_ctx,
143 0 : fd_solana_manifest_t * manifest ) {
144 :
145 0 : fd_exec_epoch_ctx_t * epoch_ctx = slot_ctx->epoch_ctx;
146 0 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( epoch_ctx );
147 0 : fd_valloc_t slot_valloc = slot_ctx->valloc;
148 :
149 : /* Clean out prior bank */
150 0 : fd_bincode_destroy_ctx_t destroy = { .valloc = slot_valloc };
151 0 : fd_slot_bank_t * slot_bank = &slot_ctx->slot_bank;
152 0 : fd_slot_bank_destroy( slot_bank, &destroy );
153 0 : fd_slot_bank_new( slot_bank );
154 :
155 0 : for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
156 0 : epoch_bank->stakes.vote_accounts.vote_accounts_pool,
157 0 : epoch_bank->stakes.vote_accounts.vote_accounts_root );
158 0 : n;
159 0 : n = fd_vote_accounts_pair_t_map_successor( epoch_bank->stakes.vote_accounts.vote_accounts_pool, n ) ) {
160 :
161 0 : const fd_pubkey_t null_pubkey = {{ 0 }};
162 0 : if ( memcmp( &n->elem.key, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
163 0 : continue;
164 0 : }
165 0 : }
166 :
167 0 : fd_deserializable_versioned_bank_t * oldbank = &manifest->bank;
168 :
169 : /* Populate the epoch context, using the already-allocated statically allocated memory */
170 : /* Copy stakes */
171 0 : epoch_bank->stakes.epoch = oldbank->stakes.epoch;
172 :
173 : /* Copy stakes->vote_accounts */
174 0 : for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
175 0 : oldbank->stakes.vote_accounts.vote_accounts_pool,
176 0 : oldbank->stakes.vote_accounts.vote_accounts_root );
177 0 : n;
178 0 : n = fd_vote_accounts_pair_t_map_successor( oldbank->stakes.vote_accounts.vote_accounts_pool, n ) ) {
179 :
180 0 : const fd_pubkey_t null_pubkey = {{ 0 }};
181 0 : if ( memcmp( &n->elem.key, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
182 0 : continue;
183 0 : }
184 :
185 0 : FD_TEST( fd_vote_accounts_pair_t_map_free( epoch_bank->stakes.vote_accounts.vote_accounts_pool ) );
186 0 : fd_vote_accounts_pair_t_mapnode_t * new_node = fd_vote_accounts_pair_t_map_acquire( epoch_bank->stakes.vote_accounts.vote_accounts_pool );
187 0 : FD_TEST( new_node );
188 0 : fd_memcpy( &new_node->elem, &n->elem, FD_VOTE_ACCOUNTS_PAIR_FOOTPRINT );
189 0 : fd_vote_accounts_pair_t_map_insert(
190 0 : epoch_bank->stakes.vote_accounts.vote_accounts_pool,
191 0 : &epoch_bank->stakes.vote_accounts.vote_accounts_root,
192 0 : new_node
193 0 : );
194 0 : }
195 :
196 : /* Copy stakes->stake_delegations */
197 0 : for ( fd_delegation_pair_t_mapnode_t * n = fd_delegation_pair_t_map_minimum(
198 0 : oldbank->stakes.stake_delegations_pool,
199 0 : oldbank->stakes.stake_delegations_root );
200 0 : n;
201 0 : n = fd_delegation_pair_t_map_successor( oldbank->stakes.stake_delegations_pool, n ) ) {
202 :
203 0 : const fd_pubkey_t null_pubkey = {{ 0 }};
204 0 : if ( memcmp( &n->elem.account, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
205 0 : continue;
206 0 : }
207 :
208 0 : fd_delegation_pair_t_mapnode_t * new_node = fd_delegation_pair_t_map_acquire( epoch_bank->stakes.stake_delegations_pool );
209 0 : FD_TEST( new_node );
210 0 : fd_memcpy( &new_node->elem, &n->elem, FD_DELEGATION_PAIR_FOOTPRINT );
211 0 : fd_delegation_pair_t_map_insert(
212 0 : epoch_bank->stakes.stake_delegations_pool,
213 0 : &epoch_bank->stakes.stake_delegations_root,
214 0 : new_node
215 0 : );
216 0 : }
217 :
218 : /* Copy stakes->stake_history */
219 0 : for ( fd_stake_history_treap_fwd_iter_t iter = fd_stake_history_treap_fwd_iter_init(
220 0 : oldbank->stakes.stake_history.treap,
221 0 : oldbank->stakes.stake_history.pool );
222 0 : !fd_stake_history_treap_fwd_iter_done( iter );
223 0 : iter = fd_stake_history_treap_fwd_iter_next( iter, oldbank->stakes.stake_history.pool ) ) {
224 :
225 0 : fd_stake_history_entry_t const * ele = fd_stake_history_treap_fwd_iter_ele_const( iter, oldbank->stakes.stake_history.pool );
226 :
227 0 : FD_TEST( fd_stake_history_pool_free( epoch_bank->stakes.stake_history.pool ) );
228 0 : fd_stake_history_entry_t * new_ele = fd_stake_history_pool_ele_acquire( epoch_bank->stakes.stake_history.pool );
229 :
230 0 : new_ele->epoch = ele->epoch;
231 0 : new_ele->activating = ele->activating;
232 0 : new_ele->deactivating = ele->deactivating;
233 0 : new_ele->effective = ele->effective;
234 :
235 0 : epoch_bank->stakes.stake_history.treap = fd_stake_history_treap_ele_insert(
236 0 : epoch_bank->stakes.stake_history.treap,
237 0 : new_ele,
238 0 : epoch_bank->stakes.stake_history.pool
239 0 : );
240 0 : }
241 :
242 0 : fd_stakes_destroy( &oldbank->stakes, &destroy );
243 :
244 : /* Index vote accounts */
245 :
246 : /* Copy over fields */
247 :
248 0 : if( oldbank->blockhash_queue.last_hash )
249 0 : slot_bank->poh = *oldbank->blockhash_queue.last_hash;
250 0 : slot_bank->slot = oldbank->slot;
251 0 : slot_bank->prev_slot = oldbank->parent_slot;
252 0 : fd_memcpy(&slot_bank->banks_hash, &oldbank->hash, sizeof(oldbank->hash));
253 0 : fd_memcpy(&slot_bank->fee_rate_governor, &oldbank->fee_rate_governor, sizeof(oldbank->fee_rate_governor));
254 0 : slot_bank->lamports_per_signature = oldbank->fee_calculator.lamports_per_signature;
255 0 : slot_ctx->prev_lamports_per_signature = oldbank->fee_calculator.lamports_per_signature;
256 0 : if( oldbank->hashes_per_tick )
257 0 : epoch_bank->hashes_per_tick = *oldbank->hashes_per_tick;
258 0 : else
259 0 : epoch_bank->hashes_per_tick = 0;
260 0 : epoch_bank->ticks_per_slot = oldbank->ticks_per_slot;
261 0 : fd_memcpy(&epoch_bank->ns_per_slot, &oldbank->ns_per_slot, sizeof(oldbank->ns_per_slot));
262 0 : epoch_bank->genesis_creation_time = oldbank->genesis_creation_time;
263 0 : epoch_bank->slots_per_year = oldbank->slots_per_year;
264 0 : slot_bank->max_tick_height = oldbank->max_tick_height;
265 0 : fd_memcpy( &epoch_bank->inflation, &oldbank->inflation, FD_INFLATION_FOOTPRINT );
266 0 : fd_memcpy( &epoch_bank->epoch_schedule, &oldbank->epoch_schedule, FD_EPOCH_SCHEDULE_FOOTPRINT );
267 0 : epoch_bank->rent = oldbank->rent_collector.rent;
268 0 : fd_memcpy( &epoch_bank->rent, &oldbank->rent_collector.rent, FD_RENT_FOOTPRINT );
269 0 : fd_memcpy( &epoch_bank->rent_epoch_schedule, &oldbank->rent_collector.epoch_schedule, FD_EPOCH_SCHEDULE_FOOTPRINT );
270 :
271 0 : if( manifest->epoch_account_hash )
272 0 : slot_bank->epoch_account_hash = *manifest->epoch_account_hash;
273 :
274 0 : slot_bank->collected_rent = oldbank->collected_rent;
275 : // did they not change the bank?!
276 0 : slot_bank->collected_execution_fees = oldbank->collector_fees;
277 0 : slot_bank->collected_priority_fees = 0;
278 0 : slot_bank->capitalization = oldbank->capitalization;
279 0 : slot_bank->block_height = oldbank->block_height;
280 0 : slot_bank->transaction_count = oldbank->transaction_count;
281 0 : if ( oldbank->blockhash_queue.last_hash ) {
282 0 : slot_bank->block_hash_queue.last_hash = fd_valloc_malloc( slot_ctx->valloc, FD_HASH_ALIGN, FD_HASH_FOOTPRINT );
283 0 : fd_memcpy( slot_bank->block_hash_queue.last_hash, oldbank->blockhash_queue.last_hash, sizeof(fd_hash_t) );
284 0 : } else {
285 0 : slot_bank->block_hash_queue.last_hash = NULL;
286 0 : }
287 0 : slot_bank->block_hash_queue.last_hash_index = oldbank->blockhash_queue.last_hash_index;
288 0 : slot_bank->block_hash_queue.max_age = oldbank->blockhash_queue.max_age;
289 0 : slot_bank->block_hash_queue.ages_root = NULL;
290 0 : slot_bank->block_hash_queue.ages_pool = fd_hash_hash_age_pair_t_map_alloc( slot_ctx->valloc, 400 );
291 0 : for ( ulong i = 0; i < oldbank->blockhash_queue.ages_len; i++ ) {
292 0 : fd_hash_hash_age_pair_t * elem = &oldbank->blockhash_queue.ages[i];
293 0 : fd_hash_hash_age_pair_t_mapnode_t * node = fd_hash_hash_age_pair_t_map_acquire( slot_bank->block_hash_queue.ages_pool );
294 0 : fd_memcpy( &node->elem, elem, FD_HASH_HASH_AGE_PAIR_FOOTPRINT );
295 0 : fd_hash_hash_age_pair_t_map_insert( slot_bank->block_hash_queue.ages_pool, &slot_bank->block_hash_queue.ages_root, node );
296 0 : }
297 :
298 0 : recover_clock( slot_ctx );
299 :
300 : /* Update last restart slot
301 : https://github.com/solana-labs/solana/blob/30531d7a5b74f914dde53bfbb0bc2144f2ac92bb/runtime/src/bank.rs#L2152
302 :
303 : oldbank->hard_forks is sorted ascending by slot number.
304 : To find the last restart slot, take the highest hard fork slot
305 : number that is less or equal than the current slot number.
306 : (There might be some hard forks in the future, ignore these) */
307 0 : do {
308 0 : slot_bank->last_restart_slot.slot = 0UL;
309 0 : if( FD_UNLIKELY( oldbank->hard_forks.hard_forks_len == 0 ) ) {
310 : /* SIMD-0047: The first restart slot should be `0` */
311 0 : break;
312 0 : }
313 :
314 0 : fd_slot_pair_t const * head = oldbank->hard_forks.hard_forks;
315 0 : fd_slot_pair_t const * tail = head + oldbank->hard_forks.hard_forks_len - 1UL;
316 :
317 0 : for( fd_slot_pair_t const *pair = tail; pair >= head; pair-- ) {
318 0 : if( pair->slot <= slot_bank->slot ) {
319 0 : slot_bank->last_restart_slot.slot = pair->slot;
320 0 : break;
321 0 : }
322 0 : }
323 0 : } while (0);
324 :
325 : /* Move EpochStakes */
326 0 : do {
327 0 : ulong epoch = fd_slot_to_epoch( &epoch_bank->epoch_schedule, slot_bank->slot, NULL );
328 :
329 : /* Find EpochStakes object matching epoch */
330 0 : fd_epoch_epoch_stakes_pair_t * epochs = oldbank->epoch_stakes;
331 0 : fd_epoch_stakes_t * stakes0 = NULL; /* current */
332 0 : fd_epoch_stakes_t * stakes1 = NULL; /* next */
333 0 : slot_ctx->slot_bank.has_use_preceeding_epoch_stakes = 1;
334 0 : slot_ctx->slot_bank.use_preceeding_epoch_stakes = epoch + 2UL;
335 :
336 0 : for( ulong i=0UL; i < manifest->bank.epoch_stakes_len; i++ ) {
337 0 : if( epochs[i].key == epoch )
338 0 : stakes0 = &epochs[i].value;
339 0 : if( epochs[i].key == epoch+1UL )
340 0 : stakes1 = &epochs[i].value;
341 :
342 : /* When loading from a snapshot, Agave's stake caches mean that we have to special-case the epoch stakes
343 : that are used for the second epoch E+2 after the snapshot epoch E.
344 :
345 : If the snapshot contains the epoch stakes for E+2, we should use those.
346 :
347 : 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
348 : all other epochs. */
349 0 : if ( epochs[i].key == epoch+2UL ) {
350 0 : slot_ctx->slot_bank.has_use_preceeding_epoch_stakes = 0;
351 0 : }
352 0 : }
353 0 : if( FD_UNLIKELY( (!stakes0) | (!stakes1) ) ) {
354 0 : FD_LOG_WARNING(( "snapshot missing EpochStakes for epochs %lu and/or %lu", epoch, epoch+1UL ));
355 0 : return 0;
356 0 : }
357 :
358 : /* Move current EpochStakes */
359 0 : slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool =
360 0 : fd_vote_accounts_pair_t_map_alloc( slot_ctx->valloc, 100000 ); /* FIXME remove magic constant */
361 0 : slot_ctx->slot_bank.epoch_stakes.vote_accounts_root = NULL;
362 :
363 0 : for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
364 0 : stakes0->stakes.vote_accounts.vote_accounts_pool,
365 0 : stakes0->stakes.vote_accounts.vote_accounts_root );
366 0 : n;
367 0 : n = fd_vote_accounts_pair_t_map_successor( stakes0->stakes.vote_accounts.vote_accounts_pool, n ) ) {
368 :
369 0 : fd_vote_accounts_pair_t_mapnode_t * elem = fd_vote_accounts_pair_t_map_acquire(
370 0 : slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool );
371 0 : FD_TEST( elem );
372 :
373 0 : fd_memcpy( &elem->elem, &n->elem, sizeof(fd_vote_accounts_pair_t));
374 :
375 0 : fd_vote_accounts_pair_t_map_insert(
376 0 : slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool,
377 0 : &slot_ctx->slot_bank.epoch_stakes.vote_accounts_root,
378 0 : elem );
379 0 : }
380 :
381 0 : fd_vote_accounts_destroy( &stakes0->stakes.vote_accounts, &destroy );
382 :
383 : /* Move next EpochStakes
384 : TODO Can we derive this instead of trusting the snapshot? */
385 :
386 0 : fd_vote_accounts_pair_t_mapnode_t * pool = stakes1->stakes.vote_accounts.vote_accounts_pool;
387 0 : fd_vote_accounts_pair_t_mapnode_t * root = stakes1->stakes.vote_accounts.vote_accounts_root;
388 :
389 0 : for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(pool, root);
390 0 : n;
391 0 : n = fd_vote_accounts_pair_t_map_successor(pool, n) ) {
392 :
393 0 : fd_vote_accounts_pair_t_mapnode_t * elem = fd_vote_accounts_pair_t_map_acquire(
394 0 : epoch_bank->next_epoch_stakes.vote_accounts_pool );
395 0 : FD_TEST( elem );
396 :
397 0 : fd_memcpy( &elem->elem, &n->elem, sizeof(fd_vote_accounts_pair_t));
398 :
399 0 : fd_vote_accounts_pair_t_map_insert(
400 0 : epoch_bank->next_epoch_stakes.vote_accounts_pool,
401 0 : &epoch_bank->next_epoch_stakes.vote_accounts_root,
402 0 : elem );
403 :
404 0 : }
405 :
406 0 : fd_vote_accounts_destroy( &stakes1->stakes.vote_accounts, &destroy );
407 0 : } while(0);
408 :
409 : // TODO Backup to database
410 : //int result = fd_runtime_save_epoch_bank(slot_ctx);
411 : //if( result != FD_EXECUTOR_INSTR_SUCCESS ) {
412 : // FD_LOG_WARNING(("save epoch bank failed"));
413 : // return result;
414 : //}
415 : //
416 : //return fd_runtime_save_slot_bank(slot_ctx);
417 :
418 0 : return slot_ctx;
419 0 : }
420 :
421 : fd_exec_slot_ctx_t *
422 : fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t * slot_ctx,
423 0 : fd_solana_manifest_t * manifest ) {
424 :
425 0 : fd_exec_slot_ctx_t * res = fd_exec_slot_ctx_recover_( slot_ctx, manifest );
426 :
427 : /* Regardless of result, always destroy manifest */
428 0 : fd_bincode_destroy_ctx_t destroy = { .valloc = slot_ctx->valloc };
429 0 : fd_solana_manifest_destroy( manifest, &destroy );
430 0 : fd_memset( manifest, 0, sizeof(fd_solana_manifest_t) );
431 :
432 0 : return res;
433 0 : }
434 :
435 : fd_exec_slot_ctx_t *
436 : fd_exec_slot_ctx_recover_status_cache( fd_exec_slot_ctx_t * ctx,
437 0 : fd_bank_slot_deltas_t * slot_deltas ) {
438 0 : fd_txncache_t * status_cache = ctx->status_cache;
439 0 : if( !status_cache ) {
440 0 : FD_LOG_WARNING(("No status cache in slot ctx"));
441 0 : return NULL;
442 0 : }
443 :
444 0 : FD_SCRATCH_SCOPE_BEGIN {
445 0 : ulong num_entries = 0;
446 0 : for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
447 0 : fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[i];
448 0 : for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
449 0 : num_entries += slot_delta->slot_delta_vec[j].value.statuses_len;
450 0 : }
451 0 : }
452 0 : fd_txncache_insert_t * insert_vals = fd_scratch_alloc( alignof(fd_txncache_insert_t), num_entries * sizeof(fd_txncache_insert_t) );
453 :
454 : /* Dumb sort for 300 slot entries to insert in order. */
455 0 : fd_slot_delta_t ** deltas = fd_scratch_alloc(alignof(fd_slot_delta_t *), slot_deltas->slot_deltas_len * sizeof(fd_slot_delta_t *));
456 :
457 0 : ulong curr = 0;
458 0 : for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
459 0 : ulong curr_min = ULONG_MAX;
460 0 : ulong curr_min_idx = ULONG_MAX;
461 0 : for( ulong j = 0; j < slot_deltas->slot_deltas_len; j++ ) {
462 0 : fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[j];
463 0 : if( slot_delta->slot <= curr ) continue;
464 :
465 0 : if( curr_min > slot_delta->slot ) {
466 0 : curr_min = slot_delta->slot;
467 0 : curr_min_idx = j;
468 0 : }
469 0 : }
470 0 : deltas[i] = &slot_deltas->slot_deltas[curr_min_idx];
471 0 : curr = slot_deltas->slot_deltas[curr_min_idx].slot;
472 0 : }
473 :
474 0 : ulong idx = 0;
475 0 : for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
476 0 : fd_slot_delta_t * slot_delta = deltas[i];
477 0 : ulong slot = slot_delta->slot;
478 0 : if( slot_delta->is_root ) {
479 0 : fd_txncache_register_root_slot( ctx->status_cache, slot );
480 0 : }
481 0 : for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
482 0 : fd_status_pair_t * pair = &slot_delta->slot_delta_vec[j];
483 0 : fd_hash_t * blockhash = &pair->hash;
484 :
485 0 : for( ulong k = 0; k < pair->value.statuses_len; k++ ) {
486 0 : fd_cache_status_t * status = &pair->value.statuses[k];
487 0 : uchar result = (uchar)status->result.discriminant;
488 0 : insert_vals[idx++] = (fd_txncache_insert_t){
489 0 : .blockhash = blockhash->uc,
490 0 : .slot = slot,
491 0 : .txnhash = status->key_slice,
492 0 : .result = &result
493 0 : };
494 0 : }
495 0 : }
496 0 : }
497 0 : fd_txncache_insert_batch( ctx->status_cache, insert_vals, num_entries );
498 :
499 0 : for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
500 0 : fd_slot_delta_t * slot_delta = deltas[i];
501 0 : ulong slot = slot_delta->slot;
502 0 : for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
503 0 : fd_status_pair_t * pair = &slot_delta->slot_delta_vec[j];
504 0 : fd_hash_t * blockhash = &pair->hash;
505 0 : fd_txncache_set_txnhash_offset( ctx->status_cache, slot, blockhash->uc, pair->value.txn_idx );
506 0 : }
507 0 : }
508 0 : } FD_SCRATCH_SCOPE_END;
509 0 : return ctx;
510 0 : }
511 :
512 : void
513 108786 : fd_exec_slot_ctx_free( fd_exec_slot_ctx_t * slot_ctx ) {
514 108786 : fd_bincode_destroy_ctx_t ctx;
515 108786 : ctx.valloc = slot_ctx->valloc;
516 108786 : fd_slot_bank_destroy( &slot_ctx->slot_bank, &ctx );
517 :
518 : /* leader points to a caller-allocated leader schedule */
519 108786 : fd_exec_slot_ctx_delete( fd_exec_slot_ctx_leave( slot_ctx ) );
520 108786 : }
|