Add SyscallStubs to enable syscall interception when building programs for non-BPF
This commit is contained in:
parent
75d62ca095
commit
9c53e1dfb2
|
@ -4440,6 +4440,7 @@ dependencies = [
|
|||
"hex",
|
||||
"hmac",
|
||||
"itertools 0.9.0",
|
||||
"lazy_static",
|
||||
"libsecp256k1",
|
||||
"log 0.4.8",
|
||||
"memmap",
|
||||
|
|
|
@ -2121,6 +2121,7 @@ dependencies = [
|
|||
"hex",
|
||||
"hmac",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"libsecp256k1",
|
||||
"log",
|
||||
"memmap",
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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<E> {
|
||||
fn decode_custom_error_to_enum(custom: u32) -> Option<E>
|
||||
where
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,6 +29,8 @@ pub fn invoke_signed(
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "bpf")]
|
||||
{
|
||||
let result = unsafe {
|
||||
sol_invoke_signed_rust(
|
||||
instruction as *const _ as *const u8,
|
||||
|
@ -42,10 +41,16 @@ pub fn invoke_signed(
|
|||
)
|
||||
};
|
||||
match result {
|
||||
SUCCESS => Ok(()),
|
||||
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,
|
||||
|
|
|
@ -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<RwLock<Box<dyn SyscallStubs>>> = 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<dyn SyscallStubs>) -> Box<dyn SyscallStubs> {
|
||||
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()");
|
||||
}
|
||||
|
||||
#[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();
|
||||
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)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -204,13 +204,18 @@ impl Pubkey {
|
|||
}
|
||||
|
||||
/// Log a `Pubkey` from a program
|
||||
#[cfg(feature = "program")]
|
||||
pub fn log(&self) {
|
||||
#[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());
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Pubkey {
|
||||
|
|
Loading…
Reference in New Issue