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

Generated by: LCOV version 1.14