solana_sysvar/
program_stubs.rs

1//! Implementations of syscalls used when `solana-program` is built for non-SBF targets.
2
3#![cfg(not(target_os = "solana"))]
4
5use {
6    base64::{prelude::BASE64_STANDARD, Engine},
7    solana_account_info::AccountInfo,
8    solana_instruction::{error::UNSUPPORTED_SYSVAR, Instruction},
9    solana_program_error::ProgramResult,
10    solana_program_memory::stubs,
11    solana_pubkey::Pubkey,
12    std::sync::{Arc, RwLock},
13};
14
15lazy_static::lazy_static! {
16    static ref SYSCALL_STUBS: Arc<RwLock<Box<dyn SyscallStubs>>> = Arc::new(RwLock::new(Box::new(DefaultSyscallStubs {})));
17}
18
19// The default syscall stubs may not do much, but `set_syscalls()` can be used
20// to swap in alternatives
21pub fn set_syscall_stubs(syscall_stubs: Box<dyn SyscallStubs>) -> Box<dyn SyscallStubs> {
22    std::mem::replace(&mut SYSCALL_STUBS.write().unwrap(), syscall_stubs)
23}
24
25pub trait SyscallStubs: Sync + Send {
26    fn sol_log(&self, message: &str) {
27        println!("{message}");
28    }
29    fn sol_log_compute_units(&self) {
30        sol_log("SyscallStubs: sol_log_compute_units() not available");
31    }
32    fn sol_remaining_compute_units(&self) -> u64 {
33        sol_log("SyscallStubs: sol_remaining_compute_units() defaulting to 0");
34        0
35    }
36    fn sol_invoke_signed(
37        &self,
38        _instruction: &Instruction,
39        _account_infos: &[AccountInfo],
40        _signers_seeds: &[&[&[u8]]],
41    ) -> ProgramResult {
42        sol_log("SyscallStubs: sol_invoke_signed() not available");
43        Ok(())
44    }
45    fn sol_get_sysvar(
46        &self,
47        _sysvar_id_addr: *const u8,
48        _var_addr: *mut u8,
49        _offset: u64,
50        _length: u64,
51    ) -> u64 {
52        UNSUPPORTED_SYSVAR
53    }
54    fn sol_get_clock_sysvar(&self, _var_addr: *mut u8) -> u64 {
55        UNSUPPORTED_SYSVAR
56    }
57    fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 {
58        UNSUPPORTED_SYSVAR
59    }
60    fn sol_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 {
61        UNSUPPORTED_SYSVAR
62    }
63    fn sol_get_rent_sysvar(&self, _var_addr: *mut u8) -> u64 {
64        UNSUPPORTED_SYSVAR
65    }
66    fn sol_get_epoch_rewards_sysvar(&self, _var_addr: *mut u8) -> u64 {
67        UNSUPPORTED_SYSVAR
68    }
69    fn sol_get_last_restart_slot(&self, _var_addr: *mut u8) -> u64 {
70        UNSUPPORTED_SYSVAR
71    }
72    fn sol_get_epoch_stake(&self, _vote_address: *const u8) -> u64 {
73        0
74    }
75    /// # Safety
76    unsafe fn sol_memcpy(&self, dst: *mut u8, src: *const u8, n: usize) {
77        stubs::sol_memcpy(dst, src, n)
78    }
79    /// # Safety
80    unsafe fn sol_memmove(&self, dst: *mut u8, src: *const u8, n: usize) {
81        stubs::sol_memmove(dst, src, n)
82    }
83    /// # Safety
84    unsafe fn sol_memcmp(&self, s1: *const u8, s2: *const u8, n: usize, result: *mut i32) {
85        stubs::sol_memcmp(s1, s2, n, result)
86    }
87    /// # Safety
88    unsafe fn sol_memset(&self, s: *mut u8, c: u8, n: usize) {
89        stubs::sol_memset(s, c, n)
90    }
91    fn sol_get_return_data(&self) -> Option<(Pubkey, Vec<u8>)> {
92        None
93    }
94    fn sol_set_return_data(&self, _data: &[u8]) {}
95    fn sol_log_data(&self, fields: &[&[u8]]) {
96        println!(
97            "data: {}",
98            fields
99                .iter()
100                .map(|v| BASE64_STANDARD.encode(v))
101                .collect::<Vec<_>>()
102                .join(" ")
103        );
104    }
105    fn sol_get_processed_sibling_instruction(&self, _index: usize) -> Option<Instruction> {
106        None
107    }
108    fn sol_get_stack_height(&self) -> u64 {
109        0
110    }
111}
112
113struct DefaultSyscallStubs {}
114impl SyscallStubs for DefaultSyscallStubs {}
115
116pub fn sol_log(message: &str) {
117    SYSCALL_STUBS.read().unwrap().sol_log(message);
118}
119
120pub fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
121    sol_log(&format!(
122        "{arg1:#x}, {arg2:#x}, {arg3:#x}, {arg4:#x}, {arg5:#x}"
123    ));
124}
125
126pub fn sol_log_compute_units() {
127    SYSCALL_STUBS.read().unwrap().sol_log_compute_units();
128}
129
130pub fn sol_remaining_compute_units() -> u64 {
131    SYSCALL_STUBS.read().unwrap().sol_remaining_compute_units()
132}
133
134pub fn sol_invoke_signed(
135    instruction: &Instruction,
136    account_infos: &[AccountInfo],
137    signers_seeds: &[&[&[u8]]],
138) -> ProgramResult {
139    SYSCALL_STUBS
140        .read()
141        .unwrap()
142        .sol_invoke_signed(instruction, account_infos, signers_seeds)
143}
144
145#[allow(dead_code)]
146pub(crate) fn sol_get_sysvar(
147    sysvar_id_addr: *const u8,
148    var_addr: *mut u8,
149    offset: u64,
150    length: u64,
151) -> u64 {
152    SYSCALL_STUBS
153        .read()
154        .unwrap()
155        .sol_get_sysvar(sysvar_id_addr, var_addr, offset, length)
156}
157
158#[cfg(feature = "bincode")]
159pub(crate) fn sol_get_clock_sysvar(var_addr: *mut u8) -> u64 {
160    SYSCALL_STUBS.read().unwrap().sol_get_clock_sysvar(var_addr)
161}
162
163#[cfg(feature = "bincode")]
164pub(crate) fn sol_get_epoch_schedule_sysvar(var_addr: *mut u8) -> u64 {
165    SYSCALL_STUBS
166        .read()
167        .unwrap()
168        .sol_get_epoch_schedule_sysvar(var_addr)
169}
170
171#[cfg(feature = "bincode")]
172pub(crate) fn sol_get_fees_sysvar(var_addr: *mut u8) -> u64 {
173    SYSCALL_STUBS.read().unwrap().sol_get_fees_sysvar(var_addr)
174}
175
176#[cfg(feature = "bincode")]
177pub(crate) fn sol_get_rent_sysvar(var_addr: *mut u8) -> u64 {
178    SYSCALL_STUBS.read().unwrap().sol_get_rent_sysvar(var_addr)
179}
180
181#[cfg(feature = "bincode")]
182pub(crate) fn sol_get_last_restart_slot(var_addr: *mut u8) -> u64 {
183    SYSCALL_STUBS
184        .read()
185        .unwrap()
186        .sol_get_last_restart_slot(var_addr)
187}
188
189pub fn sol_get_epoch_stake(vote_address: *const u8) -> u64 {
190    SYSCALL_STUBS
191        .read()
192        .unwrap()
193        .sol_get_epoch_stake(vote_address)
194}
195
196pub fn sol_get_return_data() -> Option<(Pubkey, Vec<u8>)> {
197    SYSCALL_STUBS.read().unwrap().sol_get_return_data()
198}
199
200pub fn sol_set_return_data(data: &[u8]) {
201    SYSCALL_STUBS.read().unwrap().sol_set_return_data(data)
202}
203
204pub fn sol_log_data(data: &[&[u8]]) {
205    SYSCALL_STUBS.read().unwrap().sol_log_data(data)
206}
207
208pub fn sol_get_processed_sibling_instruction(index: usize) -> Option<Instruction> {
209    SYSCALL_STUBS
210        .read()
211        .unwrap()
212        .sol_get_processed_sibling_instruction(index)
213}
214
215pub fn sol_get_stack_height() -> u64 {
216    SYSCALL_STUBS.read().unwrap().sol_get_stack_height()
217}
218
219#[cfg(feature = "bincode")]
220pub(crate) fn sol_get_epoch_rewards_sysvar(var_addr: *mut u8) -> u64 {
221    SYSCALL_STUBS
222        .read()
223        .unwrap()
224        .sol_get_epoch_rewards_sysvar(var_addr)
225}