Line data Source code
1 : #include "fd_ssload.h"
2 :
3 : #include "../../../flamenco/runtime/context/fd_exec_slot_ctx.h"
4 : #include "../../../flamenco/runtime/program/fd_vote_program.h"
5 : #include "fd_ssmsg.h"
6 :
7 : void
8 : blockhashes_recover( fd_blockhashes_t * blockhashes,
9 : fd_snapshot_manifest_blockhash_t const * ages,
10 : ulong age_cnt,
11 0 : ulong seed ) {
12 0 : FD_TEST( fd_blockhashes_init( blockhashes, seed ) );
13 0 : FD_TEST( age_cnt && age_cnt<=FD_BLOCKHASHES_MAX );
14 :
15 : /* For depressing reasons, the ages array is not sorted when ingested
16 : from a snapshot. The hash_index field is also not validated.
17 : Firedancer assumes that the sequence of hash_index numbers is
18 : gapless and does not wrap around. */
19 :
20 0 : ulong seq_min = ULONG_MAX-1;
21 0 : for( ulong i=0UL; i<age_cnt; i++ ) {
22 0 : seq_min = fd_ulong_min( seq_min, ages[ i ].hash_index );
23 0 : }
24 0 : ulong seq_max;
25 0 : if( FD_UNLIKELY( __builtin_uaddl_overflow( seq_min, age_cnt, &seq_max ) ) ) {
26 : /* TODO: Move to snapin validations so we can retry */
27 0 : FD_LOG_ERR(( "Corrupt snapshot: blockhash queue sequence number wraparound (seq_min=%lu age_cnt=%lu)", seq_min, age_cnt ));
28 0 : }
29 :
30 : /* Reset */
31 :
32 0 : for( ulong i=0UL; i<age_cnt; i++ ) {
33 0 : fd_blockhash_info_t * ele = fd_blockhash_deq_push_tail_nocopy( blockhashes->d.deque );
34 0 : memset( ele, 0, sizeof(fd_blockhash_info_t) );
35 0 : }
36 :
37 : /* Load hashes */
38 :
39 0 : for( ulong i=0UL; i<age_cnt; i++ ) {
40 0 : fd_snapshot_manifest_blockhash_t const * elem = &ages[ i ];
41 0 : ulong idx;
42 0 : if( FD_UNLIKELY( __builtin_usubl_overflow( elem->hash_index, seq_min, &idx ) ) ) {
43 : /* TODO: Move to snapin validations so we can retry */
44 0 : FD_LOG_ERR(( "Corrupt snapshot: gap in blockhash queue (seq=[%lu,%lu) idx=%lu)",
45 0 : seq_min, seq_max, elem->hash_index ));
46 0 : }
47 0 : fd_blockhash_info_t * info = &blockhashes->d.deque[ idx ];
48 0 : if( FD_UNLIKELY( info->exists ) ) {
49 : /* TODO: Move to snapin validations so we can retry */
50 0 : FD_LOG_HEXDUMP_NOTICE(( "info", info, sizeof(fd_blockhash_info_t) ));
51 0 : FD_LOG_ERR(( "Corrupt snapshot: duplicate blockhash queue index %lu", idx ));
52 0 : }
53 0 : info->exists = 1;
54 0 : fd_memcpy( info->hash.uc, elem->hash, 32UL );
55 0 : info->fee_calculator.lamports_per_signature = elem->lamports_per_signature;
56 0 : fd_blockhash_map_idx_insert( blockhashes->map, idx, blockhashes->d.deque );
57 0 : }
58 0 : }
59 :
60 : void
61 : fd_ssload_recover( fd_snapshot_manifest_t * manifest,
62 0 : fd_exec_slot_ctx_t * slot_ctx ) {
63 0 : slot_ctx->bank = fd_banks_rekey_root_bank( slot_ctx->banks, manifest->slot );
64 0 : FD_TEST( slot_ctx->bank );
65 :
66 : /* Bank Hash */
67 :
68 0 : fd_hash_t hash;
69 0 : fd_memcpy( &hash.uc, manifest->bank_hash, 32UL );
70 0 : fd_bank_bank_hash_set( slot_ctx->bank, hash );
71 :
72 0 : fd_hash_t parent_hash;
73 0 : fd_memcpy( &parent_hash.uc, manifest->parent_bank_hash, 32UL );
74 0 : fd_bank_prev_bank_hash_set( slot_ctx->bank, parent_hash );
75 :
76 0 : fd_fee_rate_governor_t * fee_rate_governor = fd_bank_fee_rate_governor_modify( slot_ctx->bank );
77 0 : fee_rate_governor->target_lamports_per_signature = manifest->fee_rate_governor.target_lamports_per_signature;
78 0 : fee_rate_governor->target_signatures_per_slot = manifest->fee_rate_governor.target_signatures_per_slot;
79 0 : fee_rate_governor->min_lamports_per_signature = manifest->fee_rate_governor.min_lamports_per_signature;
80 0 : fee_rate_governor->max_lamports_per_signature = manifest->fee_rate_governor.max_lamports_per_signature;
81 0 : fee_rate_governor->burn_percent = manifest->fee_rate_governor.burn_percent;
82 :
83 0 : fd_inflation_t * inflation = fd_bank_inflation_modify( slot_ctx->bank );
84 0 : inflation->initial = manifest->inflation_params.initial;
85 0 : inflation->terminal = manifest->inflation_params.terminal;
86 0 : inflation->taper = manifest->inflation_params.taper;
87 0 : inflation->foundation = manifest->inflation_params.foundation;
88 0 : inflation->foundation_term = manifest->inflation_params.foundation_term;
89 0 : inflation->unused = 0.0;
90 :
91 0 : fd_epoch_schedule_t * epoch_schedule = fd_bank_epoch_schedule_modify( slot_ctx->bank );
92 0 : epoch_schedule->slots_per_epoch = manifest->epoch_schedule_params.slots_per_epoch;
93 0 : epoch_schedule->leader_schedule_slot_offset = manifest->epoch_schedule_params.leader_schedule_slot_offset;
94 0 : epoch_schedule->warmup = manifest->epoch_schedule_params.warmup;
95 0 : epoch_schedule->first_normal_epoch = manifest->epoch_schedule_params.first_normal_epoch;
96 0 : epoch_schedule->first_normal_slot = manifest->epoch_schedule_params.first_normal_slot;
97 :
98 0 : fd_rent_t * rent = fd_bank_rent_modify( slot_ctx->bank );
99 0 : rent->lamports_per_uint8_year = manifest->rent_params.lamports_per_uint8_year;
100 0 : rent->exemption_threshold = manifest->rent_params.exemption_threshold;
101 0 : rent->burn_percent = manifest->rent_params.burn_percent;
102 :
103 0 : if( FD_LIKELY( manifest->has_hashes_per_tick ) ) fd_bank_hashes_per_tick_set( slot_ctx->bank, manifest->hashes_per_tick );
104 0 : else fd_bank_hashes_per_tick_set( slot_ctx->bank, 0UL );
105 :
106 0 : if( FD_LIKELY( manifest->has_epoch_account_hash ) ) {
107 0 : fd_hash_t epoch_account_hash;
108 0 : fd_memcpy( &epoch_account_hash.uc, manifest->epoch_account_hash, 32UL );
109 0 : fd_bank_epoch_account_hash_set( slot_ctx->bank, epoch_account_hash );
110 0 : } else {
111 0 : fd_hash_t epoch_account_hash = {0};
112 0 : fd_bank_epoch_account_hash_set( slot_ctx->bank, epoch_account_hash );
113 0 : }
114 :
115 0 : if( FD_LIKELY( manifest->has_accounts_lthash ) ) {
116 0 : fd_slot_lthash_t lthash;
117 0 : fd_memcpy( lthash.lthash, manifest->accounts_lthash, 2048UL );
118 0 : fd_bank_lthash_set( slot_ctx->bank, lthash );
119 0 : } else {
120 0 : fd_slot_lthash_t lthash = {0};
121 0 : fd_bank_lthash_set( slot_ctx->bank, lthash );
122 0 : }
123 :
124 0 : fd_blockhashes_t * blockhashes = fd_bank_block_hash_queue_modify( slot_ctx->bank );
125 0 : blockhashes_recover( blockhashes, manifest->blockhashes, manifest->blockhashes_len, 42UL /* TODO */ );
126 :
127 : /* PoH */
128 0 : fd_blockhashes_t const * bhq = fd_bank_block_hash_queue_query( slot_ctx->bank );
129 0 : fd_hash_t const * last_hash = fd_blockhashes_peek_last( bhq );
130 0 : if( FD_LIKELY( last_hash ) ) fd_bank_poh_set( slot_ctx->bank, *last_hash );
131 :
132 0 : fd_bank_capitalization_set( slot_ctx->bank, manifest->capitalization );
133 0 : fd_bank_lamports_per_signature_set( slot_ctx->bank, manifest->lamports_per_signature );
134 0 : fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, manifest->lamports_per_signature );
135 0 : fd_bank_transaction_count_set( slot_ctx->bank, manifest->transaction_count );
136 0 : fd_bank_parent_signature_cnt_set( slot_ctx->bank, manifest->signature_count );
137 0 : fd_bank_tick_height_set( slot_ctx->bank, manifest->tick_height );
138 0 : fd_bank_max_tick_height_set( slot_ctx->bank, manifest->max_tick_height );
139 0 : fd_bank_ns_per_slot_set( slot_ctx->bank, manifest->ns_per_slot );
140 0 : fd_bank_ticks_per_slot_set( slot_ctx->bank, manifest->ticks_per_slot );
141 0 : fd_bank_genesis_creation_time_set( slot_ctx->bank, manifest->creation_time_millis );
142 0 : fd_bank_slots_per_year_set( slot_ctx->bank, manifest->slots_per_year );
143 0 : fd_bank_block_height_set( slot_ctx->bank, manifest->block_height );
144 0 : fd_bank_parent_slot_set( slot_ctx->bank, manifest->parent_slot );
145 0 : fd_bank_execution_fees_set( slot_ctx->bank, manifest->collector_fees );
146 0 : fd_bank_priority_fees_set( slot_ctx->bank, 0UL );
147 :
148 : /* FIXME: Remove the magic number here. */
149 0 : fd_clock_timestamp_votes_global_t * clock_timestamp_votes = fd_bank_clock_timestamp_votes_locking_modify( slot_ctx->bank );
150 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() );
151 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 ) );
152 0 : clock_timestamp_votes->votes_pool_offset = (ulong)fd_clock_timestamp_vote_t_map_leave( clock_pool) - (ulong)clock_timestamp_votes;
153 0 : clock_timestamp_votes->votes_root_offset = 0UL;
154 0 : fd_bank_clock_timestamp_votes_end_locking_modify( slot_ctx->bank );
155 :
156 0 : for( ulong i=0UL; i<manifest->vote_accounts_len; i++ ) {
157 0 : fd_snapshot_manifest_vote_account_t * account = &manifest->vote_accounts[ i ];
158 0 : fd_pubkey_t vote_account_pubkey;
159 0 : fd_memcpy( vote_account_pubkey.uc, account->vote_account_pubkey, 32UL );
160 0 : if( FD_LIKELY( account->last_slot || account->stake ) ) {
161 0 : fd_vote_record_timestamp_vote_with_slot( &vote_account_pubkey, account->last_timestamp, account->last_slot, slot_ctx->bank );
162 0 : }
163 0 : }
164 :
165 : /* Update last restart slot
166 : https://github.com/solana-labs/solana/blob/30531d7a5b74f914dde53bfbb0bc2144f2ac92bb/runtime/src/bank.rs#L2152
167 :
168 : old_bank->hard_forks is sorted ascending by slot number.
169 : To find the last restart slot, take the highest hard fork slot
170 : number that is less or equal than the current slot number.
171 : (There might be some hard forks in the future, ignore these)
172 :
173 : SIMD-0047: The first restart slot should be `0` */
174 0 : fd_sol_sysvar_last_restart_slot_t * last_restart_slot = fd_bank_last_restart_slot_modify( slot_ctx->bank );
175 0 : last_restart_slot->slot = 0UL;
176 0 : if( FD_LIKELY( manifest->hard_forks_len ) ) {
177 0 : for( ulong i=0UL; i<manifest->hard_forks_len; i++ ) {
178 0 : ulong slot = manifest->hard_forks[ manifest->hard_forks_len-1UL-i ];
179 0 : if( FD_LIKELY( slot<=manifest->slot ) ) {
180 0 : last_restart_slot->slot = slot;
181 0 : break;
182 0 : }
183 0 : }
184 0 : }
185 0 : }
|