diff --git a/Cargo.lock b/Cargo.lock index 2aeecbdd32..000dbbe2d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4399,6 +4399,7 @@ dependencies = [ "hex", "hmac", "itertools 0.9.0", + "lazy_static", "libsecp256k1", "log 0.4.8", "memmap", diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 7fb89d1696..5d67e7a608 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -2080,6 +2080,7 @@ dependencies = [ "hex", "hmac", "itertools", + "lazy_static", "libsecp256k1", "log", "memmap", diff --git a/programs/bpf/rust/128bit/src/lib.rs b/programs/bpf/rust/128bit/src/lib.rs index 7d8fa04782..0ad5ba5c6b 100644 --- a/programs/bpf/rust/128bit/src/lib.rs +++ b/programs/bpf/rust/128bit/src/lib.rs @@ -53,8 +53,6 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_entrypoint() { diff --git a/programs/bpf/rust/alloc/src/lib.rs b/programs/bpf/rust/alloc/src/lib.rs index 3e4d31b1ae..b627a1e6ed 100644 --- a/programs/bpf/rust/alloc/src/lib.rs +++ b/programs/bpf/rust/alloc/src/lib.rs @@ -85,8 +85,6 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_entrypoint() { diff --git a/programs/bpf/rust/dep_crate/src/lib.rs b/programs/bpf/rust/dep_crate/src/lib.rs index 8321c27d42..98d5da0806 100644 --- a/programs/bpf/rust/dep_crate/src/lib.rs +++ b/programs/bpf/rust/dep_crate/src/lib.rs @@ -20,8 +20,6 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_entrypoint() { diff --git a/programs/bpf/rust/deprecated_loader/src/lib.rs b/programs/bpf/rust/deprecated_loader/src/lib.rs index d71b967523..3698194a41 100644 --- a/programs/bpf/rust/deprecated_loader/src/lib.rs +++ b/programs/bpf/rust/deprecated_loader/src/lib.rs @@ -67,8 +67,6 @@ fn process_instruction( #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_return_sstruct() { diff --git a/programs/bpf/rust/invoke/src/lib.rs b/programs/bpf/rust/invoke/src/lib.rs index e4fa21c39a..e578f667c6 100644 --- a/programs/bpf/rust/invoke/src/lib.rs +++ b/programs/bpf/rust/invoke/src/lib.rs @@ -365,8 +365,6 @@ fn process_instruction( #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn create_program_address_is_defined() { diff --git a/programs/bpf/rust/invoked/src/processor.rs b/programs/bpf/rust/invoked/src/processor.rs index 1a884db888..df6671acb5 100644 --- a/programs/bpf/rust/invoked/src/processor.rs +++ b/programs/bpf/rust/invoked/src/processor.rs @@ -194,6 +194,3 @@ fn process_instruction( Ok(()) } - -// Pull in syscall stubs when building for non-BPF targets -solana_sdk::program_stubs!(); diff --git a/programs/bpf/rust/iter/src/lib.rs b/programs/bpf/rust/iter/src/lib.rs index 501f6e5741..ec82f8f5a9 100644 --- a/programs/bpf/rust/iter/src/lib.rs +++ b/programs/bpf/rust/iter/src/lib.rs @@ -21,8 +21,6 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_entrypoint() { diff --git a/programs/bpf/rust/many_args/src/lib.rs b/programs/bpf/rust/many_args/src/lib.rs index 1b220ac72a..dfe9262f70 100644 --- a/programs/bpf/rust/many_args/src/lib.rs +++ b/programs/bpf/rust/many_args/src/lib.rs @@ -29,8 +29,6 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_entrypoint() { diff --git a/programs/bpf/rust/many_args_dep/src/lib.rs b/programs/bpf/rust/many_args_dep/src/lib.rs index 98e8799cdf..201a339dab 100644 --- a/programs/bpf/rust/many_args_dep/src/lib.rs +++ b/programs/bpf/rust/many_args_dep/src/lib.rs @@ -51,8 +51,6 @@ pub fn many_args_sret( #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_many_args() { diff --git a/programs/bpf/rust/param_passing/src/lib.rs b/programs/bpf/rust/param_passing/src/lib.rs index 5968b1bd12..65a536371f 100644 --- a/programs/bpf/rust/param_passing/src/lib.rs +++ b/programs/bpf/rust/param_passing/src/lib.rs @@ -26,8 +26,6 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_entrypoint() { diff --git a/programs/bpf/rust/param_passing_dep/src/lib.rs b/programs/bpf/rust/param_passing_dep/src/lib.rs index 70e6fd5827..caa6dc55a8 100644 --- a/programs/bpf/rust/param_passing_dep/src/lib.rs +++ b/programs/bpf/rust/param_passing_dep/src/lib.rs @@ -27,8 +27,6 @@ impl<'a> TestDep { #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_dep() { diff --git a/programs/bpf/rust/ristretto/src/lib.rs b/programs/bpf/rust/ristretto/src/lib.rs index 14c49d4663..4eec95afc1 100644 --- a/programs/bpf/rust/ristretto/src/lib.rs +++ b/programs/bpf/rust/ristretto/src/lib.rs @@ -38,8 +38,6 @@ fn process_instruction( #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_ristretto() { diff --git a/programs/bpf/rust/sanity/src/lib.rs b/programs/bpf/rust/sanity/src/lib.rs index 704fde03c2..e44a3d3f0d 100644 --- a/programs/bpf/rust/sanity/src/lib.rs +++ b/programs/bpf/rust/sanity/src/lib.rs @@ -67,8 +67,6 @@ fn process_instruction( #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_return_sstruct() { diff --git a/programs/bpf/rust/sha256/src/lib.rs b/programs/bpf/rust/sha256/src/lib.rs index 38762bc530..d239e8d7ec 100644 --- a/programs/bpf/rust/sha256/src/lib.rs +++ b/programs/bpf/rust/sha256/src/lib.rs @@ -25,8 +25,6 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { #[cfg(test)] mod test { use super::*; - // Pull in syscall stubs when building for non-BPF targets - solana_sdk::program_stubs!(); #[test] fn test_sha256() { diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 752401dd03..135f2aaa17 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -42,6 +42,7 @@ generic-array = { version = "0.14.3", default-features = false, features = ["ser hex = "0.4.2" hmac = "0.7.0" itertools = { version = "0.9.0" } +lazy_static = "1.4.0" log = { version = "0.4.8" } memmap = { version = "0.7.0", optional = true } num-derive = { version = "0.3" } diff --git a/sdk/src/decode_error.rs b/sdk/src/decode_error.rs index f50e5bfd00..7ca44864d7 100644 --- a/sdk/src/decode_error.rs +++ b/sdk/src/decode_error.rs @@ -1,6 +1,6 @@ use num_traits::FromPrimitive; -/// Allows customer errors to be decoded back to their original enum +/// Allows custom errors to be decoded back to their original enum pub trait DecodeError { fn decode_custom_error_to_enum(custom: u32) -> Option where diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index c69001323e..5bf9035232 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -84,7 +84,23 @@ pub mod entrypoint_deprecated; pub mod log; pub mod program; pub mod program_error; + +#[cfg(all(feature = "program", not(target_arch = "bpf")))] +extern crate lazy_static; + +#[cfg(all(feature = "program", not(target_arch = "bpf")))] pub mod program_stubs; + +// Unused `solana_sdk::program_stubs!()` macro retained for source backwards compatibility with v1.3.x programs +#[macro_export] +#[deprecated( + since = "1.4.2", + note = "program_stubs macro is obsolete and can be safely removed" +)] +macro_rules! program_stubs { + () => {}; +} + pub mod serialize_utils; // Modules not usable by on-chain programs diff --git a/sdk/src/log.rs b/sdk/src/log.rs index d96c55e6b1..1c6d5f0ea3 100644 --- a/sdk/src/log.rs +++ b/sdk/src/log.rs @@ -31,10 +31,16 @@ macro_rules! info { /// @param message - Message to print #[inline] pub fn sol_log(message: &str) { + #[cfg(target_arch = "bpf")] unsafe { sol_log_(message.as_ptr(), message.len() as u64); } + + #[cfg(not(target_arch = "bpf"))] + crate::program_stubs::sol_log(message); } + +#[cfg(target_arch = "bpf")] extern "C" { fn sol_log_(message: *const u8, len: u64); } @@ -45,10 +51,16 @@ extern "C" { #[inline] pub fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) { + #[cfg(target_arch = "bpf")] unsafe { sol_log_64_(arg1, arg2, arg3, arg4, arg5); } + + #[cfg(not(target_arch = "bpf"))] + crate::program_stubs::sol_log_64(arg1, arg2, arg3, arg4, arg5); } + +#[cfg(target_arch = "bpf")] extern "C" { fn sol_log_64_(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64); } diff --git a/sdk/src/program.rs b/sdk/src/program.rs index 6058175544..c6b4cf3497 100644 --- a/sdk/src/program.rs +++ b/sdk/src/program.rs @@ -1,9 +1,6 @@ #![cfg(feature = "program")] -use crate::{ - account_info::AccountInfo, entrypoint::ProgramResult, entrypoint::SUCCESS, - instruction::Instruction, -}; +use crate::{account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction}; /// Invoke a cross-program instruction pub fn invoke(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult { @@ -32,20 +29,28 @@ pub fn invoke_signed( } } - let result = unsafe { - sol_invoke_signed_rust( - instruction as *const _ as *const u8, - account_infos as *const _ as *const u8, - account_infos.len() as u64, - signers_seeds as *const _ as *const u8, - signers_seeds.len() as u64, - ) - }; - match result { - SUCCESS => Ok(()), - _ => Err(result.into()), + #[cfg(target_arch = "bpf")] + { + let result = unsafe { + sol_invoke_signed_rust( + instruction as *const _ as *const u8, + account_infos as *const _ as *const u8, + account_infos.len() as u64, + signers_seeds as *const _ as *const u8, + signers_seeds.len() as u64, + ) + }; + match result { + crate::entrypoint::SUCCESS => Ok(()), + _ => Err(result.into()), + } } + + #[cfg(not(target_arch = "bpf"))] + crate::program_stubs::sol_invoke_signed(instruction, account_infos, signers_seeds) } + +#[cfg(target_arch = "bpf")] extern "C" { fn sol_invoke_signed_rust( instruction_addr: *const u8, diff --git a/sdk/src/program_stubs.rs b/sdk/src/program_stubs.rs index 9228f5a766..809c70d8de 100644 --- a/sdk/src/program_stubs.rs +++ b/sdk/src/program_stubs.rs @@ -1,36 +1,54 @@ -//! @brief Syscall stubs when building for non-BPF targets +//! @brief Syscall stubs when building for programs for non-BPF targets -#[cfg(not(target_arch = "bpf"))] -#[no_mangle] -/// # Safety -pub unsafe fn sol_log_(message: *const u8, length: u64) { - let slice = std::slice::from_raw_parts(message, length as usize); - let string = std::str::from_utf8(&slice).unwrap(); - println!("{}", string); +use crate::{ + account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction, + program_error::ProgramError, +}; +use std::sync::{Arc, RwLock}; + +lazy_static::lazy_static! { + static ref SYSCALL_STUBS: Arc>> = Arc::new(RwLock::new(Box::new(DefaultSyscallStubs {}))); } -#[cfg(not(target_arch = "bpf"))] -#[no_mangle] -pub fn sol_log_64_(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) { - println!("{} {} {} {} {}", arg1, arg2, arg3, arg4, arg5); +// The default syscall stubs don't do much, but `set_syscalls()` can be used to swap in +// alternatives +pub fn set_syscall_stubs(syscall_stubs: Box) -> Box { + std::mem::replace(&mut SYSCALL_STUBS.write().unwrap(), syscall_stubs) } -#[cfg(not(target_arch = "bpf"))] -#[no_mangle] -pub fn sol_invoke_signed_rust() { - println!("sol_invoke_signed_rust()"); +pub trait SyscallStubs: Sync + Send { + fn sol_log(&self, message: &str) { + println!("{}", message); + } + fn sol_invoke_signed( + &self, + _instruction: &Instruction, + _account_infos: &[AccountInfo], + _signers_seeds: &[&[&[u8]]], + ) -> ProgramResult { + sol_log("SyscallStubs: sol_invoke_signed() not available"); + Err(ProgramError::InvalidArgument) + } } -#[macro_export] -macro_rules! program_stubs { - () => { - #[cfg(not(target_arch = "bpf"))] - #[test] - fn pull_in_externs() { - use solana_sdk::program_stubs::{sol_invoke_signed_rust, sol_log_, sol_log_64_}; - unsafe { sol_log_("sol_log_".as_ptr(), 8) }; - sol_log_64_(1, 2, 3, 4, 5); - sol_invoke_signed_rust(); - } - }; +struct DefaultSyscallStubs {} +impl SyscallStubs for DefaultSyscallStubs {} + +pub(crate) fn sol_log(message: &str) { + SYSCALL_STUBS.read().unwrap().sol_log(message); +} + +pub(crate) fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) { + sol_log(&format!("{} {} {} {} {}", arg1, arg2, arg3, arg4, arg5)); +} + +pub(crate) fn sol_invoke_signed( + instruction: &Instruction, + account_infos: &[AccountInfo], + signers_seeds: &[&[&[u8]]], +) -> ProgramResult { + SYSCALL_STUBS + .read() + .unwrap() + .sol_invoke_signed(instruction, account_infos, signers_seeds) } diff --git a/sdk/src/pubkey.rs b/sdk/src/pubkey.rs index d6c1350af7..64e31dd0ac 100644 --- a/sdk/src/pubkey.rs +++ b/sdk/src/pubkey.rs @@ -204,12 +204,17 @@ impl Pubkey { } /// Log a `Pubkey` from a program - #[cfg(feature = "program")] pub fn log(&self) { - extern "C" { - fn sol_log_pubkey(pubkey_addr: *const u8); - }; - unsafe { sol_log_pubkey(self.as_ref() as *const _ as *const u8) }; + #[cfg(all(feature = "program", target_arch = "bpf"))] + { + extern "C" { + fn sol_log_pubkey(pubkey_addr: *const u8); + }; + unsafe { sol_log_pubkey(self.as_ref() as *const _ as *const u8) }; + } + + #[cfg(all(feature = "program", not(target_arch = "bpf")))] + crate::program_stubs::sol_log(&self.to_string()); } }