1#![cfg(not(target_os = "solana"))]
4
5use {
6 crate::{
7 account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction,
8 program_error::UNSUPPORTED_SYSVAR, pubkey::Pubkey,
9 },
10 base64::{prelude::BASE64_STANDARD, Engine},
11 itertools::Itertools,
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
19pub 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
25#[allow(clippy::arithmetic_side_effects)]
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_clock_sysvar(&self, _var_addr: *mut u8) -> u64 {
47 UNSUPPORTED_SYSVAR
48 }
49 fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 {
50 UNSUPPORTED_SYSVAR
51 }
52 fn sol_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 {
53 UNSUPPORTED_SYSVAR
54 }
55 fn sol_get_rent_sysvar(&self, _var_addr: *mut u8) -> u64 {
56 UNSUPPORTED_SYSVAR
57 }
58 fn sol_get_epoch_rewards_sysvar(&self, _var_addr: *mut u8) -> u64 {
59 UNSUPPORTED_SYSVAR
60 }
61 fn sol_get_last_restart_slot(&self, _var_addr: *mut u8) -> u64 {
62 UNSUPPORTED_SYSVAR
63 }
64 unsafe fn sol_memcpy(&self, dst: *mut u8, src: *const u8, n: usize) {
66 assert!(
68 is_nonoverlapping(src as usize, n, dst as usize, n),
69 "memcpy does not support overlapping regions"
70 );
71 std::ptr::copy_nonoverlapping(src, dst, n);
72 }
73 unsafe fn sol_memmove(&self, dst: *mut u8, src: *const u8, n: usize) {
75 std::ptr::copy(src, dst, n);
76 }
77 unsafe fn sol_memcmp(&self, s1: *const u8, s2: *const u8, n: usize, result: *mut i32) {
79 let mut i = 0;
80 while i < n {
81 let a = *s1.add(i);
82 let b = *s2.add(i);
83 if a != b {
84 *result = a as i32 - b as i32;
85 return;
86 }
87 i += 1;
88 }
89 *result = 0
90 }
91 unsafe fn sol_memset(&self, s: *mut u8, c: u8, n: usize) {
93 let s = std::slice::from_raw_parts_mut(s, n);
94 for val in s.iter_mut().take(n) {
95 *val = c;
96 }
97 }
98 fn sol_get_return_data(&self) -> Option<(Pubkey, Vec<u8>)> {
99 None
100 }
101 fn sol_set_return_data(&self, _data: &[u8]) {}
102 fn sol_log_data(&self, fields: &[&[u8]]) {
103 println!(
104 "data: {}",
105 fields.iter().map(|v| BASE64_STANDARD.encode(v)).join(" ")
106 );
107 }
108 fn sol_get_processed_sibling_instruction(&self, _index: usize) -> Option<Instruction> {
109 None
110 }
111 fn sol_get_stack_height(&self) -> u64 {
112 0
113 }
114}
115
116struct DefaultSyscallStubs {}
117impl SyscallStubs for DefaultSyscallStubs {}
118
119pub(crate) fn sol_log(message: &str) {
120 SYSCALL_STUBS.read().unwrap().sol_log(message);
121}
122
123pub(crate) fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
124 sol_log(&format!(
125 "{arg1:#x}, {arg2:#x}, {arg3:#x}, {arg4:#x}, {arg5:#x}"
126 ));
127}
128
129pub(crate) fn sol_log_compute_units() {
130 SYSCALL_STUBS.read().unwrap().sol_log_compute_units();
131}
132
133pub(crate) fn sol_remaining_compute_units() -> u64 {
134 SYSCALL_STUBS.read().unwrap().sol_remaining_compute_units()
135}
136
137pub(crate) fn sol_invoke_signed(
138 instruction: &Instruction,
139 account_infos: &[AccountInfo],
140 signers_seeds: &[&[&[u8]]],
141) -> ProgramResult {
142 SYSCALL_STUBS
143 .read()
144 .unwrap()
145 .sol_invoke_signed(instruction, account_infos, signers_seeds)
146}
147
148pub(crate) fn sol_get_clock_sysvar(var_addr: *mut u8) -> u64 {
149 SYSCALL_STUBS.read().unwrap().sol_get_clock_sysvar(var_addr)
150}
151
152pub(crate) fn sol_get_epoch_schedule_sysvar(var_addr: *mut u8) -> u64 {
153 SYSCALL_STUBS
154 .read()
155 .unwrap()
156 .sol_get_epoch_schedule_sysvar(var_addr)
157}
158
159pub(crate) fn sol_get_fees_sysvar(var_addr: *mut u8) -> u64 {
160 SYSCALL_STUBS.read().unwrap().sol_get_fees_sysvar(var_addr)
161}
162
163pub(crate) fn sol_get_rent_sysvar(var_addr: *mut u8) -> u64 {
164 SYSCALL_STUBS.read().unwrap().sol_get_rent_sysvar(var_addr)
165}
166
167pub(crate) fn sol_get_last_restart_slot(var_addr: *mut u8) -> u64 {
168 SYSCALL_STUBS
169 .read()
170 .unwrap()
171 .sol_get_last_restart_slot(var_addr)
172}
173
174pub(crate) fn sol_memcpy(dst: *mut u8, src: *const u8, n: usize) {
175 unsafe {
176 SYSCALL_STUBS.read().unwrap().sol_memcpy(dst, src, n);
177 }
178}
179
180pub(crate) fn sol_memmove(dst: *mut u8, src: *const u8, n: usize) {
181 unsafe {
182 SYSCALL_STUBS.read().unwrap().sol_memmove(dst, src, n);
183 }
184}
185
186pub(crate) fn sol_memcmp(s1: *const u8, s2: *const u8, n: usize, result: *mut i32) {
187 unsafe {
188 SYSCALL_STUBS.read().unwrap().sol_memcmp(s1, s2, n, result);
189 }
190}
191
192pub(crate) fn sol_memset(s: *mut u8, c: u8, n: usize) {
193 unsafe {
194 SYSCALL_STUBS.read().unwrap().sol_memset(s, c, n);
195 }
196}
197
198pub(crate) fn sol_get_return_data() -> Option<(Pubkey, Vec<u8>)> {
199 SYSCALL_STUBS.read().unwrap().sol_get_return_data()
200}
201
202pub(crate) fn sol_set_return_data(data: &[u8]) {
203 SYSCALL_STUBS.read().unwrap().sol_set_return_data(data)
204}
205
206pub(crate) fn sol_log_data(data: &[&[u8]]) {
207 SYSCALL_STUBS.read().unwrap().sol_log_data(data)
208}
209
210pub(crate) fn sol_get_processed_sibling_instruction(index: usize) -> Option<Instruction> {
211 SYSCALL_STUBS
212 .read()
213 .unwrap()
214 .sol_get_processed_sibling_instruction(index)
215}
216
217pub(crate) fn sol_get_stack_height() -> u64 {
218 SYSCALL_STUBS.read().unwrap().sol_get_stack_height()
219}
220
221pub(crate) fn sol_get_epoch_rewards_sysvar(var_addr: *mut u8) -> u64 {
222 SYSCALL_STUBS
223 .read()
224 .unwrap()
225 .sol_get_epoch_rewards_sysvar(var_addr)
226}
227
228#[doc(hidden)]
232pub fn is_nonoverlapping<N>(src: N, src_len: N, dst: N, dst_len: N) -> bool
233where
234 N: Ord + num_traits::SaturatingSub,
235{
236 if src > dst {
239 src.saturating_sub(&dst) >= dst_len
240 } else {
241 dst.saturating_sub(&src) >= src_len
242 }
243}
244
245#[cfg(test)]
246mod tests {
247 use super::*;
248
249 #[test]
250 fn test_is_nonoverlapping() {
251 for dst in 0..8 {
252 assert!(is_nonoverlapping(10, 3, dst, 3));
253 }
254 for dst in 8..13 {
255 assert!(!is_nonoverlapping(10, 3, dst, 3));
256 }
257 for dst in 13..20 {
258 assert!(is_nonoverlapping(10, 3, dst, 3));
259 }
260 assert!(is_nonoverlapping::<u8>(255, 3, 254, 1));
261 assert!(!is_nonoverlapping::<u8>(255, 2, 254, 3));
262 }
263}