Move process_instruction defs to runtime (#12507)
This commit is contained in:
parent
322dbd894f
commit
2ff983647f
|
@ -1,2 +0,0 @@
|
||||||
/target/
|
|
||||||
/farf/
|
|
|
@ -14,15 +14,15 @@ use solana_runtime::{
|
||||||
bank_client::BankClient,
|
bank_client::BankClient,
|
||||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||||
loader_utils::load_program,
|
loader_utils::load_program,
|
||||||
|
process_instruction::{
|
||||||
|
ComputeBudget, ComputeMeter, Executor, InvokeContext, Logger, ProcessInstruction,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
bpf_loader,
|
bpf_loader,
|
||||||
client::SyncClient,
|
client::SyncClient,
|
||||||
entrypoint::SUCCESS,
|
entrypoint::SUCCESS,
|
||||||
entrypoint_native::{
|
|
||||||
ComputeBudget, ComputeMeter, Executor, InvokeContext, Logger, ProcessInstruction,
|
|
||||||
},
|
|
||||||
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
||||||
message::Message,
|
message::Message,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
|
|
|
@ -13,6 +13,9 @@ use solana_runtime::{
|
||||||
bank_client::BankClient,
|
bank_client::BankClient,
|
||||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||||
loader_utils::load_program,
|
loader_utils::load_program,
|
||||||
|
process_instruction::{
|
||||||
|
ComputeBudget, ComputeMeter, Executor, InvokeContext, Logger, ProcessInstruction,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{Account, KeyedAccount},
|
account::{Account, KeyedAccount},
|
||||||
|
@ -20,9 +23,7 @@ use solana_sdk::{
|
||||||
client::SyncClient,
|
client::SyncClient,
|
||||||
clock::{DEFAULT_SLOTS_PER_EPOCH, MAX_PROCESSING_AGE},
|
clock::{DEFAULT_SLOTS_PER_EPOCH, MAX_PROCESSING_AGE},
|
||||||
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
|
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
|
||||||
entrypoint_native::{
|
|
||||||
ComputeBudget, ComputeMeter, Executor, InvokeContext, Logger, ProcessInstruction,
|
|
||||||
},
|
|
||||||
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
||||||
message::Message,
|
message::Message,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
|
@ -629,12 +630,12 @@ fn assert_instruction_count() {
|
||||||
("solana_bpf_rust_128bit", 543),
|
("solana_bpf_rust_128bit", 543),
|
||||||
("solana_bpf_rust_alloc", 19082),
|
("solana_bpf_rust_alloc", 19082),
|
||||||
("solana_bpf_rust_dep_crate", 2),
|
("solana_bpf_rust_dep_crate", 2),
|
||||||
("solana_bpf_rust_external_spend", 473),
|
("solana_bpf_rust_external_spend", 477),
|
||||||
("solana_bpf_rust_iter", 723),
|
("solana_bpf_rust_iter", 723),
|
||||||
("solana_bpf_rust_many_args", 231),
|
("solana_bpf_rust_many_args", 231),
|
||||||
("solana_bpf_rust_noop", 447),
|
("solana_bpf_rust_noop", 451),
|
||||||
("solana_bpf_rust_param_passing", 54),
|
("solana_bpf_rust_param_passing", 54),
|
||||||
("solana_bpf_rust_sanity", 2211),
|
("solana_bpf_rust_sanity", 2215),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,12 @@ use solana_rbpf::{
|
||||||
memory_region::MemoryRegion,
|
memory_region::MemoryRegion,
|
||||||
vm::{EbpfVm, Executable, InstructionMeter},
|
vm::{EbpfVm, Executable, InstructionMeter},
|
||||||
};
|
};
|
||||||
|
use solana_runtime::process_instruction::{ComputeMeter, Executor, InvokeContext};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{is_executable, next_keyed_account, KeyedAccount},
|
account::{is_executable, next_keyed_account, KeyedAccount},
|
||||||
bpf_loader, bpf_loader_deprecated,
|
bpf_loader, bpf_loader_deprecated,
|
||||||
decode_error::DecodeError,
|
decode_error::DecodeError,
|
||||||
entrypoint::SUCCESS,
|
entrypoint::SUCCESS,
|
||||||
entrypoint_native::{ComputeMeter, Executor, InvokeContext},
|
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
loader_instruction::LoaderInstruction,
|
loader_instruction::LoaderInstruction,
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
|
@ -270,14 +270,13 @@ impl Executor for BPFExecutor {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use solana_runtime::message_processor::{Executors, ThisInvokeContext};
|
use solana_runtime::{
|
||||||
|
message_processor::{Executors, ThisInvokeContext},
|
||||||
|
process_instruction::{ComputeBudget, Logger, ProcessInstruction},
|
||||||
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account, instruction::CompiledInstruction, instruction::Instruction,
|
||||||
entrypoint_native::{ComputeBudget, Logger, ProcessInstruction},
|
message::Message, rent::Rent,
|
||||||
instruction::CompiledInstruction,
|
|
||||||
instruction::Instruction,
|
|
||||||
message::Message,
|
|
||||||
rent::Rent,
|
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, fs::File, io::Read, ops::Range, rc::Rc};
|
use std::{cell::RefCell, fs::File, io::Read, ops::Range, rc::Rc};
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,16 @@ use solana_rbpf::{
|
||||||
memory_region::{translate_addr, MemoryRegion},
|
memory_region::{translate_addr, MemoryRegion},
|
||||||
vm::{EbpfVm, SyscallObject},
|
vm::{EbpfVm, SyscallObject},
|
||||||
};
|
};
|
||||||
use solana_runtime::message_processor::MessageProcessor;
|
use solana_runtime::{
|
||||||
|
message_processor::MessageProcessor,
|
||||||
|
process_instruction::{ComputeMeter, InvokeContext, Logger},
|
||||||
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
account::KeyedAccount,
|
account::KeyedAccount,
|
||||||
account_info::AccountInfo,
|
account_info::AccountInfo,
|
||||||
bpf_loader, bpf_loader_deprecated,
|
bpf_loader, bpf_loader_deprecated,
|
||||||
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
|
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
|
||||||
entrypoint_native::{ComputeMeter, InvokeContext, Logger},
|
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
message::Message,
|
message::Message,
|
||||||
program_error::ProgramError,
|
program_error::ProgramError,
|
||||||
|
|
|
@ -18,6 +18,9 @@ use crate::{
|
||||||
log_collector::LogCollector,
|
log_collector::LogCollector,
|
||||||
message_processor::{Executors, MessageProcessor},
|
message_processor::{Executors, MessageProcessor},
|
||||||
nonce_utils,
|
nonce_utils,
|
||||||
|
process_instruction::{
|
||||||
|
ComputeBudget, Executor, ProcessInstruction, ProcessInstructionWithContext,
|
||||||
|
},
|
||||||
rent_collector::RentCollector,
|
rent_collector::RentCollector,
|
||||||
stakes::Stakes,
|
stakes::Stakes,
|
||||||
status_cache::{SlotDelta, StatusCache},
|
status_cache::{SlotDelta, StatusCache},
|
||||||
|
@ -38,9 +41,6 @@ use solana_sdk::{
|
||||||
Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND,
|
Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND,
|
||||||
MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES, SECONDS_PER_DAY,
|
MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES, SECONDS_PER_DAY,
|
||||||
},
|
},
|
||||||
entrypoint_native::{
|
|
||||||
ComputeBudget, Executor, ProcessInstruction, ProcessInstructionWithContext,
|
|
||||||
},
|
|
||||||
epoch_info::EpochInfo,
|
epoch_info::EpochInfo,
|
||||||
epoch_schedule::EpochSchedule,
|
epoch_schedule::EpochSchedule,
|
||||||
fee_calculator::{FeeCalculator, FeeConfig, FeeRateGovernor},
|
fee_calculator::{FeeCalculator, FeeConfig, FeeRateGovernor},
|
||||||
|
@ -211,7 +211,6 @@ pub struct Builtins {
|
||||||
const MAX_CACHED_EXECUTORS: usize = 100; // 10 MB assuming programs are around 100k
|
const MAX_CACHED_EXECUTORS: usize = 100; // 10 MB assuming programs are around 100k
|
||||||
|
|
||||||
/// LFU Cache of executors
|
/// LFU Cache of executors
|
||||||
#[derive(AbiExample)]
|
|
||||||
struct CachedExecutors {
|
struct CachedExecutors {
|
||||||
max: usize,
|
max: usize,
|
||||||
executors: HashMap<Pubkey, (AtomicU64, Arc<dyn Executor>)>,
|
executors: HashMap<Pubkey, (AtomicU64, Arc<dyn Executor>)>,
|
||||||
|
@ -224,6 +223,17 @@ impl Default for CachedExecutors {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
||||||
|
impl AbiExample for CachedExecutors {
|
||||||
|
fn example() -> Self {
|
||||||
|
// Delegate AbiExample impl to Default before going deep and stuck with
|
||||||
|
// not easily impl-able Arc<dyn Executor> due to rust's coherence issue
|
||||||
|
// This is safe because CachedExecutors isn't serializable by definition.
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Clone for CachedExecutors {
|
impl Clone for CachedExecutors {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
let mut executors = HashMap::new();
|
let mut executors = HashMap::new();
|
||||||
|
@ -3816,13 +3826,13 @@ mod tests {
|
||||||
genesis_utils::{
|
genesis_utils::{
|
||||||
create_genesis_config_with_leader, GenesisConfigInfo, BOOTSTRAP_VALIDATOR_LAMPORTS,
|
create_genesis_config_with_leader, GenesisConfigInfo, BOOTSTRAP_VALIDATOR_LAMPORTS,
|
||||||
},
|
},
|
||||||
|
process_instruction::InvokeContext,
|
||||||
status_cache::MAX_CACHE_ENTRIES,
|
status_cache::MAX_CACHE_ENTRIES,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::KeyedAccount,
|
account::KeyedAccount,
|
||||||
account_utils::StateMut,
|
account_utils::StateMut,
|
||||||
clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_TICKS_PER_SLOT},
|
clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_TICKS_PER_SLOT},
|
||||||
entrypoint_native::InvokeContext,
|
|
||||||
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
|
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
|
||||||
genesis_config::create_genesis_config,
|
genesis_config::create_genesis_config,
|
||||||
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
||||||
|
@ -8750,7 +8760,7 @@ mod tests {
|
||||||
_pubkey: &Pubkey,
|
_pubkey: &Pubkey,
|
||||||
_ka: &[KeyedAccount],
|
_ka: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
_context: &mut dyn solana_sdk::entrypoint_native::InvokeContext,
|
_context: &mut dyn InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ pub mod log_collector;
|
||||||
pub mod message_processor;
|
pub mod message_processor;
|
||||||
mod native_loader;
|
mod native_loader;
|
||||||
pub mod nonce_utils;
|
pub mod nonce_utils;
|
||||||
|
pub mod process_instruction;
|
||||||
pub mod rent_collector;
|
pub mod rent_collector;
|
||||||
pub mod serde_snapshot;
|
pub mod serde_snapshot;
|
||||||
pub mod snapshot_package;
|
pub mod snapshot_package;
|
||||||
|
|
|
@ -3,6 +3,10 @@ use crate::{
|
||||||
instruction_recorder::InstructionRecorder,
|
instruction_recorder::InstructionRecorder,
|
||||||
log_collector::LogCollector,
|
log_collector::LogCollector,
|
||||||
native_loader::NativeLoader,
|
native_loader::NativeLoader,
|
||||||
|
process_instruction::{
|
||||||
|
ComputeBudget, ComputeMeter, ErasedProcessInstruction, ErasedProcessInstructionWithContext,
|
||||||
|
Executor, InvokeContext, Logger, ProcessInstruction, ProcessInstructionWithContext,
|
||||||
|
},
|
||||||
rent_collector::RentCollector,
|
rent_collector::RentCollector,
|
||||||
};
|
};
|
||||||
use log::*;
|
use log::*;
|
||||||
|
@ -10,10 +14,6 @@ use serde::{Deserialize, Serialize};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{create_keyed_readonly_accounts, Account, KeyedAccount},
|
account::{create_keyed_readonly_accounts, Account, KeyedAccount},
|
||||||
clock::Epoch,
|
clock::Epoch,
|
||||||
entrypoint_native::{
|
|
||||||
ComputeBudget, ComputeMeter, ErasedProcessInstruction, ErasedProcessInstructionWithContext,
|
|
||||||
Executor, InvokeContext, Logger, ProcessInstruction, ProcessInstructionWithContext,
|
|
||||||
},
|
|
||||||
instruction::{CompiledInstruction, Instruction, InstructionError},
|
instruction::{CompiledInstruction, Instruction, InstructionError},
|
||||||
message::Message,
|
message::Message,
|
||||||
native_loader,
|
native_loader,
|
||||||
|
@ -1694,7 +1694,7 @@ mod tests {
|
||||||
_pubkey: &Pubkey,
|
_pubkey: &Pubkey,
|
||||||
_ka: &[KeyedAccount],
|
_ka: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
_context: &mut dyn solana_sdk::entrypoint_native::InvokeContext,
|
_context: &mut dyn InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
//! Native loader
|
//! Native loader
|
||||||
|
use crate::process_instruction::{InvokeContext, LoaderEntrypoint};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use libloading::os::unix::*;
|
use libloading::os::unix::*;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -8,7 +9,7 @@ use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{next_keyed_account, KeyedAccount},
|
account::{next_keyed_account, KeyedAccount},
|
||||||
decode_error::DecodeError,
|
decode_error::DecodeError,
|
||||||
entrypoint_native::{InvokeContext, LoaderEntrypoint, ProgramEntrypoint},
|
entrypoint_native::ProgramEntrypoint,
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
use solana_sdk::{
|
||||||
|
account::{Account, KeyedAccount},
|
||||||
|
instruction::{CompiledInstruction, Instruction, InstructionError},
|
||||||
|
message::Message,
|
||||||
|
pubkey::Pubkey,
|
||||||
|
};
|
||||||
|
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
||||||
|
|
||||||
|
// Prototype of a native loader entry point
|
||||||
|
///
|
||||||
|
/// program_id: Program ID of the currently executing program
|
||||||
|
/// keyed_accounts: Accounts passed as part of the instruction
|
||||||
|
/// instruction_data: Instruction data
|
||||||
|
/// invoke_context: Invocation context
|
||||||
|
pub type LoaderEntrypoint = unsafe extern "C" fn(
|
||||||
|
program_id: &Pubkey,
|
||||||
|
keyed_accounts: &[KeyedAccount],
|
||||||
|
instruction_data: &[u8],
|
||||||
|
invoke_context: &dyn InvokeContext,
|
||||||
|
) -> Result<(), InstructionError>;
|
||||||
|
|
||||||
|
pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>;
|
||||||
|
pub type ProcessInstructionWithContext =
|
||||||
|
fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>;
|
||||||
|
|
||||||
|
// These are just type aliases for work around of Debug-ing above function pointers
|
||||||
|
pub type ErasedProcessInstructionWithContext = fn(
|
||||||
|
&'static Pubkey,
|
||||||
|
&'static [KeyedAccount<'static>],
|
||||||
|
&'static [u8],
|
||||||
|
&'static mut dyn InvokeContext,
|
||||||
|
) -> Result<(), InstructionError>;
|
||||||
|
|
||||||
|
pub type ErasedProcessInstruction = fn(
|
||||||
|
&'static Pubkey,
|
||||||
|
&'static [KeyedAccount<'static>],
|
||||||
|
&'static [u8],
|
||||||
|
) -> Result<(), InstructionError>;
|
||||||
|
|
||||||
|
/// Invocation context passed to loaders
|
||||||
|
pub trait InvokeContext {
|
||||||
|
/// Push a program ID on to the invocation stack
|
||||||
|
fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError>;
|
||||||
|
/// Pop a program ID off of the invocation stack
|
||||||
|
fn pop(&mut self);
|
||||||
|
/// Verify and update PreAccount state based on program execution
|
||||||
|
fn verify_and_update(
|
||||||
|
&mut self,
|
||||||
|
message: &Message,
|
||||||
|
instruction: &CompiledInstruction,
|
||||||
|
accounts: &[Rc<RefCell<Account>>],
|
||||||
|
) -> Result<(), InstructionError>;
|
||||||
|
/// Get the program ID of the currently executing program
|
||||||
|
fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
|
||||||
|
/// Get a list of built-in programs
|
||||||
|
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)];
|
||||||
|
/// Get this invocation's logger
|
||||||
|
fn get_logger(&self) -> Rc<RefCell<dyn Logger>>;
|
||||||
|
/// Are cross program invocations supported
|
||||||
|
fn is_cross_program_supported(&self) -> bool;
|
||||||
|
/// Get this invocation's compute budget
|
||||||
|
fn get_compute_budget(&self) -> ComputeBudget;
|
||||||
|
/// Get this invocation's compute meter
|
||||||
|
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>>;
|
||||||
|
/// Loaders may need to do work in order to execute a program. Cache
|
||||||
|
/// the work that can be re-used across executions
|
||||||
|
fn add_executor(&mut self, pubkey: &Pubkey, executor: Arc<dyn Executor>);
|
||||||
|
/// Get the completed loader work that can be re-used across executions
|
||||||
|
fn get_executor(&mut self, pubkey: &Pubkey) -> Option<Arc<dyn Executor>>;
|
||||||
|
/// Record invoked instruction
|
||||||
|
fn record_instruction(&self, instruction: &Instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct ComputeBudget {
|
||||||
|
/// Number of compute units that an instruction is allowed. Compute units
|
||||||
|
/// are consumed by program execution, resources they use, etc...
|
||||||
|
pub max_units: u64,
|
||||||
|
/// Number of compute units consumed by a log call
|
||||||
|
pub log_units: u64,
|
||||||
|
/// Number of compute units consumed by a log_u64 call
|
||||||
|
pub log_64_units: u64,
|
||||||
|
/// Number of compute units consumed by a create_program_address call
|
||||||
|
pub create_program_address_units: u64,
|
||||||
|
/// Number of compute units consumed by an invoke call (not including the cost incured by
|
||||||
|
/// the called program)
|
||||||
|
pub invoke_units: u64,
|
||||||
|
/// Maximum cross-program invocation depth allowed including the orignal caller
|
||||||
|
pub max_invoke_depth: usize,
|
||||||
|
}
|
||||||
|
impl Default for ComputeBudget {
|
||||||
|
fn default() -> Self {
|
||||||
|
// Tuned for ~1ms
|
||||||
|
ComputeBudget {
|
||||||
|
max_units: 200_000,
|
||||||
|
log_units: 100,
|
||||||
|
log_64_units: 100,
|
||||||
|
create_program_address_units: 1500,
|
||||||
|
invoke_units: 1000,
|
||||||
|
max_invoke_depth: 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute meter
|
||||||
|
pub trait ComputeMeter {
|
||||||
|
/// Consume compute units
|
||||||
|
fn consume(&mut self, amount: u64) -> Result<(), InstructionError>;
|
||||||
|
/// Get the number of remaining compute units
|
||||||
|
fn get_remaining(&self) -> u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log messages
|
||||||
|
pub trait Logger {
|
||||||
|
fn log_enabled(&self) -> bool;
|
||||||
|
/// Log a message
|
||||||
|
fn log(&mut self, message: &str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Program executor
|
||||||
|
pub trait Executor: Send + Sync {
|
||||||
|
/// Execute the program
|
||||||
|
fn execute(
|
||||||
|
&self,
|
||||||
|
program_id: &Pubkey,
|
||||||
|
keyed_accounts: &[KeyedAccount],
|
||||||
|
instruction_data: &[u8],
|
||||||
|
invoke_context: &mut dyn InvokeContext,
|
||||||
|
) -> Result<(), InstructionError>;
|
||||||
|
}
|
|
@ -1,14 +1,6 @@
|
||||||
//! @brief Solana Native program entry point
|
//! @brief Solana Native program entry point
|
||||||
|
|
||||||
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
use crate::{account::KeyedAccount, instruction::InstructionError, pubkey::Pubkey};
|
||||||
use crate::abi_example::AbiExample;
|
|
||||||
use crate::{
|
|
||||||
account::{Account, KeyedAccount},
|
|
||||||
instruction::{CompiledInstruction, Instruction, InstructionError},
|
|
||||||
message::Message,
|
|
||||||
pubkey::Pubkey,
|
|
||||||
};
|
|
||||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
|
||||||
|
|
||||||
// Prototype of a native program entry point
|
// Prototype of a native program entry point
|
||||||
///
|
///
|
||||||
|
@ -21,19 +13,6 @@ pub type ProgramEntrypoint = unsafe extern "C" fn(
|
||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
) -> Result<(), InstructionError>;
|
) -> Result<(), InstructionError>;
|
||||||
|
|
||||||
// Prototype of a native loader entry point
|
|
||||||
///
|
|
||||||
/// program_id: Program ID of the currently executing program
|
|
||||||
/// keyed_accounts: Accounts passed as part of the instruction
|
|
||||||
/// instruction_data: Instruction data
|
|
||||||
/// invoke_context: Invocation context
|
|
||||||
pub type LoaderEntrypoint = unsafe extern "C" fn(
|
|
||||||
program_id: &Pubkey,
|
|
||||||
keyed_accounts: &[KeyedAccount],
|
|
||||||
instruction_data: &[u8],
|
|
||||||
invoke_context: &dyn InvokeContext,
|
|
||||||
) -> Result<(), InstructionError>;
|
|
||||||
|
|
||||||
#[rustversion::since(1.46.0)]
|
#[rustversion::since(1.46.0)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! declare_name {
|
macro_rules! declare_name {
|
||||||
|
@ -178,131 +157,3 @@ macro_rules! declare_program(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>;
|
|
||||||
pub type ProcessInstructionWithContext =
|
|
||||||
fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>;
|
|
||||||
|
|
||||||
// These are just type aliases for work around of Debug-ing above function pointers
|
|
||||||
pub type ErasedProcessInstructionWithContext = fn(
|
|
||||||
&'static Pubkey,
|
|
||||||
&'static [KeyedAccount<'static>],
|
|
||||||
&'static [u8],
|
|
||||||
&'static mut dyn InvokeContext,
|
|
||||||
) -> Result<(), InstructionError>;
|
|
||||||
|
|
||||||
pub type ErasedProcessInstruction = fn(
|
|
||||||
&'static Pubkey,
|
|
||||||
&'static [KeyedAccount<'static>],
|
|
||||||
&'static [u8],
|
|
||||||
) -> Result<(), InstructionError>;
|
|
||||||
|
|
||||||
/// Invocation context passed to loaders
|
|
||||||
pub trait InvokeContext {
|
|
||||||
/// Push a program ID on to the invocation stack
|
|
||||||
fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError>;
|
|
||||||
/// Pop a program ID off of the invocation stack
|
|
||||||
fn pop(&mut self);
|
|
||||||
/// Verify and update PreAccount state based on program execution
|
|
||||||
fn verify_and_update(
|
|
||||||
&mut self,
|
|
||||||
message: &Message,
|
|
||||||
instruction: &CompiledInstruction,
|
|
||||||
accounts: &[Rc<RefCell<Account>>],
|
|
||||||
) -> Result<(), InstructionError>;
|
|
||||||
/// Get the program ID of the currently executing program
|
|
||||||
fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
|
|
||||||
/// Get a list of built-in programs
|
|
||||||
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)];
|
|
||||||
/// Get this invocation's logger
|
|
||||||
fn get_logger(&self) -> Rc<RefCell<dyn Logger>>;
|
|
||||||
/// Are cross program invocations supported
|
|
||||||
fn is_cross_program_supported(&self) -> bool;
|
|
||||||
/// Get this invocation's compute budget
|
|
||||||
fn get_compute_budget(&self) -> ComputeBudget;
|
|
||||||
/// Get this invocation's compute meter
|
|
||||||
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>>;
|
|
||||||
/// Loaders may need to do work in order to execute a program. Cache
|
|
||||||
/// the work that can be re-used across executions
|
|
||||||
fn add_executor(&mut self, pubkey: &Pubkey, executor: Arc<dyn Executor>);
|
|
||||||
/// Get the completed loader work that can be re-used across executions
|
|
||||||
fn get_executor(&mut self, pubkey: &Pubkey) -> Option<Arc<dyn Executor>>;
|
|
||||||
/// Record invoked instruction
|
|
||||||
fn record_instruction(&self, instruction: &Instruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct ComputeBudget {
|
|
||||||
/// Number of compute units that an instruction is allowed. Compute units
|
|
||||||
/// are consumed by program execution, resources they use, etc...
|
|
||||||
pub max_units: u64,
|
|
||||||
/// Number of compute units consumed by a log call
|
|
||||||
pub log_units: u64,
|
|
||||||
/// Number of compute units consumed by a log_u64 call
|
|
||||||
pub log_64_units: u64,
|
|
||||||
/// Number of compute units consumed by a create_program_address call
|
|
||||||
pub create_program_address_units: u64,
|
|
||||||
/// Number of compute units consumed by an invoke call (not including the cost incured by
|
|
||||||
/// the called program)
|
|
||||||
pub invoke_units: u64,
|
|
||||||
/// Maximum cross-program invocation depth allowed including the orignal caller
|
|
||||||
pub max_invoke_depth: usize,
|
|
||||||
}
|
|
||||||
impl Default for ComputeBudget {
|
|
||||||
fn default() -> Self {
|
|
||||||
// Tuned for ~1ms
|
|
||||||
ComputeBudget {
|
|
||||||
max_units: 200_000,
|
|
||||||
log_units: 100,
|
|
||||||
log_64_units: 100,
|
|
||||||
create_program_address_units: 1500,
|
|
||||||
invoke_units: 1000,
|
|
||||||
max_invoke_depth: 2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compute meter
|
|
||||||
pub trait ComputeMeter {
|
|
||||||
/// Consume compute units
|
|
||||||
fn consume(&mut self, amount: u64) -> Result<(), InstructionError>;
|
|
||||||
/// Get the number of remaining compute units
|
|
||||||
fn get_remaining(&self) -> u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Log messages
|
|
||||||
pub trait Logger {
|
|
||||||
fn log_enabled(&self) -> bool;
|
|
||||||
/// Log a message
|
|
||||||
fn log(&mut self, message: &str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Program executor
|
|
||||||
pub trait Executor: Send + Sync {
|
|
||||||
/// Execute the program
|
|
||||||
fn execute(
|
|
||||||
&self,
|
|
||||||
program_id: &Pubkey,
|
|
||||||
keyed_accounts: &[KeyedAccount],
|
|
||||||
instruction_data: &[u8],
|
|
||||||
invoke_context: &mut dyn InvokeContext,
|
|
||||||
) -> Result<(), InstructionError>;
|
|
||||||
}
|
|
||||||
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
|
||||||
impl AbiExample for Arc<dyn Executor> {
|
|
||||||
fn example() -> Self {
|
|
||||||
struct ExampleExecutor {}
|
|
||||||
impl Executor for ExampleExecutor {
|
|
||||||
fn execute(
|
|
||||||
&self,
|
|
||||||
_program_id: &Pubkey,
|
|
||||||
_keyed_accounts: &[KeyedAccount],
|
|
||||||
_instruction_data: &[u8],
|
|
||||||
_invoke_context: &mut dyn InvokeContext,
|
|
||||||
) -> std::result::Result<(), InstructionError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Arc::new(ExampleExecutor {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue