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