Add SyscallStubs to enable syscall interception when building programs for non-BPF
This commit is contained in:
committed by
mergify[bot]
parent
75d62ca095
commit
9c53e1dfb2
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -4440,6 +4440,7 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"hmac",
|
"hmac",
|
||||||
"itertools 0.9.0",
|
"itertools 0.9.0",
|
||||||
|
"lazy_static",
|
||||||
"libsecp256k1",
|
"libsecp256k1",
|
||||||
"log 0.4.8",
|
"log 0.4.8",
|
||||||
"memmap",
|
"memmap",
|
||||||
|
1
programs/bpf/Cargo.lock
generated
1
programs/bpf/Cargo.lock
generated
@ -2121,6 +2121,7 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"hmac",
|
"hmac",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"lazy_static",
|
||||||
"libsecp256k1",
|
"libsecp256k1",
|
||||||
"log",
|
"log",
|
||||||
"memmap",
|
"memmap",
|
||||||
|
@ -42,6 +42,7 @@ generic-array = { version = "0.14.3", default-features = false, features = ["ser
|
|||||||
hex = "0.4.2"
|
hex = "0.4.2"
|
||||||
hmac = "0.7.0"
|
hmac = "0.7.0"
|
||||||
itertools = { version = "0.9.0" }
|
itertools = { version = "0.9.0" }
|
||||||
|
lazy_static = "1.4.0"
|
||||||
log = { version = "0.4.8" }
|
log = { version = "0.4.8" }
|
||||||
memmap = { version = "0.7.0", optional = true }
|
memmap = { version = "0.7.0", optional = true }
|
||||||
num-derive = { version = "0.3" }
|
num-derive = { version = "0.3" }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use num_traits::FromPrimitive;
|
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> {
|
pub trait DecodeError<E> {
|
||||||
fn decode_custom_error_to_enum(custom: u32) -> Option<E>
|
fn decode_custom_error_to_enum(custom: u32) -> Option<E>
|
||||||
where
|
where
|
||||||
|
@ -84,7 +84,23 @@ pub mod entrypoint_deprecated;
|
|||||||
pub mod log;
|
pub mod log;
|
||||||
pub mod program;
|
pub mod program;
|
||||||
pub mod program_error;
|
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;
|
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;
|
pub mod serialize_utils;
|
||||||
|
|
||||||
// Modules not usable by on-chain programs
|
// Modules not usable by on-chain programs
|
||||||
|
@ -31,10 +31,16 @@ macro_rules! info {
|
|||||||
/// @param message - Message to print
|
/// @param message - Message to print
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sol_log(message: &str) {
|
pub fn sol_log(message: &str) {
|
||||||
|
#[cfg(target_arch = "bpf")]
|
||||||
unsafe {
|
unsafe {
|
||||||
sol_log_(message.as_ptr(), message.len() as u64);
|
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" {
|
extern "C" {
|
||||||
fn sol_log_(message: *const u8, len: u64);
|
fn sol_log_(message: *const u8, len: u64);
|
||||||
}
|
}
|
||||||
@ -45,10 +51,16 @@ extern "C" {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
|
pub fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
|
||||||
|
#[cfg(target_arch = "bpf")]
|
||||||
unsafe {
|
unsafe {
|
||||||
sol_log_64_(arg1, arg2, arg3, arg4, arg5);
|
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" {
|
extern "C" {
|
||||||
fn sol_log_64_(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64);
|
fn sol_log_64_(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
#![cfg(feature = "program")]
|
#![cfg(feature = "program")]
|
||||||
|
|
||||||
use crate::{
|
use crate::{account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction};
|
||||||
account_info::AccountInfo, entrypoint::ProgramResult, entrypoint::SUCCESS,
|
|
||||||
instruction::Instruction,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Invoke a cross-program instruction
|
/// Invoke a cross-program instruction
|
||||||
pub fn invoke(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult {
|
pub fn invoke(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult {
|
||||||
@ -32,20 +29,28 @@ pub fn invoke_signed(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = unsafe {
|
#[cfg(target_arch = "bpf")]
|
||||||
sol_invoke_signed_rust(
|
{
|
||||||
instruction as *const _ as *const u8,
|
let result = unsafe {
|
||||||
account_infos as *const _ as *const u8,
|
sol_invoke_signed_rust(
|
||||||
account_infos.len() as u64,
|
instruction as *const _ as *const u8,
|
||||||
signers_seeds as *const _ as *const u8,
|
account_infos as *const _ as *const u8,
|
||||||
signers_seeds.len() as u64,
|
account_infos.len() as u64,
|
||||||
)
|
signers_seeds as *const _ as *const u8,
|
||||||
};
|
signers_seeds.len() as u64,
|
||||||
match result {
|
)
|
||||||
SUCCESS => Ok(()),
|
};
|
||||||
_ => Err(result.into()),
|
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" {
|
extern "C" {
|
||||||
fn sol_invoke_signed_rust(
|
fn sol_invoke_signed_rust(
|
||||||
instruction_addr: *const u8,
|
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"))]
|
use crate::{
|
||||||
#[no_mangle]
|
account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction,
|
||||||
/// # Safety
|
program_error::ProgramError,
|
||||||
pub unsafe fn sol_log_(message: *const u8, length: u64) {
|
};
|
||||||
let slice = std::slice::from_raw_parts(message, length as usize);
|
use std::sync::{Arc, RwLock};
|
||||||
let string = std::str::from_utf8(&slice).unwrap();
|
|
||||||
println!("{}", string);
|
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"))]
|
// The default syscall stubs don't do much, but `set_syscalls()` can be used to swap in
|
||||||
#[no_mangle]
|
// alternatives
|
||||||
pub fn sol_log_64_(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
|
pub fn set_syscall_stubs(syscall_stubs: Box<dyn SyscallStubs>) -> Box<dyn SyscallStubs> {
|
||||||
println!("{} {} {} {} {}", arg1, arg2, arg3, arg4, arg5);
|
std::mem::replace(&mut SYSCALL_STUBS.write().unwrap(), syscall_stubs)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "bpf"))]
|
pub trait SyscallStubs: Sync + Send {
|
||||||
#[no_mangle]
|
fn sol_log(&self, message: &str) {
|
||||||
pub fn sol_invoke_signed_rust() {
|
println!("{}", message);
|
||||||
println!("sol_invoke_signed_rust()");
|
}
|
||||||
|
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]
|
struct DefaultSyscallStubs {}
|
||||||
macro_rules! program_stubs {
|
impl SyscallStubs for DefaultSyscallStubs {}
|
||||||
() => {
|
|
||||||
#[cfg(not(target_arch = "bpf"))]
|
pub(crate) fn sol_log(message: &str) {
|
||||||
#[test]
|
SYSCALL_STUBS.read().unwrap().sol_log(message);
|
||||||
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) };
|
pub(crate) fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
|
||||||
sol_log_64_(1, 2, 3, 4, 5);
|
sol_log(&format!("{} {} {} {} {}", arg1, arg2, arg3, arg4, arg5));
|
||||||
sol_invoke_signed_rust();
|
}
|
||||||
}
|
|
||||||
};
|
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,12 +204,17 @@ impl Pubkey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Log a `Pubkey` from a program
|
/// Log a `Pubkey` from a program
|
||||||
#[cfg(feature = "program")]
|
|
||||||
pub fn log(&self) {
|
pub fn log(&self) {
|
||||||
extern "C" {
|
#[cfg(all(feature = "program", target_arch = "bpf"))]
|
||||||
fn sol_log_pubkey(pubkey_addr: *const u8);
|
{
|
||||||
};
|
extern "C" {
|
||||||
unsafe { sol_log_pubkey(self.as_ref() as *const _ as *const u8) };
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user