Line data Source code
1 : #include "fd_snapshot.h"
2 : #include "fd_snapshot_loader.h"
3 : #include "fd_snapshot_restore.h"
4 : #include "../runtime/fd_acc_mgr.h"
5 : #include "../runtime/fd_hashes.h"
6 : #include "../runtime/fd_runtime_init.h"
7 : #include "../runtime/fd_system_ids.h"
8 : #include "../runtime/context/fd_exec_epoch_ctx.h"
9 : #include "../runtime/context/fd_exec_slot_ctx.h"
10 : #include "../rewards/fd_rewards.h"
11 : #include "../runtime/fd_runtime.h"
12 :
13 : #include <assert.h>
14 : #include <errno.h>
15 :
16 : /* FIXME: don't hardcode this param */
17 0 : #define ZSTD_WINDOW_SZ (33554432UL)
18 :
19 : struct fd_snapshot_load_ctx {
20 : /* User-defined parameters. */
21 : const char * snapshot_file;
22 : fd_exec_slot_ctx_t * slot_ctx;
23 : fd_tpool_t * tpool;
24 : uint verify_hash;
25 : uint check_hash;
26 : int snapshot_type;
27 :
28 : /* Internal state. */
29 : fd_funk_txn_t * par_txn;
30 : fd_funk_txn_t * child_txn;
31 :
32 : fd_snapshot_loader_t * loader;
33 : fd_snapshot_restore_t * restore;
34 :
35 : fd_spad_t * runtime_spad;
36 : };
37 : typedef struct fd_snapshot_load_ctx fd_snapshot_load_ctx_t;
38 :
39 : static void
40 0 : fd_hashes_load( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
41 0 : FD_TXN_ACCOUNT_DECL( block_hashes_rec );
42 0 : int err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, &fd_sysvar_recent_block_hashes_id, block_hashes_rec );
43 :
44 0 : if( err != FD_ACC_MGR_SUCCESS ) {
45 0 : FD_LOG_ERR(( "missing recent block hashes account" ));
46 0 : }
47 :
48 : /* FIXME: Do not hardcode the number of vote accounts */
49 :
50 0 : slot_ctx->slot_bank.stake_account_keys.account_keys_root = NULL;
51 0 : uchar * pool_mem = fd_spad_alloc( runtime_spad, fd_account_keys_pair_t_map_align(), fd_account_keys_pair_t_map_footprint( 100000UL ) );
52 :
53 0 : slot_ctx->slot_bank.stake_account_keys.account_keys_pool = fd_account_keys_pair_t_map_join( fd_account_keys_pair_t_map_new( pool_mem, 100000UL ) );
54 :
55 0 : slot_ctx->slot_bank.vote_account_keys.account_keys_root = NULL;
56 0 : pool_mem = fd_spad_alloc( runtime_spad, fd_account_keys_pair_t_map_align(), fd_account_keys_pair_t_map_footprint( 100000UL ) );
57 0 : slot_ctx->slot_bank.vote_account_keys.account_keys_pool = fd_account_keys_pair_t_map_join( fd_account_keys_pair_t_map_new( pool_mem, 100000UL ) );
58 :
59 0 : slot_ctx->slot_bank.collected_execution_fees = 0UL;
60 0 : slot_ctx->slot_bank.collected_priority_fees = 0UL;
61 0 : slot_ctx->slot_bank.collected_rent = 0UL;
62 :
63 0 : fd_runtime_save_slot_bank( slot_ctx );
64 0 : fd_runtime_save_epoch_bank( slot_ctx );
65 0 : }
66 :
67 : static int
68 : restore_manifest( void * ctx,
69 : fd_solana_manifest_t * manifest,
70 0 : fd_spad_t * spad ) {
71 0 : return (!!fd_exec_slot_ctx_recover( ctx, manifest, spad ) ? 0 : EINVAL);
72 0 : }
73 :
74 : static int
75 : restore_status_cache( void * ctx,
76 : fd_bank_slot_deltas_t * slot_deltas,
77 0 : fd_spad_t * spad ) {
78 0 : return (!!fd_exec_slot_ctx_recover_status_cache( ctx, slot_deltas, spad ) ? 0 : EINVAL);
79 0 : }
80 :
81 : static int
82 : restore_rent_fresh_account( fd_exec_slot_ctx_t * slot_ctx,
83 0 : fd_pubkey_t const * pubkey ) {
84 0 : fd_runtime_register_new_fresh_account( slot_ctx, pubkey );
85 0 : return 0;
86 0 : }
87 :
88 : ulong
89 0 : fd_snapshot_load_ctx_align( void ) {
90 0 : return alignof(fd_snapshot_load_ctx_t);
91 0 : }
92 :
93 : ulong
94 0 : fd_snapshot_load_ctx_footprint( void ) {
95 0 : return sizeof(fd_snapshot_load_ctx_t);
96 0 : }
97 :
98 : fd_snapshot_load_ctx_t *
99 : fd_snapshot_load_new( uchar * mem,
100 : const char * snapshot_file,
101 : fd_exec_slot_ctx_t * slot_ctx,
102 : fd_tpool_t * tpool,
103 : uint verify_hash,
104 : uint check_hash,
105 : int snapshot_type,
106 : fd_spad_t * * exec_spads,
107 : ulong exec_spad_cnt,
108 0 : fd_spad_t * runtime_spad ) {
109 :
110 0 : (void)exec_spads;
111 0 : (void)exec_spad_cnt;
112 :
113 0 : fd_snapshot_load_ctx_t * ctx = (fd_snapshot_load_ctx_t *)mem;
114 0 : ctx->snapshot_file = snapshot_file;
115 0 : ctx->slot_ctx = slot_ctx;
116 0 : ctx->tpool = tpool;
117 0 : ctx->verify_hash = verify_hash;
118 0 : ctx->check_hash = check_hash;
119 0 : ctx->snapshot_type = snapshot_type;
120 0 : ctx->runtime_spad = runtime_spad;
121 0 : return ctx;
122 0 : }
123 :
124 : void
125 0 : fd_snapshot_load_init( fd_snapshot_load_ctx_t * ctx ) {
126 0 : switch( ctx->snapshot_type ) {
127 0 : case FD_SNAPSHOT_TYPE_UNSPECIFIED:
128 0 : FD_LOG_ERR(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, FD_SNAPSHOT_TYPE_UNSPECIFIED)", ctx->snapshot_file, ctx->verify_hash ? "true" : "false", ctx->check_hash ? "true" : "false"));
129 0 : break;
130 0 : case FD_SNAPSHOT_TYPE_FULL:
131 0 : FD_LOG_NOTICE(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, FD_SNAPSHOT_TYPE_FULL)", ctx->snapshot_file, ctx->verify_hash ? "true" : "false", ctx->check_hash ? "true" : "false"));
132 0 : break;
133 0 : case FD_SNAPSHOT_TYPE_INCREMENTAL:
134 0 : FD_LOG_NOTICE(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, FD_SNAPSHOT_TYPE_INCREMENTAL)", ctx->snapshot_file, ctx->verify_hash ? "true" : "false", ctx->check_hash ? "true" : "false"));
135 0 : break;
136 0 : default:
137 0 : FD_LOG_ERR(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, huh?)", ctx->snapshot_file, ctx->verify_hash ? "true" : "false", ctx->check_hash ? "true" : "false"));
138 0 : break;
139 0 : }
140 :
141 0 : fd_funk_start_write( ctx->slot_ctx->acc_mgr->funk );
142 :
143 0 : ctx->par_txn = ctx->slot_ctx->funk_txn;
144 0 : ctx->child_txn = ctx->slot_ctx->funk_txn;
145 0 : if( ctx->verify_hash && FD_FEATURE_ACTIVE( ctx->slot_ctx->slot_bank.slot, ctx->slot_ctx->epoch_ctx->features, incremental_snapshot_only_incremental_hash_calculation ) ) {
146 0 : fd_funk_txn_xid_t xid;
147 0 : memset( &xid, 0xc3, sizeof(xid) );
148 0 : ctx->child_txn = fd_funk_txn_prepare( ctx->slot_ctx->acc_mgr->funk, ctx->child_txn, &xid, 0 );
149 0 : ctx->slot_ctx->funk_txn = ctx->child_txn;
150 0 : }
151 0 : }
152 :
153 : void
154 : fd_snapshot_load_manifest_and_status_cache( fd_snapshot_load_ctx_t * ctx,
155 : ulong * base_slot_override,
156 0 : int restore_manifest_flags ) {
157 :
158 0 : size_t slen = strlen( ctx->snapshot_file );
159 0 : char * snapshot_cstr = fd_spad_alloc( ctx->runtime_spad, 8UL, slen + 1 );
160 0 : fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( snapshot_cstr ), ctx->snapshot_file, slen ) );
161 :
162 0 : fd_snapshot_src_t src[1];
163 0 : if( FD_UNLIKELY( !fd_snapshot_src_parse( src, snapshot_cstr ) ) ) {
164 0 : FD_LOG_ERR(( "Failed to load snapshot" ));
165 0 : }
166 :
167 0 : fd_exec_epoch_ctx_bank_mem_clear( ctx->slot_ctx->epoch_ctx );
168 :
169 0 : fd_acc_mgr_t * acc_mgr = ctx->slot_ctx->acc_mgr;
170 0 : fd_funk_txn_t * funk_txn = ctx->slot_ctx->funk_txn;
171 :
172 0 : void * restore_mem = fd_spad_alloc( ctx->runtime_spad, fd_snapshot_restore_align(), fd_snapshot_restore_footprint() );
173 0 : void * loader_mem = fd_spad_alloc( ctx->runtime_spad, fd_snapshot_loader_align(), fd_snapshot_loader_footprint( ZSTD_WINDOW_SZ ) );
174 :
175 0 : ctx->restore = fd_snapshot_restore_new( restore_mem,
176 0 : acc_mgr,
177 0 : funk_txn,
178 0 : ctx->runtime_spad,
179 0 : ctx->slot_ctx,
180 0 : (restore_manifest_flags & FD_SNAPSHOT_RESTORE_MANIFEST) ? restore_manifest : NULL,
181 0 : (restore_manifest_flags & FD_SNAPSHOT_RESTORE_STATUS_CACHE) ? restore_status_cache : NULL,
182 0 : restore_rent_fresh_account );
183 :
184 0 : ctx->loader = fd_snapshot_loader_new ( loader_mem, ZSTD_WINDOW_SZ );
185 :
186 0 : if( FD_UNLIKELY( !ctx->restore || !ctx->loader ) ) {
187 0 : FD_LOG_ERR(( "Failed to load snapshot" ));
188 0 : }
189 :
190 0 : if( FD_UNLIKELY( !fd_snapshot_loader_init( ctx->loader,
191 0 : ctx->restore,
192 0 : src,
193 0 : base_slot_override ? *base_slot_override : ctx->slot_ctx->slot_bank.slot,
194 0 : 1 ) ) ) {
195 0 : FD_LOG_ERR(( "Failed to init snapshot loader" ));
196 0 : }
197 :
198 : /* First load in the manifest. */
199 0 : for(;;) {
200 0 : int err = fd_snapshot_loader_advance( ctx->loader );
201 0 : if( err==MANIFEST_DONE ) break; /* We have finished loading in the manifest. */
202 0 : if( FD_LIKELY( !err ) ) continue; /* Keep going. */
203 :
204 : /* If we have reached the end of the snapshot(err==-1), throw an error because
205 : this is not expected. */
206 0 : FD_LOG_ERR(( "Failed to load snapshot (%d-%s)", err, fd_io_strerror( err ) ));
207 0 : }
208 :
209 0 : }
210 :
211 : void
212 0 : fd_snapshot_load_accounts( fd_snapshot_load_ctx_t * ctx ) {
213 :
214 : /* Now, that the manifest is done being read in. Read in the rest of the accounts. */
215 0 : for(;;) {
216 0 : int err = fd_snapshot_loader_advance( ctx->loader );
217 0 : if( err==-1 ) break; /* We have finished loading in the snapshot. */
218 0 : if( FD_LIKELY( err==0 ) ) continue; /* Keep going. */
219 :
220 0 : FD_LOG_ERR(( "Failed to load snapshot (%d-%s)", err, fd_io_strerror( err ) ));
221 0 : }
222 :
223 0 : fd_snapshot_name_t const * name = fd_snapshot_loader_get_name( ctx->loader );
224 0 : if( FD_UNLIKELY( !name ) ) FD_LOG_ERR(( "name is NULL" ));
225 :
226 0 : FD_LOG_NOTICE(( "Done loading accounts" ));
227 :
228 0 : FD_LOG_NOTICE(( "Finished reading snapshot %s", ctx->snapshot_file ));
229 0 : }
230 :
231 : void
232 0 : fd_snapshot_load_fini( fd_snapshot_load_ctx_t * ctx ) {
233 :
234 0 : fd_snapshot_name_t const * name = fd_snapshot_loader_get_name( ctx->loader );
235 0 : fd_hash_t const * fhash = &name->fhash;
236 :
237 0 : if( name->type != ctx->snapshot_type ) {
238 0 : FD_LOG_ERR(( "snapshot %s is wrong type", ctx->snapshot_file ));
239 0 : }
240 :
241 : // In order to calculate the snapshot hash, we need to know what features are active...
242 0 : fd_features_restore( ctx->slot_ctx, ctx->runtime_spad );
243 0 : fd_calculate_epoch_accounts_hash_values( ctx->slot_ctx );
244 :
245 : // https://github.com/anza-xyz/agave/blob/766cd682423b8049ddeac3c0ec6cebe0a1356e9e/runtime/src/bank.rs#L1831
246 0 : if( FD_FEATURE_ACTIVE( ctx->slot_ctx->slot_bank.slot, ctx->slot_ctx->epoch_ctx->features, accounts_lt_hash ) ) {
247 0 : ulong *p = (ulong *) ctx->slot_ctx->slot_bank.lthash.lthash;
248 0 : ulong *e = (ulong *) &ctx->slot_ctx->slot_bank.lthash.lthash[sizeof(ctx->slot_ctx->slot_bank.lthash.lthash)];
249 0 : while (p < e) {
250 0 : if ( 0 != *(p++) )
251 0 : break;
252 0 : }
253 0 : if (p >= e)
254 0 : FD_LOG_ERR(( "snapshot must have an accounts lt hash if the feature is enabled" ));
255 0 : }
256 :
257 0 : if( ctx->verify_hash ) {
258 0 : if( ctx->snapshot_type==FD_SNAPSHOT_TYPE_FULL ) {
259 0 : fd_hash_t accounts_hash;
260 0 : FD_SPAD_FRAME_BEGIN( ctx->runtime_spad ) {
261 0 : fd_snapshot_hash( ctx->slot_ctx, ctx->tpool, &accounts_hash, ctx->check_hash, ctx->runtime_spad );
262 0 : } FD_SPAD_FRAME_END;
263 :
264 0 : if( memcmp( fhash->uc, accounts_hash.uc, sizeof(fd_hash_t) ) ) {
265 0 : FD_LOG_ERR(( "snapshot accounts_hash (calculated) %s != (expected) %s", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash ), FD_BASE58_ENC_32_ALLOCA( fhash->uc ) ));
266 0 : } else {
267 0 : FD_LOG_NOTICE(( "snapshot accounts_hash %s verified successfully", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash ) ));
268 0 : }
269 0 : } else if( ctx->snapshot_type == FD_SNAPSHOT_TYPE_INCREMENTAL ) {
270 0 : fd_hash_t accounts_hash;
271 :
272 0 : if( FD_FEATURE_ACTIVE( ctx->slot_ctx->slot_bank.slot, ctx->slot_ctx->epoch_ctx->features, incremental_snapshot_only_incremental_hash_calculation ) ) {
273 0 : FD_LOG_NOTICE(( "hashing incremental snapshot with only deltas" ));
274 0 : fd_snapshot_inc_hash( ctx->slot_ctx, &accounts_hash, ctx->child_txn, ctx->check_hash, ctx->runtime_spad );
275 0 : } else {
276 0 : FD_LOG_NOTICE(( "hashing incremental snapshot with all accounts" ));
277 0 : fd_snapshot_hash( ctx->slot_ctx, ctx->tpool, &accounts_hash, ctx->check_hash, ctx->runtime_spad );
278 0 : }
279 :
280 0 : if( memcmp( fhash->uc, accounts_hash.uc, sizeof(fd_hash_t) ) ) {
281 0 : FD_LOG_ERR(( "incremental accounts_hash %s != %s", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash ), FD_BASE58_ENC_32_ALLOCA( fhash->uc ) ));
282 0 : } else {
283 0 : FD_LOG_NOTICE(( "incremental accounts_hash %s verified successfully", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash ) ));
284 0 : }
285 0 : } else {
286 0 : FD_LOG_ERR(( "invalid snapshot type %d", ctx->snapshot_type ));
287 0 : }
288 0 : }
289 :
290 0 : if( ctx->child_txn != ctx->par_txn ) {
291 0 : fd_funk_txn_publish( ctx->slot_ctx->acc_mgr->funk, ctx->child_txn, 0 );
292 0 : ctx->slot_ctx->funk_txn = ctx->par_txn;
293 0 : }
294 :
295 0 : fd_hashes_load( ctx->slot_ctx, ctx->runtime_spad );
296 :
297 : /* We don't need to free any of the loader memory since it is allocated
298 : from a spad. */
299 :
300 0 : fd_funk_end_write( ctx->slot_ctx->acc_mgr->funk );
301 0 : }
302 :
303 : void
304 : fd_snapshot_load_all( const char * source_cstr,
305 : fd_exec_slot_ctx_t * slot_ctx,
306 : ulong * base_slot_override,
307 : fd_tpool_t * tpool,
308 : uint verify_hash,
309 : uint check_hash,
310 : int snapshot_type,
311 : fd_spad_t * * exec_spads,
312 : ulong exec_spad_cnt,
313 0 : fd_spad_t * runtime_spad ) {
314 :
315 0 : uchar * mem = fd_spad_alloc( runtime_spad, fd_snapshot_load_ctx_align(), fd_snapshot_load_ctx_footprint() );
316 0 : fd_snapshot_load_ctx_t * ctx = fd_snapshot_load_new( mem,
317 0 : source_cstr,
318 0 : slot_ctx,
319 0 : tpool,
320 0 : verify_hash,
321 0 : check_hash,
322 0 : snapshot_type,
323 0 : exec_spads,
324 0 : exec_spad_cnt,
325 0 : runtime_spad );
326 :
327 0 : fd_snapshot_load_init( ctx );
328 0 : fd_runtime_update_slots_per_epoch( slot_ctx, 432000UL, runtime_spad );
329 0 : fd_snapshot_load_manifest_and_status_cache( ctx, base_slot_override,
330 0 : FD_SNAPSHOT_RESTORE_STATUS_CACHE | FD_SNAPSHOT_RESTORE_MANIFEST );
331 0 : fd_snapshot_load_accounts( ctx );
332 0 : fd_snapshot_load_fini( ctx );
333 :
334 0 : }
335 :
336 : void
337 0 : fd_snapshot_load_prefetch_manifest( fd_snapshot_load_ctx_t * ctx ) {
338 :
339 0 : fd_funk_start_write( ctx->slot_ctx->acc_mgr->funk );
340 :
341 0 : size_t slen = strlen( ctx->snapshot_file );
342 0 : char * snapshot_cstr = fd_spad_alloc( ctx->runtime_spad, 8UL, slen + 1 );
343 0 : fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( snapshot_cstr ), ctx->snapshot_file, slen ) );
344 :
345 0 : fd_snapshot_src_t src[1];
346 0 : if( FD_UNLIKELY( !fd_snapshot_src_parse( src, snapshot_cstr ) ) ) {
347 0 : FD_LOG_ERR(( "Failed to load snapshot" ));
348 0 : }
349 :
350 0 : fd_acc_mgr_t * acc_mgr = ctx->slot_ctx->acc_mgr;
351 0 : fd_funk_txn_t * funk_txn = ctx->slot_ctx->funk_txn;
352 :
353 0 : void * restore_mem = fd_spad_alloc( ctx->runtime_spad, fd_snapshot_restore_align(), fd_snapshot_restore_footprint() );
354 0 : void * loader_mem = fd_spad_alloc( ctx->runtime_spad, fd_snapshot_loader_align(), fd_snapshot_loader_footprint( ZSTD_WINDOW_SZ ) );
355 :
356 0 : ctx->restore = fd_snapshot_restore_new( restore_mem, acc_mgr, funk_txn, ctx->runtime_spad, ctx->slot_ctx, restore_manifest, restore_status_cache, restore_rent_fresh_account );
357 0 : ctx->loader = fd_snapshot_loader_new( loader_mem, ZSTD_WINDOW_SZ );
358 :
359 0 : if( FD_UNLIKELY( !fd_snapshot_loader_init( ctx->loader, ctx->restore, src, ctx->slot_ctx->slot_bank.slot, 0 ) ) ) {
360 0 : FD_LOG_ERR(( "Failed to init snapshot loader" ));
361 0 : }
362 :
363 : /* First load in the manifest. */
364 0 : for(;;) {
365 0 : int err = fd_snapshot_loader_advance( ctx->loader );
366 0 : if( err==MANIFEST_DONE ) break; /* We have finished loading in the manifest. */
367 0 : if( FD_LIKELY( !err ) ) continue; /* Keep going. */
368 :
369 : /* If we have reached the end of the snapshot(err==-1), throw an error because
370 : this is not expected. */
371 0 : FD_LOG_ERR(( "Failed to load snapshot (%d-%s)", err, fd_io_strerror( err ) ));
372 0 : }
373 :
374 0 : fd_funk_end_write( ctx->slot_ctx->acc_mgr->funk );
375 0 : }
376 :
377 : ulong
378 0 : fd_snapshot_get_slot( fd_snapshot_load_ctx_t * ctx ) {
379 0 : return fd_snapshot_restore_get_slot( ctx->restore );
380 0 : }
|