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 : #include "../../../ballet/lthash/fd_lthash.h"
6 :
7 : #include <assert.h>
8 : #include <time.h>
9 :
10 : void *
11 : fd_exec_slot_ctx_new( void * mem,
12 0 : fd_spad_t * runtime_spad ) {
13 0 : if( FD_UNLIKELY( !mem ) ) {
14 0 : FD_LOG_WARNING(( "NULL mem" ));
15 0 : return NULL;
16 0 : }
17 :
18 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_SLOT_CTX_ALIGN ) ) ) {
19 0 : FD_LOG_WARNING(( "misaligned mem" ));
20 0 : return NULL;
21 0 : }
22 :
23 0 : fd_memset( mem, 0, sizeof(fd_exec_slot_ctx_t) );
24 :
25 0 : fd_exec_slot_ctx_t * self = (fd_exec_slot_ctx_t *)mem;
26 0 : fd_slot_bank_new( &self->slot_bank );
27 :
28 0 : self->sysvar_cache = fd_sysvar_cache_new( fd_spad_alloc( runtime_spad, fd_sysvar_cache_align(), fd_sysvar_cache_footprint() ) );
29 :
30 : /* This is inactive by default */
31 0 : self->epoch_reward_status.discriminant = fd_epoch_reward_status_enum_Inactive;
32 :
33 0 : FD_COMPILER_MFENCE();
34 0 : self->magic = FD_EXEC_SLOT_CTX_MAGIC;
35 0 : FD_COMPILER_MFENCE();
36 :
37 0 : return mem;
38 0 : }
39 :
40 : fd_exec_slot_ctx_t *
41 0 : fd_exec_slot_ctx_join( void * mem ) {
42 0 : if( FD_UNLIKELY( !mem ) ) {
43 0 : FD_LOG_WARNING(( "NULL block" ));
44 0 : return NULL;
45 0 : }
46 :
47 0 : fd_exec_slot_ctx_t * ctx = (fd_exec_slot_ctx_t *) mem;
48 :
49 0 : if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
50 0 : FD_LOG_WARNING(( "bad magic" ));
51 0 : return NULL;
52 0 : }
53 :
54 0 : return ctx;
55 0 : }
56 :
57 : void *
58 0 : fd_exec_slot_ctx_leave( fd_exec_slot_ctx_t * ctx) {
59 0 : if( FD_UNLIKELY( !ctx ) ) {
60 0 : FD_LOG_WARNING(( "NULL block" ));
61 0 : return NULL;
62 0 : }
63 :
64 0 : if( FD_UNLIKELY( ctx->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
65 0 : FD_LOG_WARNING(( "bad magic" ));
66 0 : return NULL;
67 0 : }
68 :
69 0 : return (void *) ctx;
70 0 : }
71 :
72 : void *
73 0 : fd_exec_slot_ctx_delete( void * mem ) {
74 0 : if( FD_UNLIKELY( !mem ) ) {
75 0 : FD_LOG_WARNING(( "NULL mem" ));
76 0 : return NULL;
77 0 : }
78 :
79 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_EXEC_SLOT_CTX_ALIGN) ) ) {
80 0 : FD_LOG_WARNING(( "misaligned mem" ));
81 0 : return NULL;
82 0 : }
83 :
84 0 : fd_exec_slot_ctx_t * hdr = (fd_exec_slot_ctx_t *)mem;
85 0 : if( FD_UNLIKELY( hdr->magic!=FD_EXEC_SLOT_CTX_MAGIC ) ) {
86 0 : FD_LOG_WARNING(( "bad magic" ));
87 0 : return NULL;
88 0 : }
89 :
90 0 : hdr->sysvar_cache = NULL;
91 :
92 0 : FD_COMPILER_MFENCE();
93 0 : FD_VOLATILE( hdr->magic ) = 0UL;
94 0 : FD_COMPILER_MFENCE();
95 :
96 0 : return mem;
97 0 : }
98 :
99 : /* recover_clock recovers PoH/wallclock synchronization. Walks all vote
100 : accounts in current epoch stakes. */
101 :
102 : static int
103 0 : recover_clock( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
104 :
105 0 : fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
106 0 : fd_vote_accounts_t const * vote_accounts = &epoch_bank->stakes.vote_accounts;
107 :
108 0 : fd_vote_accounts_pair_t_mapnode_t * vote_accounts_pool = vote_accounts->vote_accounts_pool;
109 0 : fd_vote_accounts_pair_t_mapnode_t * vote_accounts_root = vote_accounts->vote_accounts_root;
110 :
111 0 : for( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(vote_accounts_pool, vote_accounts_root);
112 0 : n;
113 0 : n = fd_vote_accounts_pair_t_map_successor( vote_accounts_pool, n ) ) {
114 :
115 : /* Extract vote timestamp of account */
116 :
117 0 : fd_bincode_decode_ctx_t ctx = {
118 0 : .data = n->elem.value.data,
119 0 : .dataend = n->elem.value.data + n->elem.value.data_len,
120 0 : };
121 :
122 0 : ulong total_sz = 0UL;
123 0 : int err = fd_vote_state_versioned_decode_footprint( &ctx, &total_sz );
124 0 : if( FD_UNLIKELY( err ) ) {
125 0 : FD_LOG_WARNING(( "vote state decode footprint failed" ));
126 0 : return 0;
127 0 : }
128 :
129 0 : uchar * mem = fd_spad_alloc( runtime_spad, fd_vote_state_versioned_align(), total_sz );
130 0 : if( FD_UNLIKELY( !mem ) ) {
131 0 : FD_LOG_ERR(( "Unable to allocate memory for versioned vote state" ));
132 0 : }
133 :
134 0 : fd_vote_state_versioned_t * vsv = fd_vote_state_versioned_decode( mem, &ctx );
135 :
136 0 : long timestamp = 0;
137 0 : ulong slot = 0;
138 0 : switch( vsv->discriminant ) {
139 0 : case fd_vote_state_versioned_enum_v0_23_5:
140 0 : timestamp = vsv->inner.v0_23_5.last_timestamp.timestamp;
141 0 : slot = vsv->inner.v0_23_5.last_timestamp.slot;
142 0 : break;
143 0 : case fd_vote_state_versioned_enum_v1_14_11:
144 0 : timestamp = vsv->inner.v1_14_11.last_timestamp.timestamp;
145 0 : slot = vsv->inner.v1_14_11.last_timestamp.slot;
146 0 : break;
147 0 : case fd_vote_state_versioned_enum_current:
148 0 : timestamp = vsv->inner.current.last_timestamp.timestamp;
149 0 : slot = vsv->inner.current.last_timestamp.slot;
150 0 : break;
151 0 : default:
152 0 : __builtin_unreachable();
153 0 : }
154 :
155 :
156 :
157 : /* Record timestamp */
158 0 : if( slot != 0 || n->elem.stake != 0 ) {
159 0 : fd_vote_record_timestamp_vote_with_slot( slot_ctx, &n->elem.key, timestamp, slot );
160 0 : }
161 0 : }
162 :
163 0 : return 1;
164 0 : }
165 :
166 : /* Implementation note: fd_exec_slot_ctx_recover moves objects from
167 : manifest to slot_ctx. This function must not share pointers between
168 : slot_ctx and manifest. Otherwise, would cause a use-after-free. */
169 :
170 : static fd_exec_slot_ctx_t *
171 : fd_exec_slot_ctx_recover_( fd_exec_slot_ctx_t * slot_ctx,
172 : fd_solana_manifest_t * manifest,
173 0 : fd_spad_t * runtime_spad ) {
174 :
175 0 : fd_valloc_t valloc = fd_spad_virtual( runtime_spad );
176 :
177 0 : fd_exec_epoch_ctx_t * epoch_ctx = slot_ctx->epoch_ctx;
178 0 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( epoch_ctx );
179 :
180 : /* Clean out prior bank */
181 0 : fd_slot_bank_t * slot_bank = &slot_ctx->slot_bank;
182 0 : fd_slot_bank_destroy( slot_bank );
183 0 : fd_slot_bank_new( slot_bank );
184 :
185 0 : for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
186 0 : epoch_bank->stakes.vote_accounts.vote_accounts_pool,
187 0 : epoch_bank->stakes.vote_accounts.vote_accounts_root );
188 0 : n;
189 0 : n = fd_vote_accounts_pair_t_map_successor( epoch_bank->stakes.vote_accounts.vote_accounts_pool, n ) ) {
190 :
191 0 : const fd_pubkey_t null_pubkey = {{ 0 }};
192 0 : if ( memcmp( &n->elem.key, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
193 0 : continue;
194 0 : }
195 0 : }
196 :
197 0 : fd_versioned_bank_t * oldbank = &manifest->bank;
198 :
199 : /* Populate the epoch context, using the already-allocated statically allocated memory */
200 : /* Copy stakes */
201 0 : epoch_bank->stakes.epoch = oldbank->stakes.epoch;
202 :
203 : /* Copy stakes->vote_accounts */
204 0 : for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
205 0 : oldbank->stakes.vote_accounts.vote_accounts_pool,
206 0 : oldbank->stakes.vote_accounts.vote_accounts_root );
207 0 : n;
208 0 : n = fd_vote_accounts_pair_t_map_successor( oldbank->stakes.vote_accounts.vote_accounts_pool, n ) ) {
209 :
210 0 : const fd_pubkey_t null_pubkey = {{ 0 }};
211 0 : if ( memcmp( &n->elem.key, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
212 0 : continue;
213 0 : }
214 :
215 0 : FD_TEST( fd_vote_accounts_pair_t_map_free( epoch_bank->stakes.vote_accounts.vote_accounts_pool ) );
216 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 );
217 0 : FD_TEST( new_node );
218 0 : fd_memcpy( &new_node->elem, &n->elem, FD_VOTE_ACCOUNTS_PAIR_FOOTPRINT );
219 0 : fd_vote_accounts_pair_t_map_insert(
220 0 : epoch_bank->stakes.vote_accounts.vote_accounts_pool,
221 0 : &epoch_bank->stakes.vote_accounts.vote_accounts_root,
222 0 : new_node
223 0 : );
224 0 : }
225 :
226 : /* Copy stakes->stake_delegations */
227 0 : for ( fd_delegation_pair_t_mapnode_t * n = fd_delegation_pair_t_map_minimum(
228 0 : oldbank->stakes.stake_delegations_pool,
229 0 : oldbank->stakes.stake_delegations_root );
230 0 : n;
231 0 : n = fd_delegation_pair_t_map_successor( oldbank->stakes.stake_delegations_pool, n ) ) {
232 :
233 0 : const fd_pubkey_t null_pubkey = {{ 0 }};
234 0 : if ( memcmp( &n->elem.account, &null_pubkey, FD_PUBKEY_FOOTPRINT ) == 0 ) {
235 0 : continue;
236 0 : }
237 :
238 0 : fd_delegation_pair_t_mapnode_t * new_node = fd_delegation_pair_t_map_acquire( epoch_bank->stakes.stake_delegations_pool );
239 0 : FD_TEST( new_node );
240 0 : fd_memcpy( &new_node->elem, &n->elem, FD_DELEGATION_PAIR_FOOTPRINT );
241 0 : fd_delegation_pair_t_map_insert(
242 0 : epoch_bank->stakes.stake_delegations_pool,
243 0 : &epoch_bank->stakes.stake_delegations_root,
244 0 : new_node
245 0 : );
246 0 : }
247 :
248 : /* Copy stakes->stake_history */
249 0 : fd_memcpy( &epoch_bank->stakes.stake_history, &oldbank->stakes.stake_history, sizeof(oldbank->stakes.stake_history));
250 :
251 0 : fd_stakes_destroy( &oldbank->stakes );
252 :
253 : /* Index vote accounts */
254 :
255 : /* Copy over fields */
256 :
257 0 : slot_ctx->slot_bank.parent_signature_cnt = oldbank->signature_count;
258 0 : slot_ctx->slot_bank.tick_height = oldbank->tick_height;
259 :
260 0 : if( oldbank->blockhash_queue.last_hash )
261 0 : slot_bank->poh = *oldbank->blockhash_queue.last_hash;
262 0 : slot_bank->slot = oldbank->slot;
263 0 : slot_bank->prev_slot = oldbank->parent_slot;
264 0 : fd_memcpy(&slot_bank->banks_hash, &oldbank->hash, sizeof(oldbank->hash));
265 0 : fd_memcpy(&slot_ctx->slot_bank.prev_banks_hash, &oldbank->parent_hash, sizeof(oldbank->parent_hash));
266 0 : fd_memcpy(&slot_bank->fee_rate_governor, &oldbank->fee_rate_governor, sizeof(oldbank->fee_rate_governor));
267 0 : slot_bank->lamports_per_signature = manifest->lamports_per_signature;
268 0 : slot_ctx->prev_lamports_per_signature = manifest->lamports_per_signature;
269 0 : slot_ctx->slot_bank.parent_signature_cnt = oldbank->signature_count;
270 0 : if( oldbank->hashes_per_tick )
271 0 : epoch_bank->hashes_per_tick = *oldbank->hashes_per_tick;
272 0 : else
273 0 : epoch_bank->hashes_per_tick = 0;
274 0 : epoch_bank->ticks_per_slot = oldbank->ticks_per_slot;
275 0 : fd_memcpy(&epoch_bank->ns_per_slot, &oldbank->ns_per_slot, sizeof(oldbank->ns_per_slot));
276 0 : epoch_bank->genesis_creation_time = oldbank->genesis_creation_time;
277 0 : epoch_bank->slots_per_year = oldbank->slots_per_year;
278 0 : slot_bank->max_tick_height = oldbank->max_tick_height;
279 0 : fd_memcpy( &epoch_bank->inflation, &oldbank->inflation, FD_INFLATION_FOOTPRINT );
280 0 : fd_memcpy( &epoch_bank->epoch_schedule, &oldbank->epoch_schedule, FD_EPOCH_SCHEDULE_FOOTPRINT );
281 0 : epoch_bank->rent = oldbank->rent_collector.rent;
282 0 : fd_memcpy( &epoch_bank->rent, &oldbank->rent_collector.rent, FD_RENT_FOOTPRINT );
283 0 : fd_memcpy( &epoch_bank->rent_epoch_schedule, &oldbank->rent_collector.epoch_schedule, FD_EPOCH_SCHEDULE_FOOTPRINT );
284 :
285 0 : if( manifest->epoch_account_hash )
286 0 : slot_bank->epoch_account_hash = *manifest->epoch_account_hash;
287 :
288 0 : slot_bank->collected_rent = oldbank->collected_rent;
289 : // did they not change the bank?!
290 0 : slot_bank->collected_execution_fees = oldbank->collector_fees;
291 0 : slot_bank->collected_priority_fees = 0;
292 0 : slot_bank->capitalization = oldbank->capitalization;
293 0 : slot_bank->block_height = oldbank->block_height;
294 0 : slot_bank->transaction_count = oldbank->transaction_count;
295 0 : if ( oldbank->blockhash_queue.last_hash ) {
296 0 : slot_bank->block_hash_queue.last_hash = fd_valloc_malloc( valloc, FD_HASH_ALIGN, FD_HASH_FOOTPRINT );
297 0 : fd_memcpy( slot_bank->block_hash_queue.last_hash, oldbank->blockhash_queue.last_hash, sizeof(fd_hash_t) );
298 0 : } else {
299 0 : slot_bank->block_hash_queue.last_hash = NULL;
300 0 : }
301 :
302 : /* FIXME: Avoid using magic number for allocations */
303 0 : slot_bank->block_hash_queue.last_hash_index = oldbank->blockhash_queue.last_hash_index;
304 0 : slot_bank->block_hash_queue.max_age = oldbank->blockhash_queue.max_age;
305 0 : slot_bank->block_hash_queue.ages_root = NULL;
306 0 : uchar * pool_mem = fd_spad_alloc( runtime_spad, fd_hash_hash_age_pair_t_map_align(), fd_hash_hash_age_pair_t_map_footprint( 400 ) );
307 0 : slot_bank->block_hash_queue.ages_pool = fd_hash_hash_age_pair_t_map_join( fd_hash_hash_age_pair_t_map_new( pool_mem, 400 ) );
308 0 : for ( ulong i = 0; i < oldbank->blockhash_queue.ages_len; i++ ) {
309 0 : fd_hash_hash_age_pair_t * elem = &oldbank->blockhash_queue.ages[i];
310 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 );
311 0 : fd_memcpy( &node->elem, elem, FD_HASH_HASH_AGE_PAIR_FOOTPRINT );
312 0 : fd_hash_hash_age_pair_t_map_insert( slot_bank->block_hash_queue.ages_pool, &slot_bank->block_hash_queue.ages_root, node );
313 0 : }
314 :
315 : /* FIXME: Remove the magic number here. */
316 0 : if( !slot_ctx->slot_bank.timestamp_votes.votes_pool ) {
317 0 : pool_mem = fd_spad_alloc( runtime_spad, fd_clock_timestamp_vote_t_map_align(), fd_clock_timestamp_vote_t_map_footprint( 15000UL ) );
318 0 : slot_ctx->slot_bank.timestamp_votes.votes_pool = fd_clock_timestamp_vote_t_map_join( fd_clock_timestamp_vote_t_map_new( pool_mem, 15000UL ) );
319 0 : }
320 0 : recover_clock( slot_ctx, runtime_spad );
321 :
322 : /* Pass in the hard forks */
323 :
324 : /* The hard forks should be deep copied over.
325 : TODO:This should be in the epoch bank and not the slot bank. */
326 0 : slot_bank->hard_forks.hard_forks_len = oldbank->hard_forks.hard_forks_len;
327 0 : slot_bank->hard_forks.hard_forks = fd_valloc_malloc( valloc,
328 0 : FD_SLOT_PAIR_ALIGN,
329 0 : oldbank->hard_forks.hard_forks_len * FD_SLOT_PAIR_FOOTPRINT );
330 0 : memcpy( slot_bank->hard_forks.hard_forks, oldbank->hard_forks.hard_forks,
331 0 : oldbank->hard_forks.hard_forks_len * FD_SLOT_PAIR_FOOTPRINT );
332 :
333 : /* Update last restart slot
334 : https://github.com/solana-labs/solana/blob/30531d7a5b74f914dde53bfbb0bc2144f2ac92bb/runtime/src/bank.rs#L2152
335 :
336 : oldbank->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 : slot_bank->last_restart_slot.slot = 0UL;
342 0 : if( FD_UNLIKELY( oldbank->hard_forks.hard_forks_len == 0 ) ) {
343 : /* SIMD-0047: The first restart slot should be `0` */
344 0 : break;
345 0 : }
346 :
347 0 : fd_slot_pair_t const * head = oldbank->hard_forks.hard_forks;
348 0 : fd_slot_pair_t const * tail = head + oldbank->hard_forks.hard_forks_len - 1UL;
349 :
350 0 : for( fd_slot_pair_t const *pair = tail; pair >= head; pair-- ) {
351 0 : if( pair->slot <= slot_bank->slot ) {
352 0 : slot_bank->last_restart_slot.slot = pair->slot;
353 0 : break;
354 0 : }
355 0 : }
356 0 : } while (0);
357 :
358 : /* Move EpochStakes */
359 0 : do {
360 0 : ulong epoch = fd_slot_to_epoch( &epoch_bank->epoch_schedule, slot_bank->slot, NULL );
361 :
362 : /* We need to save the vote accounts for the current epoch and the next
363 : epoch as it is used to calculate the leader schedule at the epoch
364 : boundary. */
365 :
366 0 : fd_vote_accounts_t curr_stakes = { .vote_accounts_pool = NULL, .vote_accounts_root = NULL };
367 0 : fd_vote_accounts_t next_stakes = { .vote_accounts_pool = NULL, .vote_accounts_root = NULL };
368 :
369 0 : for( ulong i=0UL; i<manifest->bank.epoch_stakes_len; i++ ) {
370 0 : if( manifest->bank.epoch_stakes[i].key == epoch ) {
371 0 : curr_stakes.vote_accounts_pool = manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_pool;
372 0 : curr_stakes.vote_accounts_root = manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_root;
373 0 : manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_pool = NULL;
374 0 : manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_root = NULL;
375 0 : }
376 0 : if( manifest->bank.epoch_stakes[i].key == epoch+1UL ) {
377 0 : next_stakes.vote_accounts_pool = manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_pool;
378 0 : next_stakes.vote_accounts_root = manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_root;
379 0 : manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_pool = NULL;
380 0 : manifest->bank.epoch_stakes[i].value.stakes.vote_accounts.vote_accounts_root = NULL;
381 0 : }
382 :
383 : /* When loading from a snapshot, Agave's stake caches mean that we have to special-case the epoch stakes
384 : that are used for the second epoch E+2 after the snapshot epoch E.
385 :
386 : If the snapshot contains the epoch stakes for E+2, we should use those.
387 :
388 : 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
389 : all other epochs. */
390 :
391 0 : if( manifest->bank.epoch_stakes[i].key==epoch+2UL ) {
392 0 : slot_ctx->slot_bank.has_use_preceeding_epoch_stakes = 0;
393 0 : }
394 0 : }
395 :
396 0 : for( ulong i=0UL; i<manifest->versioned_epoch_stakes_len; i++ ) {
397 0 : if( manifest->versioned_epoch_stakes[i].epoch == epoch ) {
398 0 : curr_stakes.vote_accounts_pool = manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_pool;
399 0 : curr_stakes.vote_accounts_root = manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_root;
400 0 : manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_pool = NULL;
401 0 : manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_root = NULL;
402 0 : }
403 0 : if( manifest->versioned_epoch_stakes[i].epoch == epoch+1UL ) {
404 0 : next_stakes.vote_accounts_pool = manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_pool;
405 0 : next_stakes.vote_accounts_root = manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_root;
406 0 : manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_pool = NULL;
407 0 : manifest->versioned_epoch_stakes[i].val.inner.Current.stakes.vote_accounts.vote_accounts_root = NULL;
408 0 : }
409 :
410 0 : if( manifest->versioned_epoch_stakes[i].epoch==epoch+2UL ) {
411 0 : slot_ctx->slot_bank.has_use_preceeding_epoch_stakes = 0;
412 0 : }
413 0 : }
414 :
415 0 : slot_ctx->slot_bank.has_use_preceeding_epoch_stakes = 1;
416 0 : slot_ctx->slot_bank.use_preceeding_epoch_stakes = epoch + 2UL;
417 :
418 0 : if( FD_UNLIKELY( (!curr_stakes.vote_accounts_root) | (!next_stakes.vote_accounts_root) ) ) {
419 0 : FD_LOG_WARNING(( "snapshot missing EpochStakes for epochs %lu and/or %lu", epoch, epoch+1UL ));
420 0 : return 0;
421 0 : }
422 :
423 : /* Move current EpochStakes */
424 0 : pool_mem = fd_spad_alloc( runtime_spad, fd_vote_accounts_pair_t_map_align(), fd_vote_accounts_pair_t_map_footprint( 100000 ) );
425 0 : slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool =
426 0 : fd_vote_accounts_pair_t_map_join( fd_vote_accounts_pair_t_map_new( pool_mem, 100000 ) ); /* FIXME: Remove magic constant */
427 0 : slot_ctx->slot_bank.epoch_stakes.vote_accounts_root = NULL;
428 :
429 0 : for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(
430 0 : curr_stakes.vote_accounts_pool,
431 0 : curr_stakes.vote_accounts_root );
432 0 : n;
433 0 : n = fd_vote_accounts_pair_t_map_successor( curr_stakes.vote_accounts_pool, n ) ) {
434 :
435 0 : fd_vote_accounts_pair_t_mapnode_t * elem = fd_vote_accounts_pair_t_map_acquire(
436 0 : slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool );
437 0 : FD_TEST( elem );
438 :
439 0 : fd_memcpy( &elem->elem, &n->elem, sizeof(fd_vote_accounts_pair_t));
440 :
441 0 : fd_vote_accounts_pair_t_map_insert(
442 0 : slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool,
443 0 : &slot_ctx->slot_bank.epoch_stakes.vote_accounts_root,
444 0 : elem );
445 0 : }
446 :
447 0 : fd_vote_accounts_destroy( &curr_stakes );
448 :
449 : /* Move next EpochStakes
450 : TODO Can we derive this instead of trusting the snapshot? */
451 :
452 0 : fd_vote_accounts_pair_t_mapnode_t * pool = next_stakes.vote_accounts_pool;
453 0 : fd_vote_accounts_pair_t_mapnode_t * root = next_stakes.vote_accounts_root;
454 :
455 0 : for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum(pool, root);
456 0 : n;
457 0 : n = fd_vote_accounts_pair_t_map_successor(pool, n) ) {
458 :
459 0 : fd_vote_accounts_pair_t_mapnode_t * elem = fd_vote_accounts_pair_t_map_acquire(
460 0 : epoch_bank->next_epoch_stakes.vote_accounts_pool );
461 0 : FD_TEST( elem );
462 :
463 0 : fd_memcpy( &elem->elem, &n->elem, sizeof(fd_vote_accounts_pair_t));
464 :
465 0 : fd_vote_accounts_pair_t_map_insert(
466 0 : epoch_bank->next_epoch_stakes.vote_accounts_pool,
467 0 : &epoch_bank->next_epoch_stakes.vote_accounts_root,
468 0 : elem );
469 :
470 0 : }
471 :
472 0 : fd_vote_accounts_destroy( &next_stakes );
473 0 : } while(0);
474 :
475 0 : if ( NULL != manifest->lthash )
476 0 : slot_ctx->slot_bank.lthash = *manifest->lthash;
477 0 : else
478 0 : fd_lthash_zero( (fd_lthash_value_t *) slot_ctx->slot_bank.lthash.lthash );
479 :
480 : /* Allocate all the memory for the rent fresh accounts lists */
481 0 : slot_ctx->rent_fresh_accounts.partitions_root = NULL;
482 0 : slot_ctx->rent_fresh_accounts.partitions_pool = fd_rent_fresh_accounts_partition_t_map_join(
483 0 : fd_rent_fresh_accounts_partition_t_map_new(
484 0 : fd_spad_alloc(
485 0 : runtime_spad,
486 0 : fd_rent_fresh_accounts_partition_t_map_align(),
487 0 : fd_rent_fresh_accounts_partition_t_map_footprint( 432000UL * 2UL ) ), /* MAX_SLOTS_PER_EPOCH * 2 */
488 0 : 432000UL * 2UL
489 0 : )
490 0 : );
491 0 : for( ulong i = 0; i < 432000UL * 2UL; i++ ) {
492 0 : ulong partition = i;
493 0 : fd_rent_fresh_accounts_partition_t_mapnode_t * new_node = fd_rent_fresh_accounts_partition_t_map_acquire(
494 0 : slot_ctx->rent_fresh_accounts.partitions_pool
495 0 : );
496 0 : if( FD_UNLIKELY(( new_node == NULL )) ) {
497 0 : FD_LOG_ERR(( "fd_rent_fresh_accounts_partition_t_map_acquire failed" ));
498 0 : }
499 :
500 0 : new_node->elem.partition = partition;
501 0 : new_node->elem.accounts_root = NULL;
502 0 : new_node->elem.accounts_pool = fd_pubkey_node_t_map_join( fd_pubkey_node_t_map_new(
503 0 : fd_spad_alloc( runtime_spad, fd_pubkey_node_t_map_align(), fd_pubkey_node_t_map_footprint( 100 ) ),
504 0 : 100
505 0 : ) );
506 0 : fd_rent_fresh_accounts_partition_t_map_insert(
507 0 : slot_ctx->rent_fresh_accounts.partitions_pool,
508 0 : &slot_ctx->rent_fresh_accounts.partitions_root,
509 0 : new_node
510 0 : );
511 0 : }
512 :
513 0 : return slot_ctx;
514 0 : }
515 :
516 : fd_exec_slot_ctx_t *
517 : fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t * slot_ctx,
518 : fd_solana_manifest_t * manifest,
519 0 : fd_spad_t * spad ) {
520 :
521 0 : fd_exec_slot_ctx_t * res = fd_exec_slot_ctx_recover_( slot_ctx, manifest, spad );
522 :
523 : /* Regardless of result, always destroy manifest.
524 : TODO: This doesn't do anything. */
525 0 : fd_solana_manifest_destroy( manifest );
526 0 : fd_memset( manifest, 0, sizeof(fd_solana_manifest_t) );
527 :
528 0 : return res;
529 0 : }
530 :
531 : fd_exec_slot_ctx_t *
532 : fd_exec_slot_ctx_recover_status_cache( fd_exec_slot_ctx_t * ctx,
533 : fd_bank_slot_deltas_t * slot_deltas,
534 0 : fd_spad_t * runtime_spad ) {
535 :
536 0 : fd_txncache_t * status_cache = ctx->status_cache;
537 0 : if( !status_cache ) {
538 0 : FD_LOG_WARNING(("No status cache in slot ctx"));
539 0 : return NULL;
540 0 : }
541 :
542 0 : FD_SPAD_FRAME_BEGIN( runtime_spad ) {
543 :
544 0 : ulong num_entries = 0;
545 0 : for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
546 0 : fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[i];
547 0 : for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
548 0 : num_entries += slot_delta->slot_delta_vec[j].value.statuses_len;
549 0 : }
550 0 : }
551 0 : fd_txncache_insert_t * insert_vals = fd_spad_alloc( runtime_spad, alignof(fd_txncache_insert_t), num_entries * sizeof(fd_txncache_insert_t) );
552 :
553 : /* Dumb sort for 300 slot entries to insert in order. */
554 0 : fd_slot_delta_t ** deltas = fd_spad_alloc( runtime_spad, alignof(fd_slot_delta_t*), slot_deltas->slot_deltas_len * sizeof(fd_slot_delta_t*) );
555 :
556 0 : long curr = -1;
557 0 : for( ulong i = 0UL; i < slot_deltas->slot_deltas_len; i++ ) {
558 0 : ulong curr_min = ULONG_MAX;
559 0 : ulong curr_min_idx = ULONG_MAX;
560 0 : for( ulong j = 0; j < slot_deltas->slot_deltas_len; j++ ) {
561 0 : fd_slot_delta_t * slot_delta = &slot_deltas->slot_deltas[j];
562 0 : if( (long)slot_delta->slot <= curr ) continue;
563 :
564 0 : if( curr_min > slot_delta->slot ) {
565 0 : curr_min = slot_delta->slot;
566 0 : curr_min_idx = j;
567 0 : }
568 0 : }
569 0 : deltas[i] = &slot_deltas->slot_deltas[curr_min_idx];
570 0 : curr = (long)slot_deltas->slot_deltas[curr_min_idx].slot;
571 0 : }
572 :
573 0 : ulong idx = 0;
574 0 : for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
575 0 : fd_slot_delta_t * slot_delta = deltas[i];
576 0 : ulong slot = slot_delta->slot;
577 0 : if( slot_delta->is_root ) {
578 0 : fd_txncache_register_root_slot( ctx->status_cache, slot );
579 0 : }
580 0 : for( ulong j = 0; j < slot_delta->slot_delta_vec_len; j++ ) {
581 0 : fd_status_pair_t * pair = &slot_delta->slot_delta_vec[j];
582 0 : fd_hash_t * blockhash = &pair->hash;
583 0 : uchar * results = fd_spad_alloc( runtime_spad, FD_SPAD_ALIGN, pair->value.statuses_len );
584 0 : for( ulong k = 0; k < pair->value.statuses_len; k++ ) {
585 0 : fd_cache_status_t * status = &pair->value.statuses[k];
586 0 : uchar * result = results + k;
587 0 : *result = (uchar)status->result.discriminant;
588 0 : insert_vals[idx++] = (fd_txncache_insert_t){
589 0 : .blockhash = blockhash->uc,
590 0 : .slot = slot,
591 0 : .txnhash = status->key_slice,
592 0 : .result = result
593 0 : };
594 0 : }
595 0 : }
596 0 : }
597 0 : fd_txncache_insert_batch( ctx->status_cache, insert_vals, num_entries );
598 :
599 0 : for( ulong i = 0; i < slot_deltas->slot_deltas_len; i++ ) {
600 0 : fd_slot_delta_t * slot_delta = deltas[i];
601 0 : ulong slot = slot_delta->slot;
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 : fd_txncache_set_txnhash_offset( ctx->status_cache, slot, blockhash->uc, pair->value.txn_idx );
606 0 : }
607 0 : }
608 :
609 0 : } FD_SPAD_FRAME_END;
610 0 : return ctx;
611 0 : }
|