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