Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_runtime_fd_runtime_h
2 : #define HEADER_fd_src_flamenco_runtime_fd_runtime_h
3 :
4 : #include "stdarg.h"
5 :
6 : #include "fd_runtime_err.h"
7 : #include "fd_runtime_init.h"
8 : #include "fd_rocksdb.h"
9 : #include "fd_acc_mgr.h"
10 : #include "fd_hashes.h"
11 : #include "../features/fd_features.h"
12 : #include "context/fd_capture_ctx.h"
13 : #include "context/fd_exec_txn_ctx.h"
14 : #include "info/fd_runtime_block_info.h"
15 : #include "info/fd_instr_info.h"
16 : #include "../../disco/pack/fd_microblock.h"
17 : #include "info/fd_microblock_info.h"
18 : #include "../../ballet/sbpf/fd_sbpf_loader.h"
19 : #include "../vm/fd_vm_base.h"
20 :
21 : /* Various constant values used by the runtime. */
22 :
23 0 : #define MICRO_LAMPORTS_PER_LAMPORT (1000000UL)
24 :
25 0 : #define DEFAULT_HASHES_PER_TICK (12500)
26 : #define UPDATED_HASHES_PER_TICK2 (17500)
27 : #define UPDATED_HASHES_PER_TICK3 (27500)
28 : #define UPDATED_HASHES_PER_TICK4 (47500)
29 : #define UPDATED_HASHES_PER_TICK5 (57500)
30 : #define UPDATED_HASHES_PER_TICK6 (62500)
31 :
32 : #define FD_RUNTIME_TRACE_NONE (0)
33 : #define FD_RUNTIME_TRACE_SAVE (1)
34 : #define FD_RUNTIME_TRACE_REPLAY (2)
35 :
36 : #define FD_RUNTIME_OFFLINE_NUM_ROOT_BLOCKS (6UL) /* 6 root blocks for offline replay */
37 :
38 : #define FD_RENT_EXEMPT_RENT_EPOCH (ULONG_MAX)
39 :
40 0 : #define SECONDS_PER_YEAR ((double)(365.242199 * 24.0 * 60.0 * 60.0))
41 :
42 : /*
43 : * fd_block_entry_batch_t is a microblock/entry batch within a block.
44 : * The offset is relative to the start of the block's data region,
45 : * and indicates where the batch ends. The (exclusive) end offset of
46 : * batch i is the (inclusive) start offset of batch i+1. The 0th batch
47 : * always starts at offset 0.
48 : * On the wire, the presence of one of the COMPLETE flags in a data
49 : * shred marks the end of a batch.
50 : * In other words, batch ends are aligned with shred ends, and batch
51 : * starts are aligned with shred starts. Usually a batch comprises
52 : * multiple shreds, and a block comprises multiple batches.
53 : * This information is useful because bincode deserialization needs to
54 : * be performed on a per-batch basis. Precisely a single array of
55 : * microblocks/entries is expected to be deserialized from a batch.
56 : * Trailing bytes in each batch are ignored by default.
57 : */
58 : struct fd_block_entry_batch {
59 : ulong end_off; /* exclusive */
60 : };
61 : typedef struct fd_block_entry_batch fd_block_entry_batch_t;
62 :
63 : /* The below logic is used to size out the memory footprint generated by the
64 : runtime during transaction execution. */
65 :
66 : /* The prevailing layout we have in the runtime is the meta followed by
67 : the account's data. This struct encodes that layout and asserts that
68 : the alignment requirements of the constituents are satisfied. */
69 : // TODO: Use this struct at allocation sites so it's clear we use this layout
70 : struct __attribute__((packed)) fd_account_rec {
71 : fd_account_meta_t meta;
72 : uchar data[] __attribute__((aligned(8)));
73 : };
74 : typedef struct fd_account_rec fd_account_rec_t;
75 0 : #define FD_ACCOUNT_REC_ALIGN (8UL)
76 : #define FD_ACCOUNT_REC_DATA_ALIGN (8UL)
77 : FD_STATIC_ASSERT( FD_ACCOUNT_REC_ALIGN>=alignof(fd_account_meta_t), account_rec_meta_align );
78 : FD_STATIC_ASSERT( FD_ACCOUNT_REC_ALIGN>=FD_ACCOUNT_REC_DATA_ALIGN, account_rec_data_align );
79 : FD_STATIC_ASSERT( (offsetof(fd_account_rec_t, meta)%alignof(fd_account_meta_t))==0, account_rec_meta_offset );
80 : FD_STATIC_ASSERT( (offsetof(fd_account_rec_t, data)%FD_ACCOUNT_REC_DATA_ALIGN )==0, account_rec_data_offset );
81 :
82 0 : #define MAX_PERMITTED_DATA_INCREASE (10240UL) // 10KB
83 24 : #define FD_BPF_ALIGN_OF_U128 (8UL )
84 : FD_STATIC_ASSERT( FD_BPF_ALIGN_OF_U128==FD_ACCOUNT_REC_DATA_ALIGN, input_data_align );
85 0 : #define FD_RUNTIME_INPUT_REGION_ALLOC_ALIGN_UP (16UL)
86 :
87 : /******** These macros bound out memory footprint ********/
88 :
89 : /* The tight upper bound on borrowed account footprint over the
90 : execution of a single transaction. */
91 24 : #define FD_RUNTIME_BORROWED_ACCOUNT_FOOTPRINT (MAX_TX_ACCOUNT_LOCKS * FD_ULONG_ALIGN_UP( FD_ACC_TOT_SZ_MAX, FD_ACCOUNT_REC_ALIGN ))
92 :
93 : /* The tight-ish upper bound on input region footprint over the
94 : execution of a single transaction. See input serialization code for
95 : reference: fd_bpf_loader_serialization.c
96 :
97 : This bound is based off of the transaction MTU. We consider the
98 : question of what kind of transaction one would construct to
99 : maximally bloat the input region.
100 : The worst case scenario is when every nested instruction references
101 : all unique accounts in the transaction. A transaction can lock a max
102 : of MAX_TX_ACCOUNT_LOCKS accounts. Then all remaining input account
103 : references are going to be duplicates, which cost 1 byte to specify
104 : offset in payload, and which cost 8 bytes during serialization. Then
105 : there would be 0 bytes of instruction data, because they exist byte
106 : for byte in the raw payload, which is not a worthwhile bloat factor.
107 : */
108 : #define FD_RUNTIME_INPUT_REGION_UNIQUE_ACCOUNT_FOOTPRINT(direct_mapping) \
109 : (1UL /* dup byte */ + \
110 : sizeof(uchar) /* is_signer */ + \
111 : sizeof(uchar) /* is_writable */ + \
112 : sizeof(uchar) /* executable */ + \
113 : sizeof(uint) /* original_data_len */ + \
114 : sizeof(fd_pubkey_t) /* key */ + \
115 : sizeof(fd_pubkey_t) /* owner */ + \
116 : sizeof(ulong) /* lamports */ + \
117 : sizeof(ulong) /* data len */ + \
118 : (direct_mapping ? FD_BPF_ALIGN_OF_U128 : FD_ULONG_ALIGN_UP( FD_RUNTIME_ACC_SZ_MAX, FD_BPF_ALIGN_OF_U128 )) + \
119 : MAX_PERMITTED_DATA_INCREASE + \
120 : sizeof(ulong)) /* rent_epoch */
121 :
122 : #define FD_RUNTIME_INPUT_REGION_INSN_FOOTPRINT(account_lock_limit, direct_mapping) \
123 24 : (FD_ULONG_ALIGN_UP( (sizeof(ulong) /* acct_cnt */ + \
124 24 : account_lock_limit*FD_RUNTIME_INPUT_REGION_UNIQUE_ACCOUNT_FOOTPRINT(direct_mapping) + \
125 24 : sizeof(ulong) /* instr data len */ + \
126 24 : /* No instr data */ \
127 24 : sizeof(fd_pubkey_t)), /* program id */ \
128 24 : FD_RUNTIME_INPUT_REGION_ALLOC_ALIGN_UP ) + FD_BPF_ALIGN_OF_U128)
129 :
130 : #define FD_RUNTIME_INPUT_REGION_TXN_FOOTPRINT(account_lock_limit, direct_mapping) \
131 24 : ((FD_MAX_INSTRUCTION_STACK_DEPTH*FD_RUNTIME_INPUT_REGION_INSN_FOOTPRINT(account_lock_limit, direct_mapping)) + \
132 24 : ((FD_TXN_MTU-FD_TXN_MIN_SERIALIZED_SZ-account_lock_limit)*8UL)) /* We can have roughly this much duplicate offsets */
133 :
134 : /* Bincode valloc footprint over the execution of a single transaction.
135 : As well as other footprint specific to each native program type.
136 :
137 : N.B. We know that bincode valloc footprint is bounded, because
138 : whenever we alloc something, we advance our pointer into the binary
139 : buffer, so eventually we are gonna reach the end of the buffer.
140 : This buffer is usually backed by and ultimately bounded in size by
141 : either accounts data or the transaction MTU.
142 :
143 : That being said, it's not obvious what the tight upper bound would
144 : be for allocations across all possible execution paths of all native
145 : programs, including possible CPIs from native programs. The
146 : footprint estimate here is based on a manual review of our native
147 : program implementation. Note that even if the possible paths remain
148 : steady at the Solana protocol level, the footprint is subject to
149 : change when we change our implementation.
150 :
151 : ### Native programs
152 : ALUT (migrated to BPF)
153 : Loader
154 : - rodata for bpf program relocation and validation
155 : Compute budget (0 allocations)
156 : Config (migrated to BPF)
157 : Precompile (0 allocations)
158 : Stake
159 : - The instruction with the largest footprint is deactivate_delinquent
160 : - During instruction decode, no allocations
161 : - During execution, this is (vote account get_state() + vote convert_to_current()) times 2, once for delinquent_vote_account, and once for reference_vote_account
162 : System
163 : - system_program_instruction_decode seed
164 : Vote
165 : - The instruction with the largest footprint is compact vote state update
166 : - During instruction decode, this is 9*lockouts_len bytes, MTU bounded
167 : - During execution, this is vote account get_state() + vote convert_to_current() + 12*lockouts_len bytes + lockouts_len ulong + deq_fd_landed_vote_t_alloc(lockouts_len)
168 : Zk Elgamal (0 allocations)
169 :
170 : The largest footprint is hence deactivate_delinquent, in which the
171 : two get_state() calls dominate the footprint. In particular, the
172 : authorized_voters treaps bloat 40 bytes (epoch+pubkey) in a vote
173 : account to 72 bytes (sizeof(fd_vote_authorized_voter_t)) in memory.
174 : */
175 24 : #define FD_RUNTIME_BINCODE_AND_NATIVE_FOOTPRINT (2UL*FD_RUNTIME_ACC_SZ_MAX*72UL/40UL)
176 :
177 : /* Misc other footprint. */
178 24 : #define FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT (FD_MAX_INSTRUCTION_STACK_DEPTH*FD_ULONG_ALIGN_UP(FD_SBPF_SYSCALLS_FOOTPRINT, FD_SBPF_SYSCALLS_ALIGN))
179 :
180 0 : #define FD_RUNTIME_VM_TRACE_EVENT_MAX (128UL<<20)
181 0 : #define FD_RUNTIME_VM_TRACE_EVENT_DATA_MAX (2048UL)
182 0 : #define FD_RUNTIME_VM_TRACE_FOOTPRINT (FD_MAX_INSTRUCTION_STACK_DEPTH*fd_ulong_align_up( fd_vm_trace_footprint( FD_RUNTIME_VM_TRACE_EVENT_MAX, FD_RUNTIME_VM_TRACE_EVENT_DATA_MAX ), fd_vm_trace_align() ))
183 :
184 24 : #define FD_RUNTIME_MISC_FOOTPRINT (FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT)
185 0 : #define FD_SOLFUZZ_MISC_FOOTPRINT (FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT + FD_RUNTIME_VM_TRACE_FOOTPRINT)
186 :
187 : /* Now finally, we bound out the footprint of transaction execution. */
188 : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(account_lock_limit, direct_mapping) \
189 24 : (FD_RUNTIME_BORROWED_ACCOUNT_FOOTPRINT + \
190 24 : FD_RUNTIME_INPUT_REGION_TXN_FOOTPRINT(account_lock_limit, direct_mapping) + \
191 24 : FD_RUNTIME_BINCODE_AND_NATIVE_FOOTPRINT + \
192 24 : FD_RUNTIME_MISC_FOOTPRINT)
193 :
194 : /* Convenience macros for common use cases.
195 :
196 : TODO: If account lock limits are increased to 128, this macro will need to be updated. */
197 0 : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_FUZZ FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(64UL, 0) + FD_SOLFUZZ_MISC_FOOTPRINT
198 24 : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_DEFAULT FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(64UL, 0)
199 :
200 : /* Helpers for runtime public frame management. */
201 :
202 : /* Helpers for runtime spad frame management. */
203 : struct fd_runtime_spad_verify_handle_private {
204 : fd_spad_t * spad;
205 : fd_exec_txn_ctx_t * txn_ctx;
206 : };
207 : typedef struct fd_runtime_spad_verify_handle_private fd_runtime_spad_verify_handle_private_t;
208 :
209 : static inline void
210 0 : fd_runtime_spad_private_frame_end( fd_runtime_spad_verify_handle_private_t * _spad_handle ) {
211 : /* fd_spad_verify() returns 0 if everything looks good, and non-zero
212 : otherwise.
213 :
214 : Since the fast spad alloc API doesn't check for or indicate an OOM
215 : situation and is going to happily permit an OOB alloc, we need
216 : some way of detecting that. Moreover, we would also like to detect
217 : unbalanced frame push/pop or usage of more frames than allowed.
218 : While surrounding the spad with guard regions will help detect the
219 : former, it won't necessarily catch the latter.
220 :
221 : On compliant transactions, fd_spad_verify() isn't all that
222 : expensive. Nonetheless, We invoke fd_spad_verify() only at the
223 : peak of memory usage, and not gratuitously everywhere. One peak
224 : would be right before we do the most deeply nested spad frame pop.
225 : However, we do pops through compiler-inserted cleanup functions
226 : that take only a single pointer, so we define this helper function
227 : to access the needed context info. The end result is that we do
228 : super fast spad calls everywhere in the runtime, and every now and
229 : then we invoke verify to check things. */
230 : /* -1UL because spad pop is called after instr stack pop. */
231 0 : if( FD_UNLIKELY( _spad_handle->txn_ctx->instr_stack_sz>=FD_MAX_INSTRUCTION_STACK_DEPTH-1UL && fd_spad_verify( _spad_handle->txn_ctx->spad ) ) ) {
232 0 : uchar const * txn_signature = (uchar const *)fd_txn_get_signatures( TXN( &_spad_handle->txn_ctx->txn ), _spad_handle->txn_ctx->txn.payload );
233 0 : FD_BASE58_ENCODE_64_BYTES( txn_signature, sig );
234 0 : FD_LOG_ERR(( "spad corrupted or overflown on transaction %s", sig ));
235 0 : }
236 0 : fd_spad_pop( _spad_handle->spad );
237 0 : }
238 :
239 0 : #define FD_RUNTIME_TXN_SPAD_FRAME_BEGIN(_spad, _txn_ctx) do { \
240 0 : fd_runtime_spad_verify_handle_private_t _spad_handle __attribute__((cleanup(fd_runtime_spad_private_frame_end))) = \
241 0 : (fd_runtime_spad_verify_handle_private_t) { .spad = _spad, .txn_ctx = _txn_ctx }; \
242 0 : fd_spad_push( _spad_handle.spad ); \
243 0 : do
244 :
245 0 : #define FD_RUNTIME_TXN_SPAD_FRAME_END while(0); } while(0)
246 :
247 : FD_PROTOTYPES_BEGIN
248 :
249 : /* Runtime Helpers ************************************************************/
250 :
251 : /*
252 : Returns 0 on success, and non zero otherwise. On failure, the
253 : out values will not be modified.
254 : */
255 : int
256 : fd_runtime_compute_max_tick_height( ulong ticks_per_slot,
257 : ulong slot,
258 : ulong * out_max_tick_height /* out */ );
259 :
260 : void
261 : fd_runtime_update_leaders( fd_bank_t * bank,
262 : fd_spad_t * runtime_spad );
263 :
264 : /* TODO: Invoked by fd_executor: layering violation. Rent logic is deprecated
265 : and will be torn out entirely very soon. */
266 : ulong
267 : fd_runtime_collect_rent_from_account( fd_epoch_schedule_t const * schedule,
268 : fd_rent_t const * rent,
269 : double slots_per_year,
270 : fd_txn_account_t * acc,
271 : ulong epoch );
272 :
273 : void
274 : fd_runtime_update_slots_per_epoch( fd_bank_t * bank,
275 : ulong slots_per_epoch );
276 :
277 : /* Block Level Execution Prep/Finalize ****************************************/
278 :
279 : #define FD_BLOCK_OK (0UL)
280 : #define FD_BLOCK_ERR_INCOMPLETE (1UL)
281 : #define FD_BLOCK_ERR_INVALID_ENTRY_HASH (2UL)
282 : #define FD_BLOCK_ERR_INVALID_LAST_TICK (3UL)
283 : #define FD_BLOCK_ERR_TOO_FEW_TICKS (4UL)
284 : #define FD_BLOCK_ERR_TOO_MANY_TICKS (5UL)
285 : #define FD_BLOCK_ERR_INVALID_TICK_HASH_COUNT (6UL)
286 : #define FD_BLOCK_ERR_TRAILING_ENTRY (7UL)
287 : #define FD_BLOCK_ERR_DUPLICATE_BLOCK (8UL)
288 :
289 : /*
290 : https://github.com/anza-xyz/agave/blob/v2.1.0/ledger/src/blockstore_processor.rs#L1096
291 : This function assumes a full block.
292 : This needs to be called after epoch processing to get the up to date
293 : hashes_per_tick.
294 :
295 : Provide scratch memory >= the max size of a batch to use. This is because we can only
296 : assemble shreds by batch, so we iterate and assemble shreds by batch in this function
297 : without needing the caller to do so.
298 : */
299 : // FD_FN_UNUSED ulong /* FIXME */
300 : // fd_runtime_block_verify_ticks( fd_blockstore_t * blockstore,
301 : // ulong slot,
302 : // uchar * block_data_mem,
303 : // ulong block_data_sz,
304 : // ulong tick_height,
305 : // ulong max_tick_height,
306 : // ulong hashes_per_tick );
307 :
308 : /* The following microblock-level functions are exposed and non-static due to also being used for fd_replay.
309 : The block-level equivalent functions, on the other hand, are mostly static as they are only used
310 : for offline replay */
311 :
312 : /* extra fine-grained streaming tick verification */
313 : // FD_FN_UNUSED int /* FIXME */
314 : // fd_runtime_microblock_verify_ticks( fd_blockstore_t * blockstore,
315 : // ulong slot,
316 : // fd_microblock_hdr_t const * hdr,
317 : // bool slot_complete,
318 : // ulong tick_height,
319 : // ulong max_tick_height,
320 : // ulong hashes_per_tick );
321 :
322 : /*
323 : fd_runtime_microblock_verify_read_write_conflicts verifies that a
324 : list of txns (e.g., those in a microblock) do not have read-write
325 : or write-write conflits. FD_TXN_CONFLICT_MAP_MAX_NACCT defines a
326 : conservative estimation of the number of accounts touched by txns
327 : in one slot. Given the conservative estimation, the footprint of
328 : the account map (fd_conflict_detect_map) is about 2112MB. One can
329 : certainly use a better estimation leading to a smaller footprint.
330 :
331 : this function corresponds to try_lock_accounts in Agave which
332 : detects transaction conflicts:
333 : https://github.com/anza-xyz/agave/blob/v2.2.3/runtime/src/bank.rs
334 : #L3145
335 :
336 : Specifically, from the replay stage of Agave, the control flow is
337 : (1) replay_blockstore_into_bank: https://github.com/anza-xyz/agave/
338 : blob/v2.2.3/core/src/replay_stage.rs#L2232
339 : (2) confirm_slot: https://github.com/anza-xyz/agave/blob/v2.2.3/
340 : ledger/src/blockstore_processor.rs#L1561
341 : (3) confirm_slot_entries: https://github.com/anza-xyz/agave/blob/
342 : v2.2.3/ledger/src/blockstore_processor.rs#L1609
343 : (4) process_entries: https://github.com/anza-xyz/agave/blob/v2.2.3/
344 : ledger/src/blockstore_processor.rs#L704
345 : (5) queue_batches_with_lock_retry: https://github.com/anza-xyz/agave/
346 : blob/v2.2.3/ledger/src/blockstore_processor.rs#L789
347 : (6) bank.try_lock_accounts is called in queue_batches_with_lock_retry
348 : (7) this try_lock_accounts eventually calls another try_lock_accounts,
349 : (see https://github.com/anza-xyz/agave/blob/v2.2.3/accounts-db/src
350 : /account_locks.rs#L24), which acquires the locks and returns
351 : TransactionError::AccountInUse if r-w or w-w conflict is detected
352 : (8) when calling try_lock_accounts, function accounts_with_is_writable
353 : is used to decide whether an account is writable (see https://github.
354 : com/anza-xyz/agave/blob/v2.2.3/accounts-db/src/accounts.rs#L605) which
355 : internally calls the is_writable function depending on whether the txn
356 : is legacy or V0:
357 :
358 : is_writable for legacy: https://github.com/anza-xyz/solana-sdk/blob/
359 : message%40v2.2.1/message/src/sanitized.rs#L75
360 :
361 : is_writable for V0: https://github.com/anza-xyz/solana-sdk/blob/
362 : message%40v2.2.1/message/src/versions/v0/loaded.rs#L152
363 :
364 : In both cases, Agave does the following check in addition to whether
365 : an account has been specified as writable in the transaction message
366 : (https://github.com/anza-xyz/solana-sdk/blob/message%40v2.2.1/message
367 : /src/versions/v0/loaded.rs#L146). This additional check is handled by
368 : function fd_txn_account_is_writable_idx_flat in our code.
369 :
370 : txns is an array containing txn_cnt transactions in fd_txn_p_t type;
371 : acct_map is used to detect conflicts and acct_arr is used to clear the
372 : map before the function returns; funk and funk_txn are used to read
373 : Solana accounts for address lookup tables; slot and slot_hashes are
374 : needed for checking certain bounds in the address lookup table system
375 : program; features is needed in fd_txn_account_is_writable_idx_flat to
376 : decide whether a writable account is demoted to read-only.
377 :
378 : If an error occurs in runtime, the function returns the runtime error.
379 : If there's no conflict, the return value is FD_RUNTIME_EXECUTE_SUCCESS
380 : and out_conflict_detected will be 0. If there's a conflict, the return
381 : value is FD_RUNTIME_TXN_ERR_ACCOUNT_IN_USE and out_conflict_detected
382 : will be 1 (read-write) or 2 (write-write), and out_conflict_addr_opt,
383 : if not NULL, will hold the account address causing the conflict.
384 : */
385 : struct fd_conflict_detect_ele {
386 : fd_acct_addr_t key;
387 : uchar writable;
388 : };
389 : typedef struct fd_conflict_detect_ele fd_conflict_detect_ele_t;
390 426 : #define FD_TXN_CONFLICT_MAP_SEED (0UL)
391 : #define FD_TXN_CONFLICT_MAP_MAX_NACCT (FD_SHRED_DATA_PAYLOAD_MAX_PER_SLOT / FD_TXN_MIN_SERIALIZED_SZ * FD_TXN_ACCT_ADDR_MAX)
392 :
393 : static const fd_acct_addr_t fd_acct_addr_null = {.b={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
394 : #define MAP_NAME fd_conflict_detect_map
395 546 : #define MAP_KEY_T fd_acct_addr_t
396 432 : #define MAP_T fd_conflict_detect_ele_t
397 426 : #define MAP_HASH_T ulong
398 3145848 : #define MAP_KEY_NULL (fd_acct_addr_null)
399 306 : #define MAP_KEY_EQUAL(k0,k1) (0==memcmp((k0).b,(k1).b,32))
400 426 : #define MAP_KEY_HASH(key) fd_hash( FD_TXN_CONFLICT_MAP_SEED, key.b, 32 )
401 876 : #define MAP_KEY_INVAL(k) (0==memcmp(&fd_acct_addr_null, (k).b, 32))
402 : #define MAP_KEY_EQUAL_IS_SLOW 0
403 : #define MAP_MEMOIZE 0
404 :
405 : #include "../../util/tmpl/fd_map_dynamic.c"
406 :
407 270 : #define FD_RUNTIME_NO_CONFLICT_DETECTED 0
408 6 : #define FD_RUNTIME_READ_WRITE_CONFLICT_DETECTED 1
409 9 : #define FD_RUNTIME_WRITE_WRITE_CONFLICT_DETECTED 2
410 :
411 : int
412 : fd_runtime_microblock_verify_read_write_conflicts( fd_txn_p_t * txns,
413 : ulong txn_cnt,
414 : fd_conflict_detect_ele_t * acct_map,
415 : fd_acct_addr_t * acct_arr,
416 : fd_funk_t * funk,
417 : fd_funk_txn_xid_t const * xid,
418 : ulong slot,
419 : fd_slot_hash_t * slot_hashes,
420 : fd_features_t * features,
421 : int * out_conflict_detected,
422 : fd_acct_addr_t * out_conflict_addr_opt );
423 :
424 : /* Load the accounts in the address lookup tables of txn into out_accts_alt */
425 : int
426 : fd_runtime_load_txn_address_lookup_tables(
427 : fd_txn_t const * txn,
428 : uchar const * payload,
429 : fd_funk_t * funk,
430 : fd_funk_txn_xid_t const * xid,
431 : ulong slot,
432 : fd_slot_hash_t const * hashes, /* deque */
433 : fd_acct_addr_t * out_accts_alt
434 : );
435 :
436 : int
437 : fd_runtime_block_execute_prepare( fd_bank_t * bank,
438 : fd_funk_t * funk,
439 : fd_funk_txn_xid_t const * xid,
440 : fd_capture_ctx_t * capture_ctx,
441 : fd_spad_t * runtime_spad );
442 :
443 : void
444 : fd_runtime_block_execute_finalize( fd_bank_t * bank,
445 : fd_funk_t * funk,
446 : fd_funk_txn_xid_t const * xid,
447 : fd_capture_ctx_t * capture_ctx,
448 : int silent );
449 :
450 : /* Transaction Level Execution Management *************************************/
451 :
452 : int
453 : fd_runtime_pre_execute_check( fd_exec_txn_ctx_t * txn_ctx );
454 :
455 : /* fd_runtime_prepare_and_execute_txn is the main entrypoint from the
456 : executor tile. It is responsible for preparing and executing a single
457 : transaction. */
458 :
459 : int
460 : fd_runtime_prepare_and_execute_txn( fd_banks_t * banks,
461 : ulong bank_idx,
462 : fd_exec_txn_ctx_t * txn_ctx,
463 : fd_txn_p_t * txn,
464 : fd_spad_t * exec_spad,
465 : fd_capture_ctx_t * capture_ctx );
466 :
467 : void
468 : fd_runtime_finalize_txn( fd_funk_t * funk,
469 : fd_txncache_t * txncache,
470 : fd_funk_txn_xid_t const * xid,
471 : fd_exec_txn_ctx_t * txn_ctx,
472 : fd_bank_t * bank,
473 : fd_capture_ctx_t * capture_ctx );
474 :
475 : /* Epoch Boundary *************************************************************/
476 :
477 : /*
478 : This is roughly Agave's process_new_epoch() which gets called from
479 : new_from_parent() for every slot.
480 : https://github.com/anza-xyz/agave/blob/v1.18.26/runtime/src/bank.rs#L1483
481 : This needs to be called after funk_txn_prepare() because the accounts
482 : that we modify when processing a new epoch need to be hashed into
483 : the bank hash.
484 : */
485 : void
486 : fd_runtime_block_pre_execute_process_new_epoch( fd_banks_t * banks,
487 : fd_bank_t * bank,
488 : fd_funk_t * funk,
489 : fd_funk_txn_xid_t const * xid,
490 : fd_capture_ctx_t * capture_ctx,
491 : fd_spad_t * runtime_spad,
492 : int * is_epoch_boundary );
493 :
494 : /* `fd_runtime_update_program_cache()` is responsible for updating the
495 : program cache with any programs referenced in the current
496 : transaction. See fd_program_cache.h for more details.
497 :
498 : Note that ALUTs must be resolved because programs referenced in ALUTs
499 : can be invoked via CPI.
500 :
501 : TODO: We need to remove the ALUT resolution from this function
502 : because it is redundant (ALUTs get resolved again in the exec tile). */
503 : void
504 : fd_runtime_update_program_cache( fd_bank_t * bank,
505 : fd_funk_t * funk,
506 : fd_funk_txn_xid_t const * xid,
507 : fd_txn_p_t const * txn_p,
508 : fd_spad_t * runtime_spad );
509 :
510 : /* Offline Replay *************************************************************/
511 :
512 : void
513 : fd_runtime_read_genesis( fd_banks_t * banks,
514 : fd_bank_t * bank,
515 : fd_funk_t * funk,
516 : fd_funk_txn_xid_t const * xid,
517 : fd_capture_ctx_t * capture_ctx,
518 : fd_hash_t const * genesis_hash,
519 : fd_lthash_value_t const * genesis_lthash,
520 : fd_genesis_solana_global_t const * genesis_block,
521 : fd_spad_t * runtime_spad );
522 :
523 :
524 : /* Returns whether the specified epoch should use the new vote account
525 : keyed leader schedule (returns 1) or the old validator identity keyed
526 : leader schedule (returns 0). See SIMD-0180.
527 : This is the analogous of Agave's Bank::should_use_vote_keyed_leader_schedule():
528 : https://github.com/anza-xyz/agave/blob/v2.3.1/runtime/src/bank.rs#L6148 */
529 : int
530 : fd_runtime_should_use_vote_keyed_leader_schedule( fd_bank_t * bank );
531 :
532 : FD_PROTOTYPES_END
533 :
534 : #endif /* HEADER_fd_src_flamenco_runtime_fd_runtime_h */
|