Line data Source code
1 : #include "fd_vm_syscall.h"
2 : #include "../../../ballet/ed25519/fd_curve25519.h"
3 : #include "../../../util/bits/fd_uwide.h"
4 : #include "../../runtime/fd_account.h"
5 : #include "../../runtime/fd_executor.h"
6 : #include "../../runtime/fd_account_old.h" /* FIXME: remove this and update to use new APIs */
7 : #include <stdio.h>
8 : #include <sys/mman.h>
9 : #include <unistd.h>
10 : #include <errno.h>
11 : #include "../../nanopb/pb_encode.h"
12 : #include "../../runtime/tests/generated/vm.pb.h"
13 : #include "../../runtime/tests/fd_exec_instr_test.h"
14 :
15 : #define STRINGIFY(x) TOSTRING(x)
16 : #define TOSTRING(x) #x
17 :
18 : /* Captures the state of the VM (including the instruction context).
19 : Meant to be invoked at the start of the VM_SYSCALL_CPI_ENTRYPOINT like so:
20 :
21 : ```
22 : dump_vm_cpi_state(vm, STRINGIFY(FD_EXPAND_THEN_CONCAT2(sol_invoke_signed_, VM_SYSCALL_CPI_ABI)),
23 : instruction_va, acct_infos_va, acct_info_cnt, signers_seeds_va, signers_seeds_cnt);
24 : ```
25 :
26 : Assumes that a `vm_cp_state` directory exists in the current working directory. Generates a
27 : unique dump for combination of (tile_id, caller_pubkey, instr_sz). */
28 :
29 : static FD_FN_UNUSED void
30 : dump_vm_cpi_state(fd_vm_t *vm,
31 : char const * fn_name,
32 : ulong instruction_va,
33 : ulong acct_infos_va,
34 : ulong acct_info_cnt,
35 : ulong signers_seeds_va,
36 0 : ulong signers_seeds_cnt ) {
37 0 : char filename[100];
38 0 : fd_instr_info_t const *instr = vm->instr_ctx->instr;
39 0 : sprintf(filename, "vm_cpi_state/%lu_%lu%lu_%hu.sysctx", fd_tile_id(), instr->program_id_pubkey.ul[0], instr->program_id_pubkey.ul[1], instr->data_sz);
40 0 :
41 0 : // Check if file exists
42 0 : if( access (filename, F_OK) != -1 ) {
43 0 : return;
44 0 : }
45 0 :
46 0 : fd_exec_test_syscall_context_t sys_ctx = FD_EXEC_TEST_SYSCALL_CONTEXT_INIT_ZERO;
47 0 : sys_ctx.has_instr_ctx = 1;
48 0 : sys_ctx.has_vm_ctx = 1;
49 0 : sys_ctx.has_syscall_invocation = 1;
50 0 :
51 0 : // Copy function name
52 0 : sys_ctx.syscall_invocation.function_name.size = fd_uint_min( (uint) strlen(fn_name), sizeof(sys_ctx.syscall_invocation.function_name.bytes) );
53 0 : fd_memcpy( sys_ctx.syscall_invocation.function_name.bytes,
54 0 : fn_name,
55 0 : sys_ctx.syscall_invocation.function_name.size );
56 0 :
57 0 : // VM Ctx integral fields
58 0 : sys_ctx.vm_ctx.r1 = instruction_va;
59 0 : sys_ctx.vm_ctx.r2 = acct_infos_va;
60 0 : sys_ctx.vm_ctx.r3 = acct_info_cnt;
61 0 : sys_ctx.vm_ctx.r4 = signers_seeds_va;
62 0 : sys_ctx.vm_ctx.r5 = signers_seeds_cnt;
63 0 :
64 0 : sys_ctx.vm_ctx.rodata_text_section_length = vm->text_sz;
65 0 : sys_ctx.vm_ctx.rodata_text_section_offset = vm->text_off;
66 0 :
67 0 : sys_ctx.vm_ctx.heap_max = vm->heap_max; /* should be equiv. to txn_ctx->heap_sz */
68 0 :
69 0 : FD_SCRATCH_SCOPE_BEGIN{
70 0 : sys_ctx.vm_ctx.rodata = fd_scratch_alloc( 8UL, PB_BYTES_ARRAY_T_ALLOCSIZE(vm->rodata_sz) );
71 0 : sys_ctx.vm_ctx.rodata->size = (pb_size_t) vm->rodata_sz;
72 0 : fd_memcpy( sys_ctx.vm_ctx.rodata->bytes, vm->rodata, vm->rodata_sz );
73 0 :
74 0 : pb_size_t stack_sz = (pb_size_t) ( (vm->frame_cnt + 1)*FD_VM_STACK_GUARD_SZ*2 );
75 0 : sys_ctx.syscall_invocation.stack_prefix = fd_scratch_alloc( 8UL, PB_BYTES_ARRAY_T_ALLOCSIZE(stack_sz) );
76 0 : sys_ctx.syscall_invocation.stack_prefix->size = stack_sz;
77 0 : fd_memcpy( sys_ctx.syscall_invocation.stack_prefix->bytes, vm->stack, stack_sz );
78 0 :
79 0 : sys_ctx.syscall_invocation.heap_prefix = fd_scratch_alloc( 8UL, PB_BYTES_ARRAY_T_ALLOCSIZE(vm->heap_max) );
80 0 : sys_ctx.syscall_invocation.heap_prefix->size = (pb_size_t) vm->instr_ctx->txn_ctx->heap_size;
81 0 : fd_memcpy( sys_ctx.syscall_invocation.heap_prefix->bytes, vm->heap, vm->instr_ctx->txn_ctx->heap_size );
82 0 :
83 0 : sys_ctx.vm_ctx.input_data_regions_count = vm->input_mem_regions_cnt;
84 0 : sys_ctx.vm_ctx.input_data_regions = fd_scratch_alloc( 8UL, sizeof(fd_exec_test_input_data_region_t) * vm->input_mem_regions_cnt );
85 0 : for( ulong i=0UL; i<vm->input_mem_regions_cnt; i++ ) {
86 0 : sys_ctx.vm_ctx.input_data_regions[i].content = fd_scratch_alloc( 8UL, PB_BYTES_ARRAY_T_ALLOCSIZE(vm->input_mem_regions[i].region_sz) );
87 0 : sys_ctx.vm_ctx.input_data_regions[i].content->size = (pb_size_t) vm->input_mem_regions[i].region_sz;
88 0 : fd_memcpy( sys_ctx.vm_ctx.input_data_regions[i].content->bytes, (uchar *) vm->input_mem_regions[i].haddr, vm->input_mem_regions[i].region_sz );
89 0 : sys_ctx.vm_ctx.input_data_regions[i].offset = vm->input_mem_regions[i].vaddr_offset;
90 0 : sys_ctx.vm_ctx.input_data_regions[i].is_writable = vm->input_mem_regions[i].is_writable;
91 0 : }
92 0 :
93 0 : fd_create_instr_context_protobuf_from_instructions( &sys_ctx.instr_ctx,
94 0 : vm->instr_ctx->txn_ctx,
95 0 : vm->instr_ctx->instr );
96 0 :
97 0 : // Serialize the protobuf to file (using mmap)
98 0 : size_t pb_alloc_size = 100 * 1024 * 1024; // 100MB (largest so far is 19MB)
99 0 : FILE *f = fopen(filename, "wb+");
100 0 : if( ftruncate(fileno(f), (off_t) pb_alloc_size) != 0 ) {
101 0 : FD_LOG_WARNING(("Failed to resize file %s", filename));
102 0 : fclose(f);
103 0 : return;
104 0 : }
105 0 :
106 0 : uchar *pb_alloc = mmap( NULL,
107 0 : pb_alloc_size,
108 0 : PROT_READ | PROT_WRITE,
109 0 : MAP_SHARED,
110 0 : fileno(f),
111 0 : 0 /* offset */);
112 0 : if( pb_alloc == MAP_FAILED ) {
113 0 : FD_LOG_WARNING(( "Failed to mmap file %d", errno ));
114 0 : fclose(f);
115 0 : return;
116 0 : }
117 0 :
118 0 : pb_ostream_t stream = pb_ostream_from_buffer(pb_alloc, pb_alloc_size);
119 0 : if( !pb_encode( &stream, FD_EXEC_TEST_SYSCALL_CONTEXT_FIELDS, &sys_ctx ) ) {
120 0 : FD_LOG_WARNING(( "Failed to encode instruction context" ));
121 0 : }
122 0 : // resize file to actual size
123 0 : if( ftruncate( fileno(f), (off_t) stream.bytes_written ) != 0 ) {
124 0 : FD_LOG_WARNING(( "Failed to resize file %s", filename ));
125 0 : }
126 0 :
127 0 : fclose(f);
128 0 :
129 0 : } FD_SCRATCH_SCOPE_END;
130 0 : }
131 :
132 : /* FIXME: ALGO EFFICIENCY */
133 : static inline int
134 : fd_vm_syscall_cpi_is_signer( fd_pubkey_t const * account,
135 : fd_pubkey_t const * signers,
136 198 : ulong signers_cnt ) {
137 198 : for( ulong i=0UL; i<signers_cnt; i++ ) if( !memcmp( account->uc, signers[i].uc, sizeof(fd_pubkey_t) ) ) return 1;
138 3 : return 0;
139 198 : }
140 :
141 : /*
142 : fd_vm_prepare_instruction populates instruction_accounts and instruction_accounts_cnt
143 : with the instruction accounts ready for execution.
144 :
145 : The majority of this logic is taken from
146 : https://github.com/solana-labs/solana/blob/v1.17.22/program-runtime/src/invoke_context.rs#L535,
147 : and is not vm-specific, but a part of the runtime.
148 : TODO: should we move this out of the CPI section?
149 :
150 : The bulk of the logic is concerned with unifying the privileges for each duplicated account,
151 : ensuring that each duplicate account referenced has the same privileges. It also performs some
152 : priviledge checks, for example ensuring the necessary signatures are present.
153 :
154 : TODO: instruction calling convention: const parameters after non-const.
155 :
156 : Assumptions:
157 : - We do not have more than 256 unique accounts in the callee_instr.
158 : This limit comes from the fact that a Solana transaction cannot
159 : refefence more than 256 unique accounts, due to the transaction
160 : serialization format.
161 : - callee_instr is not null.
162 : - callee_instr->acct_pubkeys is at least as long as callee_instr->acct_cnt
163 : - instr_ctx->txn_ctx->accounts_cnt is less than UCHAR_MAX.
164 : This is likely because the transaction is limited to 256 accounts.
165 : - callee_instr->program_id is set to UCHAR_MAX if account is not in instr_ctx->txn_ctx.
166 : - instruction_accounts is a 256-length empty array.
167 :
168 : Parameters:
169 : - caller_instr
170 : - callee_instr
171 : - instr_ctx
172 : - instruction_accounts
173 : - instruction_accounts_cnt
174 : - signers
175 : - signers_cnt
176 :
177 : Returns:
178 : - instruction_accounts
179 : - instruction_accounts_cnt
180 : Populated with the instruction accounts with normalized permissions.
181 :
182 : TODO: is it possible to pass the transaction indexes of the accounts in?
183 : This would allow us to make some of these algorithms more efficient.
184 : */
185 : int
186 : fd_vm_prepare_instruction( fd_instr_info_t const * caller_instr,
187 : fd_instr_info_t * callee_instr,
188 : fd_exec_instr_ctx_t * instr_ctx,
189 : fd_instruction_account_t instruction_accounts[256],
190 : ulong * instruction_accounts_cnt,
191 : fd_pubkey_t const * signers,
192 528 : ulong signers_cnt ) {
193 :
194 : /* De-duplicate the instruction accounts, using the same logic as Solana */
195 528 : ulong deduplicated_instruction_accounts_cnt = 0;
196 528 : fd_instruction_account_t deduplicated_instruction_accounts[256] = {0};
197 528 : ulong duplicate_indicies_cnt = 0;
198 528 : ulong duplicate_indices[256] = {0};
199 :
200 : /* Normalize the privileges of each instruction account in the callee, after de-duping
201 : the account references.
202 : https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/program-runtime/src/invoke_context.rs#L540-L595 */
203 2451 : for( ulong i=0UL; i<callee_instr->acct_cnt; i++ ) {
204 1923 : fd_pubkey_t const * callee_pubkey = &callee_instr->acct_pubkeys[i];
205 :
206 : /* Find the corresponding transaction account index for this callee instruction account */
207 : /* TODO: passing in the transaction indicies would mean we didn't have to do this */
208 1923 : ushort index_in_transaction = USHORT_MAX;
209 22269 : for( ulong j=0UL; j<instr_ctx->txn_ctx->accounts_cnt; j++ ) {
210 22269 : if( !memcmp( instr_ctx->txn_ctx->accounts[j].uc, callee_pubkey->uc, sizeof(fd_pubkey_t) ) ) {
211 1923 : index_in_transaction = (ushort)j;
212 1923 : break;
213 1923 : }
214 22269 : }
215 1923 : if( index_in_transaction==USHORT_MAX) {
216 : /* In this case the callee instruction is referencing an unknown account not listed in the
217 : transactions accounts. */
218 0 : FD_BASE58_ENCODE_32_BYTES( callee_pubkey->uc, id_b58 );
219 0 : fd_log_collector_msg_many( instr_ctx, 2, "Unknown account ", 16UL, id_b58, id_b58_len );
220 0 : FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_MISSING_ACC, instr_ctx->txn_ctx->instr_err_idx );
221 0 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
222 0 : }
223 :
224 : /* If there was an instruction account before this one which referenced the same
225 : transaction account index, find it's index in the deduplicated_instruction_accounts
226 : array. */
227 1923 : ulong duplicate_index = ULONG_MAX;
228 6843 : for( ulong j=0UL; j<deduplicated_instruction_accounts_cnt; j++ ) {
229 4923 : if( deduplicated_instruction_accounts[j].index_in_transaction==index_in_transaction ) {
230 3 : duplicate_index = j;
231 3 : break;
232 3 : }
233 4923 : }
234 :
235 : /* If this was account referenced in a previous iteration, update the flags to include those set
236 : in this iteration. This ensures that after all the iterations, the de-duplicated account flags
237 : for each account are the union of all the flags in all the references to that account in this instruction. */
238 :
239 : /* TODO: FD_UNLIKELY? Need to check which branch is more common by running against a larger mainnet ledger */
240 : /* TODO: this code would maybe be easier to read if we inverted the branches */
241 1923 : if( duplicate_index!=ULONG_MAX ) {
242 3 : if ( FD_UNLIKELY( duplicate_index >= deduplicated_instruction_accounts_cnt ) ) {
243 0 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
244 0 : }
245 :
246 3 : duplicate_indices[duplicate_indicies_cnt++] = duplicate_index;
247 3 : fd_instruction_account_t * instruction_account = &deduplicated_instruction_accounts[duplicate_index];
248 3 : instruction_account->is_signer |= !!(callee_instr->acct_flags[i] & FD_INSTR_ACCT_FLAGS_IS_SIGNER);
249 3 : instruction_account->is_writable |= !!(callee_instr->acct_flags[i] & FD_INSTR_ACCT_FLAGS_IS_WRITABLE);
250 1920 : } else {
251 : /* In the case where the callee instruction is NOT a duplicate, we need to
252 : create the deduplicated_instruction_accounts fd_instruction_account_t object. */
253 :
254 : /* Find the index of the instruction account in the caller instruction */
255 1920 : ushort index_in_caller = USHORT_MAX;
256 22545 : for( ulong j=0UL; j<caller_instr->acct_cnt; j++ ) {
257 : /* TODO: passing transaction indicies in would also allow us to remove these memcmp's */
258 22545 : if( !memcmp( caller_instr->acct_pubkeys[j].uc, callee_instr->acct_pubkeys[i].uc, sizeof(fd_pubkey_t) ) ) {
259 1920 : index_in_caller = (ushort)j;
260 1920 : break;
261 1920 : }
262 22545 : }
263 :
264 1920 : if( index_in_caller==USHORT_MAX ) {
265 0 : FD_BASE58_ENCODE_32_BYTES( callee_pubkey->uc, id_b58 );
266 0 : fd_log_collector_msg_many( instr_ctx, 2, "Unknown account ", 16UL, id_b58, id_b58_len );
267 0 : FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_MISSING_ACC, instr_ctx->txn_ctx->instr_err_idx );
268 0 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
269 0 : }
270 :
271 : /* Add the instruction account to the duplicate indicies array */
272 1920 : duplicate_indices[duplicate_indicies_cnt++] = deduplicated_instruction_accounts_cnt;
273 :
274 : /* Initialize the instruction account in the deduplicated_instruction_accounts array */
275 1920 : fd_instruction_account_t * instruction_account = &deduplicated_instruction_accounts[deduplicated_instruction_accounts_cnt++];
276 1920 : instruction_account->index_in_callee = (ushort)i;
277 1920 : instruction_account->index_in_caller = index_in_caller;
278 1920 : instruction_account->index_in_transaction = index_in_transaction;
279 1920 : instruction_account->is_signer = !!(callee_instr->acct_flags[i] & FD_INSTR_ACCT_FLAGS_IS_SIGNER);
280 1920 : instruction_account->is_writable = !!(callee_instr->acct_flags[i] & FD_INSTR_ACCT_FLAGS_IS_WRITABLE);
281 1920 : }
282 1923 : }
283 :
284 : /* Check the normalized account permissions for privilege escalation.
285 : https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/program-runtime/src/invoke_context.rs#L596-L624 */
286 2436 : for( ulong i = 0; i < deduplicated_instruction_accounts_cnt; i++ ) {
287 1914 : fd_instruction_account_t * instruction_account = &deduplicated_instruction_accounts[i];
288 1914 : fd_pubkey_t const * pubkey = &caller_instr->acct_pubkeys[instruction_account->index_in_caller];
289 :
290 : /* Check that the account is not read-only in the caller but writable in the callee */
291 1914 : if( FD_UNLIKELY( instruction_account->is_writable && !fd_instr_acc_is_writable( instr_ctx->instr, pubkey ) ) ) {
292 3 : return FD_EXECUTOR_INSTR_ERR_PRIVILEGE_ESCALATION;
293 3 : }
294 :
295 : /* If the account is signed in the callee, it must be signed by the caller or the program */
296 1911 : if ( FD_UNLIKELY( instruction_account->is_signer && !( fd_instr_acc_is_signer( instr_ctx->instr, pubkey ) || fd_vm_syscall_cpi_is_signer( pubkey, signers, signers_cnt) ) ) ) {
297 3 : return FD_EXECUTOR_INSTR_ERR_PRIVILEGE_ESCALATION;
298 3 : }
299 1911 : }
300 :
301 : /* Copy the accounts with their normalized permissions over to the final instruction_accounts array,
302 : and set the callee_instr acct_flags. */
303 2433 : for (ulong i = 0; i < duplicate_indicies_cnt; i++) {
304 1911 : ulong duplicate_index = duplicate_indices[i];
305 :
306 : /* Failing this condition is technically impossible, but it is probably safest to keep this in
307 : so that we throw InstructionError::NotEnoughAccountKeys at the same point at Solana does,
308 : in the event any surrounding code is changed.
309 : https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/program-runtime/src/invoke_context.rs#L625-L633 */
310 1911 : if ( FD_LIKELY( duplicate_index < deduplicated_instruction_accounts_cnt ) ) {
311 1911 : instruction_accounts[i] = deduplicated_instruction_accounts[duplicate_index];
312 1911 : callee_instr->acct_flags[i] = (uchar)
313 1911 : ( ( callee_instr->acct_flags[i] ) |
314 1911 : ( !!(instruction_accounts[i].is_writable) * FD_INSTR_ACCT_FLAGS_IS_WRITABLE ) |
315 1911 : ( !!(instruction_accounts[i].is_signer ) * FD_INSTR_ACCT_FLAGS_IS_SIGNER ) );
316 1911 : } else {
317 0 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
318 0 : }
319 1911 : }
320 :
321 : /* Check that the program account is executable. We need to ensure that the
322 : program account is a valid instruction account.
323 : https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/program-runtime/src/invoke_context.rs#L635-L648 */
324 522 : fd_borrowed_account_t * program_rec = NULL;
325 :
326 : /* Caller is in charge of setting an appropriate sentinel value (i.e., UCHAR_MAX) for callee_instr->program_id if not found. */
327 : /* We allow dead accounts to be borrowed here because that's what agave currently does.
328 : https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/program-runtime/src/invoke_context.rs#L453 */
329 522 : int err = fd_txn_borrowed_account_view_idx_allow_dead( instr_ctx->txn_ctx, callee_instr->program_id, &program_rec );
330 522 : if( FD_UNLIKELY( err ) ) {
331 : /* https://github.com/anza-xyz/agave/blob/a9ac3f55fcb2bc735db0d251eda89897a5dbaaaa/program-runtime/src/invoke_context.rs#L434 */
332 0 : FD_BASE58_ENCODE_32_BYTES( callee_instr->program_id_pubkey.uc, id_b58 );
333 0 : fd_log_collector_msg_many( instr_ctx, 2, "Unknown program ", 16UL, id_b58, id_b58_len );
334 0 : FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_MISSING_ACC, instr_ctx->txn_ctx->instr_err_idx );
335 0 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
336 0 : }
337 :
338 522 : if( FD_UNLIKELY( fd_account_find_idx_of_insn_account( instr_ctx, &callee_instr->program_id_pubkey )==-1 ) ) {
339 0 : FD_BASE58_ENCODE_32_BYTES( callee_instr->program_id_pubkey.uc, id_b58 );
340 0 : fd_log_collector_msg_many( instr_ctx, 2, "Unknown program ", 16UL, id_b58, id_b58_len );
341 0 : FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_MISSING_ACC, instr_ctx->txn_ctx->instr_err_idx );
342 0 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
343 0 : }
344 :
345 522 : fd_account_meta_t const * program_meta = program_rec->const_meta;
346 :
347 522 : if( FD_UNLIKELY( !fd_account_is_executable( program_meta ) ) ) {
348 0 : FD_BASE58_ENCODE_32_BYTES( callee_instr->program_id_pubkey.uc, id_b58 );
349 0 : fd_log_collector_msg_many( instr_ctx, 3, "Account ", 8UL, id_b58, id_b58_len, " is not executable", 18UL );
350 0 : FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_ACC_NOT_EXECUTABLE, instr_ctx->txn_ctx->instr_err_idx );
351 0 : return FD_EXECUTOR_INSTR_ERR_ACC_NOT_EXECUTABLE;
352 0 : }
353 :
354 522 : *instruction_accounts_cnt = duplicate_indicies_cnt;
355 :
356 522 : return 0;
357 522 : }
358 :
359 : /**********************************************************************
360 : CROSS PROGRAM INVOCATION (Generic logic)
361 : **********************************************************************/
362 :
363 : /* FD_CPI_MAX_SIGNER_CNT is the max amount of PDA signer addresses that
364 : a cross-program invocation can include in an instruction.
365 :
366 : https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/programs/bpf_loader/src/syscalls/mod.rs#L80 */
367 :
368 : #define FD_CPI_MAX_SIGNER_CNT (16UL)
369 :
370 : /* "Maximum number of account info structs that can be used in a single CPI
371 : invocation. A limit on account info structs is effectively the same as
372 : limiting the number of unique accounts. 128 was chosen to match the max
373 : number of locked accounts per transaction (MAX_TX_ACCOUNT_LOCKS)."
374 :
375 : https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/sdk/program/src/syscalls/mod.rs#L25
376 : https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/programs/bpf_loader/src/syscalls/cpi.rs#L1011 */
377 :
378 0 : #define FD_CPI_MAX_ACCOUNT_INFOS (128UL)
379 : /* This is just encoding what Agave says in their code comments into a
380 : compile-time check, so if anyone ever inadvertently changes one of
381 : the limits, they will have to take a look. */
382 : FD_STATIC_ASSERT( FD_CPI_MAX_ACCOUNT_INFOS==MAX_TX_ACCOUNT_LOCKS, cpi_max_account_info );
383 : static inline ulong
384 0 : get_cpi_max_account_infos( fd_exec_slot_ctx_t const * slot_ctx ) {
385 0 : return fd_ulong_if( FD_FEATURE_ACTIVE( slot_ctx, increase_tx_account_lock_limit ), FD_CPI_MAX_ACCOUNT_INFOS, 64UL );
386 0 : }
387 :
388 : /* Maximum CPI instruction data size. 10 KiB was chosen to ensure that CPI
389 : instructions are not more limited than transaction instructions if the size
390 : of transactions is doubled in the future.
391 :
392 : https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/sdk/program/src/syscalls/mod.rs#L14 */
393 :
394 : #define FD_CPI_MAX_INSTRUCTION_DATA_LEN (10240UL)
395 :
396 : /* Maximum CPI instruction accounts. 255 was chosen to ensure that instruction
397 : accounts are always within the maximum instruction account limit for BPF
398 : program instructions.
399 :
400 : https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/sdk/program/src/syscalls/mod.rs#L19
401 : https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/programs/bpf_loader/src/serialization.rs#L26 */
402 :
403 : #define FD_CPI_MAX_INSTRUCTION_ACCOUNTS (255UL)
404 :
405 :
406 : /* fd_vm_syscall_cpi_check_instruction contains common instruction acct
407 : count and data sz checks. Also consumes compute units proportional
408 : to instruction data size. */
409 :
410 : static int
411 : fd_vm_syscall_cpi_check_instruction( fd_vm_t const * vm,
412 : ulong acct_cnt,
413 255 : ulong data_sz ) {
414 : /* https://github.com/solana-labs/solana/blob/eb35a5ac1e7b6abe81947e22417f34508f89f091/programs/bpf_loader/src/syscalls/cpi.rs#L958-L959 */
415 255 : if( FD_FEATURE_ACTIVE( vm->instr_ctx->slot_ctx, loosen_cpi_size_restriction ) ) {
416 0 : if( FD_UNLIKELY( data_sz > FD_CPI_MAX_INSTRUCTION_DATA_LEN ) ) {
417 0 : FD_LOG_WARNING(( "cpi: data too long (%#lx)", data_sz ));
418 : // SyscallError::MaxInstructionDataLenExceeded
419 0 : return FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_DATA_LEN_EXCEEDED;
420 0 : }
421 0 : if( FD_UNLIKELY( acct_cnt > FD_CPI_MAX_INSTRUCTION_ACCOUNTS ) ) {
422 0 : FD_LOG_WARNING(( "cpi: too many accounts (%#lx)", acct_cnt ));
423 : // SyscallError::MaxInstructionAccountsExceeded
424 0 : return FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_ACCOUNTS_EXCEEDED;
425 0 : }
426 255 : } else {
427 : // https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/programs/bpf_loader/src/syscalls/cpi.rs#L1114
428 255 : ulong tot_sz = fd_ulong_sat_add( fd_ulong_sat_mul( FD_VM_RUST_ACCOUNT_META_SIZE, acct_cnt ), data_sz );
429 255 : if ( FD_UNLIKELY( tot_sz > FD_VM_MAX_CPI_INSTRUCTION_SIZE ) ) {
430 0 : FD_LOG_WARNING(( "cpi: instruction too long (%#lx)", tot_sz ));
431 : // SyscallError::InstructionTooLarge
432 0 : return FD_VM_SYSCALL_ERR_INSTRUCTION_TOO_LARGE;
433 0 : }
434 255 : }
435 :
436 255 : return FD_VM_SUCCESS;
437 255 : }
438 :
439 : /**********************************************************************
440 : CROSS PROGRAM INVOCATION HELPERS
441 : **********************************************************************/
442 :
443 : static inline int
444 : fd_vm_syscall_cpi_check_id( fd_pubkey_t const * program_id,
445 1785 : uchar const * loader ) {
446 1785 : return !memcmp( program_id, loader, sizeof(fd_pubkey_t) );
447 1785 : }
448 :
449 : /* fd_vm_syscall_cpi_is_precompile returns true if the given program_id
450 : corresponds to a precompile. It does this by checking against a hardcoded
451 : list of known pre-compiles.
452 :
453 : This mirrors the behaviour in solana_sdk::precompiles::is_precompile
454 : https://github.com/solana-labs/solana/blob/2afde1b028ed4593da5b6c735729d8994c4bfac6/sdk/src/precompiles.rs#L93
455 : */
456 : static inline int
457 255 : fd_vm_syscall_cpi_is_precompile( fd_pubkey_t const * program_id, fd_exec_slot_ctx_t const * slot_ctx ) {
458 255 : return fd_vm_syscall_cpi_check_id(program_id, fd_solana_keccak_secp_256k_program_id.key) |
459 255 : fd_vm_syscall_cpi_check_id(program_id, fd_solana_ed25519_sig_verify_program_id.key) |
460 255 : ( fd_vm_syscall_cpi_check_id(program_id, fd_solana_secp256r1_program_id.key) && FD_FEATURE_ACTIVE( slot_ctx, enable_secp256r1_precompile ) );
461 255 : }
462 :
463 : /* fd_vm_syscall_cpi_check_authorized_program corresponds to
464 : solana_bpf_loader_program::syscalls::cpi::check_authorized_program:
465 : https://github.com/solana-labs/solana/blob/2afde1b028ed4593da5b6c735729d8994c4bfac6/programs/bpf_loader/src/syscalls/cpi.rs#L1032
466 :
467 : It determines if the given program_id is authorized to execute a CPI call.
468 :
469 : FIXME: return type
470 : */
471 : static inline ulong
472 : fd_vm_syscall_cpi_check_authorized_program( fd_pubkey_t const * program_id,
473 : fd_exec_slot_ctx_t const * slot_ctx,
474 : uchar const * instruction_data,
475 255 : ulong instruction_data_len ) {
476 : /* FIXME: do this in a branchless manner? using bitwise comparison would probably be faster */
477 255 : return ( fd_vm_syscall_cpi_check_id(program_id, fd_solana_native_loader_id.key)
478 255 : || fd_vm_syscall_cpi_check_id(program_id, fd_solana_bpf_loader_program_id.key)
479 255 : || fd_vm_syscall_cpi_check_id(program_id, fd_solana_bpf_loader_deprecated_program_id.key)
480 255 : || (fd_vm_syscall_cpi_check_id(program_id, fd_solana_bpf_loader_upgradeable_program_id.key)
481 255 : && !((instruction_data_len != 0 && instruction_data[0] == 3) /* is_upgrade_instruction() */
482 0 : || (instruction_data_len != 0 && instruction_data[0] == 4) /* is_set_authority_instruction() */
483 0 : || (FD_FEATURE_ACTIVE(slot_ctx, enable_bpf_loader_set_authority_checked_ix)
484 0 : && (instruction_data_len != 0 && instruction_data[0] == 7)) /* is_set_authority_checked_instruction() */
485 0 : || (instruction_data_len != 0 && instruction_data[0] == 5))) /* is_close_instruction */
486 255 : || fd_vm_syscall_cpi_is_precompile(program_id, slot_ctx));
487 255 : }
488 :
489 : /* Helper functions to get the absolute vaddrs of the serialized accounts pubkey, lamports and owner.
490 :
491 : For the accounts not owned by the deprecated loader, all of these offsets into the accounts metadata region
492 : are static from fd_vm_acc_region_meta->metadata_region_offset.
493 :
494 : For accounts owned by the deprecated loader, the unaligned serializer is used, which means only the pubkey
495 : and lamports offsets are static from the metadata_region_offset. The owner is serialized into the region
496 : immediately following the account data region (if present) at a fixed offset.
497 : */
498 0 : #define VM_SERIALIZED_PUBKEY_OFFSET (8UL)
499 0 : #define VM_SERIALIZED_OWNER_OFFSET (40UL)
500 0 : #define VM_SERIALIZED_LAMPORTS_OFFSET (72UL)
501 :
502 0 : #define VM_SERIALIZED_UNALIGNED_PUBKEY_OFFSET (3UL)
503 0 : #define VM_SERIALIZED_UNALIGNED_LAMPORTS_OFFSET (35UL)
504 :
505 : static inline
506 0 : ulong serialized_pubkey_vaddr( fd_vm_t * vm, fd_vm_acc_region_meta_t * acc_region_meta ) {
507 0 : return FD_VM_MEM_MAP_INPUT_REGION_START + acc_region_meta->metadata_region_offset +
508 0 : (vm->is_deprecated ? VM_SERIALIZED_UNALIGNED_PUBKEY_OFFSET : VM_SERIALIZED_PUBKEY_OFFSET);
509 0 : }
510 :
511 : static inline
512 0 : ulong serialized_owner_vaddr( fd_vm_t * vm, fd_vm_acc_region_meta_t * acc_region_meta ) {
513 0 : if ( vm->is_deprecated ) {
514 : /* For deprecated loader programs, the owner is serialized into the start of the region
515 : following the account data region (if present) at a fixed offset. */
516 0 : return FD_VM_MEM_MAP_INPUT_REGION_START + vm->input_mem_regions[
517 0 : acc_region_meta->has_data_region ? acc_region_meta->region_idx+2 : acc_region_meta->region_idx+1
518 0 : ].vaddr_offset;
519 0 : }
520 :
521 0 : return FD_VM_MEM_MAP_INPUT_REGION_START + acc_region_meta->metadata_region_offset + VM_SERIALIZED_OWNER_OFFSET;
522 0 : }
523 :
524 : static inline
525 0 : ulong serialized_lamports_vaddr( fd_vm_t * vm, fd_vm_acc_region_meta_t * acc_region_meta ) {
526 0 : return FD_VM_MEM_MAP_INPUT_REGION_START + acc_region_meta->metadata_region_offset +
527 0 : (vm->is_deprecated ? VM_SERIALIZED_UNALIGNED_LAMPORTS_OFFSET : VM_SERIALIZED_LAMPORTS_OFFSET);
528 0 : }
529 :
530 : /**********************************************************************
531 : CROSS PROGRAM INVOCATION (C ABI)
532 : **********************************************************************/
533 :
534 : #define VM_SYSCALL_CPI_ABI c
535 12 : #define VM_SYSCALL_CPI_INSTR_T fd_vm_c_instruction_t
536 : #define VM_SYSCALL_CPI_INSTR_ALIGN (FD_VM_C_INSTRUCTION_ALIGN)
537 : #define VM_SYSCALL_CPI_INSTR_SIZE (FD_VM_C_INSTRUCTION_SIZE)
538 66 : #define VM_SYSCALL_CPI_ACC_META_T fd_vm_c_account_meta_t
539 : #define VM_SYSCALL_CPI_ACC_META_ALIGN (FD_VM_C_ACCOUNT_META_ALIGN)
540 : #define VM_SYSCALL_CPI_ACC_META_SIZE (FD_VM_C_ACCOUNT_META_SIZE)
541 12 : #define VM_SYSCALL_CPI_ACC_INFO_T fd_vm_c_account_info_t
542 : #define VM_SYSCALL_CPI_ACC_INFO_ALIGN (FD_VM_C_ACCOUNT_INFO_ALIGN)
543 12 : #define VM_SYSCALL_CPI_ACC_INFO_SIZE (FD_VM_C_ACCOUNT_INFO_SIZE)
544 :
545 : /* VM_SYSCALL_CPI_INSTR_T accessors */
546 : #define VM_SYSCALL_CPI_INSTR_DATA_ADDR( instr ) instr->data_addr
547 24 : #define VM_SYSCALL_CPI_INSTR_DATA_LEN( instr ) instr->data_len
548 : #define VM_SYSCALL_CPI_INSTR_ACCS_ADDR( instr ) instr->accounts_addr
549 90 : #define VM_SYSCALL_CPI_INSTR_ACCS_LEN( instr ) instr->accounts_len
550 : #define VM_SYSCALL_CPI_INSTR_PROGRAM_ID( vm, instr ) \
551 12 : FD_VM_MEM_HADDR_LD( vm, instr->program_id_addr, alignof(uchar), sizeof(fd_pubkey_t) )
552 :
553 : /* VM_SYSCALL_CPI_ACC_META_T accessors */
554 108 : #define VM_SYSCALL_CPI_ACC_META_IS_WRITABLE( acc_meta ) acc_meta->is_writable
555 108 : #define VM_SYSCALL_CPI_ACC_META_IS_SIGNER( acc_meta ) acc_meta->is_signer
556 : #define VM_SYSCALL_CPI_ACC_META_PUBKEY( vm, acc_meta ) \
557 54 : FD_VM_MEM_HADDR_LD( vm, acc_meta->pubkey_addr, alignof(uchar), sizeof(fd_pubkey_t) )
558 :
559 : /* VM_SYSCALL_CPI_ACC_INFO_T accessors */
560 : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_VADDR( vm, acc_info, decl ) \
561 0 : ulong decl = acc_info->lamports_addr;
562 : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS( vm, acc_info, decl ) \
563 0 : ulong * decl = FD_VM_MEM_HADDR_ST( vm, acc_info->lamports_addr, alignof(ulong), sizeof(ulong) );
564 :
565 : #define VM_SYSCALL_CPI_ACC_INFO_DATA_VADDR( vm, acc_info, decl ) \
566 0 : ulong decl = acc_info->data_addr;
567 : #define VM_SYSCALL_CPI_ACC_INFO_DATA( vm, acc_info, decl ) \
568 0 : uchar * decl = FD_VM_MEM_HADDR_ST( vm, acc_info->data_addr, alignof(uchar), acc_info->data_sz ); \
569 0 : ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = acc_info->data_addr; \
570 0 : ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = acc_info->data_sz;
571 :
572 : #define VM_SYSCALL_CPI_ACC_INFO_METADATA( vm, acc_info, decl ) \
573 12 : ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = acc_info->data_addr; \
574 12 : ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = acc_info->data_sz;
575 :
576 : #define VM_SYSCALL_CPI_SET_ACC_INFO_DATA_LEN( vm, acc_info, decl, len ) \
577 0 : acc_info->data_sz = len;
578 :
579 : #include "fd_vm_syscall_cpi_common.c"
580 :
581 : #undef VM_SYSCALL_CPI_ABI
582 : #undef VM_SYSCALL_CPI_INSTR_T
583 : #undef VM_SYSCALL_CPI_INSTR_ALIGN
584 : #undef VM_SYSCALL_CPI_INSTR_SIZE
585 : #undef VM_SYSCALL_CPI_ACC_META_T
586 : #undef VM_SYSCALL_CPI_ACC_META_ALIGN
587 : #undef VM_SYSCALL_CPI_ACC_META_SIZE
588 : #undef VM_SYSCALL_CPI_ACC_INFO_T
589 : #undef VM_SYSCALL_CPI_ACC_INFO_ALIGN
590 : #undef VM_SYSCALL_CPI_ACC_INFO_SIZE
591 : #undef VM_SYSCALL_CPI_INSTR_DATA_ADDR
592 : #undef VM_SYSCALL_CPI_INSTR_DATA_LEN
593 : #undef VM_SYSCALL_CPI_INSTR_ACCS_ADDR
594 : #undef VM_SYSCALL_CPI_INSTR_ACCS_LEN
595 : #undef VM_SYSCALL_CPI_INSTR_PROGRAM_ID
596 : #undef VM_SYSCALL_CPI_ACC_META_IS_WRITABLE
597 : #undef VM_SYSCALL_CPI_ACC_META_IS_SIGNER
598 : #undef VM_SYSCALL_CPI_ACC_META_PUBKEY
599 : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_VADDR
600 : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS
601 : #undef VM_SYSCALL_CPI_ACC_INFO_DATA_VADDR
602 : #undef VM_SYSCALL_CPI_ACC_INFO_DATA
603 : #undef VM_SYSCALL_CPI_ACC_INFO_METADATA
604 : #undef VM_SYSCALL_CPI_SET_ACC_INFO_DATA_LEN
605 :
606 : /**********************************************************************
607 : CROSS PROGRAM INVOCATION (Rust ABI)
608 : **********************************************************************/
609 :
610 : #define VM_SYSCALL_CPI_ABI rust
611 243 : #define VM_SYSCALL_CPI_INSTR_T fd_vm_rust_instruction_t
612 : #define VM_SYSCALL_CPI_INSTR_ALIGN (FD_VM_RUST_INSTRUCTION_ALIGN)
613 : #define VM_SYSCALL_CPI_INSTR_SIZE (FD_VM_RUST_INSTRUCTION_SIZE)
614 1404 : #define VM_SYSCALL_CPI_ACC_META_T fd_vm_rust_account_meta_t
615 : #define VM_SYSCALL_CPI_ACC_META_ALIGN (FD_VM_RUST_ACCOUNT_META_ALIGN)
616 : #define VM_SYSCALL_CPI_ACC_META_SIZE (FD_VM_RUST_ACCOUNT_META_SIZE)
617 240 : #define VM_SYSCALL_CPI_ACC_INFO_T fd_vm_rust_account_info_t
618 : #define VM_SYSCALL_CPI_ACC_INFO_ALIGN (FD_VM_RUST_ACCOUNT_INFO_ALIGN)
619 240 : #define VM_SYSCALL_CPI_ACC_INFO_SIZE (FD_VM_RUST_ACCOUNT_INFO_SIZE)
620 :
621 : /* VM_SYSCALL_CPI_INSTR_T accessors */
622 : #define VM_SYSCALL_CPI_INSTR_DATA_ADDR( instr ) instr->data.addr
623 486 : #define VM_SYSCALL_CPI_INSTR_DATA_LEN( instr ) instr->data.len
624 : #define VM_SYSCALL_CPI_INSTR_ACCS_ADDR( instr ) instr->accounts.addr
625 1890 : #define VM_SYSCALL_CPI_INSTR_ACCS_LEN( instr ) instr->accounts.len
626 243 : #define VM_SYSCALL_CPI_INSTR_PROGRAM_ID( vm, instr ) instr->pubkey
627 :
628 : /* VM_SYSCALL_CPI_ACC_META_T accessors */
629 2322 : #define VM_SYSCALL_CPI_ACC_META_IS_WRITABLE( acc_meta ) acc_meta->is_writable
630 2322 : #define VM_SYSCALL_CPI_ACC_META_IS_SIGNER( acc_meta ) acc_meta->is_signer
631 1161 : #define VM_SYSCALL_CPI_ACC_META_PUBKEY( vm, acc_meta ) acc_meta->pubkey
632 :
633 : /* VM_SYSCALL_CPI_ACC_INFO_T accessors */
634 : /* The lamports and the account data are stored behind RefCells,
635 : so we have an additional layer of indirection to unwrap. */
636 : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_VADDR( vm, acc_info, decl ) \
637 : /* Translate the pointer to the RefCell */ \
638 0 : fd_vm_rc_refcell_t * FD_EXPAND_THEN_CONCAT2(decl, _box) = \
639 0 : FD_VM_MEM_HADDR_ST( vm, acc_info->lamports_box_addr, FD_VM_RC_REFCELL_ALIGN, sizeof(fd_vm_rc_refcell_t) ); \
640 0 : /* Extract the vaddr the RefCell points to */ \
641 0 : ulong decl = FD_EXPAND_THEN_CONCAT2(decl, _box)->addr;
642 :
643 : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS( vm, acc_info, decl ) \
644 : /* Translate the pointer to the RefCell */ \
645 1695 : fd_vm_rc_refcell_t * FD_EXPAND_THEN_CONCAT2(decl, _box) = \
646 1695 : FD_VM_MEM_HADDR_ST( vm, acc_info->lamports_box_addr, FD_VM_RC_REFCELL_ALIGN, sizeof(fd_vm_rc_refcell_t) ); \
647 1695 : /* Translate the pointer to the underlying data */ \
648 1695 : ulong * decl = FD_VM_MEM_HADDR_ST( vm, FD_EXPAND_THEN_CONCAT2(decl, _box)->addr, alignof(ulong), sizeof(ulong) );
649 :
650 : #define VM_SYSCALL_CPI_ACC_INFO_DATA_VADDR( vm, acc_info, decl ) \
651 : /* Translate the pointer to the RefCell */ \
652 0 : fd_vm_rc_refcell_vec_t * FD_EXPAND_THEN_CONCAT2(decl, _box) = \
653 0 : FD_VM_MEM_HADDR_ST( vm, acc_info->data_box_addr, FD_VM_RC_REFCELL_ALIGN, sizeof(fd_vm_rc_refcell_vec_t) ); \
654 0 : /* Extract the vaddr the RefCell points to */ \
655 0 : ulong decl = FD_EXPAND_THEN_CONCAT2(decl, _box)->addr;
656 :
657 : /* TODO: possibly define a refcell unwrapping macro to simplify this? */
658 : #define VM_SYSCALL_CPI_ACC_INFO_DATA( vm, acc_info, decl ) \
659 : /* Translate the pointer to the RefCell */ \
660 768 : fd_vm_rc_refcell_vec_t * FD_EXPAND_THEN_CONCAT2(decl, _box) = \
661 768 : FD_VM_MEM_HADDR_ST( vm, acc_info->data_box_addr, FD_VM_RC_REFCELL_ALIGN, sizeof(fd_vm_rc_refcell_vec_t) ); \
662 768 : /* Declare the vm addr of the underlying data, as we sometimes need it later */ \
663 768 : ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = FD_EXPAND_THEN_CONCAT2(decl, _box)->addr; \
664 768 : /* Translate the pointer to the underlying data */ \
665 768 : uchar * decl = FD_VM_MEM_HADDR_ST( \
666 768 : vm, FD_EXPAND_THEN_CONCAT2(decl, _box)->addr, alignof(uchar), FD_EXPAND_THEN_CONCAT2(decl, _box)->len ); \
667 768 : /* Declare the size of the underlying data */ \
668 768 : ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = FD_EXPAND_THEN_CONCAT2(decl, _box)->len;
669 :
670 : #define VM_SYSCALL_CPI_ACC_INFO_METADATA( vm, acc_info, decl ) \
671 : /* Translate the pointer to the RefCell */ \
672 1086 : fd_vm_rc_refcell_vec_t * FD_EXPAND_THEN_CONCAT2(decl, _box) = \
673 1086 : FD_VM_MEM_HADDR_ST( vm, acc_info->data_box_addr, FD_VM_RC_REFCELL_ALIGN, sizeof(fd_vm_rc_refcell_vec_t) ); \
674 1086 : /* Declare the vm addr of the underlying data, as we sometimes need it later */ \
675 1086 : ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = FD_EXPAND_THEN_CONCAT2(decl, _box)->addr; \
676 1086 : /* Declare the size of the underlying data */ \
677 1086 : ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = FD_EXPAND_THEN_CONCAT2(decl, _box)->len;
678 :
679 : /* The data and lamports fields are in an Rc<Refcell<T>> in the Rust SDK AccountInfo */
680 : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_RC_REFCELL_VADDR( vm, acc_info, decl ) \
681 0 : ulong decl = acc_info->lamports_box_addr;
682 :
683 : #define VM_SYSCALL_CPI_ACC_INFO_DATA_RC_REFCELL_VADDR( vm, acc_info, decl ) \
684 0 : ulong decl = acc_info->data_box_addr;
685 :
686 : #define VM_SYSCALL_CPI_SET_ACC_INFO_DATA_LEN( vm, acc_info, decl, len_ ) \
687 0 : FD_EXPAND_THEN_CONCAT2(decl, _box)->len = len_;
688 :
689 : #include "fd_vm_syscall_cpi_common.c"
690 :
691 : #undef VM_SYSCALL_CPI_ABI
692 : #undef VM_SYSCALL_CPI_INSTR_T
693 : #undef VM_SYSCALL_CPI_INSTR_ALIGN
694 : #undef VM_SYSCALL_CPI_INSTR_SIZE
695 : #undef VM_SYSCALL_CPI_ACC_META_T
696 : #undef VM_SYSCALL_CPI_ACC_META_ALIGN
697 : #undef VM_SYSCALL_CPI_ACC_META_SIZE
698 : #undef VM_SYSCALL_CPI_ACC_INFO_T
699 : #undef VM_SYSCALL_CPI_ACC_INFO_ALIGN
700 : #undef VM_SYSCALL_CPI_ACC_INFO_SIZE
701 : #undef VM_SYSCALL_CPI_INSTR_DATA_ADDR
702 : #undef VM_SYSCALL_CPI_INSTR_DATA_LEN
703 : #undef VM_SYSCALL_CPI_INSTR_ACCS_ADDR
704 : #undef VM_SYSCALL_CPI_INSTR_ACCS_LEN
705 : #undef VM_SYSCALL_CPI_INSTR_PROGRAM_ID
706 : #undef VM_SYSCALL_CPI_ACC_META_IS_WRITABLE
707 : #undef VM_SYSCALL_CPI_ACC_META_IS_SIGNER
708 : #undef VM_SYSCALL_CPI_ACC_META_PUBKEY
709 : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_VADDR
710 : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS
711 : #undef VM_SYSCALL_CPI_ACC_INFO_DATA_VADDR
712 : #undef VM_SYSCALL_CPI_ACC_INFO_DATA
713 : #undef VM_SYSCALL_CPI_ACC_INFO_METADATA
714 : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_RC_REFCELL_VADDR
715 : #undef VM_SYSCALL_CPI_ACC_INFO_DATA_RC_REFCELL_VADDR
716 : #undef VM_SYSCALL_CPI_SET_ACC_INFO_DATA_LEN
|