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 :
16 : /* FD_VM_SUCCESS is zero and returned to indicate that an operation
17 : completed successfully. FD_VM_ERR_* are negative integers and
18 : returned to indicate an operation that failed and why. */
19 :
20 : /* "Standard" Firedancer error codes (FIXME: harmonize and consolidate) */
21 :
22 56843730 : #define FD_VM_SUCCESS ( 0) /* success */
23 1891821 : #define FD_VM_ERR_INVAL (-1) /* invalid request */
24 3 : #define FD_VM_ERR_AGAIN (-2) /* try again later */
25 3 : #define FD_VM_ERR_UNSUP (-3) /* unsupported request */
26 3 : #define FD_VM_ERR_PERM (-4) /* unauthorized request */
27 6 : #define FD_VM_ERR_FULL (-5) /* storage full */
28 48 : #define FD_VM_ERR_EMPTY (-6) /* nothing to do */
29 3 : #define FD_VM_ERR_IO (-7) /* input-output error */
30 :
31 : /* VM exec error codes: These are only produced by the VM itself. */
32 :
33 6 : #define FD_VM_ERR_SIGTEXT ( -8) /* illegal program counter (e.g. execution ran off end of program, jump to outside the program) */
34 3 : #define FD_VM_ERR_SIGSPLIT ( -9) /* split multiword instruction (e.g. jump into the middle of a multiword instruction) */
35 18 : #define FD_VM_ERR_SIGCALL (-10) /* illegal call (e.g. call target is not the start of function) */
36 6 : #define FD_VM_ERR_SIGSTACK (-11) /* call depth limit exceeded */
37 6 : #define FD_VM_ERR_SIGILL (-12) /* illegal instruction (e.g. opcode is not valid) */
38 1170 : #define FD_VM_ERR_SIGSEGV (-13) /* illegal memory address (e.g. read/write to an address not backed by any memory) */
39 3 : #define FD_VM_ERR_SIGBUS (-14) /* misaligned memory address (e.g. read/write to an address with inappropriate alignment) */
40 3 : #define FD_VM_ERR_SIGRDONLY (-15) /* illegal write (e.g. write to a read only address) */
41 636 : #define FD_VM_ERR_SIGCOST (-16) /* compute unit limit exceeded (syscalls that exceed their budget should use this too) */
42 10794 : #define FD_VM_ERR_INVALID_PDA (-17) /* the computed pda was not a valid ed25519 point */
43 63 : #define FD_VM_ERR_SIGFPE (-18) /* divide by zero */
44 :
45 : /* FIXME: Are these exact matches to Solana? If so, provide link, if
46 : not, document and refine name / consolidate further. */
47 :
48 : /* VM syscall error codes. These are only produced by fd_vm_syscall
49 : implementations. FIXME: Consider having syscalls return standard
50 : error codes and then provide detail like this through an info arg.
51 : FIXME: Are these exact matches to Solana? If so, provide link? If
52 : not document and refine names / consolidate further. */
53 :
54 105 : #define FD_VM_ERR_ABORT (-19) /* FIXME: description */
55 27 : #define FD_VM_ERR_PANIC (-20) /* FIXME: description */
56 96 : #define FD_VM_ERR_MEM_OVERLAP (-21) /* FIXME: description */
57 3 : #define FD_VM_ERR_INSTR_ERR (-22) /* FIXME: description */
58 3 : #define FD_VM_ERR_INVOKE_CONTEXT_BORROW_FAILED (-23) /* FIXME: description */
59 3 : #define FD_VM_ERR_RETURN_DATA_TOO_LARGE (-24) /* FIXME: description */
60 :
61 : /* sBPF validation error codes. These are only produced by
62 : fd_vm_validate. FIXME: Consider having fd_vm_validate return
63 : standard error codes and then provide detail like this through an
64 : info arg. FIXME: Are these exact matches to Solana? If so, provide
65 : link, if not, document and refine name / consolidate further. */
66 :
67 867 : #define FD_VM_ERR_INVALID_OPCODE (-25) /* detected an invalid opcode */
68 201 : #define FD_VM_ERR_INVALID_SRC_REG (-26) /* detected an invalid source register */
69 291 : #define FD_VM_ERR_INVALID_DST_REG (-27) /* detected an invalid destination register */
70 3 : #define FD_VM_ERR_INF_LOOP (-28) /* detected an infinite loop */
71 156 : #define FD_VM_ERR_JMP_OUT_OF_BOUNDS (-29) /* detected an out of bounds jump */
72 126 : #define FD_VM_ERR_JMP_TO_ADDL_IMM (-30) /* detected a jump to an addl imm */
73 27 : #define FD_VM_ERR_INVALID_END_IMM (-31) /* detected an invalid immediate for an endianness conversion instruction */
74 6 : #define FD_VM_ERR_INCOMPLETE_LDQ (-32) /* detected an incomplete ldq at program end */
75 6 : #define FD_VM_ERR_LDQ_NO_ADDL_IMM (-33) /* detected a ldq without an addl imm following it */
76 3 : #define FD_VM_ERR_NO_SUCH_EXT_CALL (-34) /* detected a call imm with no function was registered for that immediate */
77 12 : #define FD_VM_ERR_INVALID_REG (-35) /* detected an invalid register */
78 162 : #define FD_VM_ERR_BAD_TEXT (-36) /* detected a bad text section (overflow, outside rodata boundary, etc.,)*/
79 60 : #define FD_VM_SH_OVERFLOW (-37) /* detected a shift overflow, equivalent to VeriferError::ShiftWithOverflow */
80 3 : #define FD_VM_TEXT_SZ_UNALIGNED (-38) /* detected a text section that is not a multiple of 8 */
81 :
82 : /* Syscall Errors
83 : https://github.com/anza-xyz/agave/blob/v2.0.7/programs/bpf_loader/src/syscalls/mod.rs#L81 */
84 :
85 12 : #define FD_VM_ERR_SYSCALL_INVALID_STRING (-1)
86 9 : #define FD_VM_ERR_SYSCALL_ABORT (-2)
87 24 : #define FD_VM_ERR_SYSCALL_PANIC (-3)
88 0 : #define FD_VM_ERR_SYSCALL_INVOKE_CONTEXT_BORROW_FAILED (-4)
89 0 : #define FD_VM_ERR_SYSCALL_MALFORMED_SIGNER_SEED (-5)
90 3 : #define FD_VM_ERR_SYSCALL_BAD_SEEDS (-6)
91 0 : #define FD_VM_ERR_SYSCALL_PROGRAM_NOT_SUPPORTED (-7)
92 24 : #define FD_VM_ERR_SYSCALL_UNALIGNED_POINTER (-8)
93 36 : #define FD_VM_ERR_SYSCALL_TOO_MANY_SIGNERS (-9)
94 36 : #define FD_VM_ERR_SYSCALL_INSTRUCTION_TOO_LARGE (-10)
95 0 : #define FD_VM_ERR_SYSCALL_TOO_MANY_ACCOUNTS (-11)
96 57 : #define FD_VM_ERR_SYSCALL_COPY_OVERLAPPING (-12)
97 0 : #define FD_VM_ERR_SYSCALL_RETURN_DATA_TOO_LARGE (-13)
98 9 : #define FD_VM_ERR_SYSCALL_TOO_MANY_SLICES (-14)
99 21 : #define FD_VM_ERR_SYSCALL_INVALID_LENGTH (-15)
100 0 : #define FD_VM_ERR_SYSCALL_MAX_INSTRUCTION_DATA_LEN_EXCEEDED (-16)
101 36 : #define FD_VM_ERR_SYSCALL_MAX_INSTRUCTION_ACCOUNTS_EXCEEDED (-17)
102 18 : #define FD_VM_ERR_SYSCALL_MAX_INSTRUCTION_ACCOUNT_INFOS_EXCEEDED (-18)
103 24 : #define FD_VM_ERR_SYSCALL_INVALID_ATTRIBUTE (-19)
104 0 : #define FD_VM_ERR_SYSCALL_INVALID_POINTER (-20)
105 0 : #define FD_VM_ERR_SYSCALL_ARITHMETIC_OVERFLOW (-21)
106 :
107 : /* Poseidon returns custom errors for some reason */
108 3 : #define FD_VM_ERR_SYSCALL_POSEIDON_INVALID_PARAMS (1)
109 3 : #define FD_VM_ERR_SYSCALL_POSEIDON_INVALID_ENDIANNESS (2)
110 :
111 : /* EbpfError
112 : https://github.com/solana-labs/rbpf/blob/v0.8.5/src/error.rs#L17 */
113 :
114 0 : #define FD_VM_ERR_EBPF_ELF_ERROR (-1)
115 0 : #define FD_VM_ERR_EBPF_FUNCTION_ALREADY_REGISTERED (-2)
116 0 : #define FD_VM_ERR_EBPF_CALL_DEPTH_EXCEEDED (-3)
117 0 : #define FD_VM_ERR_EBPF_EXIT_ROOT_CALL_FRAME (-4)
118 0 : #define FD_VM_ERR_EBPF_DIVIDE_BY_ZERO (-5)
119 0 : #define FD_VM_ERR_EBPF_DIVIDE_OVERFLOW (-6)
120 0 : #define FD_VM_ERR_EBPF_EXECUTION_OVERRUN (-7)
121 0 : #define FD_VM_ERR_EBPF_CALL_OUTSIDE_TEXT_SEGMENT (-8)
122 0 : #define FD_VM_ERR_EBPF_EXCEEDED_MAX_INSTRUCTIONS (-9)
123 0 : #define FD_VM_ERR_EBPF_JIT_NOT_COMPILED (-10)
124 0 : #define FD_VM_ERR_EBPF_INVALID_VIRTUAL_ADDRESS (-11)
125 0 : #define FD_VM_ERR_EBPF_INVALID_MEMORY_REGION (-12)
126 777 : #define FD_VM_ERR_EBPF_ACCESS_VIOLATION (-13)
127 0 : #define FD_VM_ERR_EBPF_STACK_ACCESS_VIOLATION (-14)
128 0 : #define FD_VM_ERR_EBPF_INVALID_INSTRUCTION (-15)
129 0 : #define FD_VM_ERR_EBPF_UNSUPPORTED_INSTRUCTION (-16)
130 0 : #define FD_VM_ERR_EBPF_EXHAUSTED_TEXT_SEGMENT (-17)
131 0 : #define FD_VM_ERR_EBPF_LIBC_INVOCATION_FAILED (-18)
132 0 : #define FD_VM_ERR_EBPF_VERIFIER_ERROR (-19)
133 0 : #define FD_VM_ERR_EBPF_SYSCALL_ERROR (-20)
134 :
135 :
136 : FD_PROTOTYPES_BEGIN
137 :
138 : /* fd_vm_strerror converts an FD_VM_SUCCESS / FD_VM_ERR_* code into
139 : a human readable cstr. The lifetime of the returned pointer is
140 : infinite. The returned pointer is always to a non-NULL cstr. */
141 :
142 : FD_FN_CONST char const * fd_vm_strerror( int err );
143 :
144 : FD_PROTOTYPES_END
145 :
146 : /* fd_vm_limits API ***************************************************/
147 :
148 : /* FIXME: pretty good case these actually belong in ballet/sbpf */
149 : /* FIXME: DOCUMENT THESE / LINK TO SOLANA CODE / ETC */
150 :
151 : /* VM register constants */
152 :
153 333 : #define FD_VM_REG_CNT (11UL)
154 30096 : #define FD_VM_REG_MAX (16UL) /* Actual number of SBPF instruction src/dst register indices */
155 :
156 : #define FD_VM_SHADOW_REG_CNT (4UL)
157 :
158 : /* VM stack constants */
159 :
160 87360 : #define FD_VM_STACK_FRAME_MAX (64UL)
161 102585 : #define FD_VM_STACK_FRAME_SZ FD_VM_STACK_FRAME_SIZE
162 17805 : #define FD_VM_STACK_GUARD_SZ (0x1000UL)
163 83700 : #define FD_VM_STACK_MAX (FD_VM_STACK_FRAME_MAX*(FD_VM_STACK_FRAME_SZ))
164 :
165 : /* VM heap constants */
166 :
167 108984 : #define FD_VM_HEAP_DEFAULT ( 32UL*1024UL) /* FIXME: SHOULD THIS MATCH FD_VM_HEAP_SIZE LIMIT BELOW? */
168 11220 : #define FD_VM_HEAP_MAX (256UL*1024UL)
169 :
170 : /* VM log constants */
171 :
172 27 : #define FD_VM_LOG_MAX (10000UL)
173 : #define FD_VM_LOG_TAIL (128UL) /* Large enough to cover the worst case syscall log tail clobbering in string parsing */
174 :
175 : /* VM memory map constants */
176 :
177 54 : #define FD_VM_MEM_MAP_PROGRAM_REGION_START (0x100000000UL)
178 30096 : #define FD_VM_MEM_MAP_STACK_REGION_START (0x200000000UL)
179 180 : #define FD_VM_MEM_MAP_HEAP_REGION_START (0x300000000UL)
180 30171 : #define FD_VM_MEM_MAP_INPUT_REGION_START (0x400000000UL)
181 : #define FD_VM_MEM_MAP_REGION_SZ (0x0FFFFFFFFUL)
182 : #define FD_VM_MEM_MAP_REGION_MASK (~FD_VM_MEM_MAP_REGION_SZ)
183 : #define FD_VM_MEM_MAP_REGION_VIRT_ADDR_BITS (32)
184 :
185 : /* VM compute budget. Note: these names should match exactly the names
186 : used in existing Solana validator. See:
187 : https://github.com/anza-xyz/agave/blob/v1.18.5/program-runtime/src/compute_budget.rs#L19
188 : https://github.com/anza-xyz/agave/blob/v1.18.5/program-runtime/src/compute_budget.rs#L133 */
189 : /* FIXME: DOUBLE CHECK THESE */
190 :
191 : /* FD_VM_COMPUTE_UNIT_LIMIT is the number of compute units that a
192 : transaction or individual instruction is allowed to consume. Compute
193 : units are consumed by program execution, resources they use, etc ... */
194 :
195 186 : #define FD_VM_COMPUTE_UNIT_LIMIT ( 1400000UL)
196 :
197 : /* FD_VM_LOG_64_UNITS is the number of compute units consumed by a
198 : log_64 call */
199 :
200 : #define FD_VM_LOG_64_UNITS ( 100UL)
201 :
202 : /* FD_VM_CREATE_PROGRAM_ADDRESS_UNITS is the number of compute units
203 : consumed by a create_program_address call and a try_find_program_address_call */
204 :
205 10794 : #define FD_VM_CREATE_PROGRAM_ADDRESS_UNITS ( 1500UL)
206 :
207 : /* FD_VM_INVOKE_UNITS is the number of compute units consumed by an
208 : invoke call (not including the cost incurred by the called program) */
209 :
210 : #define FD_VM_INVOKE_UNITS ( 1000UL)
211 :
212 : /* FD_VM_MAX_INVOKE_STACK_HEIGHT is the maximum program instruction
213 : invocation stack height. Invocation stack height starts at 1 for
214 : transaction instructions and the stack height is incremented each
215 : time a program invokes an instruction and decremented when a program
216 : returns */
217 :
218 : #define FD_VM_MAX_INVOKE_STACK_HEIGHT ( 5UL)
219 :
220 : /* FD_VM_MAX_INSTRUCTION_TRACE_LENGTH is the maximum cross-program
221 : invocation and instructions per transaction */
222 :
223 : #define FD_VM_MAX_INSTRUCTION_TRACE_LENGTH ( 64UL)
224 :
225 : /* FD_VM_SHA256_BASE_COST is the base number of compute units consumed
226 : to call SHA256 */
227 :
228 1437 : #define FD_VM_SHA256_BASE_COST ( 85UL)
229 :
230 : /* FD_VM_SHA256_BYTE_COST is the incremental number of units consumed by
231 : SHA256 (based on bytes) */
232 :
233 78 : #define FD_VM_SHA256_BYTE_COST ( 1UL)
234 :
235 : /* FD_VM_SHA256_MAX_SLICES is the maximum number of slices hashed per
236 : syscall */
237 :
238 9 : #define FD_VM_SHA256_MAX_SLICES ( 20000UL)
239 :
240 : /* FD_VM_MAX_CALL_DEPTH is the maximum SBF to BPF call depth */
241 :
242 : #define FD_VM_MAX_CALL_DEPTH ( 64UL)
243 :
244 : /* FD_VM_STACK_FRAME_SIZE is the size of a stack frame in bytes, must
245 : match the size specified in the LLVM SBF backend */
246 :
247 102585 : #define FD_VM_STACK_FRAME_SIZE ( 4096UL)
248 :
249 : /* FD_VM_LOG_PUBKEY_UNITS is the number of compute units consumed by
250 : logging a `Pubkey` */
251 :
252 : #define FD_VM_LOG_PUBKEY_UNITS ( 100UL)
253 :
254 : /* FD_VM_MAX_CPI_INSTRUCTION_SIZE is the maximum cross-program
255 : invocation instruction size */
256 :
257 : #define FD_VM_MAX_CPI_INSTRUCTION_SIZE ( 1280UL) /* IPv6 Min MTU size */
258 :
259 : /* FD_VM_CPI_BYTES_PER_UNIT is the number of account data bytes per
260 : compute unit charged during a cross-program invocation */
261 :
262 : #define FD_VM_CPI_BYTES_PER_UNIT ( 250UL) /* ~50MB at 200,000 units */
263 :
264 : /* FD_VM_SYSVAR_BASE_COST is the base number of compute units consumed
265 : to get a sysvar */
266 :
267 : #define FD_VM_SYSVAR_BASE_COST ( 100UL)
268 :
269 : /* FD_VM_SECP256K1_RECOVER_COST is the number of compute units consumed
270 : to call secp256k1_recover */
271 :
272 : #define FD_VM_SECP256K1_RECOVER_COST ( 25000UL)
273 :
274 : /* FD_VM_SYSCALL_BASE_COST is the number of compute units consumed to do
275 : a syscall without any work */
276 :
277 2808 : #define FD_VM_SYSCALL_BASE_COST ( 100UL)
278 :
279 : /* FD_VM_CURVE25519_EDWARDS_VALIDATE_POINT_COST is the number of compute
280 : units consumed to validate a curve25519 edwards point */
281 :
282 : #define FD_VM_CURVE25519_EDWARDS_VALIDATE_POINT_COST ( 159UL)
283 :
284 : /* FD_VM_CURVE25519_EDWARDS_ADD_COST is the number of compute units
285 : consumed to add two curve25519 edwards points */
286 :
287 21 : #define FD_VM_CURVE25519_EDWARDS_ADD_COST ( 473UL)
288 :
289 : /* FD_VM_CURVE25519_EDWARDS_SUBTRACT_COST is the number of compute units
290 : consumed to subtract two curve25519 edwards points */
291 :
292 21 : #define FD_VM_CURVE25519_EDWARDS_SUBTRACT_COST ( 475UL)
293 :
294 : /* FD_VM_CURVE25519_EDWARDS_MULTIPLY_COST is the number of compute units
295 : consumed to multiply a curve25519 edwards point */
296 :
297 69 : #define FD_VM_CURVE25519_EDWARDS_MULTIPLY_COST ( 2177UL)
298 :
299 : /* FD_VM_CURVE25519_EDWARDS_MSM_BASE_COST is the number of compute units
300 : consumed for a multiscalar multiplication (msm) of edwards points.
301 : The total cost is calculated as
302 : `msm_base_cost + (length - 1) * msm_incremental_cost` */
303 :
304 24 : #define FD_VM_CURVE25519_EDWARDS_MSM_BASE_COST ( 2273UL)
305 :
306 : /* FD_VM_CURVE25519_EDWARDS_MSM_INCREMENTAL_COST is the number of
307 : compute units consumed for a multiscalar multiplication (msm) of
308 : edwards points. The total cost is calculated as
309 : `msm_base_cost + (length - 1) * msm_incremental_cost` */
310 :
311 24 : #define FD_VM_CURVE25519_EDWARDS_MSM_INCREMENTAL_COST ( 758UL)
312 :
313 : /* FD_VM_CURVE25519_RISTRETTO_VALIDATE_POINT_COST is the number of
314 : compute units consumed to validate a curve25519 ristretto point */
315 :
316 : #define FD_VM_CURVE25519_RISTRETTO_VALIDATE_POINT_COST ( 169UL)
317 :
318 : /* FD_VM_CURVE25519_RISTRETTO_ADD_COST is the number of compute units
319 : consumed to add two curve25519 ristretto points */
320 :
321 27 : #define FD_VM_CURVE25519_RISTRETTO_ADD_COST ( 521UL)
322 :
323 : /* FD_VM_CURVE25519_RISTRETTO_SUBTRACT_COST is the number of compute
324 : units consumed to subtract two curve25519 ristretto points */
325 :
326 24 : #define FD_VM_CURVE25519_RISTRETTO_SUBTRACT_COST ( 519UL)
327 :
328 : /* FD_VM_CURVE25519_RISTRETTO_MULTIPLY_COST is the number of compute
329 : units consumed to multiply a curve25519 ristretto point */
330 :
331 72 : #define FD_VM_CURVE25519_RISTRETTO_MULTIPLY_COST ( 2208UL)
332 :
333 : /* FD_VM_CURVE25519_RISTRETTO_MSM_BASE_COST is the number of compute
334 : units consumed for a multiscalar multiplication (msm) of ristretto
335 : points. The total cost is calculated as
336 : `msm_base_cost + (length - 1) * msm_incremental_cost` */
337 :
338 21 : #define FD_VM_CURVE25519_RISTRETTO_MSM_BASE_COST ( 2303UL)
339 :
340 : /* FD_VM_CURVE25519_RISTRETTO_MSM_INCREMENTAL_COST is the number of
341 : compute units consumed for a multiscalar multiplication (msm) of
342 : ristretto points. The total cost is calculated as
343 : `msm_base_cost + (length - 1) * msm_incremental_cost` */
344 :
345 21 : #define FD_VM_CURVE25519_RISTRETTO_MSM_INCREMENTAL_COST ( 788UL)
346 :
347 : /* FD_VM_HEAP_SIZE is the program heap region size, default:
348 : solana_sdk::entrypoint::HEAP_LENGTH */
349 :
350 : #define FD_VM_HEAP_SIZE ( 32768UL)
351 :
352 : /* FD_VM_HEAP_COST is the number of compute units per additional 32k
353 : heap above the default (~.5 us per 32k at 15 units/us rounded up) */
354 :
355 7128 : #define FD_VM_HEAP_COST ( 8UL) /* DEFAULT_HEAP_COST */
356 :
357 : /* FD_VM_MEM_OP_BASE_COST is the memory operation syscall base cost */
358 :
359 78 : #define FD_VM_MEM_OP_BASE_COST ( 10UL)
360 :
361 : /* FD_VM_ALT_BN128_ADDITION_COST is the number of compute units consumed
362 : to call alt_bn128_addition */
363 :
364 54 : #define FD_VM_ALT_BN128_ADDITION_COST ( 334UL)
365 :
366 : /* FD_VM_ALT_BN128_MULTIPLICATION_COST is the number of compute units
367 : consumed to call alt_bn128_multiplication */
368 :
369 5376 : #define FD_VM_ALT_BN128_MULTIPLICATION_COST ( 3840UL)
370 :
371 : /* FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_FIRST
372 : FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_OTHER give the total cost as
373 : alt_bn128_pairing_one_pair_cost_first + alt_bn128_pairing_one_pair_cost_other * (num_elems - 1) */
374 :
375 1437 : #define FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_FIRST ( 36364UL)
376 1437 : #define FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_OTHER ( 12121UL)
377 :
378 : /* FD_VM_BIG_MODULAR_EXPONENTIATION_COST is the big integer modular
379 : exponentiation cost */
380 :
381 : #define FD_VM_BIG_MODULAR_EXPONENTIATION_COST ( 33UL)
382 :
383 : /* FD_VM_POSEIDON_COST_COEFFICIENT_A is the coefficient `a` of the
384 : quadratic function which determines the number of compute units
385 : consumed to call poseidon syscall for a given number of inputs */
386 :
387 114 : #define FD_VM_POSEIDON_COST_COEFFICIENT_A ( 61UL)
388 :
389 : /* FD_VM_POSEIDON_COST_COEFFICIENT_C is the coefficient `c` of the
390 : quadratic function which determines the number of compute units
391 : consumed to call poseidon syscall for a given number of inputs */
392 :
393 114 : #define FD_VM_POSEIDON_COST_COEFFICIENT_C ( 542UL)
394 :
395 : /* FD_VM_GET_REMAINING_COMPUTE_UNITS_COST is the number of compute units
396 : consumed for reading the remaining compute units */
397 :
398 : #define FD_VM_GET_REMAINING_COMPUTE_UNITS_COST ( 100UL)
399 :
400 : /* FD_VM_ALT_BN128_G1_COMPRESS is the number of compute units consumed
401 : to call alt_bn128_g1_compress */
402 :
403 606 : #define FD_VM_ALT_BN128_G1_COMPRESS ( 30UL)
404 :
405 : /* FD_VM_ALT_BN128_G1_DECOMPRESS is the number of compute units consumed
406 : to call alt_bn128_g1_decompress */
407 :
408 606 : #define FD_VM_ALT_BN128_G1_DECOMPRESS ( 398UL)
409 :
410 : /* FD_VM_ALT_BN128_G2_COMPRESS is the number of compute units consumed
411 : to call alt_bn128_g2_compress */
412 :
413 798 : #define FD_VM_ALT_BN128_G2_COMPRESS ( 86UL)
414 :
415 : /* FD_VM_ALT_BN128_G2_DECOMPRESS is the number of compute units consumed
416 : to call alt_bn128_g2_decompress */
417 :
418 798 : #define FD_VM_ALT_BN128_G2_DECOMPRESS ( 13610UL)
419 :
420 : /* FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT is the maximum accounts data
421 : size, in bytes, that a transaction is allowed to load */
422 :
423 108828 : #define FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT (64UL*1024UL*1024UL) /* 64MiB */
424 :
425 : /* fd_vm_disasm API ***************************************************/
426 :
427 : /* FIXME: pretty good case this actually belongs in ballet/sbpf */
428 : /* FIXME: fd_sbpf_instr_t is nominally a ulong but implemented using
429 : bit-fields. Compilers tend to generate notoriously poor asm for bit
430 : fields ... check ASM here. */
431 :
432 : FD_PROTOTYPES_BEGIN
433 :
434 : /* fd_vm_disasm_{instr,program} appends to the *_out_len (in strlen
435 : sense) cstr in the out_max byte buffer out a pretty printed cstr of
436 : the {instruction,program}. If syscalls is non-NULL, syscalls will be
437 : annotated with the names from the provided syscall mapping.
438 :
439 : On input, *_out_len should be strlen(out) and in [0,out_max). For
440 : instr, pc is the program counter corresponding to text[0] (as such
441 : text_cnt should be positive) and text_cnt is the number of words
442 : available at text to support safely printing multiword instructions.
443 :
444 : Given a valid out on input, on output, *_out_len will be strlen(out)
445 : and in [0,out_max), even if there was an error.
446 :
447 : Returns:
448 :
449 : FD_VM_SUCCESS - out buffer and *_out_len updated.
450 :
451 : FD_VM_ERR_INVAL - Invalid input. For instr, out buffer and *_out_len
452 : are unchanged. For program, out buffer and *_out_len will have been
453 : updated up to the point where the error occurred.
454 :
455 : FD_VM_ERR_UNSUP - For program, too many functions and/or labels for
456 : the current implementation. out buffer and *_out_len unchanged.
457 :
458 : FD_VM_ERR_FULL - Not enough room in out to hold the result so output
459 : was truncated. out buffer and *_out_len updated.
460 :
461 : FD_VM_ERR_IO - An error occured formatting the string to append. For
462 : instr, out_buffer and *_out_len unchanged. For program, out buffer
463 : and *_out_len will have been updated up to the point where the error
464 : occurred. In both cases, trailing bytes of out might have been
465 : clobbered. */
466 :
467 : int
468 : fd_vm_disasm_instr( ulong const * text, /* Indexed [0,text_cnt) */
469 : ulong text_cnt,
470 : ulong pc,
471 : fd_sbpf_syscalls_t const * syscalls,
472 : char * out, /* Indexed [0,out_max) */
473 : ulong out_max,
474 : ulong * _out_len );
475 :
476 : int
477 : fd_vm_disasm_program( ulong const * text, /* Indexed [0,text_cnt) */
478 : ulong text_cnt,
479 : fd_sbpf_syscalls_t const * syscalls,
480 : char * out, /* Indexed [0,out_max) */
481 : ulong out_max,
482 : ulong * _out_len );
483 :
484 : FD_PROTOTYPES_END
485 :
486 : /* fd_vm_trace API ****************************************************/
487 :
488 : /* FIXME: pretty good case this actually belongs in ballet/sbpf */
489 :
490 : /* A FD_VM_TRACE_EVENT_TYPE_* indicates how a fd_vm_trace_event_t should
491 : be interpreted. */
492 :
493 33 : #define FD_VM_TRACE_EVENT_TYPE_EXE (0)
494 24 : #define FD_VM_TRACE_EVENT_TYPE_READ (1)
495 24 : #define FD_VM_TRACE_EVENT_TYPE_WRITE (2)
496 :
497 : struct fd_vm_trace_event_exe {
498 : /* This point is aligned 8 */
499 : ulong info; /* Event info bit field */
500 : ulong pc; /* pc */
501 : ulong ic; /* ic */
502 : ulong cu; /* cu */
503 : ulong ic_correction; /* ic_correction */
504 : ulong frame_cnt; /* frame_cnt */
505 : ulong reg[ FD_VM_REG_CNT ]; /* registers */
506 : ulong text[ 2 ]; /* If the event has valid clear, this is actually text[1] */
507 : /* This point is aligned 8 */
508 : };
509 :
510 : typedef struct fd_vm_trace_event_exe fd_vm_trace_event_exe_t;
511 :
512 : struct fd_vm_trace_event_mem {
513 : /* This point is aligned 8 */
514 : ulong info; /* Event info bit field */
515 : ulong vaddr; /* VM address range associated with event */
516 : ulong sz;
517 : /* This point is aligned 8
518 : If event has valid set:
519 : min(sz,event_data_max) bytes user data bytes
520 : padding to aligned 8 */
521 : };
522 :
523 : typedef struct fd_vm_trace_event_mem fd_vm_trace_event_mem_t;
524 :
525 6 : #define FD_VM_TRACE_MAGIC (0xfdc377ace3a61c00UL) /* FD VM TRACE MAGIC version 0 */
526 :
527 : struct fd_vm_trace {
528 : /* This point is aligned 8 */
529 : ulong magic; /* ==FD_VM_TRACE_MAGIC */
530 : ulong event_max; /* Number bytes of event storage */
531 : ulong event_data_max; /* Max bytes to capture per data event */
532 : ulong event_sz; /* Used bytes of event storage */
533 : /* This point is aligned 8
534 : event_max bytes storage
535 : padding to aligned 8 */
536 : };
537 :
538 : typedef struct fd_vm_trace fd_vm_trace_t;
539 :
540 : FD_PROTOTYPES_BEGIN
541 :
542 : /* trace object structors */
543 : /* FIXME: DOCUMENT (USUAL CONVENTIONS) */
544 :
545 : FD_FN_CONST ulong
546 : fd_vm_trace_align( void );
547 :
548 : FD_FN_CONST ulong
549 : fd_vm_trace_footprint( ulong event_max, /* Maximum amount of event storage (<=1 EiB) */
550 : ulong event_data_max ); /* Maximum number of bytes that can be captured in an event (<=1 EiB) */
551 :
552 : void *
553 : fd_vm_trace_new( void * shmem,
554 : ulong event_max,
555 : ulong event_data_max );
556 :
557 : fd_vm_trace_t *
558 : fd_vm_trace_join( void * _trace );
559 :
560 : void *
561 : fd_vm_trace_leave( fd_vm_trace_t * trace );
562 :
563 : void *
564 : fd_vm_trace_delete( void * _trace );
565 :
566 : /* Given a current local join, fd_vm_trace_event returns the location in
567 : the caller's address space where trace events are stored and
568 : fd_vm_trace_event_sz returns number of bytes of trace events stored
569 : at that location. event_max is the number of bytes of event storage
570 : (value used to construct the trace) and event_data_max is the maximum
571 : number of data bytes that can be captured per event (value used to
572 : construct the trace). event will be aligned 8 and event_sz will be a
573 : multiple of 8 in [0,event_max]. The lifetime of the returned pointer
574 : is the lifetime of the current join. The first 8 bytes of an event
575 : are an info field used by trace inspection tools how to interpret the
576 : event. */
577 :
578 6 : FD_FN_CONST static inline void const * fd_vm_trace_event ( fd_vm_trace_t const * trace ) { return (void *)(trace+1); }
579 6 : FD_FN_CONST static inline ulong fd_vm_trace_event_sz ( fd_vm_trace_t const * trace ) { return trace->event_sz; }
580 3 : FD_FN_CONST static inline ulong fd_vm_trace_event_max ( fd_vm_trace_t const * trace ) { return trace->event_max; }
581 6 : FD_FN_CONST static inline ulong fd_vm_trace_event_data_max( fd_vm_trace_t const * trace ) { return trace->event_data_max; }
582 :
583 : /* fd_vm_trace_event_info returns the event info corresponding to the
584 : given (type,valid) tuple. Assumes type is a FD_VM_TRACE_EVENT_TYPE_*
585 : and that valid is in [0,1]. fd_vm_trace_event_info_{type,valid}
586 : extract from the given info {type,valid}. Assumes info is valid. */
587 :
588 48 : FD_FN_CONST static inline ulong fd_vm_trace_event_info( int type, int valid ) { return (ulong)((valid<<2) | type); }
589 :
590 45 : FD_FN_CONST static inline int fd_vm_trace_event_info_type ( ulong info ) { return (int)(info & 3UL); } /* EVENT_TYPE_* */
591 45 : FD_FN_CONST static inline int fd_vm_trace_event_info_valid( ulong info ) { return (int)(info >> 2); } /* In [0,1] */
592 :
593 : /* fd_vm_trace_reset frees all events in the trace. Returns
594 : FD_VM_SUCCESS (0) on success or FD_VM_ERR code (negative) on failure.
595 : Reasons for failure include NULL trace. */
596 :
597 : static inline int
598 0 : fd_vm_trace_reset( fd_vm_trace_t * trace ) {
599 0 : if( FD_UNLIKELY( !trace ) ) return FD_VM_ERR_INVAL;
600 0 : trace->event_sz = 0UL;
601 0 : return FD_VM_SUCCESS;
602 0 : }
603 :
604 : /* fd_vm_trace_event_exe records the the current pc, ic, cu and
605 : register file of the VM and the instruction about to execute. Text
606 : points to the first word of the instruction about to execute and
607 : text_cnt points to the number of words available at that point.
608 : Returns FD_VM_SUCCESS (0) on success and a FD_VM_ERR code (negative)
609 : on failure. Reasons for failure include INVAL (trace NULL, reg NULL,
610 : text NULL, and/or text_cnt 0) and FULL (insufficient trace event
611 : storage available). */
612 :
613 : int
614 : fd_vm_trace_event_exe( fd_vm_trace_t * trace,
615 : ulong pc,
616 : ulong ic,
617 : ulong cu,
618 : ulong reg[ FD_VM_REG_CNT ],
619 : ulong const * text, /* Indexed [0,text_cnt) */
620 : ulong text_cnt,
621 : ulong ic_correction,
622 : ulong frame_cnt );
623 :
624 : /* fd_vm_trace_event_mem records an attempt to access the VM address
625 : range [vaddr,vaddr+sz). If write==0, it was a read attempt,
626 : otherwise, it was a write attempt. Data points to the location of
627 : the memory range in host memory or NULL if the range is invalid. If
628 : data is not NULL and sz is non-zero, this will record
629 : min(sz,event_data_max) of data for the event and mark the event has
630 : having valid data. Returns FD_VM_SUCCESS (0) on success and a
631 : FD_VM_ERR code (negative) on failure. Reasons for failure include
632 : INVAL (trace NULL) and FULL (insufficient trace event storage
633 : available to store the event). */
634 :
635 : int
636 : fd_vm_trace_event_mem( fd_vm_trace_t * trace,
637 : int write,
638 : ulong vaddr,
639 : ulong sz,
640 : void * data );
641 :
642 : /* fd_vm_trace_printf pretty prints the current trace to stdout. If
643 : syscalls is non-NULL, the trace will annotate syscalls in its
644 : disassembly according the syscall mapping. Returns FD_VM_SUCCESS (0)
645 : on success and a FD_VM_ERR code (negative) on failure. Reasons for
646 : failure include INVAL (NULL trace) and IO (corruption detected while
647 : parsing the trace events). FIXME: REVAMP THIS API FOR MORE GENERAL
648 : USE CASES. */
649 :
650 : int
651 : fd_vm_trace_printf( fd_vm_trace_t const * trace,
652 : fd_sbpf_syscalls_t const * syscalls );
653 :
654 : /* fd_vm_syscall API **************************************************/
655 :
656 : /* FIXME: fd_sbpf_syscalls_t and fd_sbpf_syscall_func_t probably should
657 : be moved from ballet/sbpf to here. */
658 :
659 : /* Note: the syscall map is kept separate from the fd_vm_t itself to
660 : support, for example, multiple fd_vm_t executing transactions
661 : concurrently for a slot. They could use the same syscalls for setup,
662 : memory and cache efficiency. */
663 :
664 : /* fd_vm_syscall_register inserts the syscall with the given cstr name
665 : into the given syscalls. The VM syscall implementation to use is
666 : given by func (NULL is fine though a VM itself may not accept such as
667 : valid). The caller promises there is room in the syscall map.
668 : Returns FD_VM_SUCCESS (0) on success or a FD_VM_ERR code (negative)
669 : on failure. Reasons for failure include INVAL (NULL syscalls, NULL
670 : name, name or the hash of name already in the map). On success,
671 : syscalls retains a read-only interest in name (e.g. use an infinite
672 : lifetime cstr here). (This function is exposed to allow VM users to
673 : add custom syscalls but most use cases probably should just call
674 : fd_vm_syscall_register_slot below.)
675 :
676 : IMPORTANT SAFETY TIP! See notes in syscall/fd_vm_syscall.h on what a
677 : syscall should expect to see and what to return. */
678 :
679 : int
680 : fd_vm_syscall_register( fd_sbpf_syscalls_t * syscalls,
681 : char const * name,
682 : fd_sbpf_syscall_func_t func );
683 :
684 : /* fd_vm_syscall_register_slot unmaps all syscalls in the current map
685 : (also ending any interest in the corresponding name cstr) and
686 : registers all syscalls appropriate for the slot described by
687 : slot_ctx. Returns FD_VM_SUCCESS (0) on success and FD_VM_ERR code
688 : (negative) on failure. Reasons for failure include INVAL (NULL
689 : syscalls) and FULL (tried to register too many system calls ...
690 : compile time map size needs to be adjusted). If slot_ctx is NULL,
691 : will register all fd_vm syscall implementations (whether or not that
692 : makes sense ... may change between Firedancer versions without
693 : warning). FIXME: probably better to pass the features for a slot
694 : than pass the whole slot_ctx.
695 :
696 : is_deploy should be 1 if the set of syscalls registered should be that
697 : used to verify programs before they are deployed, and 0 if it
698 : should be the set used to execute programs. */
699 :
700 : int
701 : fd_vm_syscall_register_slot( fd_sbpf_syscalls_t * syscalls,
702 : fd_exec_slot_ctx_t const * slot_ctx,
703 : uchar is_deploy );
704 :
705 : /* fd_vm_syscall_register_all is a shorthand for registering all
706 : syscalls (see register slot). */
707 :
708 : static inline int
709 11808 : fd_vm_syscall_register_all( fd_sbpf_syscalls_t * syscalls, uchar is_deploy ) {
710 11808 : return fd_vm_syscall_register_slot( syscalls, NULL, is_deploy );
711 11808 : }
712 :
713 : FD_PROTOTYPES_END
714 :
715 : #endif /* HEADER_fd_src_flamenco_vm_fd_vm_base_h */
|