LCOV - code coverage report
Current view: top level - flamenco/vm/syscall - fd_vm_syscall_runtime.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 317 0.0 %
Date: 2025-07-13 05:02:02 Functions: 0 11 0.0 %

          Line data    Source code
       1             : #include "fd_vm_syscall.h"
       2             : #include "../../runtime/program/fd_vote_program.h"
       3             : #include "../../runtime/sysvar/fd_sysvar.h"
       4             : #include "../../runtime/sysvar/fd_sysvar_clock.h"
       5             : #include "../../runtime/sysvar/fd_sysvar_epoch_rewards.h"
       6             : #include "../../runtime/sysvar/fd_sysvar_epoch_schedule.h"
       7             : #include "../../runtime/sysvar/fd_sysvar_rent.h"
       8             : #include "../../runtime/sysvar/fd_sysvar_last_restart_slot.h"
       9             : #include "../../runtime/context/fd_exec_txn_ctx.h"
      10             : #include "../../runtime/context/fd_exec_instr_ctx.h"
      11             : #include "../../runtime/fd_system_ids.h"
      12             : #include "fd_vm_syscall_macros.h"
      13             : 
      14             : int
      15             : fd_vm_syscall_sol_get_clock_sysvar( /**/            void *  _vm,
      16             :                                     /**/            ulong   out_vaddr,
      17             :                                     FD_PARAM_UNUSED ulong   r2,
      18             :                                     FD_PARAM_UNUSED ulong   r3,
      19             :                                     FD_PARAM_UNUSED ulong   r4,
      20             :                                     FD_PARAM_UNUSED ulong   r5,
      21           0 :                                     /**/            ulong * _ret ) {
      22           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      23             : 
      24             :   /* FIXME: In the original version of this code, there was an FD_TEST
      25             :      to check if the VM was attached to an instruction context (that
      26             :      would have crashed anyway because of pointer chasing).  If the VM
      27             :      is being run outside the Solana runtime, it should never invoke
      28             :      this syscall in the first place.  So we treat this as a SIGCALL in
      29             :      a non-crashing way. */
      30             : 
      31           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
      32           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
      33             : 
      34           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_sol_sysvar_clock_t) ) );
      35             : 
      36           0 :   fd_vm_haddr_query_t var_query = {
      37           0 :     .vaddr    = out_vaddr,
      38           0 :     .align    = FD_VM_ALIGN_RUST_SYSVAR_CLOCK,
      39           0 :     .sz       = sizeof(fd_sol_sysvar_clock_t),
      40           0 :     .is_slice = 0,
      41           0 :   };
      42             : 
      43           0 :   fd_vm_haddr_query_t * queries[] = { &var_query };
      44           0 :   FD_VM_TRANSLATE_MUT( vm, queries );
      45             : 
      46           0 :   fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->txn_ctx->funk,
      47           0 :                                                               instr_ctx->txn_ctx->funk_txn,
      48           0 :                                                               instr_ctx->txn_ctx->spad );
      49           0 :   if( FD_UNLIKELY( !clock ) ) {
      50           0 :     FD_LOG_ERR(( "failed to read sysvar clock" ));
      51           0 :   }
      52             : 
      53           0 :   memcpy( var_query.haddr, clock, sizeof(fd_sol_sysvar_clock_t) );
      54             : 
      55           0 :   *_ret = 0UL;
      56           0 :   return FD_VM_SUCCESS;
      57           0 : }
      58             : 
      59             : int
      60             : fd_vm_syscall_sol_get_epoch_schedule_sysvar( /**/            void *  _vm,
      61             :                                              /**/            ulong   out_vaddr,
      62             :                                              FD_PARAM_UNUSED ulong   r2,
      63             :                                              FD_PARAM_UNUSED ulong   r3,
      64             :                                              FD_PARAM_UNUSED ulong   r4,
      65             :                                              FD_PARAM_UNUSED ulong   r5,
      66           0 :                                              /**/            ulong * _ret ) {
      67           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      68             : 
      69             :   /* FIXME: In the original version of this code, there was an FD_TEST
      70             :      to check if the VM was attached to an instruction context (that
      71             :      would have crashed anyway because of pointer chasing).  If the VM
      72             :      is being run outside the Solana runtime, it should never invoke
      73             :      this syscall in the first place.  So we treat this as a SIGCALL in
      74             :      a non-crashing way for the time being. */
      75             : 
      76           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
      77           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
      78             : 
      79           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_epoch_schedule_t) ) );
      80             : 
      81           0 :   fd_vm_haddr_query_t var_query = {
      82           0 :     .vaddr    = out_vaddr,
      83           0 :     .align    = FD_VM_ALIGN_RUST_SYSVAR_EPOCH_SCHEDULE,
      84           0 :     .sz       = sizeof(fd_epoch_schedule_t),
      85           0 :     .is_slice = 0,
      86           0 :   };
      87             : 
      88           0 :   fd_vm_haddr_query_t * queries[] = { &var_query };
      89           0 :   FD_VM_TRANSLATE_MUT( vm, queries );
      90             : 
      91           0 :   fd_epoch_schedule_t * schedule = fd_sysvar_epoch_schedule_read( instr_ctx->txn_ctx->funk,
      92           0 :                                                                   instr_ctx->txn_ctx->funk_txn,
      93           0 :                                                                   instr_ctx->txn_ctx->spad );
      94           0 :   if( FD_UNLIKELY( schedule == NULL ) ) {
      95           0 :     FD_LOG_ERR(( "failed to read sysvar epoch schedule" ));
      96           0 :   }
      97             : 
      98           0 :   memcpy( var_query.haddr, schedule, sizeof(fd_epoch_schedule_t) );
      99             : 
     100           0 :   *_ret = 0UL;
     101           0 :   return FD_VM_SUCCESS;
     102           0 : }
     103             : 
     104             : int
     105             : fd_vm_syscall_sol_get_rent_sysvar( /**/            void *  _vm,
     106             :                                    /**/            ulong   out_vaddr,
     107             :                                    FD_PARAM_UNUSED ulong   r2,
     108             :                                    FD_PARAM_UNUSED ulong   r3,
     109             :                                    FD_PARAM_UNUSED ulong   r4,
     110             :                                    FD_PARAM_UNUSED ulong   r5,
     111           0 :                                    /**/            ulong * _ret ) {
     112           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     113             : 
     114             :   /* FIXME: In the original version of this code, there was an FD_TEST
     115             :      to check if the VM was attached to an instruction context (that
     116             :      would have crashed anyway because of pointer chasing).  If the VM
     117             :      is being run outside the Solana runtime, it should never invoke
     118             :      this syscall in the first place.  So we treat this as a SIGCALL in
     119             :      a non-crashing way for the time being. */
     120             : 
     121           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     122           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     123             : 
     124           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_rent_t) ) );
     125             : 
     126           0 :   fd_vm_haddr_query_t var_query = {
     127           0 :     .vaddr    = out_vaddr,
     128           0 :     .align    = FD_VM_ALIGN_RUST_SYSVAR_RENT,
     129           0 :     .sz       = sizeof(fd_rent_t),
     130           0 :     .is_slice = 0,
     131           0 :   };
     132             : 
     133           0 :   fd_vm_haddr_query_t * queries[] = { &var_query };
     134           0 :   FD_VM_TRANSLATE_MUT( vm, queries );
     135             : 
     136           0 :   fd_rent_t const * rent = fd_sysvar_rent_read( instr_ctx->txn_ctx->funk,
     137           0 :                                                 instr_ctx->txn_ctx->funk_txn,
     138           0 :                                                 instr_ctx->txn_ctx->spad );
     139           0 :   if( FD_UNLIKELY( !rent ) ) {
     140           0 :     FD_LOG_ERR(( "failed to read sysvar rent" ));
     141           0 :   }
     142             : 
     143           0 :   memcpy( var_query.haddr, rent, sizeof(fd_rent_t) );
     144             : 
     145           0 :   *_ret = 0UL;
     146           0 :   return FD_VM_SUCCESS;
     147           0 : }
     148             : 
     149             : /* https://github.com/anza-xyz/agave/blob/36323b6dcd3e29e4d6fe6d73d716a3f33927148b/programs/bpf_loader/src/syscalls/sysvar.rs#L144 */
     150             : int
     151             : fd_vm_syscall_sol_get_last_restart_slot_sysvar( /**/            void *  _vm,
     152             :                                                 /**/            ulong   out_vaddr,
     153             :                                                 FD_PARAM_UNUSED ulong   r2,
     154             :                                                 FD_PARAM_UNUSED ulong   r3,
     155             :                                                 FD_PARAM_UNUSED ulong   r4,
     156             :                                                 FD_PARAM_UNUSED ulong   r5,
     157           0 :                                                 /**/            ulong * _ret ) {
     158           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     159             : 
     160           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_sol_sysvar_last_restart_slot_t) ) );
     161             : 
     162           0 :   fd_vm_haddr_query_t var_query = {
     163           0 :     .vaddr    = out_vaddr,
     164           0 :     .align    = FD_VM_ALIGN_RUST_SYSVAR_LAST_RESTART_SLOT,
     165           0 :     .sz       = sizeof(fd_sol_sysvar_last_restart_slot_t),
     166           0 :     .is_slice = 0,
     167           0 :   };
     168             : 
     169           0 :   fd_vm_haddr_query_t * queries[] = { &var_query };
     170           0 :   FD_VM_TRANSLATE_MUT( vm, queries );
     171             : 
     172           0 :   fd_sol_sysvar_last_restart_slot_t * last_restart_slot = fd_sysvar_last_restart_slot_read( vm->instr_ctx->txn_ctx->funk,
     173           0 :                                                                                             vm->instr_ctx->txn_ctx->funk_txn,
     174           0 :                                                                                             vm->instr_ctx->txn_ctx->spad );
     175           0 :   if( FD_UNLIKELY( !last_restart_slot ) ) {
     176           0 :     FD_LOG_ERR(( "failed to read sysvar last restart slot" ));
     177           0 :   }
     178             : 
     179           0 :   memcpy( var_query.haddr, last_restart_slot, sizeof(fd_sol_sysvar_last_restart_slot_t) );
     180             : 
     181           0 :   *_ret = 0UL;
     182           0 :   return FD_VM_SUCCESS;
     183           0 : }
     184             : 
     185             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L167-L232 */
     186             : int
     187             : fd_vm_syscall_sol_get_sysvar( /**/            void *  _vm,
     188             :                               /**/            ulong   sysvar_id_vaddr,
     189             :                               /**/            ulong   out_vaddr,
     190             :                               /**/            ulong   offset,
     191             :                               /**/            ulong   sz,
     192             :                               FD_PARAM_UNUSED ulong   r5,
     193           0 :                               /**/            ulong * _ret ) {
     194           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     195             : 
     196             :   /* sysvar_id_cost seems to just always be 32 / 250 = 0...
     197             :      https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L190-L197 */
     198           0 :   ulong sysvar_buf_cost = sz / FD_VM_CPI_BYTES_PER_UNIT;
     199           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, fd_ulong_max( sysvar_buf_cost, FD_VM_MEM_OP_BASE_COST ) ) );
     200             : 
     201             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/sysvar.rs#L207-L211 */
     202           0 :   fd_vm_haddr_query_t var_query = {
     203           0 :     .vaddr    = out_vaddr,
     204           0 :     .align    = FD_VM_ALIGN_RUST_U8,
     205           0 :     .sz       = sz,
     206           0 :     .is_slice = 1,
     207           0 :   };
     208             : 
     209           0 :   fd_vm_haddr_query_t * queries[] = { &var_query };
     210           0 :   FD_VM_TRANSLATE_MUT( vm, queries );
     211             : 
     212             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L199-L200 */
     213           0 :   const fd_pubkey_t * sysvar_id = FD_VM_MEM_HADDR_LD( vm, sysvar_id_vaddr, FD_VM_ALIGN_RUST_PUBKEY, FD_PUBKEY_FOOTPRINT );
     214             : 
     215             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L205-L208 */
     216           0 :   ulong offset_length;
     217           0 :   int err = fd_int_if( __builtin_uaddl_overflow( offset, sz, &offset_length ), FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW, FD_EXECUTOR_INSTR_SUCCESS );
     218           0 :   if( FD_UNLIKELY( err ) ) {
     219           0 :     FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     220           0 :     return FD_VM_SYSCALL_ERR_ABORT;
     221           0 :   }
     222             : 
     223             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L210-L213
     224             :      We don't need this, we already checked we can store in out_vaddr with requested sz. */
     225             : 
     226             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L215-L221 */
     227           0 :   if( FD_UNLIKELY( memcmp( sysvar_id->uc, fd_sysvar_clock_id.uc,             FD_PUBKEY_FOOTPRINT ) &&
     228           0 :                    memcmp( sysvar_id->uc, fd_sysvar_epoch_schedule_id.uc,    FD_PUBKEY_FOOTPRINT ) &&
     229           0 :                    memcmp( sysvar_id->uc, fd_sysvar_epoch_rewards_id.uc,     FD_PUBKEY_FOOTPRINT ) &&
     230           0 :                    memcmp( sysvar_id->uc, fd_sysvar_rent_id.uc,              FD_PUBKEY_FOOTPRINT ) &&
     231           0 :                    memcmp( sysvar_id->uc, fd_sysvar_slot_hashes_id.uc,       FD_PUBKEY_FOOTPRINT ) &&
     232           0 :                    memcmp( sysvar_id->uc, fd_sysvar_stake_history_id.uc,     FD_PUBKEY_FOOTPRINT ) &&
     233           0 :                    memcmp( sysvar_id->uc, fd_sysvar_last_restart_slot_id.uc, FD_PUBKEY_FOOTPRINT ) ) ) {
     234           0 :     *_ret = 2UL;
     235           0 :     return FD_VM_SUCCESS;
     236           0 :   }
     237             : 
     238             :   /* we know that the account data won't be changed for the lifetime of this view, because sysvars don't change inter-block */
     239           0 :   FD_TXN_ACCOUNT_DECL( sysvar_account );
     240           0 :   err = fd_txn_account_init_from_funk_readonly( sysvar_account, sysvar_id, vm->instr_ctx->txn_ctx->funk, vm->instr_ctx->txn_ctx->funk_txn );
     241           0 :   if( FD_UNLIKELY( err ) ) {
     242           0 :     *_ret = 2UL;
     243           0 :     return FD_VM_SUCCESS;
     244           0 :   }
     245             : 
     246             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L223-L228
     247             :      Note the length check is at the very end to fail after performing sufficient checks. */
     248           0 :   const uchar * sysvar_buf     = sysvar_account->vt->get_data( sysvar_account );
     249           0 :   ulong         sysvar_buf_len = sysvar_account->vt->get_data_len( sysvar_account );
     250             : 
     251           0 :   if( FD_UNLIKELY( offset_length>sysvar_buf_len ) ) {
     252           0 :     *_ret = 1UL;
     253           0 :     return FD_VM_SUCCESS;
     254           0 :   }
     255             : 
     256           0 :   if( FD_UNLIKELY( sz==0UL ) ) {
     257           0 :     *_ret = 0UL;
     258           0 :     return FD_VM_SUCCESS;
     259           0 :   }
     260             : 
     261           0 :   fd_memcpy( var_query.haddr, sysvar_buf + offset, sz );
     262           0 :   *_ret = 0;
     263           0 :   return FD_VM_SUCCESS;
     264           0 : }
     265             : 
     266             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2043-L2118
     267             : 
     268             :    This syscall is meant to return the latest frozen stakes at an epoch
     269             :    boundary.  So for instance, when we are executing in epoch 7, this
     270             :    should return the stakes at the end of epoch 6.  Note that this is
     271             :    also the stakes that determined the leader schedule for the upcoming
     272             :    epoch, namely epoch 8. */
     273             : int
     274             : fd_vm_syscall_sol_get_epoch_stake( /**/            void *  _vm,
     275             :                                    /**/            ulong   var_addr,
     276             :                                    FD_PARAM_UNUSED ulong   r2,
     277             :                                    FD_PARAM_UNUSED ulong   r3,
     278             :                                    FD_PARAM_UNUSED ulong   r4,
     279             :                                    FD_PARAM_UNUSED ulong   r5,
     280           0 :                                    /**/            ulong * _ret ) {
     281           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     282             : 
     283             :   /* Var addr of 0 returns the total active stake on the cluster.
     284             : 
     285             :      https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2057-L2075 */
     286           0 :   if( FD_UNLIKELY( var_addr==0UL ) ) {
     287             :     /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2065-L2066 */
     288           0 :     FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     289             : 
     290             :     /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2074 */
     291           0 :     *_ret = fd_bank_total_epoch_stake_get( vm->instr_ctx->txn_ctx->bank );
     292           0 :     return FD_VM_SUCCESS;
     293           0 :   }
     294             : 
     295             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2083-L2091 */
     296           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_MEM_OP_BASE_COST,
     297           0 :                        fd_ulong_sat_add( FD_VM_SYSCALL_BASE_COST, FD_PUBKEY_FOOTPRINT / FD_VM_CPI_BYTES_PER_UNIT ) ) );
     298             : 
     299             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2103-L2104 */
     300           0 :   const fd_pubkey_t * vote_address = FD_VM_MEM_HADDR_LD( vm, var_addr, FD_VM_ALIGN_RUST_PUBKEY, FD_PUBKEY_FOOTPRINT );
     301             : 
     302             :   /* https://github.com/anza-xyz/agave/blob/v2.2.14/runtime/src/bank.rs#L6954 */
     303           0 :   fd_vote_accounts_global_t const * next_epoch_stakes = fd_bank_next_epoch_stakes_locking_query( vm->instr_ctx->txn_ctx->bank );
     304           0 :   *_ret = fd_query_pubkey_stake( vote_address, next_epoch_stakes );
     305           0 :   fd_bank_next_epoch_stakes_end_locking_query( vm->instr_ctx->txn_ctx->bank );
     306             : 
     307           0 :   return FD_VM_SUCCESS;
     308           0 : }
     309             : 
     310             : int
     311             : fd_vm_syscall_sol_get_stack_height( /**/            void *  _vm,
     312             :                                     FD_PARAM_UNUSED ulong   r1,
     313             :                                     FD_PARAM_UNUSED ulong   r2,
     314             :                                     FD_PARAM_UNUSED ulong   r3,
     315             :                                     FD_PARAM_UNUSED ulong   r4,
     316             :                                     FD_PARAM_UNUSED ulong   r5,
     317           0 :                                     /**/            ulong * _ret ) {
     318             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1547 */
     319           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     320             : 
     321           0 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     322             : 
     323           0 :   *_ret = vm->instr_ctx->txn_ctx->instr_stack_sz;
     324           0 :   return FD_VM_SUCCESS;
     325           0 : }
     326             : 
     327             : int
     328             : fd_vm_syscall_sol_get_return_data( /**/            void *  _vm,
     329             :                                    /**/            ulong   return_data_vaddr,
     330             :                                    /**/            ulong   sz,
     331             :                                    /**/            ulong   program_id_vaddr,
     332             :                                    FD_PARAM_UNUSED ulong   r4,
     333             :                                    FD_PARAM_UNUSED ulong   r5,
     334           0 :                                    /**/            ulong * _ret ) {
     335           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     336             : 
     337             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1465 */
     338           0 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     339             : 
     340             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1467 */
     341           0 :   fd_txn_return_data_t const * return_data = &vm->instr_ctx->txn_ctx->return_data;
     342             : 
     343             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1468 */
     344           0 :   ulong length = fd_ulong_min( return_data->len, sz );
     345             : 
     346             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1469-L1492 */
     347           0 :   if( FD_LIKELY( length ) ) {
     348             : 
     349             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1470-L1474 */
     350           0 :     FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( length, sizeof(fd_pubkey_t) ) / FD_VM_CPI_BYTES_PER_UNIT );
     351             : 
     352             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1476-L1481 */
     353           0 :     fd_vm_haddr_query_t return_data_query = {
     354           0 :       .vaddr    = return_data_vaddr,
     355           0 :       .align    = FD_VM_ALIGN_RUST_U8,
     356           0 :       .sz       = length,
     357           0 :       .is_slice = 1
     358           0 :     };
     359             : 
     360           0 :     fd_vm_haddr_query_t program_id_query = {
     361           0 :       .vaddr    = program_id_vaddr,
     362           0 :       .align    = FD_VM_ALIGN_RUST_PUBKEY,
     363           0 :       .sz       = sizeof(fd_pubkey_t),
     364           0 :       .is_slice = 0
     365           0 :     };
     366             : 
     367           0 :     fd_vm_haddr_query_t * queries[] = { &return_data_query, &program_id_query };
     368           0 :     FD_VM_TRANSLATE_MUT( vm, queries );
     369             : 
     370             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1490-L1491 */
     371           0 :     memcpy( return_data_query.haddr, return_data->data, length );
     372           0 :     memcpy( program_id_query.haddr, &return_data->program_id, sizeof(fd_pubkey_t) );
     373           0 :   }
     374             : 
     375             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1495 */
     376           0 :   *_ret = return_data->len;
     377           0 :   return FD_VM_SUCCESS;
     378           0 : }
     379             : 
     380             : int
     381             : fd_vm_syscall_sol_set_return_data( /**/            void *  _vm,
     382             :                                    /**/            ulong   src_vaddr,
     383             :                                    /**/            ulong   src_sz,
     384             :                                    FD_PARAM_UNUSED ulong   r3,
     385             :                                    FD_PARAM_UNUSED ulong   r4,
     386             :                                    FD_PARAM_UNUSED ulong   r5,
     387           0 :                                    /**/            ulong * _ret ) {
     388             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1297 */
     389           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     390             : 
     391             :   /* FIXME: In the original version of this code, there was an FD_TEST
     392             :      to check if the VM was attached to an instruction context (that
     393             :      would have crashed anyway because of pointer chasing).  If the VM
     394             :      is being run outside the Solana runtime, it should never invoke
     395             :      this syscall in the first place.  So we treat this as a SIGCALL in
     396             :      a non-crashing way for the time being. */
     397           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     398           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     399             : 
     400           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSCALL_BASE_COST, src_sz / FD_VM_CPI_BYTES_PER_UNIT ) );
     401             : 
     402             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1316 */
     403           0 :   if( FD_UNLIKELY( src_sz>FD_VM_RETURN_DATA_MAX ) ) {
     404             :     /* TODO: this is a bit annoying, we may want to unify return codes...
     405             :        - FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE is Agave's return code,
     406             :          also used for logging */
     407           0 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE );
     408           0 :     return FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE;
     409           0 :   }
     410             : 
     411             :   /* src_sz == 0 is ok */
     412           0 :   void const * src = FD_VM_MEM_SLICE_HADDR_LD( vm, src_vaddr, FD_VM_ALIGN_RUST_U8, src_sz );
     413             : 
     414             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/programs/bpf_loader/src/syscalls/mod.rs#L1480-L1484 */
     415           0 :   fd_pubkey_t const * program_id = NULL;
     416           0 :   int err = fd_exec_instr_ctx_get_last_program_key( vm->instr_ctx, &program_id );
     417           0 :   if( FD_UNLIKELY( err ) ) {
     418           0 :     FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     419           0 :     return err;
     420           0 :   }
     421             : 
     422           0 :   fd_txn_return_data_t * return_data = &instr_ctx->txn_ctx->return_data;
     423             : 
     424           0 :   return_data->len = src_sz;
     425           0 :   if( FD_LIKELY( src_sz!=0UL ) ) {
     426           0 :     fd_memcpy( return_data->data, src, src_sz );
     427           0 :   }
     428           0 :   return_data->program_id = *program_id;
     429             : 
     430           0 :   *_ret = 0;
     431           0 :   return FD_VM_SUCCESS;
     432           0 : }
     433             : 
     434             : /* Used to query and convey information about the sibling instruction
     435             :    https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L676
     436             : 
     437             :     */
     438             : struct fd_vm_syscall_processed_sibling_instruction {
     439             :   /* Length of the instruction data */
     440             :   ulong data_len;
     441             :   /* Number of accounts */
     442             :   ulong accounts_len;
     443             : };
     444             : typedef struct fd_vm_syscall_processed_sibling_instruction fd_vm_syscall_processed_sibling_instruction_t;
     445             : 
     446           0 : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE  (16UL)
     447           0 : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN (8UL )
     448             : 
     449             : /*
     450             : sol_get_last_processed_sibling_instruction returns the last element from a reverse-ordered
     451             : list of successfully processed sibling instructions: the "processed sibling instruction list".
     452             : 
     453             : For example, given the call flow:
     454             : A
     455             : B -> C -> D
     456             : B -> E
     457             : B -> F          (current execution point)
     458             : 
     459             : B's processed sibling instruction list is [A]
     460             : F's processed sibling instruction list is [E, C]
     461             : 
     462             : This allows the current instruction to know what the last processed sibling instruction was.
     463             : This is useful to check that critical preceeding instructions have actually executed: for example
     464             : ensuring that an assert instruction has successfully executed.
     465             : 
     466             : Parameters:
     467             : - index:
     468             : - result_meta_vaddr: virtual address of the object where metadata about the last processed sibling instruction will be stored upon successful execution (the length of the arrays in the result).
     469             :   Has the type solana_program::instruction::ProcessedSiblingInstruction
     470             :     https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L672-L681
     471             : - result_program_id_vaddr: virtual address where the pubkey of the program ID of the last processed sibling instruction will be stored upon successful execution
     472             : - result_data_vaddr: virtual address where the instruction data of the last processed sibling instruction will be stored upon successful execution. The length of the data will be stored in ProcessedSiblingInstruction.data_len
     473             : - result_accounts_vaddr: virtual address where an array of account meta structures will be stored into upon successful execution. The length of the data will be stored in ProcessedSiblingInstruction.accounts_len
     474             :   Each account meta has the type solana_program::instruction::AccountMeta
     475             :     https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L525-L548
     476             : 
     477             : Result:
     478             : If a processed sibling instruction is found then 1 will be written into r0, and the result_* data structures
     479             : above will be populated with the last processed sibling instruction.
     480             : If there is no processed sibling instruction, 0 will be written into r0.
     481             : 
     482             : Syscall entrypoint: https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1402
     483             : */
     484             : int
     485             : fd_vm_syscall_sol_get_processed_sibling_instruction(
     486             :     void * _vm,
     487             :     ulong index,
     488             :     ulong result_meta_vaddr,
     489             :     ulong result_program_id_vaddr,
     490             :     ulong result_data_vaddr,
     491             :     ulong result_accounts_vaddr,
     492             :     ulong * ret
     493           0 : ) {
     494             : 
     495           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     496             : 
     497             :   /* Consume base compute cost
     498             :      https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1513 */
     499           0 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     500             : 
     501             :   /*
     502             :     Get the current instruction stack height. This value is 1-indexed (top level instrution has a stack height
     503             :     of 1).
     504             :     https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1517 */
     505           0 :   ulong stack_height = vm->instr_ctx->txn_ctx->instr_stack_sz;
     506             : 
     507             :   /* Reverse iterate through the instruction trace, ignoring anything except instructions on the same level.
     508             :      https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1518-L1522 */
     509           0 :   ulong instruction_trace_length = vm->instr_ctx->txn_ctx->instr_trace_length;
     510           0 :   ulong reverse_index_at_stack_height = 0UL;
     511           0 :   fd_exec_instr_trace_entry_t * found_instruction_context = NULL;
     512           0 :   for( ulong index_in_trace=instruction_trace_length; index_in_trace>0UL; index_in_trace-- ) {
     513             : 
     514             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1524-L1526
     515             :        This error can never happen */
     516             : 
     517             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1527-L1529 */
     518           0 :     fd_exec_instr_trace_entry_t * instruction_context = &vm->instr_ctx->txn_ctx->instr_trace[ index_in_trace-1UL ];
     519           0 :     if( FD_LIKELY( instruction_context->stack_height<stack_height ) ) {
     520           0 :       break;
     521           0 :     }
     522             : 
     523             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1530-L1536 */
     524           0 :     if( FD_UNLIKELY( instruction_context->stack_height==stack_height ) ) {
     525           0 :       if( FD_UNLIKELY( fd_ulong_sat_add( index, 1UL )==reverse_index_at_stack_height ) ) {
     526           0 :         found_instruction_context = instruction_context;
     527           0 :         break;
     528           0 :       }
     529           0 :       reverse_index_at_stack_height = fd_ulong_sat_add( reverse_index_at_stack_height, 1UL );
     530           0 :     }
     531           0 :   }
     532             : 
     533             :   /* If we have found an entry, then copy the instruction into the result addresses
     534             :      https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1440-L1533
     535             :    */
     536           0 :   if( FD_LIKELY( found_instruction_context != NULL ) ) {
     537           0 :     fd_instr_info_t * instr_info = found_instruction_context->instr_info;
     538             : 
     539           0 :     fd_vm_haddr_query_t result_header_query = {
     540           0 :       .vaddr    = result_meta_vaddr,
     541           0 :       .align    = FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN,
     542           0 :       .sz       = FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
     543           0 :       .is_slice = 0,
     544           0 :     };
     545             : 
     546           0 :     fd_vm_haddr_query_t * queries[] = { &result_header_query };
     547           0 :     FD_VM_TRANSLATE_MUT( vm, queries );
     548             : 
     549           0 :     fd_vm_syscall_processed_sibling_instruction_t * result_header = result_header_query.haddr;
     550             : 
     551             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1546-L1583 */
     552           0 :     if( result_header->data_len==instr_info->data_sz && result_header->accounts_len==instr_info->acct_cnt ) {
     553           0 :       fd_vm_haddr_query_t program_id_query = {
     554           0 :         .vaddr    = result_program_id_vaddr,
     555           0 :         .align    = FD_VM_ALIGN_RUST_PUBKEY,
     556           0 :         .sz       = sizeof(fd_pubkey_t),
     557           0 :         .is_slice = 0,
     558           0 :       };
     559             : 
     560           0 :       fd_vm_haddr_query_t data_query = {
     561           0 :         .vaddr    = result_data_vaddr,
     562           0 :         .align    = FD_VM_ALIGN_RUST_U8,
     563           0 :         .sz       = result_header->data_len,
     564           0 :         .is_slice = 1,
     565           0 :       };
     566             : 
     567           0 :       fd_vm_haddr_query_t accounts_query = {
     568           0 :         .vaddr    = result_accounts_vaddr,
     569           0 :         .align    = FD_VM_RUST_ACCOUNT_META_ALIGN,
     570           0 :         .sz       = fd_ulong_sat_mul( result_header->accounts_len, FD_VM_RUST_ACCOUNT_META_SIZE ),
     571           0 :         .is_slice = 1,
     572           0 :       };
     573             : 
     574           0 :       fd_vm_haddr_query_t * queries[] = { &program_id_query, &data_query, &accounts_query, &result_header_query };
     575           0 :       FD_VM_TRANSLATE_MUT( vm, queries );
     576             : 
     577           0 :       fd_pubkey_t *               program_id = program_id_query.haddr;
     578           0 :       uchar *                     data       = data_query.haddr;
     579           0 :       fd_vm_rust_account_meta_t * accounts   = accounts_query.haddr;
     580             : 
     581             :       /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1561-L1562 */
     582           0 :       fd_pubkey_t const * instr_ctx_program_id = NULL;
     583           0 :       int err = fd_exec_txn_ctx_get_key_of_account_at_index( vm->instr_ctx->txn_ctx,
     584           0 :                                                              instr_info->program_id,
     585           0 :                                                              &instr_ctx_program_id );
     586           0 :       if( FD_UNLIKELY( err ) ) {
     587           0 :         FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     588           0 :         return err;
     589           0 :       }
     590           0 :       fd_memcpy( program_id, instr_ctx_program_id, sizeof(fd_pubkey_t) );
     591             : 
     592             :       /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1563 */
     593           0 :       fd_memcpy( data, instr_info->data, instr_info->data_sz );
     594             : 
     595             :       /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1564-L1581 */
     596           0 :       for( ushort i=0; i<instr_info->acct_cnt; i++ ) {
     597           0 :         fd_pubkey_t const * account_key;
     598           0 :         ushort txn_idx = instr_info->accounts[ i ].index_in_transaction;
     599           0 :         err            = fd_exec_txn_ctx_get_key_of_account_at_index( vm->instr_ctx->txn_ctx, txn_idx, &account_key );
     600           0 :         if( FD_UNLIKELY( err ) ) {
     601           0 :           FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     602           0 :           return err;
     603           0 :         }
     604             : 
     605           0 :         fd_memcpy( accounts[ i ].pubkey, account_key, sizeof(fd_pubkey_t) );
     606           0 :         accounts[ i ].is_signer   = !!(instr_info->accounts[ i ].is_signer );
     607           0 :         accounts[ i ].is_writable = !!(instr_info->accounts[ i ].is_writable );
     608           0 :       }
     609           0 :     } else {
     610             :       /* Copy the actual metadata into the result meta struct
     611             :          https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1584-L1586 */
     612           0 :       result_header->data_len     = instr_info->data_sz;
     613           0 :       result_header->accounts_len = instr_info->acct_cnt;
     614           0 :     }
     615             : 
     616             :     /* Return true as we found a sibling instruction
     617             :        https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1588 */
     618           0 :     *ret = 1UL;
     619           0 :     return FD_VM_SUCCESS;
     620           0 :   }
     621             : 
     622             :   /* Return false if we didn't find a sibling instruction
     623             :      https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1590 */
     624           0 :   *ret = 0UL;
     625           0 :   return FD_VM_SUCCESS;
     626           0 : }
     627             : 
     628             : // https://github.com/anza-xyz/agave/blob/master/programs/bpf_loader/src/syscalls/sysvar.rs#L75
     629             : int
     630             : fd_vm_syscall_sol_get_epoch_rewards_sysvar( /**/            void *  _vm,
     631             :                                             /**/            ulong   out_vaddr,
     632             :                                             FD_PARAM_UNUSED ulong   r2,
     633             :                                             FD_PARAM_UNUSED ulong   r3,
     634             :                                             FD_PARAM_UNUSED ulong   r4,
     635             :                                             FD_PARAM_UNUSED ulong   r5,
     636           0 :                                             /**/            ulong * _ret ) {
     637           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     638             : 
     639           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     640           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     641             : 
     642           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_sysvar_epoch_rewards_t) ) );
     643             : 
     644           0 :   void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_EPOCH_REWARDS, sizeof(fd_sysvar_epoch_rewards_t) );
     645             : 
     646           0 :   fd_sysvar_epoch_rewards_t const * epoch_rewards = fd_sysvar_epoch_rewards_read( instr_ctx->txn_ctx->funk,
     647           0 :                                                                                   instr_ctx->txn_ctx->funk_txn,
     648           0 :                                                                                   instr_ctx->txn_ctx->spad );
     649           0 :   if( FD_UNLIKELY( !epoch_rewards ) ) {
     650           0 :     FD_LOG_ERR(( "failed to read sysvar epoch rewards" ));
     651           0 :   }
     652             : 
     653           0 :   memcpy( out, epoch_rewards, sizeof(fd_sysvar_epoch_rewards_t) );
     654             : 
     655           0 :   *_ret = 0UL;
     656           0 :   return FD_VM_SUCCESS;
     657           0 : }

Generated by: LCOV version 1.14