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: 104 257 40.5 %
Date: 2025-01-08 12:08:44 Functions: 7 12 58.3 %

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

Generated by: LCOV version 1.14