Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_vm_fd_vm_base_h
2 : #define HEADER_fd_src_flamenco_vm_fd_vm_base_h
3 :
4 : /* FIXME: Headers included from other modules need cleanup. As it
5 : stands, flamenco_base brings in types/custom, types/meta,
6 : types/bincode, ballet/base58, ballet/sha256, ballet/sha512,
7 : ballet/ed25519, ballet/txnthis also brings in util, flamenco_base,
8 : ballet/base58, util and the optional util/net/ipv4 ballet/sha256,
9 : most of which is probably not necessary to use this module in a
10 : somewhat haphazard fashion (include no-no things that are only
11 : available in hosted environments like stdio and stdlib) */
12 :
13 : #include "../fd_flamenco_base.h"
14 : #include "../../ballet/sbpf/fd_sbpf_loader.h" /* FIXME: functionality needed from here probably should be moved here */
15 : #include "../features/fd_features.h"
16 :
17 : /* Defines the different VM access types */
18 165 : #define FD_VM_ACCESS_TYPE_LD (1)
19 90 : #define FD_VM_ACCESS_TYPE_ST (2)
20 :
21 : /* FD_VM_SUCCESS is zero and returned to indicate that an operation
22 : completed successfully. FD_VM_ERR_* are negative integers and
23 : returned to indicate an operation that failed and why. */
24 :
25 : /* "Standard" Firedancer error codes (FIXME: harmonize and consolidate) */
26 :
27 56253606 : #define FD_VM_SUCCESS ( 0) /* success */
28 1891752 : #define FD_VM_ERR_INVAL (-1) /* invalid request */
29 3 : #define FD_VM_ERR_UNSUP (-3) /* unsupported request */
30 6 : #define FD_VM_ERR_FULL (-5) /* storage full */
31 3 : #define FD_VM_ERR_EMPTY (-6) /* nothing to do */
32 3 : #define FD_VM_ERR_IO (-7) /* input-output error */
33 :
34 : /* VM exec error codes: These are only produced by the VM itself. */
35 :
36 60 : #define FD_VM_ERR_SIGFPE (-18) /* divide by zero */
37 :
38 : /* sBPF validation error codes. These are only produced by
39 : fd_vm_validate. FIXME: Consider having fd_vm_validate return
40 : standard error codes and then provide detail like this through an
41 : info arg. FIXME: Are these exact matches to Solana? If so, provide
42 : link, if not, document and refine name / consolidate further. */
43 :
44 1185 : #define FD_VM_ERR_INVALID_OPCODE (-25) /* detected an invalid opcode */
45 471 : #define FD_VM_ERR_INVALID_SRC_REG (-26) /* detected an invalid source register */
46 675 : #define FD_VM_ERR_INVALID_DST_REG (-27) /* detected an invalid destination register */
47 150 : #define FD_VM_ERR_JMP_OUT_OF_BOUNDS (-29) /* detected an out of bounds jump */
48 3 : #define FD_VM_ERR_JMP_TO_ADDL_IMM (-30) /* detected a jump to an addl imm */
49 21 : #define FD_VM_ERR_INVALID_END_IMM (-31) /* detected an invalid immediate for an endianness conversion instruction */
50 3 : #define FD_VM_ERR_INCOMPLETE_LDQ (-32) /* detected an incomplete ldq at program end */
51 3 : #define FD_VM_ERR_LDQ_NO_ADDL_IMM (-33) /* detected a ldq without an addl imm following it */
52 21 : #define FD_VM_ERR_INVALID_REG (-35) /* detected an invalid register */
53 0 : #define FD_VM_ERR_BAD_TEXT (-36) /* detected a bad text section (overflow, outside rodata boundary, etc.,)*/
54 198 : #define FD_VM_SH_OVERFLOW (-37) /* detected a shift overflow, equivalent to VeriferError::ShiftWithOverflow */
55 0 : #define FD_VM_TEXT_SZ_UNALIGNED (-38) /* detected a text section that is not a multiple of 8 */
56 : #define FD_VM_INVALID_FUNCTION (-39) /* detected an invalid function */
57 : #define FD_VM_INVALID_SYSCALL (-40) /* detected an invalid syscall */
58 :
59 : /* Syscall Errors
60 : https://github.com/anza-xyz/agave/blob/v2.0.7/programs/bpf_loader/src/syscalls/mod.rs#L81 */
61 :
62 0 : #define FD_VM_SYSCALL_ERR_INVALID_STRING (-1)
63 0 : #define FD_VM_SYSCALL_ERR_ABORT (-2)
64 0 : #define FD_VM_SYSCALL_ERR_PANIC (-3)
65 0 : #define FD_VM_SYSCALL_ERR_INVOKE_CONTEXT_BORROW_FAILED (-4)
66 0 : #define FD_VM_SYSCALL_ERR_MALFORMED_SIGNER_SEED (-5)
67 0 : #define FD_VM_SYSCALL_ERR_BAD_SEEDS (-6)
68 0 : #define FD_VM_SYSCALL_ERR_PROGRAM_NOT_SUPPORTED (-7)
69 0 : #define FD_VM_SYSCALL_ERR_UNALIGNED_POINTER (-8)
70 0 : #define FD_VM_SYSCALL_ERR_TOO_MANY_SIGNERS (-9)
71 0 : #define FD_VM_SYSCALL_ERR_INSTRUCTION_TOO_LARGE (-10)
72 0 : #define FD_VM_SYSCALL_ERR_TOO_MANY_ACCOUNTS (-11)
73 36 : #define FD_VM_SYSCALL_ERR_COPY_OVERLAPPING (-12)
74 0 : #define FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE (-13)
75 0 : #define FD_VM_SYSCALL_ERR_TOO_MANY_SLICES (-14)
76 3 : #define FD_VM_SYSCALL_ERR_INVALID_LENGTH (-15)
77 0 : #define FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_DATA_LEN_EXCEEDED (-16)
78 0 : #define FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_ACCOUNTS_EXCEEDED (-17)
79 24 : #define FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_ACCOUNT_INFOS_EXCEEDED (-18)
80 3 : #define FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE (-19)
81 0 : #define FD_VM_SYSCALL_ERR_INVALID_POINTER (-20)
82 0 : #define FD_VM_SYSCALL_ERR_ARITHMETIC_OVERFLOW (-21)
83 :
84 : /* These syscall errors are unique to Firedancer and do not have an Agave equivalent. */
85 0 : #define FD_VM_SYSCALL_ERR_INSTR_ERR (-22)
86 0 : #define FD_VM_SYSCALL_ERR_INVALID_PDA (-23) /* the computed pda was not a valid ed25519 point */
87 0 : #define FD_VM_SYSCALL_ERR_COMPUTE_BUDGET_EXCEEDED (-24) /* compute unit limit exceeded in syscall */
88 102 : #define FD_VM_SYSCALL_ERR_SEGFAULT (-25) /* illegal memory address (e.g. read/write to an address not backed by any memory) in syscall */
89 0 : #define FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME (-26) /* syscall called with vm not running in solana runtime */
90 :
91 : /* Poseidon returns custom errors for some reason */
92 0 : #define FD_VM_SYSCALL_ERR_POSEIDON_INVALID_PARAMS (1)
93 0 : #define FD_VM_SYSCALL_ERR_POSEIDON_INVALID_ENDIANNESS (2)
94 :
95 : /* EbpfError
96 : https://github.com/solana-labs/rbpf/blob/v0.8.5/src/error.rs#L17 */
97 :
98 0 : #define FD_VM_ERR_EBPF_ELF_ERROR (-1)
99 0 : #define FD_VM_ERR_EBPF_FUNCTION_ALREADY_REGISTERED (-2)
100 3 : #define FD_VM_ERR_EBPF_CALL_DEPTH_EXCEEDED (-3)
101 0 : #define FD_VM_ERR_EBPF_EXIT_ROOT_CALL_FRAME (-4)
102 138 : #define FD_VM_ERR_EBPF_DIVIDE_BY_ZERO (-5)
103 36 : #define FD_VM_ERR_EBPF_DIVIDE_OVERFLOW (-6)
104 87 : #define FD_VM_ERR_EBPF_EXECUTION_OVERRUN (-7)
105 42 : #define FD_VM_ERR_EBPF_CALL_OUTSIDE_TEXT_SEGMENT (-8)
106 801 : #define FD_VM_ERR_EBPF_EXCEEDED_MAX_INSTRUCTIONS (-9)
107 0 : #define FD_VM_ERR_EBPF_JIT_NOT_COMPILED (-10)
108 0 : #define FD_VM_ERR_EBPF_INVALID_VIRTUAL_ADDRESS (-11)
109 0 : #define FD_VM_ERR_EBPF_INVALID_MEMORY_REGION (-12)
110 255 : #define FD_VM_ERR_EBPF_ACCESS_VIOLATION (-13)
111 0 : #define FD_VM_ERR_EBPF_STACK_ACCESS_VIOLATION (-14)
112 18 : #define FD_VM_ERR_EBPF_INVALID_INSTRUCTION (-15)
113 1203 : #define FD_VM_ERR_EBPF_UNSUPPORTED_INSTRUCTION (-16)
114 0 : #define FD_VM_ERR_EBPF_EXHAUSTED_TEXT_SEGMENT (-17)
115 0 : #define FD_VM_ERR_EBPF_LIBC_INVOCATION_FAILED (-18)
116 0 : #define FD_VM_ERR_EBPF_VERIFIER_ERROR (-19)
117 0 : #define FD_VM_ERR_EBPF_SYSCALL_ERROR (-20)
118 :
119 :
120 : FD_PROTOTYPES_BEGIN
121 :
122 : /* fd_vm_strerror converts an FD_VM_SUCCESS / FD_VM_ERR_* code into
123 : a human readable cstr. The lifetime of the returned pointer is
124 : infinite. The returned pointer is always to a non-NULL cstr. */
125 :
126 : FD_FN_CONST char const * fd_vm_strerror( int err );
127 :
128 : FD_PROTOTYPES_END
129 :
130 : /* fd_vm_limits API ***************************************************/
131 :
132 : /* FIXME: pretty good case these actually belong in ballet/sbpf */
133 : /* FIXME: DOCUMENT THESE / LINK TO SOLANA CODE / ETC */
134 :
135 : /* VM register constants */
136 :
137 330 : #define FD_VM_REG_CNT (11UL)
138 9060 : #define FD_VM_REG_MAX (16UL) /* Actual number of SBPF instruction src/dst register indices */
139 :
140 : #define FD_VM_SHADOW_REG_CNT (4UL)
141 :
142 : /* VM stack constants */
143 :
144 32184 : #define FD_VM_STACK_FRAME_MAX (64UL)
145 28317 : #define FD_VM_STACK_FRAME_SZ FD_VM_STACK_FRAME_SIZE
146 : #define FD_VM_STACK_GUARD_SZ (0x1000UL)
147 23337 : #define FD_VM_STACK_MAX (FD_VM_STACK_FRAME_MAX*(FD_VM_STACK_FRAME_SZ))
148 :
149 : /* VM heap constants */
150 :
151 654 : #define FD_VM_HEAP_DEFAULT ( 32UL*1024UL) /* FIXME: SHOULD THIS MATCH FD_VM_HEAP_SIZE LIMIT BELOW? */
152 0 : #define FD_VM_HEAP_MAX (256UL*1024UL)
153 :
154 : /* VM log constants */
155 :
156 27 : #define FD_VM_LOG_MAX (10000UL)
157 : #define FD_VM_LOG_TAIL (128UL) /* Large enough to cover the worst case syscall log tail clobbering in string parsing */
158 :
159 : /* VM memory map constants
160 :
161 : The sBPF virtual address space is divided into 4 GiB regions:
162 :
163 : SBPF V0-V2:
164 : region 0 0x000000000 (unmapped)
165 : region 1 0x100000000 program (full ELF: rodata + text)
166 : region 2 0x200000000 stack
167 : region 3 0x300000000 heap
168 : region 4 0x400000000 input
169 :
170 : SBPF V3:
171 : region 0 0x000000000 rodata segment (read-only)
172 : region 1 0x100000000 (unmapped, bytecode execute-only)
173 : region 2 0x200000000 stack
174 : region 3 0x300000000 heap
175 : region 4 0x400000000 input
176 :
177 : https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/ebpf.rs#L42-L51 */
178 :
179 : #define FD_VM_LO_REGION (0UL)
180 28494 : #define FD_VM_PROG_REGION (1UL)
181 28494 : #define FD_VM_STACK_REGION (2UL)
182 28494 : #define FD_VM_HEAP_REGION (3UL)
183 32112 : #define FD_VM_INPUT_REGION (4UL)
184 3618 : #define FD_VM_HIGH_REGION (5UL)
185 :
186 : #define FD_VM_MEM_MAP_RODATA_REGION_START (0x000000000UL) /* SBPF V3+ only */
187 54 : #define FD_VM_MEM_MAP_PROGRAM_REGION_START (0x100000000UL)
188 9315 : #define FD_VM_MEM_MAP_STACK_REGION_START (0x200000000UL)
189 13545 : #define FD_VM_MEM_MAP_HEAP_REGION_START (0x300000000UL)
190 11121 : #define FD_VM_MEM_MAP_INPUT_REGION_START (0x400000000UL)
191 : #define FD_VM_MEM_MAP_REGION_SZ (0x0FFFFFFFFUL)
192 : #define FD_VM_MEM_MAP_REGION_MASK (~FD_VM_MEM_MAP_REGION_SZ)
193 3618 : #define FD_VM_MEM_MAP_REGION_VIRT_ADDR_BITS (32)
194 :
195 : /* VM compute budget. Note: these names should match exactly the names
196 : used in existing Solana validator. See:
197 : https://github.com/anza-xyz/agave/blob/v1.18.5/program-runtime/src/compute_budget.rs#L19
198 : https://github.com/anza-xyz/agave/blob/v1.18.5/program-runtime/src/compute_budget.rs#L133 */
199 : /* FIXME: DOUBLE CHECK THESE */
200 :
201 : /* FD_VM_COMPUTE_UNIT_LIMIT is the number of compute units that a
202 : transaction or individual instruction is allowed to consume. Compute
203 : units are consumed by program execution, resources they use, etc ... */
204 :
205 480 : #define FD_VM_COMPUTE_UNIT_LIMIT ( 1400000UL)
206 :
207 : /* FD_VM_LOG_64_UNITS is the number of compute units consumed by a
208 : log_64 call */
209 :
210 : #define FD_VM_LOG_64_UNITS ( 100UL)
211 :
212 : /* FD_VM_CREATE_PROGRAM_ADDRESS_UNITS is the number of compute units
213 : consumed by a create_program_address call and a try_find_program_address_call */
214 :
215 : #define FD_VM_CREATE_PROGRAM_ADDRESS_UNITS ( 1500UL)
216 :
217 : /* FD_VM_INVOKE_UNITS is the number of compute units consumed by an
218 : invoke call (not including the cost incurred by the called program)
219 : https://github.com/anza-xyz/agave/blob/v3.1.2/program-runtime/src/execution_budget.rs#L20-L21 */
220 :
221 60 : #define FD_VM_INVOKE_UNITS ( 1000UL)
222 :
223 : /* FD_VM_INVOKE_UNITS_SIMD_0339 is the number of compute units consumed by
224 : an invoke call (not including the cost incurred by the called program)
225 : with SIMD-0339 (increase_cpi_account_info_limit) active.
226 : https://github.com/anza-xyz/agave/blob/v3.1.2/program-runtime/src/execution_budget.rs#L22-L23 */
227 60 : #define FD_VM_INVOKE_UNITS_SIMD_0339 ( 946UL)
228 :
229 : /* SIMD-0339 uses a fixed size (80 bytes) to bill each account info:
230 : - 32 bytes for account address
231 : - 32 bytes for owner address
232 : - 8 bytes for lamports
233 : - 8 bytes for data length
234 : https://github.com/anza-xyz/agave/blob/v3.1.2/program-runtime/src/cpi.rs#L63-L68
235 : */
236 12 : #define FD_VM_ACCOUNT_INFO_BYTE_SIZE ( 80UL)
237 :
238 : /* FD_VM_MAX_INVOKE_STACK_HEIGHT is the maximum program instruction
239 : invocation stack height. Invocation stack height starts at 1 for
240 : transaction instructions and the stack height is incremented each
241 : time a program invokes an instruction and decremented when a program
242 : returns */
243 :
244 : #define FD_VM_MAX_INVOKE_STACK_HEIGHT ( 5UL)
245 :
246 : /* FD_VM_MAX_INSTRUCTION_TRACE_LENGTH is the maximum cross-program
247 : invocation and instructions per transaction */
248 :
249 : #define FD_VM_MAX_INSTRUCTION_TRACE_LENGTH ( 64UL)
250 :
251 : /* FD_VM_SHA256_BASE_COST is the base number of compute units consumed
252 : to call SHA256 */
253 :
254 0 : #define FD_VM_SHA256_BASE_COST ( 85UL)
255 :
256 : /* FD_VM_SHA256_BYTE_COST is the incremental number of units consumed by
257 : SHA256 (based on bytes) */
258 :
259 0 : #define FD_VM_SHA256_BYTE_COST ( 1UL)
260 :
261 : /* FD_VM_SHA256_MAX_SLICES is the maximum number of slices hashed per
262 : syscall */
263 :
264 0 : #define FD_VM_SHA256_MAX_SLICES ( 20000UL)
265 :
266 : /* FD_VM_MAX_CALL_DEPTH is the maximum SBF to BPF call depth */
267 :
268 69 : #define FD_VM_MAX_CALL_DEPTH ( 64UL)
269 :
270 : /* FD_VM_STACK_FRAME_SIZE is the size of a stack frame in bytes, must
271 : match the size specified in the LLVM SBF backend */
272 :
273 28317 : #define FD_VM_STACK_FRAME_SIZE ( 4096UL)
274 :
275 : /* FD_VM_LOG_PUBKEY_UNITS is the number of compute units consumed by
276 : logging a `Pubkey` */
277 :
278 : #define FD_VM_LOG_PUBKEY_UNITS ( 100UL)
279 :
280 : /* FD_VM_MAX_CPI_INSTRUCTION_SIZE is the maximum cross-program
281 : invocation instruction size */
282 :
283 : #define FD_VM_MAX_CPI_INSTRUCTION_SIZE ( 1280UL) /* IPv6 Min MTU size */
284 :
285 : /* FD_VM_CPI_MAX_INSTRUCTION_ACCOUNTS is the maximum number of accounts
286 : that can be referenced by a single CPI instruction.
287 :
288 : Agave's bound for this is the same as their bound for the bound
289 : enforced by the bpf loader serializer.
290 : https://github.com/anza-xyz/agave/blob/v3.1.1/transaction-context/src/lib.rs#L32
291 :
292 : TODO: when SIMD-406 is activated, we can use FD_INSTR_ACCT_MAX instead. */
293 :
294 : #define FD_VM_CPI_MAX_INSTRUCTION_ACCOUNTS (FD_BPF_INSTR_ACCT_MAX)
295 :
296 : /* FD_VM_CPI_BYTES_PER_UNIT is the number of account data bytes per
297 : compute unit charged during a cross-program invocation */
298 :
299 60 : #define FD_VM_CPI_BYTES_PER_UNIT ( 250UL) /* ~50MB at 200,000 units */
300 :
301 : /* FD_VM_SYSVAR_BASE_COST is the base number of compute units consumed
302 : to get a sysvar */
303 :
304 : #define FD_VM_SYSVAR_BASE_COST ( 100UL)
305 :
306 : /* FD_VM_SECP256K1_RECOVER_COST is the number of compute units consumed
307 : to call secp256k1_recover */
308 :
309 : #define FD_VM_SECP256K1_RECOVER_COST ( 25000UL)
310 :
311 : /* FD_VM_SYSCALL_BASE_COST is the number of compute units consumed to do
312 : a syscall without any work */
313 :
314 0 : #define FD_VM_SYSCALL_BASE_COST ( 100UL)
315 :
316 : /* FD_VM_CURVE_EDWARDS_VALIDATE_POINT_COST is the number of compute
317 : units consumed to validate a curve25519 edwards point */
318 :
319 : #define FD_VM_CURVE_EDWARDS_VALIDATE_POINT_COST ( 159UL)
320 :
321 : /* FD_VM_CURVE_EDWARDS_ADD_COST is the number of compute units
322 : consumed to add two curve25519 edwards points */
323 :
324 0 : #define FD_VM_CURVE_EDWARDS_ADD_COST ( 473UL)
325 :
326 : /* FD_VM_CURVE_EDWARDS_SUBTRACT_COST is the number of compute units
327 : consumed to subtract two curve25519 edwards points */
328 :
329 0 : #define FD_VM_CURVE_EDWARDS_SUBTRACT_COST ( 475UL)
330 :
331 : /* FD_VM_CURVE_EDWARDS_MULTIPLY_COST is the number of compute units
332 : consumed to multiply a curve25519 edwards point */
333 :
334 0 : #define FD_VM_CURVE_EDWARDS_MULTIPLY_COST ( 2177UL)
335 :
336 : /* FD_VM_CURVE_EDWARDS_MSM_BASE_COST is the number of compute units
337 : consumed for a multiscalar multiplication (msm) of edwards points.
338 : The total cost is calculated as
339 : `msm_base_cost + (length - 1) * msm_incremental_cost` */
340 :
341 6 : #define FD_VM_CURVE_EDWARDS_MSM_BASE_COST ( 2273UL)
342 :
343 : /* FD_VM_CURVE_EDWARDS_MSM_INCREMENTAL_COST is the number of
344 : compute units consumed for a multiscalar multiplication (msm) of
345 : edwards points. The total cost is calculated as
346 : `msm_base_cost + (length - 1) * msm_incremental_cost` */
347 :
348 6 : #define FD_VM_CURVE_EDWARDS_MSM_INCREMENTAL_COST ( 758UL)
349 :
350 : /* FD_VM_CURVE_RISTRETTO_VALIDATE_POINT_COST is the number of
351 : compute units consumed to validate a curve25519 ristretto point */
352 :
353 : #define FD_VM_CURVE_RISTRETTO_VALIDATE_POINT_COST ( 169UL)
354 :
355 : /* FD_VM_CURVE_RISTRETTO_ADD_COST is the number of compute units
356 : consumed to add two curve25519 ristretto points */
357 :
358 6 : #define FD_VM_CURVE_RISTRETTO_ADD_COST ( 521UL)
359 :
360 : /* FD_VM_CURVE_RISTRETTO_SUBTRACT_COST is the number of compute
361 : units consumed to subtract two curve25519 ristretto points */
362 :
363 3 : #define FD_VM_CURVE_RISTRETTO_SUBTRACT_COST ( 519UL)
364 :
365 : /* FD_VM_CURVE_RISTRETTO_MULTIPLY_COST is the number of compute
366 : units consumed to multiply a curve25519 ristretto point */
367 :
368 3 : #define FD_VM_CURVE_RISTRETTO_MULTIPLY_COST ( 2208UL)
369 :
370 : /* FD_VM_CURVE_RISTRETTO_MSM_BASE_COST is the number of compute
371 : units consumed for a multiscalar multiplication (msm) of ristretto
372 : points. The total cost is calculated as
373 : `msm_base_cost + (length - 1) * msm_incremental_cost` */
374 :
375 3 : #define FD_VM_CURVE_RISTRETTO_MSM_BASE_COST ( 2303UL)
376 :
377 : /* FD_VM_CURVE_RISTRETTO_MSM_INCREMENTAL_COST is the number of
378 : compute units consumed for a multiscalar multiplication (msm) of
379 : ristretto points. The total cost is calculated as
380 : `msm_base_cost + (length - 1) * msm_incremental_cost` */
381 :
382 3 : #define FD_VM_CURVE_RISTRETTO_MSM_INCREMENTAL_COST ( 788UL)
383 :
384 : /* FD_VM_CURVE_BLS12_381_G1_ADD_COST is the number of compute
385 : units consumed for addition in BLS12-381 G1. */
386 :
387 3 : #define FD_VM_CURVE_BLS12_381_G1_ADD_COST ( 128UL)
388 :
389 : /* FD_VM_CURVE_BLS12_381_G2_ADD_COST is the number of compute
390 : units consumed for addition in BLS12-381 G2. */
391 :
392 0 : #define FD_VM_CURVE_BLS12_381_G2_ADD_COST ( 203UL)
393 :
394 : /* FD_VM_CURVE_BLS12_381_G1_SUB_COST is the number of compute
395 : units consumed for subtraction in BLS12-381 G1. */
396 :
397 0 : #define FD_VM_CURVE_BLS12_381_G1_SUB_COST ( 129UL)
398 :
399 : /* FD_VM_CURVE_BLS12_381_G2_SUB_COST is the number of compute
400 : units consumed for subtraction in BLS12-381 G2. */
401 :
402 0 : #define FD_VM_CURVE_BLS12_381_G2_SUB_COST ( 204UL)
403 :
404 : /* FD_VM_CURVE_BLS12_381_G1_MUL_COST is the number of compute
405 : units consumed for multiplication in BLS12-381 G1. */
406 :
407 0 : #define FD_VM_CURVE_BLS12_381_G1_MUL_COST ( 4627UL)
408 :
409 : /* FD_VM_CURVE_BLS12_381_G2_MUL_COST is the number of compute
410 : units consumed for multiplication in BLS12-381 G2. */
411 :
412 0 : #define FD_VM_CURVE_BLS12_381_G2_MUL_COST ( 8255UL)
413 :
414 : /* FD_VM_CURVE_BLS12_381_G1_DECOMPRESS_COST is the number of compute
415 : units consumed for point decompression in BLS12-381 G1. */
416 : #define FD_VM_CURVE_BLS12_381_G1_DECOMPRESS_COST ( 2100UL)
417 :
418 : /* FD_VM_CURVE_BLS12_381_G2_DECOMPRESS_COST is the number of compute
419 : units consumed for point decompression in BLS12-381 G2. */
420 :
421 : #define FD_VM_CURVE_BLS12_381_G2_DECOMPRESS_COST ( 3050UL)
422 :
423 : /* FD_VM_CURVE_BLS12_381_G1_VALIDATE_COST is the number of compute
424 : units consumed for point validation in BLS12-381 G1. */
425 :
426 : #define FD_VM_CURVE_BLS12_381_G1_VALIDATE_COST ( 1565UL)
427 :
428 : /* FD_VM_CURVE_BLS12_381_G2_VALIDATE_COST is the number of compute
429 : units consumed for point validation in BLS12-381 G2. */
430 :
431 : #define FD_VM_CURVE_BLS12_381_G2_VALIDATE_COST ( 1968UL)
432 :
433 : /* FD_VM_CURVE_BLS12_381_PAIRING_*_COST are the number of compute
434 : units consumed for calculating a pairing map in BLS12-381.
435 : The total cost is calculated as
436 : `pairing_base_cost + (length-1) * pairing_incr_cost` */
437 :
438 0 : #define FD_VM_CURVE_BLS12_381_PAIRING_BASE_COST ( 25445UL)
439 0 : #define FD_VM_CURVE_BLS12_381_PAIRING_INCR_COST ( 13023UL)
440 :
441 : /* FD_VM_HEAP_SIZE is the program heap region size, default:
442 : solana_sdk::entrypoint::HEAP_LENGTH */
443 :
444 : #define FD_VM_HEAP_SIZE ( 32768UL)
445 :
446 : /* FD_VM_HEAP_COST is the number of compute units per additional 32k
447 : heap above the default (~.5 us per 32k at 15 units/us rounded up) */
448 :
449 168 : #define FD_VM_HEAP_COST ( 8UL) /* DEFAULT_HEAP_COST */
450 :
451 : /* FD_VM_MEM_OP_BASE_COST is the memory operation syscall base cost */
452 :
453 0 : #define FD_VM_MEM_OP_BASE_COST ( 10UL)
454 :
455 : /* FD_VM_ALT_BN128_ADDITION_COST is the number of compute units consumed
456 : to call alt_bn128_addition */
457 :
458 0 : #define FD_VM_ALT_BN128_G1_ADDITION_COST ( 334UL)
459 0 : #define FD_VM_ALT_BN128_G2_ADDITION_COST ( 535UL)
460 :
461 : /* FD_VM_ALT_BN128_MULTIPLICATION_COST is the number of compute units
462 : consumed to call alt_bn128_multiplication */
463 :
464 0 : #define FD_VM_ALT_BN128_G1_MULTIPLICATION_COST ( 3840UL)
465 0 : #define FD_VM_ALT_BN128_G2_MULTIPLICATION_COST ( 15670UL)
466 :
467 : /* FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_FIRST
468 : FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_OTHER give the total cost as
469 : alt_bn128_pairing_one_pair_cost_first + alt_bn128_pairing_one_pair_cost_other * (num_elems - 1) */
470 :
471 0 : #define FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_FIRST ( 36364UL)
472 0 : #define FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_OTHER ( 12121UL)
473 :
474 : /* FD_VM_BIG_MODULAR_EXPONENTIATION_COST is the big integer modular
475 : exponentiation cost */
476 :
477 : #define FD_VM_BIG_MODULAR_EXPONENTIATION_COST ( 33UL)
478 :
479 : /* FD_VM_POSEIDON_COST_COEFFICIENT_A is the coefficient `a` of the
480 : quadratic function which determines the number of compute units
481 : consumed to call poseidon syscall for a given number of inputs */
482 :
483 0 : #define FD_VM_POSEIDON_COST_COEFFICIENT_A ( 61UL)
484 :
485 : /* FD_VM_POSEIDON_COST_COEFFICIENT_C is the coefficient `c` of the
486 : quadratic function which determines the number of compute units
487 : consumed to call poseidon syscall for a given number of inputs */
488 :
489 0 : #define FD_VM_POSEIDON_COST_COEFFICIENT_C ( 542UL)
490 :
491 : /* FD_VM_GET_REMAINING_COMPUTE_UNITS_COST is the number of compute units
492 : consumed for reading the remaining compute units */
493 :
494 : #define FD_VM_GET_REMAINING_COMPUTE_UNITS_COST ( 100UL)
495 :
496 : /* FD_VM_ALT_BN128_G1_COMPRESS is the number of compute units consumed
497 : to call alt_bn128_g1_compress */
498 :
499 0 : #define FD_VM_ALT_BN128_G1_COMPRESS ( 30UL)
500 :
501 : /* FD_VM_ALT_BN128_G1_DECOMPRESS is the number of compute units consumed
502 : to call alt_bn128_g1_decompress */
503 :
504 0 : #define FD_VM_ALT_BN128_G1_DECOMPRESS ( 398UL)
505 :
506 : /* FD_VM_ALT_BN128_G2_COMPRESS is the number of compute units consumed
507 : to call alt_bn128_g2_compress */
508 :
509 0 : #define FD_VM_ALT_BN128_G2_COMPRESS ( 86UL)
510 :
511 : /* FD_VM_ALT_BN128_G2_DECOMPRESS is the number of compute units consumed
512 : to call alt_bn128_g2_decompress */
513 :
514 0 : #define FD_VM_ALT_BN128_G2_DECOMPRESS ( 13610UL)
515 :
516 : /* FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT is the maximum accounts data
517 : size, in bytes, that a transaction is allowed to load */
518 :
519 168 : #define FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT (64UL*1024UL*1024UL) /* 64MiB */
520 :
521 : /* fd_vm_disasm API ***************************************************/
522 :
523 : /* FIXME: pretty good case this actually belongs in ballet/sbpf */
524 : /* FIXME: fd_sbpf_instr_t is nominally a ulong but implemented using
525 : bit-fields. Compilers tend to generate notoriously poor asm for bit
526 : fields ... check ASM here. */
527 :
528 : FD_PROTOTYPES_BEGIN
529 :
530 : /* fd_vm_disasm_{instr,program} appends to the *_out_len (in strlen
531 : sense) cstr in the out_max byte buffer out a pretty printed cstr of
532 : the {instruction,program}. If syscalls is non-NULL, syscalls will be
533 : annotated with the names from the provided syscall mapping.
534 :
535 : On input, *_out_len should be strlen(out) and in [0,out_max). For
536 : instr, pc is the program counter corresponding to text[0] (as such
537 : text_cnt should be positive) and text_cnt is the number of words
538 : available at text to support safely printing multiword instructions.
539 :
540 : Given a valid out on input, on output, *_out_len will be strlen(out)
541 : and in [0,out_max), even if there was an error.
542 :
543 : Returns:
544 :
545 : FD_VM_SUCCESS - out buffer and *_out_len updated.
546 :
547 : FD_VM_ERR_INVAL - Invalid input. For instr, out buffer and *_out_len
548 : are unchanged. For program, out buffer and *_out_len will have been
549 : updated up to the point where the error occurred.
550 :
551 : FD_VM_ERR_UNSUP - For program, too many functions and/or labels for
552 : the current implementation. out buffer and *_out_len unchanged.
553 :
554 : FD_VM_ERR_FULL - Not enough room in out to hold the result so output
555 : was truncated. out buffer and *_out_len updated.
556 :
557 : FD_VM_ERR_IO - An error occurred formatting the string to append. For
558 : instr, out_buffer and *_out_len unchanged. For program, out buffer
559 : and *_out_len will have been updated up to the point where the error
560 : occurred. In both cases, trailing bytes of out might have been
561 : clobbered. */
562 :
563 : int
564 : fd_vm_disasm_instr( ulong const * text, /* Indexed [0,text_cnt) */
565 : ulong text_cnt,
566 : ulong pc,
567 : fd_sbpf_syscalls_t const * syscalls,
568 : char * out, /* Indexed [0,out_max) */
569 : ulong out_max,
570 : ulong * _out_len );
571 :
572 : int
573 : fd_vm_disasm_program( ulong const * text, /* Indexed [0,text_cnt) */
574 : ulong text_cnt,
575 : fd_sbpf_syscalls_t const * syscalls,
576 : char * out, /* Indexed [0,out_max) */
577 : ulong out_max,
578 : ulong * _out_len );
579 :
580 : FD_PROTOTYPES_END
581 :
582 : /* fd_vm_trace API ****************************************************/
583 :
584 : /* FIXME: pretty good case this actually belongs in ballet/sbpf */
585 :
586 : /* A FD_VM_TRACE_EVENT_TYPE_* indicates how a fd_vm_trace_event_t should
587 : be interpreted. */
588 :
589 30 : #define FD_VM_TRACE_EVENT_TYPE_EXE (0)
590 24 : #define FD_VM_TRACE_EVENT_TYPE_READ (1)
591 24 : #define FD_VM_TRACE_EVENT_TYPE_WRITE (2)
592 :
593 : struct fd_vm_trace_event_exe {
594 : /* This point is aligned 8 */
595 : ulong info; /* Event info bit field */
596 : ulong pc; /* pc */
597 : ulong ic; /* ic */
598 : ulong cu; /* cu */
599 : ulong ic_correction; /* ic_correction */
600 : ulong frame_cnt; /* frame_cnt */
601 : ulong reg[ FD_VM_REG_CNT ]; /* registers */
602 : ulong text[ 2 ]; /* If the event has valid clear, this is actually text[1] */
603 : /* This point is aligned 8 */
604 : };
605 :
606 : typedef struct fd_vm_trace_event_exe fd_vm_trace_event_exe_t;
607 :
608 : struct fd_vm_trace_event_mem {
609 : /* This point is aligned 8 */
610 : ulong info; /* Event info bit field */
611 : ulong vaddr; /* VM address range associated with event */
612 : ulong sz;
613 : /* This point is aligned 8
614 : If event has valid set:
615 : min(sz,event_data_max) bytes user data bytes
616 : padding to aligned 8 */
617 : };
618 :
619 : typedef struct fd_vm_trace_event_mem fd_vm_trace_event_mem_t;
620 :
621 3 : #define FD_VM_TRACE_MAGIC (0xfdc377ace3a61c00UL) /* FD VM TRACE MAGIC version 0 */
622 :
623 : struct fd_vm_trace {
624 : /* This point is aligned 8 */
625 : ulong magic; /* ==FD_VM_TRACE_MAGIC */
626 : ulong event_max; /* Number bytes of event storage */
627 : ulong event_data_max; /* Max bytes to capture per data event */
628 : ulong event_sz; /* Used bytes of event storage */
629 : /* This point is aligned 8
630 : event_max bytes storage
631 : padding to aligned 8 */
632 : };
633 :
634 : typedef struct fd_vm_trace fd_vm_trace_t;
635 :
636 : FD_PROTOTYPES_BEGIN
637 :
638 : /* trace object structors */
639 : /* FIXME: DOCUMENT (USUAL CONVENTIONS) */
640 :
641 : FD_FN_CONST ulong
642 : fd_vm_trace_align( void );
643 :
644 : FD_FN_CONST ulong
645 : fd_vm_trace_footprint( ulong event_max, /* Maximum amount of event storage (<=1 EiB) */
646 : ulong event_data_max ); /* Maximum number of bytes that can be captured in an event (<=1 EiB) */
647 :
648 : void *
649 : fd_vm_trace_new( void * shmem,
650 : ulong event_max,
651 : ulong event_data_max );
652 :
653 : fd_vm_trace_t *
654 : fd_vm_trace_join( void * _trace );
655 :
656 : void *
657 : fd_vm_trace_leave( fd_vm_trace_t * trace );
658 :
659 : void *
660 : fd_vm_trace_delete( void * _trace );
661 :
662 : /* Given a current local join, fd_vm_trace_event returns the location in
663 : the caller's address space where trace events are stored and
664 : fd_vm_trace_event_sz returns number of bytes of trace events stored
665 : at that location. event_max is the number of bytes of event storage
666 : (value used to construct the trace) and event_data_max is the maximum
667 : number of data bytes that can be captured per event (value used to
668 : construct the trace). event will be aligned 8 and event_sz will be a
669 : multiple of 8 in [0,event_max]. The lifetime of the returned pointer
670 : is the lifetime of the current join. The first 8 bytes of an event
671 : are an info field used by trace inspection tools how to interpret the
672 : event. */
673 :
674 6 : FD_FN_CONST static inline void const * fd_vm_trace_event ( fd_vm_trace_t const * trace ) { return (void *)(trace+1); }
675 6 : FD_FN_CONST static inline ulong fd_vm_trace_event_sz ( fd_vm_trace_t const * trace ) { return trace->event_sz; }
676 3 : FD_FN_CONST static inline ulong fd_vm_trace_event_max ( fd_vm_trace_t const * trace ) { return trace->event_max; }
677 6 : FD_FN_CONST static inline ulong fd_vm_trace_event_data_max( fd_vm_trace_t const * trace ) { return trace->event_data_max; }
678 :
679 : /* fd_vm_trace_event_info returns the event info corresponding to the
680 : given (type,valid) tuple. Assumes type is a FD_VM_TRACE_EVENT_TYPE_*
681 : and that valid is in [0,1]. fd_vm_trace_event_info_{type,valid}
682 : extract from the given info {type,valid}. Assumes info is valid. */
683 :
684 45 : FD_FN_CONST static inline ulong fd_vm_trace_event_info( int type, int valid ) { return (ulong)((valid<<2) | type); }
685 :
686 45 : FD_FN_CONST static inline int fd_vm_trace_event_info_type ( ulong info ) { return (int)(info & 3UL); } /* EVENT_TYPE_* */
687 45 : FD_FN_CONST static inline int fd_vm_trace_event_info_valid( ulong info ) { return (int)(info >> 2); } /* In [0,1] */
688 :
689 : /* fd_vm_trace_reset frees all events in the trace. Returns
690 : FD_VM_SUCCESS (0) on success or FD_VM_ERR code (negative) on failure.
691 : Reasons for failure include NULL trace. */
692 :
693 : static inline int
694 0 : fd_vm_trace_reset( fd_vm_trace_t * trace ) {
695 0 : if( FD_UNLIKELY( !trace ) ) return FD_VM_ERR_INVAL;
696 0 : trace->event_sz = 0UL;
697 0 : return FD_VM_SUCCESS;
698 0 : }
699 :
700 : /* fd_vm_trace_event_exe records the current pc, ic, cu and
701 : register file of the VM and the instruction about to execute. Text
702 : points to the first word of the instruction about to execute and
703 : text_cnt points to the number of words available at that point.
704 : Returns FD_VM_SUCCESS (0) on success and a FD_VM_ERR code (negative)
705 : on failure. Reasons for failure include INVAL (trace NULL, reg NULL,
706 : text NULL, and/or text_cnt 0) and FULL (insufficient trace event
707 : storage available). */
708 :
709 : int
710 : fd_vm_trace_event_exe( fd_vm_trace_t * trace,
711 : ulong pc,
712 : ulong ic,
713 : ulong cu,
714 : ulong reg[ FD_VM_REG_CNT ],
715 : ulong const * text, /* Indexed [0,text_cnt) */
716 : ulong text_cnt,
717 : ulong ic_correction,
718 : ulong frame_cnt );
719 :
720 : /* fd_vm_trace_event_mem records an attempt to access the VM address
721 : range [vaddr,vaddr+sz). If write==0, it was a read attempt,
722 : otherwise, it was a write attempt. Data points to the location of
723 : the memory range in host memory or NULL if the range is invalid. If
724 : data is not NULL and sz is non-zero, this will record
725 : min(sz,event_data_max) of data for the event and mark the event has
726 : having valid data. Returns FD_VM_SUCCESS (0) on success and a
727 : FD_VM_ERR code (negative) on failure. Reasons for failure include
728 : INVAL (trace NULL) and FULL (insufficient trace event storage
729 : available to store the event). */
730 :
731 : int
732 : fd_vm_trace_event_mem( fd_vm_trace_t * trace,
733 : int write,
734 : ulong vaddr,
735 : ulong sz,
736 : void * data );
737 :
738 : /* fd_vm_trace_printf pretty prints the current trace to stdout. If
739 : syscalls is non-NULL, the trace will annotate syscalls in its
740 : disassembly according the syscall mapping. Returns FD_VM_SUCCESS (0)
741 : on success and a FD_VM_ERR code (negative) on failure. Reasons for
742 : failure include INVAL (NULL trace) and IO (corruption detected while
743 : parsing the trace events). FIXME: REVAMP THIS API FOR MORE GENERAL
744 : USE CASES. */
745 :
746 : int
747 : fd_vm_trace_printf( fd_vm_trace_t const * trace,
748 : fd_sbpf_syscalls_t const * syscalls );
749 :
750 : /* fd_vm_syscall API **************************************************/
751 :
752 : /* FIXME: fd_sbpf_syscalls_t and fd_sbpf_syscall_func_t probably should
753 : be moved from ballet/sbpf to here. */
754 :
755 : /* Note: the syscall map is kept separate from the fd_vm_t itself to
756 : support, for example, multiple fd_vm_t executing transactions
757 : concurrently for a slot. They could use the same syscalls for setup,
758 : memory and cache efficiency. */
759 :
760 : /* fd_vm_syscall_register inserts the syscall with the given cstr name
761 : into the given syscalls. The VM syscall implementation to use is
762 : given by func (NULL is fine though a VM itself may not accept such as
763 : valid). The caller promises there is room in the syscall map.
764 : Returns FD_VM_SUCCESS (0) on success or a FD_VM_ERR code (negative)
765 : on failure. Reasons for failure include INVAL (NULL syscalls, NULL
766 : name, name or the hash of name already in the map). On success,
767 : syscalls retains a read-only interest in name (e.g. use an infinite
768 : lifetime cstr here). (This function is exposed to allow VM users to
769 : add custom syscalls but most use cases probably should just call
770 : fd_vm_syscall_register_slot below.)
771 :
772 : IMPORTANT SAFETY TIP! See notes in syscall/fd_vm_syscall.h on what a
773 : syscall should expect to see and what to return. */
774 :
775 : int
776 : fd_vm_syscall_register( fd_sbpf_syscalls_t * syscalls,
777 : char const * name,
778 : fd_sbpf_syscall_func_t func );
779 :
780 : /* fd_vm_syscall_register_slot unmaps all syscalls in the current map
781 : (also ending any interest in the corresponding name cstr) and
782 : registers all syscalls appropriate for the slot. Returns
783 : FD_VM_SUCCESS (0) on success and FD_VM_ERR code (negative) on
784 : failure. Reasons for failure include INVAL (NULL syscalls) and FULL
785 : (tried to register too many system calls ... compile time map size
786 : needs to be adjusted).
787 :
788 : is_deploy should be 1 if the set of syscalls registered should be that
789 : used to verify programs before they are deployed, and 0 if it
790 : should be the set used to execute programs. */
791 :
792 : int
793 : fd_vm_syscall_register_slot( fd_sbpf_syscalls_t * syscalls,
794 : ulong slot,
795 : fd_features_t const * features,
796 : uchar is_deploy );
797 :
798 : /* fd_vm_syscall_register_all is a shorthand for registering all
799 : syscalls (see register slot). */
800 :
801 : static inline int
802 3 : fd_vm_syscall_register_all( fd_sbpf_syscalls_t * syscalls, uchar is_deploy ) {
803 : return fd_vm_syscall_register_slot( syscalls, 0UL, NULL, is_deploy );
804 3 : }
805 :
806 : FD_PROTOTYPES_END
807 :
808 : #endif /* HEADER_fd_src_flamenco_vm_fd_vm_base_h */
|