Line data Source code
1 : #include "fd_runtime_init.h"
2 : #include "fd_runtime_err.h"
3 : #include "../types/fd_types.h"
4 : #include "context/fd_exec_epoch_ctx.h"
5 : #include "context/fd_exec_slot_ctx.h"
6 : #include "../../ballet/lthash/fd_lthash.h"
7 :
8 : /* This file must not depend on fd_executor.h */
9 :
10 : fd_funk_rec_key_t
11 0 : fd_runtime_epoch_bank_key( void ) {
12 0 : fd_funk_rec_key_t id;
13 0 : fd_memset(&id, 1, sizeof(id));
14 0 : id.c[FD_FUNK_REC_KEY_FOOTPRINT - 1] = FD_BLOCK_EPOCH_BANK_TYPE;
15 :
16 0 : return id;
17 0 : }
18 :
19 : fd_funk_rec_key_t
20 0 : fd_runtime_slot_bank_key( void ) {
21 0 : fd_funk_rec_key_t id;
22 0 : fd_memset(&id, 1, sizeof(id));
23 0 : id.c[FD_FUNK_REC_KEY_FOOTPRINT - 1] = FD_BLOCK_SLOT_BANK_TYPE;
24 :
25 0 : return id;
26 0 : }
27 :
28 : int
29 0 : fd_runtime_save_epoch_bank( fd_exec_slot_ctx_t * slot_ctx ) {
30 0 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
31 0 : ulong sz = sizeof(uint) + fd_epoch_bank_size(epoch_bank);
32 0 : fd_funk_rec_key_t id = fd_runtime_epoch_bank_key();
33 0 : int opt_err = 0;
34 0 : fd_funk_rec_t *rec = fd_funk_rec_write_prepare(slot_ctx->acc_mgr->funk, slot_ctx->funk_txn, &id, sz, 1, NULL, &opt_err);
35 0 : if (NULL == rec)
36 0 : {
37 0 : FD_LOG_WARNING(("fd_runtime_save_banks failed: %s", fd_funk_strerror(opt_err)));
38 0 : return opt_err;
39 0 : }
40 :
41 0 : uchar *buf = fd_funk_val(rec, fd_funk_wksp(slot_ctx->acc_mgr->funk));
42 0 : *(uint*)buf = FD_RUNTIME_ENC_BINCODE;
43 0 : fd_bincode_encode_ctx_t ctx = {
44 0 : .data = buf + sizeof(uint),
45 0 : .dataend = buf + sz,
46 0 : };
47 :
48 0 : if (FD_UNLIKELY(fd_epoch_bank_encode(epoch_bank, &ctx) != FD_BINCODE_SUCCESS))
49 0 : {
50 0 : FD_LOG_WARNING(("fd_runtime_save_banks: fd_firedancer_banks_encode failed"));
51 0 : return -1;
52 0 : }
53 0 : FD_TEST(ctx.data == ctx.dataend);
54 :
55 0 : FD_LOG_DEBUG(( "epoch frozen, slot=%lu bank_hash=%s poh_hash=%s", slot_ctx->slot_bank.slot, FD_BASE58_ENC_32_ALLOCA( slot_ctx->slot_bank.banks_hash.hash ), FD_BASE58_ENC_32_ALLOCA( slot_ctx->slot_bank.poh.hash ) ));
56 :
57 0 : return FD_RUNTIME_EXECUTE_SUCCESS;
58 0 : }
59 :
60 : int
61 0 : fd_runtime_save_epoch_bank_archival( fd_exec_slot_ctx_t * slot_ctx ) {
62 0 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
63 0 : ulong sz = sizeof(uint) + fd_epoch_bank_size(epoch_bank)*2; /* Conservatively estimate double the bincode size */
64 0 : fd_funk_rec_key_t id = fd_runtime_epoch_bank_key();
65 0 : int opt_err = 0;
66 0 : fd_funk_rec_t *rec = fd_funk_rec_write_prepare(slot_ctx->acc_mgr->funk, slot_ctx->funk_txn, &id, sz, 1, NULL, &opt_err);
67 0 : if (NULL == rec)
68 0 : {
69 0 : FD_LOG_WARNING(("fd_runtime_save_banks failed: %s", fd_funk_strerror(opt_err)));
70 0 : return opt_err;
71 0 : }
72 :
73 0 : uchar *buf = fd_funk_val(rec, fd_funk_wksp(slot_ctx->acc_mgr->funk));
74 0 : *(uint*)buf = FD_RUNTIME_ENC_ARCHIVE;
75 0 : fd_bincode_encode_ctx_t ctx = {
76 0 : .data = buf + sizeof(uint),
77 0 : .dataend = buf + sz,
78 0 : };
79 :
80 0 : if (FD_UNLIKELY(fd_epoch_bank_encode_archival(epoch_bank, &ctx) != FD_BINCODE_SUCCESS))
81 0 : {
82 0 : FD_LOG_WARNING(("fd_runtime_save_banks: fd_firedancer_banks_encode failed"));
83 0 : return -1;
84 0 : }
85 :
86 0 : rec->val_sz = (uint)((uchar *)ctx.data - buf); /* Fix the final size */
87 :
88 0 : return FD_RUNTIME_EXECUTE_SUCCESS;
89 0 : }
90 :
91 : int fd_runtime_save_slot_bank(fd_exec_slot_ctx_t *slot_ctx)
92 0 : {
93 0 : ulong sz = sizeof(uint) + fd_slot_bank_size(&slot_ctx->slot_bank);
94 :
95 0 : fd_funk_rec_key_t id = fd_runtime_slot_bank_key();
96 0 : int opt_err = 0;
97 0 : fd_funk_rec_t *rec = fd_funk_rec_write_prepare(slot_ctx->acc_mgr->funk, slot_ctx->funk_txn, &id, sz, 1, NULL, &opt_err);
98 0 : if (NULL == rec)
99 0 : {
100 0 : FD_LOG_WARNING(("fd_runtime_save_banks failed: %s", fd_funk_strerror(opt_err)));
101 0 : return opt_err;
102 0 : }
103 :
104 0 : uchar *buf = fd_funk_val(rec, fd_funk_wksp(slot_ctx->acc_mgr->funk));
105 0 : *(uint*)buf = FD_RUNTIME_ENC_BINCODE;
106 0 : fd_bincode_encode_ctx_t ctx = {
107 0 : .data = buf + sizeof(uint),
108 0 : .dataend = buf + sz,
109 0 : };
110 0 : if (FD_UNLIKELY(fd_slot_bank_encode(&slot_ctx->slot_bank, &ctx) != FD_BINCODE_SUCCESS))
111 0 : {
112 0 : FD_LOG_WARNING(("fd_runtime_save_banks: fd_firedancer_banks_encode failed"));
113 0 : return -1;
114 0 : }
115 0 : FD_TEST(ctx.data == ctx.dataend);
116 :
117 0 : FD_LOG_DEBUG(( "slot frozen, slot=%lu bank_hash=%s poh_hash=%s",
118 0 : slot_ctx->slot_bank.slot,
119 0 : FD_BASE58_ENC_32_ALLOCA( slot_ctx->slot_bank.banks_hash.hash ),
120 0 : FD_BASE58_ENC_32_ALLOCA( slot_ctx->slot_bank.poh.hash ) ));
121 :
122 0 : return FD_RUNTIME_EXECUTE_SUCCESS;
123 0 : }
124 :
125 : int fd_runtime_save_slot_bank_archival(fd_exec_slot_ctx_t *slot_ctx)
126 0 : {
127 0 : ulong sz = sizeof(uint) + fd_slot_bank_size(&slot_ctx->slot_bank)*2; /* Conservatively estimate double the bincode size */
128 :
129 0 : fd_funk_rec_key_t id = fd_runtime_slot_bank_key();
130 0 : int opt_err = 0;
131 0 : fd_funk_rec_t *rec = fd_funk_rec_write_prepare(slot_ctx->acc_mgr->funk, slot_ctx->funk_txn, &id, sz, 1, NULL, &opt_err);
132 0 : if (NULL == rec)
133 0 : {
134 0 : FD_LOG_WARNING(("fd_runtime_save_banks failed: %s", fd_funk_strerror(opt_err)));
135 0 : return opt_err;
136 0 : }
137 :
138 0 : uchar *buf = fd_funk_val(rec, fd_funk_wksp(slot_ctx->acc_mgr->funk));
139 0 : *(uint*)buf = FD_RUNTIME_ENC_ARCHIVE;
140 0 : fd_bincode_encode_ctx_t ctx = {
141 0 : .data = buf + sizeof(uint),
142 0 : .dataend = buf + sz,
143 0 : };
144 0 : if (FD_UNLIKELY(fd_slot_bank_encode_archival(&slot_ctx->slot_bank, &ctx) != FD_BINCODE_SUCCESS))
145 0 : {
146 0 : FD_LOG_WARNING(("fd_runtime_save_banks: fd_firedancer_banks_encode failed"));
147 0 : return -1;
148 0 : }
149 :
150 0 : rec->val_sz = (uint)((uchar *)ctx.data - buf); /* Fix the final size */
151 :
152 0 : return FD_RUNTIME_EXECUTE_SUCCESS;
153 0 : }
154 :
155 : void
156 0 : fd_runtime_recover_banks( fd_exec_slot_ctx_t * slot_ctx, int delete_first, int clear_first ) {
157 0 : fd_funk_t * funk = slot_ctx->acc_mgr->funk;
158 0 : fd_funk_txn_t * txn = slot_ctx->funk_txn;
159 0 : fd_exec_epoch_ctx_t * epoch_ctx = slot_ctx->epoch_ctx;
160 0 : {
161 0 : fd_funk_rec_key_t id = fd_runtime_epoch_bank_key();
162 0 : fd_funk_rec_t const * rec = fd_funk_rec_query_global(funk, txn, &id, NULL);
163 0 : if ( rec == NULL )
164 0 : FD_LOG_ERR(("failed to read banks record: missing record"));
165 0 : void * val = fd_funk_val( rec, fd_funk_wksp(funk) );
166 :
167 0 : if( fd_funk_val_sz( rec ) < sizeof(uint) ) {
168 0 : FD_LOG_ERR(("failed to read banks record: empty record"));
169 0 : }
170 0 : uint magic = *(uint*)val;
171 :
172 0 : if( clear_first ) {
173 0 : fd_exec_epoch_ctx_bank_mem_clear( epoch_ctx );
174 0 : }
175 0 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_bank_mem_setup( epoch_ctx );
176 0 : fd_bincode_decode_ctx_t ctx;
177 0 : ctx.data = (uchar*)val + sizeof(uint);
178 0 : ctx.dataend = (uchar*)val + fd_funk_val_sz( rec );
179 : /* We use this special allocator to indicate that the data
180 : structure has already been constructed in its final memory layout */
181 0 : ctx.valloc = fd_null_alloc_virtual();
182 0 : if( magic == FD_RUNTIME_ENC_BINCODE ) {
183 0 : FD_TEST( fd_epoch_bank_decode( epoch_bank, &ctx )==FD_BINCODE_SUCCESS );
184 0 : } else if( magic == FD_RUNTIME_ENC_ARCHIVE ) {
185 0 : FD_TEST( fd_epoch_bank_decode_archival( epoch_bank, &ctx )==FD_BINCODE_SUCCESS );
186 0 : } else {
187 0 : FD_LOG_ERR(("failed to read banks record: invalid magic number"));
188 0 : }
189 :
190 0 : FD_LOG_NOTICE(( "recovered epoch_bank" ));
191 0 : }
192 :
193 0 : {
194 0 : if ( delete_first ) {
195 0 : fd_bincode_destroy_ctx_t ctx;
196 0 : ctx.valloc = slot_ctx->valloc;
197 0 : fd_slot_bank_destroy(&slot_ctx->slot_bank, &ctx);
198 0 : }
199 0 : fd_funk_rec_key_t id = fd_runtime_slot_bank_key();
200 0 : fd_funk_rec_t const * rec = fd_funk_rec_query_global(funk, txn, &id, NULL);
201 0 : if ( rec == NULL )
202 0 : FD_LOG_ERR(("failed to read banks record: missing record"));
203 0 : void * val = fd_funk_val( rec, fd_funk_wksp(funk) );
204 :
205 0 : if( fd_funk_val_sz( rec ) < sizeof(uint) ) {
206 0 : FD_LOG_ERR(("failed to read banks record: empty record"));
207 0 : }
208 0 : uint magic = *(uint*)val;
209 :
210 0 : fd_bincode_decode_ctx_t ctx;
211 0 : ctx.data = (uchar*)val + sizeof(uint);
212 0 : ctx.dataend = (uchar*)val + fd_funk_val_sz( rec );
213 0 : ctx.valloc = slot_ctx->valloc;
214 0 : if( magic == FD_RUNTIME_ENC_BINCODE ) {
215 0 : FD_TEST( fd_slot_bank_decode(&slot_ctx->slot_bank, &ctx )==FD_BINCODE_SUCCESS );
216 0 : } else if( magic == FD_RUNTIME_ENC_ARCHIVE ) {
217 0 : FD_TEST( fd_slot_bank_decode_archival(&slot_ctx->slot_bank, &ctx )==FD_BINCODE_SUCCESS );
218 0 : } else {
219 0 : FD_LOG_ERR(("failed to read banks record: invalid magic number"));
220 0 : }
221 :
222 0 : FD_LOG_NOTICE(( "recovered slot_bank for slot=%ld banks_hash=%s poh_hash %s lthash %s",
223 0 : (long)slot_ctx->slot_bank.slot,
224 0 : FD_BASE58_ENC_32_ALLOCA( slot_ctx->slot_bank.banks_hash.hash ),
225 0 : FD_BASE58_ENC_32_ALLOCA( slot_ctx->slot_bank.poh.hash ),
226 0 : FD_LTHASH_ENC_32_ALLOCA( (fd_lthash_value_t *) slot_ctx->slot_bank.lthash.lthash ) ));
227 :
228 0 : slot_ctx->slot_bank.collected_execution_fees = 0;
229 0 : slot_ctx->slot_bank.collected_priority_fees = 0;
230 0 : slot_ctx->slot_bank.collected_rent = 0;
231 0 : slot_ctx->txn_count = 0;
232 0 : slot_ctx->nonvote_txn_count = 0;
233 0 : slot_ctx->failed_txn_count = 0;
234 0 : slot_ctx->nonvote_failed_txn_count = 0;
235 0 : slot_ctx->total_compute_units_used = 0;
236 0 : }
237 :
238 0 : }
239 :
240 : void
241 0 : fd_runtime_delete_banks( fd_exec_slot_ctx_t * slot_ctx ) {
242 :
243 : /* As the collection pointers are not owned by fd_alloc, zero them
244 : out to prevent invalid frees by the destroy function. */
245 :
246 0 : fd_bincode_destroy_ctx_t ctx = { .valloc = slot_ctx->valloc };
247 0 : fd_exec_epoch_ctx_epoch_bank_delete( slot_ctx->epoch_ctx );
248 0 : fd_slot_bank_destroy( &slot_ctx->slot_bank, &ctx );
249 0 : }
250 :
251 :
252 : /* fd_feature_restore loads a feature from the accounts database and
253 : updates the bank's feature activation state, given a feature account
254 : address. */
255 :
256 : static void
257 : fd_feature_restore( fd_exec_slot_ctx_t * slot_ctx,
258 : fd_feature_id_t const * id,
259 0 : uchar const acct[ static 32 ] ) {
260 :
261 0 : FD_BORROWED_ACCOUNT_DECL(acct_rec);
262 0 : int err = fd_acc_mgr_view(slot_ctx->acc_mgr, slot_ctx->funk_txn, (fd_pubkey_t *)acct, acct_rec);
263 0 : if (FD_UNLIKELY(err != FD_ACC_MGR_SUCCESS))
264 0 : return;
265 :
266 : // Skip reverted features
267 0 : if ( id->reverted )
268 0 : return;
269 :
270 0 : fd_feature_t feature[1];
271 :
272 0 : FD_SCRATCH_SCOPE_BEGIN
273 0 : {
274 :
275 0 : fd_bincode_decode_ctx_t ctx = {
276 0 : .data = acct_rec->const_data,
277 0 : .dataend = acct_rec->const_data + acct_rec->const_meta->dlen,
278 0 : .valloc = fd_scratch_virtual(),
279 0 : };
280 0 : int decode_err = fd_feature_decode(feature, &ctx);
281 0 : if (FD_UNLIKELY(decode_err != FD_BINCODE_SUCCESS))
282 0 : {
283 0 : FD_LOG_ERR(("Failed to decode feature account %s (%d)", FD_BASE58_ENC_32_ALLOCA( acct ), decode_err));
284 0 : return;
285 0 : }
286 :
287 0 : if( feature->has_activated_at ) {
288 0 : FD_LOG_INFO(( "Feature %s activated at %lu", FD_BASE58_ENC_32_ALLOCA( acct ), feature->activated_at ));
289 0 : fd_features_set(&slot_ctx->epoch_ctx->features, id, feature->activated_at);
290 0 : } else {
291 0 : FD_LOG_DEBUG(( "Feature %s not activated at %lu", FD_BASE58_ENC_32_ALLOCA( acct ), feature->activated_at ));
292 0 : }
293 : /* No need to call destroy, since we are using fd_scratch allocator. */
294 0 : } FD_SCRATCH_SCOPE_END;
295 0 : }
296 :
297 : void
298 0 : fd_features_restore( fd_exec_slot_ctx_t * slot_ctx ) {
299 0 : for( fd_feature_id_t const * id = fd_feature_iter_init();
300 0 : !fd_feature_iter_done( id );
301 0 : id = fd_feature_iter_next( id ) ) {
302 0 : fd_feature_restore( slot_ctx, id, id->id.key );
303 0 : }
304 0 : }
|