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