gemachain_program/
program_stubs.rs

1//! @brief Syscall stubs when building for programs for non-BPF targets
2
3#![cfg(not(target_arch = "bpf"))]
4
5use crate::{
6    account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction,
7    program_error::UNSUPPORTED_SYSVAR, pubkey::Pubkey,
8};
9use itertools::Itertools;
10use std::sync::{Arc, RwLock};
11
12lazy_static::lazy_static! {
13    static ref SYSCALL_STUBS: Arc<RwLock<Box<dyn SyscallStubs>>> = Arc::new(RwLock::new(Box::new(DefaultSyscallStubs {})));
14}
15
16// The default syscall stubs may not do much, but `set_syscalls()` can be used
17// to swap in alternatives
18pub fn set_syscall_stubs(syscall_stubs: Box<dyn SyscallStubs>) -> Box<dyn SyscallStubs> {
19    std::mem::replace(&mut SYSCALL_STUBS.write().unwrap(), syscall_stubs)
20}
21
22#[allow(clippy::integer_arithmetic)]
23pub trait SyscallStubs: Sync + Send {
24    fn gema_log(&self, message: &str) {
25        println!("{}", message);
26    }
27    fn gema_log_compute_units(&self) {
28        gema_log("SyscallStubs: gema_log_compute_units() not available");
29    }
30    fn gema_invoke_signed(
31        &self,
32        _instruction: &Instruction,
33        _account_infos: &[AccountInfo],
34        _signers_seeds: &[&[&[u8]]],
35    ) -> ProgramResult {
36        gema_log("SyscallStubs: gema_invoke_signed() not available");
37        Ok(())
38    }
39    fn gema_get_clock_sysvar(&self, _var_addr: *mut u8) -> u64 {
40        UNSUPPORTED_SYSVAR
41    }
42    fn gema_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 {
43        UNSUPPORTED_SYSVAR
44    }
45    fn gema_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 {
46        UNSUPPORTED_SYSVAR
47    }
48    fn gema_get_rent_sysvar(&self, _var_addr: *mut u8) -> u64 {
49        UNSUPPORTED_SYSVAR
50    }
51    /// # Safety
52    unsafe fn gema_memcpy(&self, dst: *mut u8, src: *const u8, n: usize) {
53        // cannot be overlapping
54        if dst as usize + n > src as usize && src as usize > dst as usize {
55            panic!("memcpy does not support overlapping regions");
56        }
57        std::ptr::copy_nonoverlapping(src, dst, n as usize);
58    }
59    /// # Safety
60    unsafe fn gema_memmove(&self, dst: *mut u8, src: *const u8, n: usize) {
61        std::ptr::copy(src, dst, n as usize);
62    }
63    /// # Safety
64    unsafe fn gema_memcmp(&self, s1: *const u8, s2: *const u8, n: usize, result: *mut i32) {
65        let mut i = 0;
66        while i < n {
67            let a = *s1.add(i);
68            let b = *s2.add(i);
69            if a != b {
70                *result = a as i32 - b as i32;
71                return;
72            }
73            i += 1;
74        }
75        *result = 0
76    }
77    /// # Safety
78    unsafe fn gema_memset(&self, s: *mut u8, c: u8, n: usize) {
79        let s = std::slice::from_raw_parts_mut(s, n);
80        for val in s.iter_mut().take(n) {
81            *val = c;
82        }
83    }
84    fn gema_get_return_data(&self) -> Option<(Pubkey, Vec<u8>)> {
85        None
86    }
87    fn gema_set_return_data(&mut self, _data: &[u8]) {}
88    fn gema_log_data(&self, fields: &[&[u8]]) {
89        println!("data: {}", fields.iter().map(base64::encode).join(" "));
90    }
91}
92
93struct DefaultSyscallStubs {}
94impl SyscallStubs for DefaultSyscallStubs {}
95
96pub(crate) fn gema_log(message: &str) {
97    SYSCALL_STUBS.read().unwrap().gema_log(message);
98}
99
100pub(crate) fn gema_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
101    gema_log(&format!(
102        "{:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
103        arg1, arg2, arg3, arg4, arg5
104    ));
105}
106
107pub(crate) fn gema_log_compute_units() {
108    SYSCALL_STUBS.read().unwrap().gema_log_compute_units();
109}
110
111pub(crate) fn gema_invoke_signed(
112    instruction: &Instruction,
113    account_infos: &[AccountInfo],
114    signers_seeds: &[&[&[u8]]],
115) -> ProgramResult {
116    SYSCALL_STUBS
117        .read()
118        .unwrap()
119        .gema_invoke_signed(instruction, account_infos, signers_seeds)
120}
121
122pub(crate) fn gema_get_clock_sysvar(var_addr: *mut u8) -> u64 {
123    SYSCALL_STUBS.read().unwrap().gema_get_clock_sysvar(var_addr)
124}
125
126pub(crate) fn gema_get_epoch_schedule_sysvar(var_addr: *mut u8) -> u64 {
127    SYSCALL_STUBS
128        .read()
129        .unwrap()
130        .gema_get_epoch_schedule_sysvar(var_addr)
131}
132
133pub(crate) fn gema_get_fees_sysvar(_var_addr: *mut u8) -> u64 {
134    UNSUPPORTED_SYSVAR
135}
136
137pub(crate) fn gema_get_rent_sysvar(var_addr: *mut u8) -> u64 {
138    SYSCALL_STUBS.read().unwrap().gema_get_rent_sysvar(var_addr)
139}
140
141pub(crate) fn gema_memcpy(dst: *mut u8, src: *const u8, n: usize) {
142    unsafe {
143        SYSCALL_STUBS.read().unwrap().gema_memcpy(dst, src, n);
144    }
145}
146
147pub(crate) fn gema_memmove(dst: *mut u8, src: *const u8, n: usize) {
148    unsafe {
149        SYSCALL_STUBS.read().unwrap().gema_memmove(dst, src, n);
150    }
151}
152
153pub(crate) fn gema_memcmp(s1: *const u8, s2: *const u8, n: usize, result: *mut i32) {
154    unsafe {
155        SYSCALL_STUBS.read().unwrap().gema_memcmp(s1, s2, n, result);
156    }
157}
158
159pub(crate) fn gema_memset(s: *mut u8, c: u8, n: usize) {
160    unsafe {
161        SYSCALL_STUBS.read().unwrap().gema_memset(s, c, n);
162    }
163}
164
165pub(crate) fn gema_get_return_data() -> Option<(Pubkey, Vec<u8>)> {
166    SYSCALL_STUBS.read().unwrap().gema_get_return_data()
167}
168
169pub(crate) fn gema_set_return_data(data: &[u8]) {
170    SYSCALL_STUBS.write().unwrap().gema_set_return_data(data)
171}
172
173pub(crate) fn gema_log_data(data: &[&[u8]]) {
174    SYSCALL_STUBS.read().unwrap().gema_log_data(data)
175}