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 : #include "program/fd_bpf_loader_program.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 0 : #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 : /* https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/ebpf.rs#L37-L38 */
86 : #define FD_RUNTIME_EBPF_HOST_ALIGN (16UL)
87 :
88 : /******** These macros bound out memory footprint ********/
89 :
90 : /* The tight upper bound on borrowed account footprint over the
91 : execution of a single transaction. */
92 : #define FD_RUNTIME_BORROWED_ACCOUNT_FOOTPRINT (MAX_TX_ACCOUNT_LOCKS * FD_ULONG_ALIGN_UP( FD_ACC_TOT_SZ_MAX, FD_ACCOUNT_REC_ALIGN ))
93 :
94 : /* The bpf loader's serialization footprint is bounded in the worst case
95 : by 64 unique writable accounts which are each 10MiB in size (bounded
96 : by the amount of transaction accounts). We can also have up to
97 : FD_INSTR_ACCT_MAX (256) referenced accounts in an instruction.
98 :
99 : - 8 bytes for the account count
100 : For each account:
101 : If duplicated:
102 : - 8 bytes for each duplicated account
103 : If not duplicated:
104 : - header for each unique account (96 bytes)
105 : - 1 account idx byte
106 : - 1 is_signer byte
107 : - 1 is_writable byte
108 : - 1 executable byte
109 : - 4 bytes for the original data length
110 : - 32 bytes for the key
111 : - 32 bytes for the owner
112 : - 8 bytes for the lamports
113 : - 8 bytes for the data length
114 : - 8 bytes for the rent epoch
115 : - 10MiB for the data (10485760 bytes)
116 : - 10240 bytes for resizing the data
117 : - 0 padding bytes because this is already 8 byte aligned
118 : - 8 bytes for instruction data length
119 : - 1232 bytes for the instruction data (TXN_MTU)
120 : - 32 bytes for the program id
121 :
122 : So the total footprint is:
123 : 8 header bytes +
124 : 192 duplicate accounts (256 instr accounts - 64 unique accounts) * 8 bytes = 1536 duplicate account bytes +
125 : 64 unique accounts * (96 header bytes + 10485760 bytes + 10240 resizing bytes) = 671750144 unique account bytes +
126 : 8 + 1232 + 32 = 1272 bytes trailer bytes + program id = 671751416 bytes
127 : Total footprint: 671752960 bytes
128 :
129 : This is a reasonably tight-ish upper bound on the input region
130 : footprint for a single instruction at a single stack depth. In
131 : reality the footprint would be slightly smaller because the
132 : instruction data can't be equal to the transaction MTU.
133 : */
134 : #define FD_BPF_LOADER_UNIQUE_ACCOUNT_FOOTPRINT(direct_mapping) \
135 : (1UL /* dup byte */ + \
136 : sizeof(uchar) /* is_signer */ + \
137 : sizeof(uchar) /* is_writable */ + \
138 : sizeof(uchar) /* executable */ + \
139 : sizeof(uint) /* original_data_len */ + \
140 : sizeof(fd_pubkey_t) /* key */ + \
141 : sizeof(fd_pubkey_t) /* owner */ + \
142 : sizeof(ulong) /* lamports */ + \
143 : sizeof(ulong) /* data len */ + \
144 : (direct_mapping ? FD_BPF_ALIGN_OF_U128 : FD_ULONG_ALIGN_UP( FD_RUNTIME_ACC_SZ_MAX, FD_BPF_ALIGN_OF_U128 )) + \
145 : MAX_PERMITTED_DATA_INCREASE + \
146 : sizeof(ulong)) /* rent_epoch */
147 : #define FD_BPF_LOADER_DUPLICATE_ACCOUNT_FOOTPRINT (8UL) /* 1 dup byte + 7 bytes for padding */
148 :
149 : #define FD_BPF_LOADER_INPUT_REGION_FOOTPRINT(account_lock_limit, direct_mapping) \
150 : (FD_ULONG_ALIGN_UP( (sizeof(ulong) /* acct_cnt */ + \
151 : account_lock_limit*FD_BPF_LOADER_UNIQUE_ACCOUNT_FOOTPRINT(direct_mapping) + \
152 : (FD_INSTR_ACCT_MAX-account_lock_limit)*FD_BPF_LOADER_DUPLICATE_ACCOUNT_FOOTPRINT + \
153 : sizeof(ulong) /* instr data len */ + \
154 : FD_TXN_MTU /* No instr data */ + \
155 : sizeof(fd_pubkey_t)), /* program id */ \
156 : FD_RUNTIME_EBPF_HOST_ALIGN ))
157 :
158 :
159 :
160 : #define BPF_LOADER_SERIALIZATION_FOOTPRINT (671752960UL)
161 : FD_STATIC_ASSERT( BPF_LOADER_SERIALIZATION_FOOTPRINT==FD_BPF_LOADER_INPUT_REGION_FOOTPRINT(64UL, 0), bpf_loader_serialization_footprint );
162 :
163 : /* Bincode alloc footprint over the execution of a single transaction.
164 : As well as other footprint specific to each native program type.
165 :
166 : N.B. We know that bincode alloc footprint is bounded, because
167 : whenever we alloc something, we advance our pointer into the binary
168 : buffer, so eventually we are gonna reach the end of the buffer.
169 : This buffer is usually backed by and ultimately bounded in size by
170 : either accounts data or the transaction MTU.
171 :
172 : That being said, it's not obvious what the tight upper bound would
173 : be for allocations across all possible execution paths of all native
174 : programs, including possible CPIs from native programs. The
175 : footprint estimate here is based on a manual review of our native
176 : program implementation. Note that even if the possible paths remain
177 : steady at the Solana protocol level, the footprint is subject to
178 : change when we change our implementation.
179 :
180 : ### Native programs
181 : ALUT (migrated to BPF)
182 : Loader
183 : - rodata for bpf program relocation and validation
184 : Compute budget (0 allocations)
185 : Config (migrated to BPF)
186 : Precompile (0 allocations)
187 : Stake
188 : - The instruction with the largest footprint is deactivate_delinquent
189 : - During instruction decode, no allocations
190 : - 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
191 : System
192 : - system_program_instruction_decode seed
193 : Vote
194 : - The instruction with the largest footprint is compact vote state update
195 : - During instruction decode, this is 9*lockouts_len bytes, MTU bounded
196 : - 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)
197 : Zk Elgamal (0 allocations)
198 :
199 : The largest footprint is hence deactivate_delinquent, in which the
200 : two get_state() calls dominate the footprint. In particular, the
201 : authorized_voters treaps bloat 40 bytes (epoch+pubkey) in a vote
202 : account to 72 bytes (sizeof(fd_vote_authorized_voter_t)) in memory.
203 : */
204 : #define FD_RUNTIME_BINCODE_AND_NATIVE_FOOTPRINT (2UL*FD_RUNTIME_ACC_SZ_MAX*72UL/40UL)
205 :
206 : /* Misc other footprint. */
207 : #define FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT (FD_MAX_INSTRUCTION_STACK_DEPTH*FD_ULONG_ALIGN_UP(FD_SBPF_SYSCALLS_FOOTPRINT, FD_SBPF_SYSCALLS_ALIGN))
208 :
209 0 : #define FD_RUNTIME_VM_TRACE_EVENT_MAX (128UL<<20)
210 0 : #define FD_RUNTIME_VM_TRACE_EVENT_DATA_MAX (2048UL)
211 : #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() ))
212 :
213 0 : #define FD_RUNTIME_VM_TRACE_STATIC_FOOTPRINT (FD_RUNTIME_VM_TRACE_EVENT_MAX + sizeof(fd_vm_trace_t))
214 0 : #define FD_RUNTIME_VM_TRACE_STATIC_ALIGN (8UL)
215 :
216 : #define FD_RUNTIME_MISC_FOOTPRINT (FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT)
217 : #define FD_SOLFUZZ_MISC_FOOTPRINT (FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT + FD_RUNTIME_VM_TRACE_FOOTPRINT)
218 :
219 : /* Now finally, we bound out the footprint of transaction execution. */
220 : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(account_lock_limit, direct_mapping) \
221 : (FD_RUNTIME_BORROWED_ACCOUNT_FOOTPRINT + \
222 : FD_RUNTIME_INPUT_REGION_TXN_FOOTPRINT(account_lock_limit, direct_mapping) + \
223 : FD_RUNTIME_BINCODE_AND_NATIVE_FOOTPRINT + \
224 : FD_RUNTIME_MISC_FOOTPRINT)
225 :
226 : /* Convenience macros for common use cases.
227 :
228 : TODO: If account lock limits are increased to 128, this macro will need to be updated. */
229 : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_FUZZ FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(64UL, 0) + FD_SOLFUZZ_MISC_FOOTPRINT
230 : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_DEFAULT FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(64UL, 0)
231 :
232 : FD_PROTOTYPES_BEGIN
233 :
234 : /* Runtime Helpers ************************************************************/
235 :
236 : /*
237 : Returns 0 on success, and non zero otherwise. On failure, the
238 : out values will not be modified.
239 : */
240 : int
241 : fd_runtime_compute_max_tick_height( ulong ticks_per_slot,
242 : ulong slot,
243 : ulong * out_max_tick_height /* out */ );
244 :
245 : void
246 : fd_runtime_update_leaders( fd_bank_t * bank,
247 : fd_runtime_stack_t * runtime_stack );
248 :
249 : /* Block Level Execution Prep/Finalize ****************************************/
250 :
251 : #define FD_BLOCK_OK (0UL)
252 : #define FD_BLOCK_ERR_INCOMPLETE (1UL)
253 : #define FD_BLOCK_ERR_INVALID_ENTRY_HASH (2UL)
254 : #define FD_BLOCK_ERR_INVALID_LAST_TICK (3UL)
255 : #define FD_BLOCK_ERR_TOO_FEW_TICKS (4UL)
256 : #define FD_BLOCK_ERR_TOO_MANY_TICKS (5UL)
257 : #define FD_BLOCK_ERR_INVALID_TICK_HASH_COUNT (6UL)
258 : #define FD_BLOCK_ERR_TRAILING_ENTRY (7UL)
259 : #define FD_BLOCK_ERR_DUPLICATE_BLOCK (8UL)
260 :
261 : /* Load the accounts in the address lookup tables of txn into out_accts_alt */
262 : int
263 : fd_runtime_load_txn_address_lookup_tables(
264 : fd_txn_t const * txn,
265 : uchar const * payload,
266 : fd_funk_t * funk,
267 : fd_funk_txn_xid_t const * xid,
268 : ulong slot,
269 : fd_slot_hash_t const * hashes, /* deque */
270 : fd_acct_addr_t * out_accts_alt
271 : );
272 :
273 : int
274 : fd_runtime_block_execute_prepare( fd_bank_t * bank,
275 : fd_accdb_user_t * accdb,
276 : fd_funk_txn_xid_t const * xid,
277 : fd_runtime_stack_t * runtime_stack,
278 : fd_capture_ctx_t * capture_ctx );
279 :
280 : void
281 : fd_runtime_block_execute_finalize( fd_bank_t * bank,
282 : fd_accdb_user_t * accdb,
283 : fd_funk_txn_xid_t const * xid,
284 : fd_capture_ctx_t * capture_ctx,
285 : int silent );
286 :
287 : /* Transaction Level Execution Management *************************************/
288 :
289 : int
290 : fd_runtime_pre_execute_check( fd_exec_txn_ctx_t * txn_ctx );
291 :
292 : /* fd_runtime_prepare_and_execute_txn is the main entrypoint from the
293 : executor tile. It is responsible for preparing and executing a single
294 : transaction. */
295 :
296 : int
297 : fd_runtime_prepare_and_execute_txn( fd_banks_t * banks,
298 : ulong bank_idx,
299 : fd_exec_txn_ctx_t * txn_ctx,
300 : fd_txn_p_t * txn,
301 : fd_capture_ctx_t * capture_ctx,
302 : fd_exec_stack_t * exec_stack,
303 : fd_exec_accounts_t * exec_accounts,
304 : uchar * dumping_mem,
305 : uchar * tracing_mem );
306 :
307 : void
308 : fd_runtime_finalize_txn( fd_funk_t * funk,
309 : fd_progcache_t * progcache,
310 : fd_txncache_t * txncache,
311 : fd_funk_txn_xid_t const * xid,
312 : fd_exec_txn_ctx_t * txn_ctx,
313 : fd_bank_t * bank,
314 : fd_capture_ctx_t * capture_ctx,
315 : ulong * tips_out_opt );
316 :
317 : /* Epoch Boundary *************************************************************/
318 :
319 : /* This is roughly Agave's process_new_epoch() which gets called from
320 : new_from_parent() for every slot.
321 : https://github.com/anza-xyz/agave/blob/v1.18.26/runtime/src/bank.rs#L1483
322 : Account changes done by this function are counted towards the first
323 : slot of the new epoch (NOT the last slot of the old epoch). */
324 : void
325 : fd_runtime_block_pre_execute_process_new_epoch( fd_banks_t * banks,
326 : fd_bank_t * bank,
327 : fd_accdb_user_t * accdb,
328 : fd_funk_txn_xid_t const * xid,
329 : fd_capture_ctx_t * capture_ctx,
330 : fd_runtime_stack_t * runtime_stack,
331 : int * is_epoch_boundary );
332 :
333 : /* Offline Replay *************************************************************/
334 :
335 : void
336 : fd_runtime_read_genesis( fd_banks_t * banks,
337 : fd_bank_t * bank,
338 : fd_accdb_user_t * accdb,
339 : fd_funk_txn_xid_t const * xid,
340 : fd_capture_ctx_t * capture_ctx,
341 : fd_hash_t const * genesis_hash,
342 : fd_lthash_value_t const * genesis_lthash,
343 : fd_genesis_solana_global_t const * genesis_block,
344 : fd_runtime_stack_t * runtime_stack );
345 :
346 :
347 : /* Returns whether the specified epoch should use the new vote account
348 : keyed leader schedule (returns 1) or the old validator identity keyed
349 : leader schedule (returns 0). See SIMD-0180.
350 : This is the analogous of Agave's Bank::should_use_vote_keyed_leader_schedule():
351 : https://github.com/anza-xyz/agave/blob/v2.3.1/runtime/src/bank.rs#L6148 */
352 : int
353 : fd_runtime_should_use_vote_keyed_leader_schedule( fd_bank_t * bank );
354 :
355 : FD_PROTOTYPES_END
356 :
357 : #endif /* HEADER_fd_src_flamenco_runtime_fd_runtime_h */
|