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