Add Cross-program invocations (#9582)
This commit is contained in:
@ -1,6 +1,10 @@
|
||||
//! @brief Solana Native program entry point
|
||||
|
||||
use crate::{account::KeyedAccount, instruction::InstructionError, pubkey::Pubkey};
|
||||
use crate::{
|
||||
account::Account, account::KeyedAccount, instruction::CompiledInstruction,
|
||||
instruction::InstructionError, message::Message, pubkey::Pubkey,
|
||||
};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
// Prototype of a native program entry point
|
||||
///
|
||||
@ -23,6 +27,7 @@ pub type LoaderEntrypoint = unsafe extern "C" fn(
|
||||
program_id: &Pubkey,
|
||||
keyed_accounts: &[KeyedAccount],
|
||||
instruction_data: &[u8],
|
||||
invoke_context: &dyn InvokeContext,
|
||||
) -> Result<(), InstructionError>;
|
||||
|
||||
/// Convenience macro to declare a native program
|
||||
@ -134,8 +139,22 @@ macro_rules! declare_loader(
|
||||
program_id: &$crate::pubkey::Pubkey,
|
||||
keyed_accounts: &[$crate::account::KeyedAccount],
|
||||
instruction_data: &[u8],
|
||||
invoke_context: &mut dyn $crate::entrypoint_native::InvokeContext,
|
||||
) -> Result<(), $crate::instruction::InstructionError> {
|
||||
$entrypoint(program_id, keyed_accounts, instruction_data)
|
||||
$entrypoint(program_id, keyed_accounts, instruction_data, invoke_context)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
/// Cross-program invocation context passed to loaders
|
||||
pub trait InvokeContext {
|
||||
fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError>;
|
||||
fn pop(&mut self);
|
||||
fn verify_and_update(
|
||||
&mut self,
|
||||
message: &Message,
|
||||
instruction: &CompiledInstruction,
|
||||
signers: &[Pubkey],
|
||||
accounts: &[Rc<RefCell<Account>>],
|
||||
) -> Result<(), InstructionError>;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ pub enum InstructionError {
|
||||
RentEpochModified,
|
||||
|
||||
/// The instruction expected additional account keys
|
||||
#[error("insufficient account key count for instruction")]
|
||||
#[error("insufficient account keys for instruction")]
|
||||
NotEnoughAccountKeys,
|
||||
|
||||
/// A non-system program changed the size of the account data
|
||||
@ -138,6 +138,26 @@ pub enum InstructionError {
|
||||
/// Unsupported program id
|
||||
#[error("Unsupported program id")]
|
||||
UnsupportedProgramId,
|
||||
|
||||
/// Writable bit on account info changed, but shouldn't have
|
||||
#[error("Writable bit on account info changed, but shouldn't have")]
|
||||
WritableModified,
|
||||
|
||||
/// Signer bit on account info changed, but shouldn't have
|
||||
#[error("Signer bit on account info changed, but shouldn't have")]
|
||||
SignerModified,
|
||||
|
||||
/// Cross-program invocation call depth too deep
|
||||
#[error("Cross-program invocation call depth too deep")]
|
||||
CallDepth,
|
||||
|
||||
/// An account required by the instruction is missing
|
||||
#[error("An account required by the instruction is missing")]
|
||||
MissingAccount,
|
||||
|
||||
/// Cross-program invocation reentrancy not allowed for this instruction
|
||||
#[error("Cross-program invocation reentrancy not allowed for this instruction")]
|
||||
ReentrancyNotAllowed,
|
||||
}
|
||||
|
||||
impl InstructionError {
|
||||
|
@ -61,6 +61,7 @@ pub use solana_sdk_macro::declare_id;
|
||||
pub mod account_info;
|
||||
pub mod entrypoint;
|
||||
pub mod log;
|
||||
pub mod program;
|
||||
pub mod program_error;
|
||||
|
||||
// Modules not usable by on-chain programs
|
||||
|
42
sdk/src/program.rs
Normal file
42
sdk/src/program.rs
Normal file
@ -0,0 +1,42 @@
|
||||
#![cfg(feature = "program")]
|
||||
|
||||
use crate::{
|
||||
account_info::AccountInfo, entrypoint::ProgramResult, entrypoint::SUCCESS,
|
||||
instruction::Instruction,
|
||||
};
|
||||
|
||||
/// Invoke a cross-program instruction
|
||||
pub fn invoke(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult {
|
||||
invoke_signed(instruction, account_infos, &[])
|
||||
}
|
||||
|
||||
/// Invoke a cross-program instruction with program signatures
|
||||
pub fn invoke_signed(
|
||||
instruction: &Instruction,
|
||||
account_infos: &[AccountInfo],
|
||||
signers_seeds: &[&[&str]],
|
||||
) -> ProgramResult {
|
||||
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()),
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn sol_invoke_signed_rust(
|
||||
instruction_addr: *const u8,
|
||||
account_infos_addr: *const u8,
|
||||
account_infos_len: u64,
|
||||
signers_seeds_addr: *const u8,
|
||||
signers_seeds_len: u64,
|
||||
) -> u64;
|
||||
}
|
Reference in New Issue
Block a user