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