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 273 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 12 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_fees.h"
       8             : #include "../../runtime/sysvar/fd_sysvar_rent.h"
       9             : #include "../../runtime/sysvar/fd_sysvar_last_restart_slot.h"
      10             : #include "../../runtime/context/fd_exec_txn_ctx.h"
      11             : #include "../../runtime/context/fd_exec_instr_ctx.h"
      12             : #include "../../runtime/fd_system_ids.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, FD_SOL_SYSVAR_CLOCK_FOOTPRINT ) );
      35             : 
      36           0 :   void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_CLOCK, FD_SOL_SYSVAR_CLOCK_FOOTPRINT );
      37             : 
      38             :   /* FIXME: is it possible to do the read in-place? */
      39           0 :   fd_sol_sysvar_clock_t clock[1];
      40           0 :   fd_sol_sysvar_clock_new( clock ); /* FIXME: probably should be init as not a distributed persistent object */
      41           0 :   fd_sysvar_clock_read( clock,
      42           0 :                         instr_ctx->txn_ctx->sysvar_cache,
      43           0 :                         instr_ctx->txn_ctx->acc_mgr,
      44           0 :                         instr_ctx->txn_ctx->funk_txn );
      45             :   /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
      46             : 
      47           0 :   memcpy( out, clock, FD_SOL_SYSVAR_CLOCK_FOOTPRINT );
      48             : 
      49           0 :   *_ret = 0UL;
      50           0 :   return FD_VM_SUCCESS;
      51           0 : }
      52             : 
      53             : int
      54             : fd_vm_syscall_sol_get_epoch_schedule_sysvar( /**/            void *  _vm,
      55             :                                              /**/            ulong   out_vaddr,
      56             :                                              FD_PARAM_UNUSED ulong   r2,
      57             :                                              FD_PARAM_UNUSED ulong   r3,
      58             :                                              FD_PARAM_UNUSED ulong   r4,
      59             :                                              FD_PARAM_UNUSED ulong   r5,
      60           0 :                                              /**/            ulong * _ret ) {
      61           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      62             : 
      63             :   /* FIXME: In the original version of this code, there was an FD_TEST
      64             :      to check if the VM was attached to an instruction context (that
      65             :      would have crashed anyway because of pointer chasing).  If the VM
      66             :      is being run outside the Solana runtime, it should never invoke
      67             :      this syscall in the first place.  So we treat this as a SIGCALL in
      68             :      a non-crashing way for the time being. */
      69             : 
      70           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
      71           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
      72             : 
      73           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_EPOCH_SCHEDULE_FOOTPRINT ) );
      74             : 
      75           0 :   void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_EPOCH_SCHEDULE, FD_EPOCH_SCHEDULE_FOOTPRINT );
      76             : 
      77             :   /* FIXME: is it possible to do the read in-place? */
      78           0 :   fd_epoch_schedule_t schedule[1];
      79           0 :   fd_epoch_schedule_new( schedule ); /* FIXME: probably should be init as not a distributed persistent object */
      80           0 :   fd_sysvar_epoch_schedule_read( schedule,
      81           0 :                                  instr_ctx->txn_ctx->sysvar_cache,
      82           0 :                                  instr_ctx->txn_ctx->acc_mgr,
      83           0 :                                  instr_ctx->txn_ctx->funk_txn );
      84             :   /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
      85             : 
      86           0 :   memcpy( out, schedule, FD_EPOCH_SCHEDULE_FOOTPRINT );
      87             : 
      88           0 :   *_ret = 0UL;
      89           0 :   return FD_VM_SUCCESS;
      90           0 : }
      91             : 
      92             : int
      93             : fd_vm_syscall_sol_get_fees_sysvar( /**/            void *  _vm,
      94             :                                    /**/            ulong   out_vaddr,
      95             :                                    FD_PARAM_UNUSED ulong   r2,
      96             :                                    FD_PARAM_UNUSED ulong   r3,
      97             :                                    FD_PARAM_UNUSED ulong   r4,
      98             :                                    FD_PARAM_UNUSED ulong   r5,
      99           0 :                                    /**/            ulong * _ret ) {
     100           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     101             : 
     102             :   /* FIXME: In the original version of this code, there was an FD_TEST
     103             :      to check if the VM was attached to an instruction context (that
     104             :      would have crashed anyway because of pointer chasing).  If the VM
     105             :      is being run outside the Solana runtime, it should never invoke
     106             :      this syscall in the first place.  So we treat this as a SIGCALL in
     107             :      a non-crashing way for the time being. */
     108             : 
     109           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     110           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     111             : 
     112           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_SYSVAR_FEES_FOOTPRINT ) );
     113             : 
     114           0 :   void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_FEES, FD_SYSVAR_FEES_FOOTPRINT );
     115             : 
     116             :   /* FIXME: is it possible to do the read in-place? */
     117           0 :   fd_sysvar_fees_t fees[1];
     118           0 :   fd_sysvar_fees_new( fees ); /* FIXME: probably should be init as not a distributed persistent object */
     119           0 :   fd_sysvar_fees_read( fees,
     120           0 :                        instr_ctx->txn_ctx->sysvar_cache,
     121           0 :                        instr_ctx->txn_ctx->acc_mgr,
     122           0 :                        instr_ctx->txn_ctx->funk_txn );
     123             :   /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
     124             : 
     125           0 :   memcpy( out, fees, FD_SYSVAR_FEES_FOOTPRINT );
     126             : 
     127           0 :   *_ret = 0UL;
     128           0 :   return FD_VM_SUCCESS;
     129           0 : }
     130             : 
     131             : int
     132             : fd_vm_syscall_sol_get_rent_sysvar( /**/            void *  _vm,
     133             :                                    /**/            ulong   out_vaddr,
     134             :                                    FD_PARAM_UNUSED ulong   r2,
     135             :                                    FD_PARAM_UNUSED ulong   r3,
     136             :                                    FD_PARAM_UNUSED ulong   r4,
     137             :                                    FD_PARAM_UNUSED ulong   r5,
     138           0 :                                    /**/            ulong * _ret ) {
     139           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     140             : 
     141             :   /* FIXME: In the original version of this code, there was an FD_TEST
     142             :      to check if the VM was attached to an instruction context (that
     143             :      would have crashed anyway because of pointer chasing).  If the VM
     144             :      is being run outside the Solana runtime, it should never invoke
     145             :      this syscall in the first place.  So we treat this as a SIGCALL in
     146             :      a non-crashing way for the time being. */
     147             : 
     148           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     149           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     150             : 
     151           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_RENT_FOOTPRINT ) );
     152             : 
     153           0 :   void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_RENT, FD_RENT_FOOTPRINT );
     154             : 
     155             :   /* FIXME: is it possible to do the read in-place? */
     156           0 :   fd_rent_t * rent = fd_sysvar_rent_read( instr_ctx->txn_ctx->sysvar_cache,
     157           0 :                                           instr_ctx->txn_ctx->acc_mgr,
     158           0 :                                           instr_ctx->txn_ctx->funk_txn,
     159           0 :                                           instr_ctx->txn_ctx->spad );
     160             :   /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
     161             : 
     162           0 :   memcpy( out, rent, FD_RENT_FOOTPRINT );
     163             : 
     164           0 :   *_ret = 0UL;
     165           0 :   return FD_VM_SUCCESS;
     166           0 : }
     167             : 
     168             : /* https://github.com/anza-xyz/agave/blob/36323b6dcd3e29e4d6fe6d73d716a3f33927148b/programs/bpf_loader/src/syscalls/sysvar.rs#L144 */
     169             : int
     170             : fd_vm_syscall_sol_get_last_restart_slot_sysvar( /**/            void *  _vm,
     171             :                                                 /**/            ulong   out_vaddr,
     172             :                                                 FD_PARAM_UNUSED ulong   r2,
     173             :                                                 FD_PARAM_UNUSED ulong   r3,
     174             :                                                 FD_PARAM_UNUSED ulong   r4,
     175             :                                                 FD_PARAM_UNUSED ulong   r5,
     176           0 :                                                 /**/            ulong * _ret ) {
     177           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     178             : 
     179           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_SOL_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT ) );
     180             : 
     181           0 :   fd_sol_sysvar_last_restart_slot_t * out =
     182           0 :     FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_LAST_RESTART_SLOT, FD_SOL_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT );
     183           0 :   if( FD_UNLIKELY( fd_sysvar_last_restart_slot_read( out,
     184           0 :                                                      vm->instr_ctx->txn_ctx->sysvar_cache,
     185           0 :                                                      vm->instr_ctx->txn_ctx->acc_mgr,
     186           0 :                                                      vm->instr_ctx->txn_ctx->funk_txn ) == NULL ) ) {
     187           0 :     return FD_VM_SYSCALL_ERR_ABORT;
     188           0 :   }
     189             : 
     190           0 :   *_ret = 0UL;
     191           0 :   return FD_VM_SUCCESS;
     192           0 : }
     193             : 
     194             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L167-L232 */
     195             : int
     196             : fd_vm_syscall_sol_get_sysvar( /**/            void *  _vm,
     197             :                               /**/            ulong   sysvar_id_vaddr,
     198             :                               /**/            ulong   out_vaddr,
     199             :                               /**/            ulong   offset,
     200             :                               /**/            ulong   sz,
     201             :                               FD_PARAM_UNUSED ulong   r5,
     202           0 :                               /**/            ulong * _ret ) {
     203           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     204             : 
     205             :   /* sysvar_id_cost seems to just always be 32 / 250 = 0...
     206             :      https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L190-L197 */
     207           0 :   ulong sysvar_buf_cost = sz / FD_VM_CPI_BYTES_PER_UNIT;
     208           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 ) ) );
     209             : 
     210             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L199-L200 */
     211           0 :   const fd_pubkey_t * sysvar_id = FD_VM_MEM_HADDR_LD( vm, sysvar_id_vaddr, FD_VM_ALIGN_RUST_PUBKEY, FD_PUBKEY_FOOTPRINT );
     212             : 
     213             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L202-L203 */
     214           0 :   void * out_haddr = FD_VM_MEM_SLICE_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_U8, sz );
     215             : 
     216             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L205-L208 */
     217           0 :   ulong offset_length;
     218           0 :   int err = fd_int_if( __builtin_uaddl_overflow( offset, sz, &offset_length ), FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW, FD_EXECUTOR_INSTR_SUCCESS );
     219           0 :   if( FD_UNLIKELY( err ) ) {
     220           0 :     FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     221           0 :     return FD_VM_SYSCALL_ERR_ABORT;
     222           0 :   }
     223             : 
     224             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L210-L213
     225             :      We don't need this, we already checked we can store in out_vaddr with requested sz. */
     226             : 
     227             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L215-L221 */
     228           0 :   if( FD_UNLIKELY( memcmp( sysvar_id->uc, fd_sysvar_clock_id.uc,             FD_PUBKEY_FOOTPRINT ) &&
     229           0 :                    memcmp( sysvar_id->uc, fd_sysvar_epoch_schedule_id.uc,    FD_PUBKEY_FOOTPRINT ) &&
     230           0 :                    memcmp( sysvar_id->uc, fd_sysvar_epoch_rewards_id.uc,     FD_PUBKEY_FOOTPRINT ) &&
     231           0 :                    memcmp( sysvar_id->uc, fd_sysvar_rent_id.uc,              FD_PUBKEY_FOOTPRINT ) &&
     232           0 :                    memcmp( sysvar_id->uc, fd_sysvar_slot_hashes_id.uc,       FD_PUBKEY_FOOTPRINT ) &&
     233           0 :                    memcmp( sysvar_id->uc, fd_sysvar_stake_history_id.uc,     FD_PUBKEY_FOOTPRINT ) &&
     234           0 :                    memcmp( sysvar_id->uc, fd_sysvar_last_restart_slot_id.uc, FD_PUBKEY_FOOTPRINT ) ) ) {
     235           0 :     *_ret = 2UL;
     236           0 :     return FD_VM_SUCCESS;
     237           0 :   }
     238             : 
     239           0 :   FD_TXN_ACCOUNT_DECL( sysvar_account );
     240           0 :   err = fd_acc_mgr_view( vm->instr_ctx->txn_ctx->acc_mgr, vm->instr_ctx->txn_ctx->funk_txn, sysvar_id, sysvar_account );
     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->const_data;
     249           0 :   ulong         sysvar_buf_len = sysvar_account->const_meta->dlen;
     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( out_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             : int
     268             : fd_vm_syscall_sol_get_epoch_stake( /**/            void *  _vm,
     269             :                                    /**/            ulong   var_addr,
     270             :                                    FD_PARAM_UNUSED ulong   r2,
     271             :                                    FD_PARAM_UNUSED ulong   r3,
     272             :                                    FD_PARAM_UNUSED ulong   r4,
     273             :                                    FD_PARAM_UNUSED ulong   r5,
     274           0 :                                    /**/            ulong * _ret ) {
     275           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     276             : 
     277             :   /* Var addr of 0 returns the total active stake on the cluster.
     278             : 
     279             :      https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2057-L2075 */
     280           0 :   if( FD_UNLIKELY( var_addr==0UL ) ) {
     281             :     /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2065-L2066 */
     282           0 :     FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     283             : 
     284             :     /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2074 */
     285           0 :     *_ret = vm->instr_ctx->txn_ctx->total_epoch_stake;
     286           0 :     return FD_VM_SUCCESS;
     287           0 :   }
     288             : 
     289             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2083-L2091 */
     290           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_MEM_OP_BASE_COST,
     291           0 :                        fd_ulong_sat_add( FD_VM_SYSCALL_BASE_COST, FD_PUBKEY_FOOTPRINT / FD_VM_CPI_BYTES_PER_UNIT ) ) );
     292             : 
     293             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2103-L2104 */
     294           0 :   const fd_pubkey_t * vote_address = FD_VM_MEM_HADDR_LD( vm, var_addr, FD_VM_ALIGN_RUST_PUBKEY, FD_PUBKEY_FOOTPRINT );
     295           0 :   *_ret = fd_query_pubkey_stake( vote_address, &vm->instr_ctx->txn_ctx->stakes.vote_accounts );
     296             : 
     297           0 :   return FD_VM_SUCCESS;
     298           0 : }
     299             : 
     300             : int
     301             : fd_vm_syscall_sol_get_stack_height( /**/            void *  _vm,
     302             :                                     FD_PARAM_UNUSED ulong   r1,
     303             :                                     FD_PARAM_UNUSED ulong   r2,
     304             :                                     FD_PARAM_UNUSED ulong   r3,
     305             :                                     FD_PARAM_UNUSED ulong   r4,
     306             :                                     FD_PARAM_UNUSED ulong   r5,
     307           0 :                                     /**/            ulong * _ret ) {
     308             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1547 */
     309           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     310             : 
     311           0 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     312             : 
     313           0 :   *_ret = vm->instr_ctx->txn_ctx->instr_stack_sz;
     314           0 :   return FD_VM_SUCCESS;
     315           0 : }
     316             : 
     317             : int
     318             : fd_vm_syscall_sol_get_return_data( /**/            void *  _vm,
     319             :                                    /**/            ulong   dst_vaddr,
     320             :                                    /**/            ulong   dst_max,
     321             :                                    /**/            ulong   program_id_vaddr,
     322             :                                    FD_PARAM_UNUSED ulong   r4,
     323             :                                    FD_PARAM_UNUSED ulong   r5,
     324           0 :                                    /**/            ulong * _ret ) {
     325             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1345 */
     326           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     327             : 
     328           0 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     329             : 
     330             :   /* FIXME: In the original version of this code, there was an FD_TEST
     331             :      to check if the VM was attached to an instruction context (that
     332             :      would have crashed anyway because of pointer chasing).  If the VM
     333             :      is being run outside the Solana runtime, it should never invoke
     334             :      this syscall in the first place.  So we treat this as a SIGCALL in
     335             :      a non-crashing way for the time being. */
     336           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     337           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     338             : 
     339           0 :   fd_txn_return_data_t const * return_data    = &instr_ctx->txn_ctx->return_data;
     340           0 :   ulong                        return_data_sz = return_data->len;
     341             : 
     342           0 :   ulong cpy_sz = fd_ulong_min( return_data_sz, dst_max );
     343             : 
     344           0 :   if( FD_LIKELY( cpy_sz ) ) {
     345             : 
     346           0 :     FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( cpy_sz, sizeof(fd_pubkey_t) ) / FD_VM_CPI_BYTES_PER_UNIT );
     347             : 
     348           0 :     void * dst        = FD_VM_MEM_SLICE_HADDR_ST( vm, dst_vaddr, FD_VM_ALIGN_RUST_U8, cpy_sz );
     349             : 
     350           0 :     memcpy( dst,         return_data->data,       cpy_sz              );
     351             : 
     352             :     /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1376-L1381
     353             :        These can never happen. */
     354             : 
     355           0 :     void * program_id = FD_VM_MEM_HADDR_ST( vm, program_id_vaddr, FD_VM_ALIGN_RUST_PUBKEY, sizeof(fd_pubkey_t) );
     356             : 
     357           0 :     FD_VM_MEM_CHECK_NON_OVERLAPPING( vm, (ulong)dst, cpy_sz, (ulong)program_id, sizeof(fd_pubkey_t) );
     358             : 
     359           0 :     memcpy( program_id, &return_data->program_id, sizeof(fd_pubkey_t) );
     360           0 :   }
     361             : 
     362           0 :   *_ret = return_data_sz;
     363           0 :   return FD_VM_SUCCESS;
     364           0 : }
     365             : 
     366             : int
     367             : fd_vm_syscall_sol_set_return_data( /**/            void *  _vm,
     368             :                                    /**/            ulong   src_vaddr,
     369             :                                    /**/            ulong   src_sz,
     370             :                                    FD_PARAM_UNUSED ulong   r3,
     371             :                                    FD_PARAM_UNUSED ulong   r4,
     372             :                                    FD_PARAM_UNUSED ulong   r5,
     373           0 :                                    /**/            ulong * _ret ) {
     374             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1297 */
     375           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     376             : 
     377             :   /* FIXME: In the original version of this code, there was an FD_TEST
     378             :      to check if the VM was attached to an instruction context (that
     379             :      would have crashed anyway because of pointer chasing).  If the VM
     380             :      is being run outside the Solana runtime, it should never invoke
     381             :      this syscall in the first place.  So we treat this as a SIGCALL in
     382             :      a non-crashing way for the time being. */
     383           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     384           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     385             : 
     386           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSCALL_BASE_COST, src_sz / FD_VM_CPI_BYTES_PER_UNIT ) );
     387             : 
     388             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1316 */
     389           0 :   if( FD_UNLIKELY( src_sz>FD_VM_RETURN_DATA_MAX ) ) {
     390             :     /* TODO: this is a bit annoying, we may want to unify return codes...
     391             :        - FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE is Agave's return code,
     392             :          also used for logging */
     393           0 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE );
     394           0 :     return FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE;
     395           0 :   }
     396             : 
     397             :   /* src_sz == 0 is ok */
     398           0 :   void const * src = FD_VM_MEM_SLICE_HADDR_LD( vm, src_vaddr, FD_VM_ALIGN_RUST_U8, src_sz );
     399             : 
     400           0 :   fd_pubkey_t const    * program_id  = &instr_ctx->instr->program_id_pubkey;
     401           0 :   fd_txn_return_data_t * return_data = &instr_ctx->txn_ctx->return_data;
     402             : 
     403           0 :   return_data->len = src_sz;
     404           0 :   if( FD_LIKELY( src_sz!=0UL ) ) {
     405           0 :     fd_memcpy( return_data->data, src, src_sz );
     406           0 :   }
     407           0 :   memcpy( &return_data->program_id, program_id, sizeof(fd_pubkey_t) );
     408             : 
     409           0 :   *_ret = 0;
     410           0 :   return FD_VM_SUCCESS;
     411           0 : }
     412             : 
     413             : /* Used to query and convey information about the sibling instruction
     414             :    https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L676
     415             : 
     416             :     */
     417             : struct fd_vm_syscall_processed_sibling_instruction {
     418             :   /* Length of the instruction data */
     419             :   ulong data_len;
     420             :   /* Number of accounts */
     421             :   ulong accounts_len;
     422             : };
     423             : typedef struct fd_vm_syscall_processed_sibling_instruction fd_vm_syscall_processed_sibling_instruction_t;
     424             : 
     425             : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE  (16UL)
     426             : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN (8UL )
     427             : 
     428             : /*
     429             : sol_get_last_processed_sibling_instruction returns the last element from a reverse-ordered
     430             : list of successfully processed sibling instructions: the "processed sibling instruction list".
     431             : 
     432             : For example, given the call flow:
     433             : A
     434             : B -> C -> D
     435             : B
     436             : B -> F          (current execution point)
     437             : 
     438             : B's processed sibling instruction list is [A]
     439             : F's processed sibling instruction list is [E, C]
     440             : 
     441             : This allows the current instruction to know what the last processed sibling instruction was.
     442             : This is useful to check that critical preceeding instructions have actually executed: for example
     443             : ensuring that an assert instruction has successfully executed.
     444             : 
     445             : Parameters:
     446             : - index:
     447             : - 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).
     448             :   Has the type solana_program::instruction::ProcessedSiblingInstruction
     449             :     https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L672-L681
     450             : - 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
     451             : - 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
     452             : - 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
     453             :   Each account meta has the type solana_program::instruction::AccountMeta
     454             :     https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L525-L548
     455             : 
     456             : Result:
     457             : If a processed sibling instruction is found then 1 will be written into r0, and the result_* data structures
     458             : above will be populated with the last processed sibling instruction.
     459             : If there is no processed sibling instruction, 0 will be written into r0.
     460             : 
     461             : Syscall entrypoint: https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1402
     462             : */
     463             : int
     464             : fd_vm_syscall_sol_get_processed_sibling_instruction(
     465             :     void * _vm,
     466             :     ulong index,
     467             :     ulong result_meta_vaddr,
     468             :     ulong result_program_id_vaddr,
     469             :     ulong result_data_vaddr,
     470             :     ulong result_accounts_vaddr,
     471             :     ulong * ret
     472           0 : ) {
     473             : 
     474           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     475             : 
     476             :   /* Consume base compute cost
     477             :      https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1414 */
     478           0 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     479             : 
     480             :   /*
     481             :     Get the current instruction stack height.
     482             : 
     483             :     Top-level instructions in Agave's invocation stack have a depth of 1
     484             :     https://github.com/anza-xyz/agave/blob/d87e23d8d91c32d5f2be2bb3557c730bee1e9434/sdk/program/src/instruction.rs#L732-L733
     485             :     Ours have a depth of 0, so we need to add 1 to account for the difference
     486             :    */
     487           0 :   ulong stack_height = fd_ulong_sat_add( vm->instr_ctx->depth, 1UL );
     488             : 
     489             :   /* Reverse iterate through the instruction trace, ignoring anything except instructions on the same level.
     490             :   https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1422 */
     491           0 :   ulong instruction_trace_length = vm->instr_ctx->txn_ctx->instr_trace_length;
     492           0 :   ulong reverse_index_at_stack_height = 0UL;
     493           0 :   fd_exec_instr_trace_entry_t * trace_entry = NULL;
     494           0 :   for( ulong index_in_trace = instruction_trace_length; index_in_trace > 0UL; index_in_trace-- ) {
     495             : 
     496             :     /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1432-L1434
     497             :        This error can never happen */
     498             : 
     499           0 :     fd_exec_instr_trace_entry_t * candidate_trace_entry = &vm->instr_ctx->txn_ctx->instr_trace[ index_in_trace - 1UL ];
     500           0 :     if( FD_LIKELY( candidate_trace_entry->stack_height < stack_height ) ) {
     501           0 :       break;
     502           0 :     }
     503             : 
     504           0 :     if( FD_UNLIKELY( candidate_trace_entry->stack_height == stack_height ) ) {
     505           0 :       if( FD_UNLIKELY( fd_ulong_sat_add( index, 1UL ) == reverse_index_at_stack_height ) ) {
     506           0 :         trace_entry = candidate_trace_entry;
     507           0 :         break;
     508           0 :       }
     509           0 :       reverse_index_at_stack_height = fd_ulong_sat_add( reverse_index_at_stack_height, 1UL );
     510           0 :     }
     511           0 :   }
     512             : 
     513             :   /* If we have found an entry, then copy the instruction into the result addresses
     514             :      https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1440-L1533
     515             :    */
     516           0 :   if( FD_LIKELY( trace_entry != NULL ) ) {
     517           0 :     fd_instr_info_t * instr_info = trace_entry->instr_info;
     518             : 
     519           0 :     fd_vm_syscall_processed_sibling_instruction_t * result_meta_haddr = FD_VM_MEM_HADDR_ST(
     520           0 :       vm,
     521           0 :       result_meta_vaddr,
     522           0 :       FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN,
     523           0 :       FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE );
     524             : 
     525             :     /* https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1447 */
     526           0 :     if( ( result_meta_haddr->data_len == trace_entry->instr_info->data_sz ) &&
     527           0 :         ( result_meta_haddr->accounts_len == trace_entry->instr_info->acct_cnt ) ) {
     528             : 
     529           0 :       fd_pubkey_t * result_program_id_haddr = FD_VM_MEM_HADDR_ST(
     530           0 :         vm,
     531           0 :         result_program_id_vaddr,
     532           0 :         FD_VM_ALIGN_RUST_PUBKEY,
     533           0 :         sizeof(fd_pubkey_t) );
     534             : 
     535           0 :       uchar * result_data_haddr = FD_VM_MEM_SLICE_HADDR_ST(
     536           0 :         vm,
     537           0 :         result_data_vaddr,
     538           0 :         FD_VM_ALIGN_RUST_U8,
     539           0 :         result_meta_haddr->data_len);
     540             : 
     541           0 :       ulong accounts_meta_total_size = fd_ulong_sat_mul( result_meta_haddr->accounts_len, FD_VM_RUST_ACCOUNT_META_SIZE );
     542           0 :       fd_vm_rust_account_meta_t * result_accounts_haddr = FD_VM_MEM_SLICE_HADDR_ST(
     543           0 :         vm,
     544           0 :         result_accounts_vaddr,
     545           0 :         FD_VM_RUST_ACCOUNT_META_ALIGN,
     546           0 :         accounts_meta_total_size);
     547             : 
     548             :       /* Check for memory overlaps
     549             :          https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1469 */
     550             : 
     551           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     552           0 :         (ulong)result_meta_haddr, FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
     553           0 :         (ulong)result_program_id_haddr, sizeof(fd_pubkey_t) );
     554           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     555           0 :         (ulong)result_meta_haddr, FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
     556           0 :         (ulong)result_accounts_haddr, accounts_meta_total_size );
     557           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     558           0 :         (ulong)result_meta_haddr, FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
     559           0 :         (ulong)result_data_haddr, result_meta_haddr->data_len );
     560           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     561           0 :         (ulong)result_program_id_haddr, sizeof(fd_pubkey_t),
     562           0 :         (ulong)result_data_haddr, result_meta_haddr->data_len );
     563           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     564           0 :         (ulong)result_program_id_haddr, sizeof(fd_pubkey_t),
     565           0 :         (ulong)result_accounts_haddr, accounts_meta_total_size );
     566           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     567           0 :         (ulong)result_data_haddr, result_meta_haddr->data_len,
     568           0 :         (ulong)result_accounts_haddr, accounts_meta_total_size );
     569             : 
     570             :       /* Copy the instruction into the result addresses
     571             :          https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1506-L1528
     572             : 
     573             :          Note: we assume that the instr accounts are already correct at this point.
     574             :          Agave has many error checks. */
     575           0 :       fd_memcpy( result_program_id_haddr->key, instr_info->program_id_pubkey.key, FD_PUBKEY_FOOTPRINT );
     576           0 :       fd_memcpy( result_data_haddr, instr_info->data, instr_info->data_sz );
     577           0 :       for( ulong i = 0UL; i < instr_info->acct_cnt; i++ ) {
     578           0 :         fd_memcpy( result_accounts_haddr[ i ].pubkey,
     579           0 :                    vm->instr_ctx->txn_ctx->account_keys[ instr_info->acct_txn_idxs[ i ] ].key,
     580           0 :                    FD_PUBKEY_FOOTPRINT );
     581           0 :         result_accounts_haddr[ i ].is_signer   = !!(instr_info->acct_flags[ i ] & FD_INSTR_ACCT_FLAGS_IS_SIGNER);
     582           0 :         result_accounts_haddr[ i ].is_writable = !!(instr_info->acct_flags[ i ] & FD_INSTR_ACCT_FLAGS_IS_WRITABLE);
     583           0 :       }
     584           0 :     }
     585             : 
     586             :     /* Copy the actual metadata into the result meta struct
     587             :        https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1529-L1531 */
     588           0 :     result_meta_haddr->data_len     = instr_info->data_sz;
     589           0 :     result_meta_haddr->accounts_len = instr_info->acct_cnt;
     590             : 
     591             :     /* Return true as we found a sibling instruction
     592             :        https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1532 */
     593           0 :     *ret = 1UL;
     594           0 :     return FD_VM_SUCCESS;
     595           0 :   }
     596             : 
     597             :   /* Return false if we didn't find a sibling instruction
     598             :      https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1534 */
     599           0 :   *ret = 0UL;
     600           0 :   return FD_VM_SUCCESS;
     601           0 : }
     602             : 
     603             : // https://github.com/anza-xyz/agave/blob/master/programs/bpf_loader/src/syscalls/sysvar.rs#L75
     604             : int
     605             : fd_vm_syscall_sol_get_epoch_rewards_sysvar( /**/            void *  _vm,
     606             :                                             /**/            ulong   out_vaddr,
     607             :                                             FD_PARAM_UNUSED ulong   r2,
     608             :                                             FD_PARAM_UNUSED ulong   r3,
     609             :                                             FD_PARAM_UNUSED ulong   r4,
     610             :                                             FD_PARAM_UNUSED ulong   r5,
     611           0 :                                             /**/            ulong * _ret ) {
     612           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     613             : 
     614           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     615           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     616             : 
     617           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_SYSVAR_EPOCH_REWARDS_FOOTPRINT ) );
     618             : 
     619           0 :   void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_SYSVAR_EPOCH_REWARDS_ALIGN, FD_SYSVAR_EPOCH_REWARDS_FOOTPRINT );
     620             : 
     621           0 :   fd_sysvar_epoch_rewards_t var[1];
     622           0 :   fd_sysvar_epoch_rewards_new ( var );
     623           0 :   fd_sysvar_epoch_rewards_read( var,
     624           0 :                                 instr_ctx->txn_ctx->sysvar_cache,
     625           0 :                                 instr_ctx->txn_ctx->acc_mgr,
     626           0 :                                 instr_ctx->txn_ctx->funk_txn );
     627             : 
     628           0 :   memcpy( out, var, FD_SYSVAR_EPOCH_REWARDS_FOOTPRINT );
     629             : 
     630           0 :   *_ret = 0UL;
     631           0 :   return FD_VM_SUCCESS;
     632           0 : }

Generated by: LCOV version 1.14