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 :
12 : #include <assert.h>
13 : #include <errno.h>
14 :
15 : static void
16 0 : fd_hashes_load(fd_exec_slot_ctx_t * slot_ctx) {
17 0 : FD_BORROWED_ACCOUNT_DECL(block_hashes_rec);
18 0 : int err = fd_acc_mgr_view(slot_ctx->acc_mgr, slot_ctx->funk_txn, &fd_sysvar_recent_block_hashes_id, block_hashes_rec);
19 :
20 0 : if( err != FD_ACC_MGR_SUCCESS )
21 0 : FD_LOG_ERR(( "missing recent block hashes account" ));
22 :
23 0 : fd_bincode_decode_ctx_t ctx = {
24 0 : .data = block_hashes_rec->const_data,
25 0 : .dataend = block_hashes_rec->const_data + block_hashes_rec->const_meta->dlen,
26 0 : .valloc = slot_ctx->valloc
27 0 : };
28 :
29 0 : fd_recent_block_hashes_decode( &slot_ctx->slot_bank.recent_block_hashes, &ctx );
30 :
31 0 : slot_ctx->slot_bank.stake_account_keys.stake_accounts_root = NULL;
32 0 : slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool = fd_stake_accounts_pair_t_map_alloc(slot_ctx->valloc, 100000);
33 :
34 0 : slot_ctx->slot_bank.vote_account_keys.vote_accounts_root = NULL;
35 0 : slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool = fd_vote_accounts_pair_t_map_alloc(slot_ctx->valloc, 100000);
36 :
37 0 : slot_ctx->slot_bank.collected_execution_fees = 0;
38 0 : slot_ctx->slot_bank.collected_priority_fees = 0;
39 0 : slot_ctx->slot_bank.collected_rent = 0;
40 :
41 0 : fd_runtime_save_slot_bank( slot_ctx );
42 0 : fd_runtime_save_epoch_bank( slot_ctx );
43 0 : }
44 :
45 :
46 : static int
47 : restore_manifest( void * ctx,
48 0 : fd_solana_manifest_t * manifest ) {
49 0 : return (!!fd_exec_slot_ctx_recover( ctx, manifest ) ? 0 : EINVAL);
50 0 : }
51 :
52 : static int
53 : restore_status_cache( void * ctx,
54 0 : fd_bank_slot_deltas_t * slot_deltas ) {
55 0 : return (!!fd_exec_slot_ctx_recover_status_cache( ctx, slot_deltas ) ? 0 : EINVAL);
56 0 : }
57 :
58 : static void
59 : load_one_snapshot( fd_exec_slot_ctx_t * slot_ctx,
60 : char * source_cstr,
61 0 : fd_snapshot_name_t * name_out ) {
62 :
63 : /* FIXME don't hardcode this param */
64 0 : static ulong const zstd_window_sz = 33554432UL;
65 :
66 0 : fd_snapshot_src_t src[1];
67 0 : if( FD_UNLIKELY( !fd_snapshot_src_parse( src, source_cstr ) ) ) {
68 0 : FD_LOG_ERR(( "Failed to load snapshot" ));
69 0 : }
70 :
71 0 : if( src->type == FD_SNAPSHOT_SRC_ARCHIVE ) {
72 0 : if( FD_UNLIKELY( fd_funk_unarchive( slot_ctx->acc_mgr->funk, src->file.path ) ) ) {
73 0 : FD_LOG_ERR(( "Failed to load snapshot" ));
74 0 : }
75 0 : fd_runtime_recover_banks( slot_ctx, 0, 1 );
76 0 : memset( name_out, 0, sizeof(fd_snapshot_name_t) );
77 0 : name_out->type = FD_SNAPSHOT_TYPE_FULL;
78 0 : name_out->slot = slot_ctx->slot_bank.slot;
79 0 : return;
80 0 : }
81 0 : fd_exec_epoch_ctx_bank_mem_clear( slot_ctx->epoch_ctx );
82 :
83 0 : fd_valloc_t valloc = slot_ctx->valloc;
84 0 : fd_acc_mgr_t * acc_mgr = slot_ctx->acc_mgr;
85 0 : fd_funk_txn_t * funk_txn = slot_ctx->funk_txn;
86 :
87 0 : void * restore_mem = fd_valloc_malloc( valloc, fd_snapshot_restore_align(), fd_snapshot_restore_footprint() );
88 0 : void * loader_mem = fd_valloc_malloc( valloc, fd_snapshot_loader_align(), fd_snapshot_loader_footprint( zstd_window_sz ) );
89 :
90 0 : fd_snapshot_restore_t * restore = fd_snapshot_restore_new( restore_mem, acc_mgr, funk_txn, valloc, slot_ctx, restore_manifest, restore_status_cache );
91 0 : fd_snapshot_loader_t * loader = fd_snapshot_loader_new ( loader_mem, zstd_window_sz );
92 :
93 0 : if( FD_UNLIKELY( !restore || !loader ) ) {
94 0 : fd_valloc_free( valloc, fd_snapshot_loader_delete ( loader_mem ) );
95 0 : fd_valloc_free( valloc, fd_snapshot_restore_delete( restore_mem ) );
96 0 : FD_LOG_ERR(( "Failed to load snapshot" ));
97 0 : }
98 :
99 0 : if( FD_UNLIKELY( !fd_snapshot_loader_init( loader, restore, src, slot_ctx->slot_bank.slot ) ) ) {
100 0 : FD_LOG_ERR(( "Failed to init snapshot loader" ));
101 0 : }
102 :
103 0 : for(;;) {
104 0 : int err = fd_snapshot_loader_advance( loader );
105 0 : if( FD_LIKELY( err == 0 ) ) continue;
106 0 : if( err == -1 ) break;
107 :
108 0 : FD_LOG_ERR(( "Failed to load snapshot (%d-%s)", err, fd_io_strerror( err ) ));
109 0 : }
110 :
111 0 : fd_snapshot_name_t const * name = fd_snapshot_loader_get_name( loader );
112 0 : if( FD_UNLIKELY( !name ) ) FD_LOG_ERR(( "name is NULL" ));
113 0 : *name_out = *name;
114 :
115 0 : fd_valloc_free( valloc, fd_snapshot_loader_delete ( loader_mem ) );
116 0 : fd_valloc_free( valloc, fd_snapshot_restore_delete( restore_mem ) );
117 :
118 0 : FD_LOG_NOTICE(( "Finished reading snapshot %s", source_cstr ));
119 0 : }
120 :
121 :
122 : void
123 : fd_snapshot_load( const char * snapshotfile,
124 : fd_exec_slot_ctx_t * slot_ctx,
125 : fd_tpool_t * tpool,
126 : uint verify_hash,
127 : uint check_hash,
128 0 : int snapshot_type ) {
129 :
130 0 : switch (snapshot_type) {
131 0 : case FD_SNAPSHOT_TYPE_UNSPECIFIED:
132 0 : FD_LOG_ERR(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, FD_SNAPSHOT_TYPE_UNSPECIFIED)", snapshotfile, verify_hash ? "true" : "false", check_hash ? "true" : "false"));
133 0 : break;
134 0 : case FD_SNAPSHOT_TYPE_FULL:
135 0 : FD_LOG_NOTICE(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, FD_SNAPSHOT_TYPE_FULL)", snapshotfile, verify_hash ? "true" : "false", check_hash ? "true" : "false"));
136 0 : break;
137 0 : case FD_SNAPSHOT_TYPE_INCREMENTAL:
138 0 : FD_LOG_NOTICE(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, FD_SNAPSHOT_TYPE_INCREMENTAL)", snapshotfile, verify_hash ? "true" : "false", check_hash ? "true" : "false"));
139 0 : break;
140 0 : default:
141 0 : FD_LOG_ERR(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, huh?)", snapshotfile, verify_hash ? "true" : "false", check_hash ? "true" : "false"));
142 0 : break;
143 0 : }
144 :
145 0 : fd_funk_start_write( slot_ctx->acc_mgr->funk );
146 : /* Speed load currently has long term memory usage consequences
147 : which are unacceptable. Consider turning it back on when we have a
148 : better design. */
149 0 : fd_funk_speed_load_mode( slot_ctx->acc_mgr->funk, 0 );
150 :
151 0 : fd_funk_txn_t * par_txn = slot_ctx->funk_txn;
152 0 : fd_funk_txn_t * child_txn = slot_ctx->funk_txn;
153 0 : if( verify_hash && FD_FEATURE_ACTIVE(slot_ctx, incremental_snapshot_only_incremental_hash_calculation) ) {
154 0 : fd_funk_txn_xid_t xid;
155 0 : memset( &xid, 0xc3, sizeof( xid ) );
156 0 : child_txn = fd_funk_txn_prepare( slot_ctx->acc_mgr->funk, child_txn, &xid, 0 );
157 0 : slot_ctx->funk_txn = child_txn;
158 0 : }
159 :
160 0 : fd_scratch_push();
161 0 : size_t slen = strlen( snapshotfile );
162 0 : char * snapshot_cstr = fd_scratch_alloc( 1UL, slen + 1 );
163 0 : fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( snapshot_cstr ), snapshotfile, slen ) );
164 0 : fd_snapshot_name_t name = {0};
165 0 : load_one_snapshot( slot_ctx, snapshot_cstr, &name );
166 0 : fd_hash_t const * fhash = &name.fhash;
167 0 : fd_scratch_pop();
168 :
169 0 : if( name.type != snapshot_type ) {
170 0 : FD_LOG_ERR(( "snapshot %s is wrong type", snapshotfile ));
171 0 : }
172 :
173 : // In order to calculate the snapshot hash, we need to know what features are active...
174 0 : fd_features_restore( slot_ctx );
175 0 : fd_calculate_epoch_accounts_hash_values( slot_ctx );
176 :
177 0 : if( verify_hash ) {
178 0 : if (snapshot_type == FD_SNAPSHOT_TYPE_FULL) {
179 0 : fd_hash_t accounts_hash;
180 0 : fd_snapshot_hash(slot_ctx, tpool, &accounts_hash, check_hash);
181 :
182 0 : if (memcmp(fhash->uc, accounts_hash.uc, 32) != 0)
183 0 : FD_LOG_ERR(( "snapshot accounts_hash %s != %s", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash ), FD_BASE58_ENC_32_ALLOCA( fhash->uc ) ));
184 0 : else
185 0 : FD_LOG_NOTICE(( "snapshot accounts_hash %s verified successfully", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash) ));
186 0 : } else if (snapshot_type == FD_SNAPSHOT_TYPE_INCREMENTAL) {
187 0 : fd_hash_t accounts_hash;
188 :
189 0 : if (FD_FEATURE_ACTIVE(slot_ctx, incremental_snapshot_only_incremental_hash_calculation)) {
190 0 : FD_LOG_NOTICE(( "hashing incremental snapshot with only deltas" ));
191 0 : fd_accounts_hash_inc_only(slot_ctx, &accounts_hash, child_txn, check_hash);
192 0 : } else {
193 0 : FD_LOG_NOTICE(( "hashing incremental snapshot with all accounts" ));
194 0 : fd_snapshot_hash(slot_ctx, tpool, &accounts_hash, check_hash);
195 0 : }
196 :
197 0 : if (memcmp(fhash->uc, accounts_hash.uc, 32) != 0)
198 0 : FD_LOG_ERR(("incremental accounts_hash %s != %s", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash ), FD_BASE58_ENC_32_ALLOCA( fhash->uc ) ));
199 0 : else
200 0 : FD_LOG_NOTICE(("incremental accounts_hash %s verified successfully", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash ) ));
201 0 : } else {
202 0 : FD_LOG_ERR(( "invalid snapshot type %d", snapshot_type ));
203 0 : }
204 0 : }
205 :
206 0 : if( child_txn != par_txn ) {
207 0 : fd_funk_txn_publish( slot_ctx->acc_mgr->funk, child_txn, 0 );
208 0 : slot_ctx->funk_txn = par_txn;
209 0 : }
210 :
211 0 : fd_hashes_load(slot_ctx);
212 :
213 0 : fd_rewards_recalculate_partitioned_rewards( slot_ctx );
214 :
215 0 : fd_funk_speed_load_mode( slot_ctx->acc_mgr->funk, 0 );
216 0 : fd_funk_end_write( slot_ctx->acc_mgr->funk );
217 0 : }
|