LCOV - code coverage report
Current view: top level - flamenco/vm/syscall - fd_vm_syscall_cpi.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 159 291 54.6 %
Date: 2024-11-13 11:58:15 Functions: 6 8 75.0 %

          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         225 :            ulong               signers_cnt ) {
     137         225 :   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         225 : }
     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         930 :                            ulong                    signers_cnt ) {
     193             : 
     194             :   /* De-duplicate the instruction accounts, using the same logic as Solana */
     195         930 :   ulong deduplicated_instruction_accounts_cnt = 0;
     196         930 :   fd_instruction_account_t deduplicated_instruction_accounts[256] = {0};
     197         930 :   ulong duplicate_indicies_cnt = 0;
     198         930 :   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        3579 :   for( ulong i=0UL; i<callee_instr->acct_cnt; i++ ) {
     204        2649 :     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        2649 :     ushort index_in_transaction = USHORT_MAX;
     209       23736 :     for( ulong j=0UL; j<instr_ctx->txn_ctx->accounts_cnt; j++ ) {
     210       23736 :       if( !memcmp( instr_ctx->txn_ctx->accounts[j].uc, callee_pubkey->uc, sizeof(fd_pubkey_t) ) ) {
     211        2649 :         index_in_transaction = (ushort)j;
     212        2649 :         break;
     213        2649 :       }
     214       23736 :     }
     215        2649 :     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        2649 :     ulong duplicate_index = ULONG_MAX;
     228        7884 :     for( ulong j=0UL; j<deduplicated_instruction_accounts_cnt; j++ ) {
     229        5259 :       if( deduplicated_instruction_accounts[j].index_in_transaction==index_in_transaction ) {
     230          24 :         duplicate_index = j;
     231          24 :         break;
     232          24 :       }
     233        5259 :     }
     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        2649 :     if( duplicate_index!=ULONG_MAX ) {
     242          24 :       if ( FD_UNLIKELY( duplicate_index >= deduplicated_instruction_accounts_cnt ) ) {
     243           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     244           0 :       }
     245             : 
     246          24 :       duplicate_indices[duplicate_indicies_cnt++] = duplicate_index;
     247          24 :       fd_instruction_account_t * instruction_account = &deduplicated_instruction_accounts[duplicate_index];
     248          24 :       instruction_account->is_signer   |= !!(callee_instr->acct_flags[i] & FD_INSTR_ACCT_FLAGS_IS_SIGNER);
     249          24 :       instruction_account->is_writable |= !!(callee_instr->acct_flags[i] & FD_INSTR_ACCT_FLAGS_IS_WRITABLE);
     250        2625 :     } 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        2625 :       ushort index_in_caller = USHORT_MAX;
     256       23865 :       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       23865 :         if( !memcmp( caller_instr->acct_pubkeys[j].uc, callee_instr->acct_pubkeys[i].uc, sizeof(fd_pubkey_t) ) ) {
     259        2625 :           index_in_caller = (ushort)j;
     260        2625 :           break;
     261        2625 :         }
     262       23865 :       }
     263             : 
     264        2625 :       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        2625 :       duplicate_indices[duplicate_indicies_cnt++] = deduplicated_instruction_accounts_cnt;
     273             : 
     274             :       /* Initialize the instruction account in the deduplicated_instruction_accounts array */
     275        2625 :       fd_instruction_account_t * instruction_account = &deduplicated_instruction_accounts[deduplicated_instruction_accounts_cnt++];
     276        2625 :       instruction_account->index_in_callee      = (ushort)i;
     277        2625 :       instruction_account->index_in_caller      = index_in_caller;
     278        2625 :       instruction_account->index_in_transaction = index_in_transaction;
     279        2625 :       instruction_account->is_signer            = !!(callee_instr->acct_flags[i] & FD_INSTR_ACCT_FLAGS_IS_SIGNER);
     280        2625 :       instruction_account->is_writable          = !!(callee_instr->acct_flags[i] & FD_INSTR_ACCT_FLAGS_IS_WRITABLE);
     281        2625 :     }
     282        2649 :   }
     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        3495 :   for( ulong i = 0; i < deduplicated_instruction_accounts_cnt; i++ ) {
     287        2595 :     fd_instruction_account_t * instruction_account = &deduplicated_instruction_accounts[i];
     288        2595 :     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        2595 :     if( FD_UNLIKELY( instruction_account->is_writable && !fd_instr_acc_is_writable( instr_ctx->instr, pubkey ) ) ) {
     292          27 :       return FD_EXECUTOR_INSTR_ERR_PRIVILEGE_ESCALATION;
     293          27 :     }
     294             : 
     295             :     /* If the account is signed in the callee, it must be signed by the caller or the program */
     296        2568 :     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        2568 :   }
     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        3489 :   for (ulong i = 0; i < duplicate_indicies_cnt; i++) {
     304        2589 :     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        2589 :     if ( FD_LIKELY( duplicate_index < deduplicated_instruction_accounts_cnt ) ) {
     311        2589 :       instruction_accounts[i] = deduplicated_instruction_accounts[duplicate_index];
     312        2589 :       callee_instr->acct_flags[i] = (uchar)
     313        2589 :         ( ( callee_instr->acct_flags[i] ) |
     314        2589 :           ( !!(instruction_accounts[i].is_writable) * FD_INSTR_ACCT_FLAGS_IS_WRITABLE ) |
     315        2589 :           ( !!(instruction_accounts[i].is_signer  ) * FD_INSTR_ACCT_FLAGS_IS_SIGNER   ) );
     316        2589 :     } else {
     317           0 :       return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     318           0 :     }
     319        2589 :   }
     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         900 :   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         900 :   int err = fd_txn_borrowed_account_view_idx_allow_dead( instr_ctx->txn_ctx, callee_instr->program_id, &program_rec );
     330         900 :   if( FD_UNLIKELY( err ) ) {
     331             :     /* https://github.com/anza-xyz/agave/blob/a9ac3f55fcb2bc735db0d251eda89897a5dbaaaa/program-runtime/src/invoke_context.rs#L434 */
     332         108 :     FD_BASE58_ENCODE_32_BYTES( callee_instr->program_id_pubkey.uc, id_b58 );
     333         108 :     fd_log_collector_msg_many( instr_ctx, 2, "Unknown program ", 16UL, id_b58, id_b58_len );
     334         108 :     FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_MISSING_ACC, instr_ctx->txn_ctx->instr_err_idx );
     335         108 :     return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
     336         108 :   }
     337             : 
     338         792 :   if( FD_UNLIKELY( fd_account_find_idx_of_insn_account( instr_ctx, &callee_instr->program_id_pubkey )==-1 ) ) {
     339           9 :     FD_BASE58_ENCODE_32_BYTES( callee_instr->program_id_pubkey.uc, id_b58 );
     340           9 :     fd_log_collector_msg_many( instr_ctx, 2, "Unknown program ", 16UL, id_b58, id_b58_len );
     341           9 :     FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_MISSING_ACC, instr_ctx->txn_ctx->instr_err_idx );
     342           9 :     return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
     343           9 :   }
     344             : 
     345         783 :   fd_account_meta_t const * program_meta = program_rec->const_meta;
     346             : 
     347         783 :   if( FD_UNLIKELY( !fd_account_is_executable( program_meta ) ) ) {
     348          45 :     FD_BASE58_ENCODE_32_BYTES( callee_instr->program_id_pubkey.uc, id_b58 );
     349          45 :     fd_log_collector_msg_many( instr_ctx, 3, "Account ", 8UL, id_b58, id_b58_len, " is not executable", 18UL );
     350          45 :     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          45 :     return FD_EXECUTOR_INSTR_ERR_ACC_NOT_EXECUTABLE;
     352          45 :   }
     353             : 
     354         738 :   *instruction_accounts_cnt = duplicate_indicies_cnt;
     355             : 
     356         738 :   return 0;
     357         783 : }
     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         264 :                                      ulong           data_sz ) {
     414             :   /* https://github.com/solana-labs/solana/blob/eb35a5ac1e7b6abe81947e22417f34508f89f091/programs/bpf_loader/src/syscalls/cpi.rs#L958-L959 */
     415         264 :   if( FD_FEATURE_ACTIVE( vm->instr_ctx->slot_ctx, loosen_cpi_size_restriction ) ) {
     416           6 :     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_ERR_SYSCALL_MAX_INSTRUCTION_DATA_LEN_EXCEEDED;
     420           0 :     }
     421           6 :     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_ERR_SYSCALL_MAX_INSTRUCTION_ACCOUNTS_EXCEEDED;
     425           0 :     }
     426         258 :   } else {
     427             :     // https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/programs/bpf_loader/src/syscalls/cpi.rs#L1114
     428         258 :     ulong tot_sz = fd_ulong_sat_add( fd_ulong_sat_mul( FD_VM_RUST_ACCOUNT_META_SIZE, acct_cnt ), data_sz );
     429         258 :     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_ERR_SYSCALL_INSTRUCTION_TOO_LARGE;
     433           0 :     }
     434         258 :   }
     435             : 
     436         264 :   return FD_VM_SUCCESS;
     437         264 : }
     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        1848 :           uchar const * loader ) {
     446        1848 :   return !memcmp( program_id, loader, sizeof(fd_pubkey_t) );
     447        1848 : }
     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         264 : fd_vm_syscall_cpi_is_precompile( fd_pubkey_t const * program_id ) {
     458         264 :   return fd_vm_syscall_cpi_check_id(program_id, fd_solana_keccak_secp_256k_program_id.key) |
     459         264 :          fd_vm_syscall_cpi_check_id(program_id, fd_solana_ed25519_sig_verify_program_id.key) |
     460         264 :          fd_vm_syscall_cpi_check_id(program_id, fd_solana_secp256r1_program_id.key);
     461         264 : }
     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         264 :                                             ulong                      instruction_data_len ) {
     476             :   /* FIXME: do this in a branchless manner? using bitwise comparison would probably be faster */
     477         264 :   return ( fd_vm_syscall_cpi_check_id(program_id, fd_solana_native_loader_id.key)
     478         264 :             || fd_vm_syscall_cpi_check_id(program_id, fd_solana_bpf_loader_program_id.key)
     479         264 :             || fd_vm_syscall_cpi_check_id(program_id, fd_solana_bpf_loader_deprecated_program_id.key)
     480         264 :             || (fd_vm_syscall_cpi_check_id(program_id, fd_solana_bpf_loader_upgradeable_program_id.key)
     481         264 :                 && !((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         264 :             || fd_vm_syscall_cpi_is_precompile(program_id));
     487         264 : }
     488             : 
     489             : /**********************************************************************
     490             :   CROSS PROGRAM INVOCATION (C ABI)
     491             :  **********************************************************************/
     492             : 
     493             : #define VM_SYSCALL_CPI_ABI                     c
     494          12 : #define VM_SYSCALL_CPI_INSTR_T                 fd_vm_c_instruction_t
     495             : #define VM_SYSCALL_CPI_INSTR_ALIGN             (FD_VM_C_INSTRUCTION_ALIGN)
     496             : #define VM_SYSCALL_CPI_INSTR_SIZE              (FD_VM_C_INSTRUCTION_SIZE)
     497          66 : #define VM_SYSCALL_CPI_ACC_META_T              fd_vm_c_account_meta_t
     498             : #define VM_SYSCALL_CPI_ACC_META_ALIGN          (FD_VM_C_ACCOUNT_META_ALIGN)
     499             : #define VM_SYSCALL_CPI_ACC_META_SIZE           (FD_VM_C_ACCOUNT_META_SIZE)
     500          12 : #define VM_SYSCALL_CPI_ACC_INFO_T              fd_vm_c_account_info_t
     501             : #define VM_SYSCALL_CPI_ACC_INFO_ALIGN          (FD_VM_C_ACCOUNT_INFO_ALIGN)
     502             : #define VM_SYSCALL_CPI_ACC_INFO_SIZE           (FD_VM_C_ACCOUNT_INFO_SIZE)
     503             : 
     504             : /* VM_SYSCALL_CPI_INSTR_T accessors */
     505             : #define VM_SYSCALL_CPI_INSTR_DATA_ADDR( instr ) instr->data_addr
     506          24 : #define VM_SYSCALL_CPI_INSTR_DATA_LEN( instr )  instr->data_len
     507             : #define VM_SYSCALL_CPI_INSTR_ACCS_ADDR( instr ) instr->accounts_addr
     508          90 : #define VM_SYSCALL_CPI_INSTR_ACCS_LEN( instr )  instr->accounts_len
     509             : #define VM_SYSCALL_CPI_INSTR_PROGRAM_ID( vm, instr ) \
     510          12 :   FD_VM_MEM_HADDR_LD( vm, instr->program_id_addr, alignof(uchar), sizeof(fd_pubkey_t)  )
     511             : 
     512             : /* VM_SYSCALL_CPI_ACC_META_T accessors */
     513         108 : #define VM_SYSCALL_CPI_ACC_META_IS_WRITABLE( acc_meta ) acc_meta->is_writable
     514         108 : #define VM_SYSCALL_CPI_ACC_META_IS_SIGNER( acc_meta ) acc_meta->is_signer
     515             : #define VM_SYSCALL_CPI_ACC_META_PUBKEY( vm, acc_meta ) \
     516          54 :   FD_VM_MEM_HADDR_LD( vm, acc_meta->pubkey_addr, alignof(uchar), sizeof(fd_pubkey_t) )
     517             : 
     518             : /* VM_SYSCALL_CPI_ACC_INFO_T accessors */
     519             : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS( vm, acc_info, decl ) \
     520           0 :   ulong * decl = FD_VM_MEM_HADDR_ST( vm, acc_info->lamports_addr, alignof(ulong), sizeof(ulong) );
     521             : 
     522             : #define VM_SYSCALL_CPI_ACC_INFO_DATA( vm, acc_info, decl ) \
     523           0 :   uchar * decl = FD_VM_MEM_HADDR_ST( vm, acc_info->data_addr, alignof(uchar), acc_info->data_sz ); \
     524           0 :   ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = acc_info->data_addr; \
     525           0 :   ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = acc_info->data_sz;
     526             : 
     527             : #define VM_SYSCALL_CPI_ACC_INFO_METADATA( vm, acc_info, decl ) \
     528          12 :   ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = acc_info->data_addr; \
     529          12 :   ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = acc_info->data_sz;
     530             : 
     531             : #define VM_SYSCALL_CPI_SET_ACC_INFO_DATA_LEN( vm, acc_info, decl, len ) \
     532           0 :   acc_info->data_sz = len;
     533             : 
     534             : #include "fd_vm_syscall_cpi_common.c"
     535             : 
     536             : #undef VM_SYSCALL_CPI_ABI
     537             : #undef VM_SYSCALL_CPI_INSTR_T
     538             : #undef VM_SYSCALL_CPI_INSTR_ALIGN
     539             : #undef VM_SYSCALL_CPI_INSTR_SIZE
     540             : #undef VM_SYSCALL_CPI_ACC_META_T
     541             : #undef VM_SYSCALL_CPI_ACC_META_ALIGN
     542             : #undef VM_SYSCALL_CPI_ACC_META_SIZE
     543             : #undef VM_SYSCALL_CPI_ACC_INFO_T
     544             : #undef VM_SYSCALL_CPI_ACC_INFO_ALIGN
     545             : #undef VM_SYSCALL_CPI_ACC_INFO_SIZE
     546             : #undef VM_SYSCALL_CPI_INSTR_DATA_ADDR
     547             : #undef VM_SYSCALL_CPI_INSTR_DATA_LEN
     548             : #undef VM_SYSCALL_CPI_INSTR_ACCS_ADDR
     549             : #undef VM_SYSCALL_CPI_INSTR_ACCS_LEN
     550             : #undef VM_SYSCALL_CPI_INSTR_PROGRAM_ID
     551             : #undef VM_SYSCALL_CPI_ACC_META_IS_WRITABLE
     552             : #undef VM_SYSCALL_CPI_ACC_META_IS_SIGNER
     553             : #undef VM_SYSCALL_CPI_ACC_META_PUBKEY
     554             : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS
     555             : #undef VM_SYSCALL_CPI_ACC_INFO_DATA
     556             : #undef VM_SYSCALL_CPI_ACC_INFO_METADATA
     557             : #undef VM_SYSCALL_CPI_SET_ACC_INFO_DATA_LEN
     558             : 
     559             : /**********************************************************************
     560             :    CROSS PROGRAM INVOCATION (Rust ABI)
     561             :  **********************************************************************/
     562             : 
     563             : #define VM_SYSCALL_CPI_ABI                     rust
     564         258 : #define VM_SYSCALL_CPI_INSTR_T                 fd_vm_rust_instruction_t
     565             : #define VM_SYSCALL_CPI_INSTR_ALIGN             (FD_VM_RUST_INSTRUCTION_ALIGN)
     566             : #define VM_SYSCALL_CPI_INSTR_SIZE              (FD_VM_RUST_INSTRUCTION_SIZE)
     567        1407 : #define VM_SYSCALL_CPI_ACC_META_T              fd_vm_rust_account_meta_t
     568             : #define VM_SYSCALL_CPI_ACC_META_ALIGN          (FD_VM_RUST_ACCOUNT_META_ALIGN)
     569             : #define VM_SYSCALL_CPI_ACC_META_SIZE           (FD_VM_RUST_ACCOUNT_META_SIZE)
     570         240 : #define VM_SYSCALL_CPI_ACC_INFO_T              fd_vm_rust_account_info_t
     571             : #define VM_SYSCALL_CPI_ACC_INFO_ALIGN          (FD_VM_RUST_ACCOUNT_INFO_ALIGN)
     572             : #define VM_SYSCALL_CPI_ACC_INFO_SIZE           (FD_VM_RUST_ACCOUNT_INFO_SIZE)
     573             : 
     574             : /* VM_SYSCALL_CPI_INSTR_T accessors */
     575             : #define VM_SYSCALL_CPI_INSTR_DATA_ADDR( instr ) instr->data.addr
     576         504 : #define VM_SYSCALL_CPI_INSTR_DATA_LEN( instr )  instr->data.len
     577             : #define VM_SYSCALL_CPI_INSTR_ACCS_ADDR( instr ) instr->accounts.addr
     578        1911 : #define VM_SYSCALL_CPI_INSTR_ACCS_LEN( instr )  instr->accounts.len
     579         252 : #define VM_SYSCALL_CPI_INSTR_PROGRAM_ID( vm, instr ) instr->pubkey
     580             : 
     581             : /* VM_SYSCALL_CPI_ACC_META_T accessors */
     582        2310 : #define VM_SYSCALL_CPI_ACC_META_IS_WRITABLE( acc_meta ) acc_meta->is_writable
     583        2310 : #define VM_SYSCALL_CPI_ACC_META_IS_SIGNER( acc_meta ) acc_meta->is_signer
     584        1155 : #define VM_SYSCALL_CPI_ACC_META_PUBKEY( vm, acc_meta ) acc_meta->pubkey
     585             : 
     586             : /* VM_SYSCALL_CPI_ACC_INFO_T accessors */
     587             : /* The lamports and the account data are stored behind RefCells,
     588             :    so we have an additional layer of indirection to unwrap. */
     589             : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS( vm, acc_info, decl )                                                         \
     590             :     /* Translate the pointer to the RefCell */                                                                          \
     591        1695 :     fd_vm_rc_refcell_t * FD_EXPAND_THEN_CONCAT2(decl, _box) =                                                          \
     592        1695 :       FD_VM_MEM_HADDR_ST( vm, acc_info->lamports_box_addr, FD_VM_RC_REFCELL_ALIGN, sizeof(fd_vm_rc_refcell_t) );       \
     593        1695 :     /* Translate the pointer to the underlying data */                                                                 \
     594        1695 :     ulong * decl = FD_VM_MEM_HADDR_ST( vm, FD_EXPAND_THEN_CONCAT2(decl, _box)->addr, alignof(ulong), sizeof(ulong) );
     595             : 
     596             : /* TODO: possibly define a refcell unwrapping macro to simplify this? */
     597             : #define VM_SYSCALL_CPI_ACC_INFO_DATA( vm, acc_info, decl )                                                       \
     598             :     /* Translate the pointer to the RefCell */                                                                   \
     599         768 :     fd_vm_rc_refcell_vec_t * FD_EXPAND_THEN_CONCAT2(decl, _box) =                                                \
     600         768 :       FD_VM_MEM_HADDR_ST( vm, acc_info->data_box_addr, FD_VM_RC_REFCELL_ALIGN, sizeof(fd_vm_rc_refcell_vec_t) ); \
     601         768 :     /* Declare the vm addr of the underlying data, as we sometimes need it later */                              \
     602         768 :     ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = FD_EXPAND_THEN_CONCAT2(decl, _box)->addr;                     \
     603         768 :     /* Translate the pointer to the underlying data */                                                           \
     604         768 :     uchar * decl = FD_VM_MEM_HADDR_ST(                                                                           \
     605         768 :       vm, FD_EXPAND_THEN_CONCAT2(decl, _box)->addr, alignof(uchar), FD_EXPAND_THEN_CONCAT2(decl, _box)->len );   \
     606         768 :     /* Declare the size of the underlying data */                                                                \
     607         768 :     ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = FD_EXPAND_THEN_CONCAT2(decl, _box)->len;
     608             : 
     609             : #define VM_SYSCALL_CPI_ACC_INFO_METADATA( vm, acc_info, decl )                                                   \
     610             :     /* Translate the pointer to the RefCell */                                                                   \
     611        1086 :     fd_vm_rc_refcell_vec_t * FD_EXPAND_THEN_CONCAT2(decl, _box) =                                                \
     612        1086 :       FD_VM_MEM_HADDR_ST( vm, acc_info->data_box_addr, FD_VM_RC_REFCELL_ALIGN, sizeof(fd_vm_rc_refcell_vec_t) ); \
     613        1086 :     /* Declare the vm addr of the underlying data, as we sometimes need it later */                              \
     614        1086 :     ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = FD_EXPAND_THEN_CONCAT2(decl, _box)->addr;                     \
     615        1086 :     /* Declare the size of the underlying data */                                                                \
     616        1086 :     ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = FD_EXPAND_THEN_CONCAT2(decl, _box)->len;
     617             : 
     618             : #define VM_SYSCALL_CPI_SET_ACC_INFO_DATA_LEN( vm, acc_info, decl, len_ ) \
     619           0 :   FD_EXPAND_THEN_CONCAT2(decl, _box)->len = len_;
     620             : 
     621             : #include "fd_vm_syscall_cpi_common.c"
     622             : 
     623             : #undef VM_SYSCALL_CPI_ABI
     624             : #undef VM_SYSCALL_CPI_INSTR_T
     625             : #undef VM_SYSCALL_CPI_INSTR_ALIGN
     626             : #undef VM_SYSCALL_CPI_INSTR_SIZE
     627             : #undef VM_SYSCALL_CPI_ACC_META_T
     628             : #undef VM_SYSCALL_CPI_ACC_META_ALIGN
     629             : #undef VM_SYSCALL_CPI_ACC_META_SIZE
     630             : #undef VM_SYSCALL_CPI_ACC_INFO_T
     631             : #undef VM_SYSCALL_CPI_ACC_INFO_ALIGN
     632             : #undef VM_SYSCALL_CPI_ACC_INFO_SIZE
     633             : #undef VM_SYSCALL_CPI_INSTR_DATA_ADDR
     634             : #undef VM_SYSCALL_CPI_INSTR_DATA_LEN
     635             : #undef VM_SYSCALL_CPI_INSTR_ACCS_ADDR
     636             : #undef VM_SYSCALL_CPI_INSTR_ACCS_LEN
     637             : #undef VM_SYSCALL_CPI_INSTR_PROGRAM_ID
     638             : #undef VM_SYSCALL_CPI_ACC_META_IS_WRITABLE
     639             : #undef VM_SYSCALL_CPI_ACC_META_IS_SIGNER
     640             : #undef VM_SYSCALL_CPI_ACC_META_PUBKEY
     641             : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS
     642             : #undef VM_SYSCALL_CPI_ACC_INFO_DATA
     643             : #undef VM_SYSCALL_CPI_ACC_INFO_METADATA
     644             : #undef VM_SYSCALL_CPI_SET_ACC_INFO_DATA_LEN

Generated by: LCOV version 1.14