Refactor - Cleanup error handling in program runtime (#30693)
* Moves stable_log::program_invoke(), stable_log::program_success() and stable_log::program_failure() calls from bpf_loader into InvokeContext::process_executable_chain(). * Turns result of ProcessInstructionWithContext from InstructionError into Box<dyn std::error::Error>. * Bump to solana_rbpf v0.3.0 * Removes Result from return type of EbpfVm::new(). * Turns EbpfError into Box<dyn std::error::Error>. * Removes BpfError. * Removes SyscallError::InstructionError. * Adds a type alias for Box<dyn std::error::Error> in syscalls.
This commit is contained in:
parent
06461fb348
commit
24a87f33a8
|
@ -7343,9 +7343,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana_rbpf"
|
name = "solana_rbpf"
|
||||||
version = "0.2.40"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a5735b8c9defc3723162321a61ef738d34168401eeef213f62a32809739b0f5"
|
checksum = "edb31627f86190e2d97f86988f1de1a757b530caa50694244d9d28812611b063"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"combine",
|
"combine",
|
||||||
|
|
|
@ -289,7 +289,7 @@ signal-hook = "0.3.14"
|
||||||
smpl_jwt = "0.7.1"
|
smpl_jwt = "0.7.1"
|
||||||
socket2 = "0.4.7"
|
socket2 = "0.4.7"
|
||||||
soketto = "0.7"
|
soketto = "0.7"
|
||||||
solana_rbpf = "=0.2.40"
|
solana_rbpf = "=0.3.0"
|
||||||
solana-account-decoder = { path = "account-decoder", version = "=1.16.0" }
|
solana-account-decoder = { path = "account-decoder", version = "=1.16.0" }
|
||||||
solana-address-lookup-table-program = { path = "programs/address-lookup-table", version = "=1.16.0" }
|
solana-address-lookup-table-program = { path = "programs/address-lookup-table", version = "=1.16.0" }
|
||||||
solana-banks-client = { path = "banks-client", version = "=1.16.0" }
|
solana-banks-client = { path = "banks-client", version = "=1.16.0" }
|
||||||
|
|
|
@ -2975,7 +2975,7 @@ pub mod tests {
|
||||||
|
|
||||||
fn mock_processor_ok(
|
fn mock_processor_ok(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
invoke_context.consume_checked(1)?;
|
invoke_context.consume_checked(1)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -3006,7 +3006,7 @@ pub mod tests {
|
||||||
|
|
||||||
fn mock_processor_err(
|
fn mock_processor_err(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let instruction_errors = get_instruction_errors();
|
let instruction_errors = get_instruction_errors();
|
||||||
|
|
||||||
invoke_context.consume_checked(1)?;
|
invoke_context.consume_checked(1)?;
|
||||||
|
@ -3017,10 +3017,12 @@ pub mod tests {
|
||||||
.get_instruction_data()
|
.get_instruction_data()
|
||||||
.first()
|
.first()
|
||||||
.expect("Failed to get instruction data");
|
.expect("Failed to get instruction data");
|
||||||
Err(instruction_errors
|
Err(Box::new(
|
||||||
.get(*err as usize)
|
instruction_errors
|
||||||
.expect("Invalid error index")
|
.get(*err as usize)
|
||||||
.clone())
|
.expect("Invalid error index")
|
||||||
|
.clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bankhash_err = None;
|
let mut bankhash_err = None;
|
||||||
|
|
|
@ -38,7 +38,27 @@ use {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type ProcessInstructionWithContext = fn(&mut InvokeContext) -> Result<(), InstructionError>;
|
/// Adapter so we can unify the interfaces of built-in programs and syscalls
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! declare_process_instruction {
|
||||||
|
($cu_to_consume:expr) => {
|
||||||
|
pub fn process_instruction(
|
||||||
|
invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::native_programs_consume_cu::id())
|
||||||
|
{
|
||||||
|
invoke_context.consume_checked($cu_to_consume)?;
|
||||||
|
}
|
||||||
|
process_instruction_inner(invoke_context)
|
||||||
|
.map_err(|err| Box::new(err) as Box<dyn std::error::Error>)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ProcessInstructionWithContext =
|
||||||
|
fn(&mut InvokeContext) -> Result<(), Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BuiltinProgram {
|
pub struct BuiltinProgram {
|
||||||
|
@ -50,7 +70,7 @@ impl std::fmt::Debug for BuiltinProgram {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
// These are just type aliases for work around of Debug-ing above pointers
|
// These are just type aliases for work around of Debug-ing above pointers
|
||||||
type ErasedProcessInstructionWithContext =
|
type ErasedProcessInstructionWithContext =
|
||||||
fn(&'static mut InvokeContext<'static>) -> Result<(), InstructionError>;
|
fn(&'static mut InvokeContext<'static>) -> Result<(), Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
// rustc doesn't compile due to bug without this work around
|
// rustc doesn't compile due to bug without this work around
|
||||||
// https://github.com/rust-lang/rust/issues/50280
|
// https://github.com/rust-lang/rust/issues/50280
|
||||||
|
@ -689,26 +709,25 @@ impl<'a> InvokeContext<'a> {
|
||||||
self.transaction_context
|
self.transaction_context
|
||||||
.set_return_data(program_id, Vec::new())?;
|
.set_return_data(program_id, Vec::new())?;
|
||||||
|
|
||||||
let is_builtin_program = builtin_id == program_id;
|
|
||||||
let pre_remaining_units = self.get_remaining();
|
let pre_remaining_units = self.get_remaining();
|
||||||
let result = if is_builtin_program {
|
let logger = self.get_log_collector();
|
||||||
let logger = self.get_log_collector();
|
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
|
||||||
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
|
let result = (entry.process_instruction)(self)
|
||||||
(entry.process_instruction)(self)
|
.map(|()| {
|
||||||
.map(|()| {
|
stable_log::program_success(&logger, &program_id);
|
||||||
stable_log::program_success(&logger, &program_id);
|
})
|
||||||
})
|
.map_err(|err| {
|
||||||
.map_err(|err| {
|
stable_log::program_failure(&logger, &program_id, err.as_ref());
|
||||||
stable_log::program_failure(&logger, &program_id, &err);
|
if let Some(err) = err.downcast_ref::<InstructionError>() {
|
||||||
err
|
err.clone()
|
||||||
})
|
} else {
|
||||||
} else {
|
InstructionError::ProgramFailedToComplete
|
||||||
(entry.process_instruction)(self)
|
}
|
||||||
};
|
});
|
||||||
let post_remaining_units = self.get_remaining();
|
let post_remaining_units = self.get_remaining();
|
||||||
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);
|
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);
|
||||||
|
|
||||||
if is_builtin_program
|
if builtin_id == program_id
|
||||||
&& result.is_ok()
|
&& result.is_ok()
|
||||||
&& *compute_units_consumed == 0
|
&& *compute_units_consumed == 0
|
||||||
&& self
|
&& self
|
||||||
|
@ -739,13 +758,13 @@ impl<'a> InvokeContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume compute units
|
/// Consume compute units
|
||||||
pub fn consume_checked(&self, amount: u64) -> Result<(), InstructionError> {
|
pub fn consume_checked(&self, amount: u64) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
self.log_consumed_bpf_units(amount);
|
self.log_consumed_bpf_units(amount);
|
||||||
let mut compute_meter = self.compute_meter.borrow_mut();
|
let mut compute_meter = self.compute_meter.borrow_mut();
|
||||||
let exceeded = *compute_meter < amount;
|
let exceeded = *compute_meter < amount;
|
||||||
*compute_meter = compute_meter.saturating_sub(amount);
|
*compute_meter = compute_meter.saturating_sub(amount);
|
||||||
if exceeded {
|
if exceeded {
|
||||||
return Err(InstructionError::ComputationalBudgetExceeded);
|
return Err(Box::new(InstructionError::ComputationalBudgetExceeded));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -986,14 +1005,14 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_program_entry_debug() {
|
fn test_program_entry_debug() {
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
|
||||||
fn mock_process_instruction(
|
fn mock_process_instruction(
|
||||||
_invoke_context: &mut InvokeContext,
|
_invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
fn mock_ix_processor(
|
||||||
fn mock_ix_processor(_invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
_invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
let builtin_programs = &[
|
let builtin_programs = &[
|
||||||
|
@ -1014,7 +1033,7 @@ mod tests {
|
||||||
#[allow(clippy::integer_arithmetic)]
|
#[allow(clippy::integer_arithmetic)]
|
||||||
fn mock_process_instruction(
|
fn mock_process_instruction(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -1048,7 +1067,7 @@ mod tests {
|
||||||
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
||||||
match instruction {
|
match instruction {
|
||||||
MockInstruction::NoopSuccess => (),
|
MockInstruction::NoopSuccess => (),
|
||||||
MockInstruction::NoopFail => return Err(InstructionError::GenericError),
|
MockInstruction::NoopFail => return Err(Box::new(InstructionError::GenericError)),
|
||||||
MockInstruction::ModifyOwned => instruction_context
|
MockInstruction::ModifyOwned => instruction_context
|
||||||
.try_borrow_instruction_account(transaction_context, 0)?
|
.try_borrow_instruction_account(transaction_context, 0)?
|
||||||
.set_data_from_slice(&[1])?,
|
.set_data_from_slice(&[1])?,
|
||||||
|
@ -1098,14 +1117,15 @@ mod tests {
|
||||||
desired_result,
|
desired_result,
|
||||||
} => {
|
} => {
|
||||||
invoke_context.consume_checked(compute_units_to_consume)?;
|
invoke_context.consume_checked(compute_units_to_consume)?;
|
||||||
return desired_result;
|
return desired_result
|
||||||
|
.map_err(|err| Box::new(err) as Box<dyn std::error::Error>);
|
||||||
}
|
}
|
||||||
MockInstruction::Resize { new_len } => instruction_context
|
MockInstruction::Resize { new_len } => instruction_context
|
||||||
.try_borrow_instruction_account(transaction_context, 0)?
|
.try_borrow_instruction_account(transaction_context, 0)?
|
||||||
.set_data(vec![0; new_len as usize])?,
|
.set_data(vec![0; new_len as usize])?,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(InstructionError::InvalidInstructionData);
|
return Err(Box::new(InstructionError::InvalidInstructionData));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ impl LoadedProgram {
|
||||||
account_size: usize,
|
account_size: usize,
|
||||||
use_jit: bool,
|
use_jit: bool,
|
||||||
metrics: &mut LoadProgramMetrics,
|
metrics: &mut LoadProgramMetrics,
|
||||||
) -> Result<Self, EbpfError> {
|
) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
let mut load_elf_time = Measure::start("load_elf_time");
|
let mut load_elf_time = Measure::start("load_elf_time");
|
||||||
let executable = Executable::load(elf_bytes, loader.clone())?;
|
let executable = Executable::load(elf_bytes, loader.clone())?;
|
||||||
load_elf_time.stop();
|
load_elf_time.stop();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{ic_logger_msg, log_collector::LogCollector},
|
crate::{ic_logger_msg, log_collector::LogCollector},
|
||||||
itertools::Itertools,
|
itertools::Itertools,
|
||||||
solana_sdk::{instruction::InstructionError, pubkey::Pubkey},
|
solana_sdk::pubkey::Pubkey,
|
||||||
std::{cell::RefCell, rc::Rc},
|
std::{cell::RefCell, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ pub fn program_success(log_collector: &Option<Rc<RefCell<LogCollector>>>, progra
|
||||||
pub fn program_failure(
|
pub fn program_failure(
|
||||||
log_collector: &Option<Rc<RefCell<LogCollector>>>,
|
log_collector: &Option<Rc<RefCell<LogCollector>>>,
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
err: &InstructionError,
|
err: &dyn std::error::Error,
|
||||||
) {
|
) {
|
||||||
ic_logger_msg!(log_collector, "Program {} failed: {}", program_id, err);
|
ic_logger_msg!(log_collector, "Program {} failed: {}", program_id, err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ fn get_invoke_context<'a, 'b>() -> &'a mut InvokeContext<'b> {
|
||||||
pub fn builtin_process_instruction(
|
pub fn builtin_process_instruction(
|
||||||
process_instruction: solana_sdk::entrypoint::ProcessInstruction,
|
process_instruction: solana_sdk::entrypoint::ProcessInstruction,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
set_invoke_context(invoke_context);
|
set_invoke_context(invoke_context);
|
||||||
|
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
|
@ -134,8 +134,8 @@ pub fn builtin_process_instruction(
|
||||||
|
|
||||||
// Execute the program
|
// Execute the program
|
||||||
process_instruction(program_id, &account_infos, instruction_data).map_err(|err| {
|
process_instruction(program_id, &account_infos, instruction_data).map_err(|err| {
|
||||||
let err = u64::from(err);
|
let err: Box<dyn std::error::Error> = Box::new(InstructionError::from(u64::from(err)));
|
||||||
stable_log::program_failure(&log_collector, program_id, &err.into());
|
stable_log::program_failure(&log_collector, program_id, err.as_ref());
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
stable_log::program_success(&log_collector, program_id);
|
stable_log::program_success(&log_collector, program_id);
|
||||||
|
|
|
@ -6,7 +6,7 @@ use {
|
||||||
LOOKUP_TABLE_MAX_ADDRESSES, LOOKUP_TABLE_META_SIZE,
|
LOOKUP_TABLE_MAX_ADDRESSES, LOOKUP_TABLE_META_SIZE,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
solana_program_runtime::{ic_msg, invoke_context::InvokeContext},
|
solana_program_runtime::{declare_process_instruction, ic_msg, invoke_context::InvokeContext},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
clock::Slot,
|
clock::Slot,
|
||||||
feature_set,
|
feature_set,
|
||||||
|
@ -18,14 +18,10 @@ use {
|
||||||
std::convert::TryFrom,
|
std::convert::TryFrom,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
declare_process_instruction!(750);
|
||||||
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
pub fn process_instruction_inner(
|
||||||
if invoke_context
|
invoke_context: &mut InvokeContext,
|
||||||
.feature_set
|
) -> Result<(), InstructionError> {
|
||||||
.is_active(&feature_set::native_programs_consume_cu::id())
|
|
||||||
{
|
|
||||||
invoke_context.consume_checked(750)?;
|
|
||||||
}
|
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
|
|
@ -10,11 +10,7 @@ pub mod upgradeable_with_jit;
|
||||||
pub mod with_jit;
|
pub mod with_jit;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::allocator_bump::BpfAllocator,
|
||||||
allocator_bump::BpfAllocator,
|
|
||||||
serialization::{deserialize_parameters, serialize_parameters},
|
|
||||||
syscalls::SyscallError,
|
|
||||||
},
|
|
||||||
solana_measure::measure::Measure,
|
solana_measure::measure::Measure,
|
||||||
solana_program_runtime::{
|
solana_program_runtime::{
|
||||||
compute_budget::ComputeBudget,
|
compute_budget::ComputeBudget,
|
||||||
|
@ -30,9 +26,8 @@ use {
|
||||||
aligned_memory::AlignedMemory,
|
aligned_memory::AlignedMemory,
|
||||||
ebpf::{self, HOST_ALIGN, MM_HEAP_START},
|
ebpf::{self, HOST_ALIGN, MM_HEAP_START},
|
||||||
elf::Executable,
|
elf::Executable,
|
||||||
error::{EbpfError, UserDefinedError},
|
|
||||||
memory_region::{MemoryCowCallback, MemoryMapping, MemoryRegion},
|
memory_region::{MemoryCowCallback, MemoryMapping, MemoryRegion},
|
||||||
verifier::{RequisiteVerifier, VerifierError},
|
verifier::RequisiteVerifier,
|
||||||
vm::{ContextObject, EbpfVm, ProgramResult, VerifiedExecutable},
|
vm::{ContextObject, EbpfVm, ProgramResult, VerifiedExecutable},
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
|
@ -65,12 +60,10 @@ use {
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{RefCell, RefMut},
|
cell::{RefCell, RefMut},
|
||||||
fmt::Debug,
|
|
||||||
mem,
|
mem,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{atomic::Ordering, Arc},
|
sync::{atomic::Ordering, Arc},
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
solana_sdk::declare_builtin!(
|
solana_sdk::declare_builtin!(
|
||||||
|
@ -79,16 +72,6 @@ solana_sdk::declare_builtin!(
|
||||||
solana_bpf_loader_program::process_instruction
|
solana_bpf_loader_program::process_instruction
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Errors returned by functions the BPF Loader registers with the VM
|
|
||||||
#[derive(Debug, Error, PartialEq, Eq)]
|
|
||||||
pub enum BpfError {
|
|
||||||
#[error("{0}")]
|
|
||||||
VerifierError(#[from] VerifierError),
|
|
||||||
#[error("{0}")]
|
|
||||||
SyscallError(#[from] SyscallError),
|
|
||||||
}
|
|
||||||
impl UserDefinedError for BpfError {}
|
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn load_program_from_bytes(
|
pub fn load_program_from_bytes(
|
||||||
feature_set: &FeatureSet,
|
feature_set: &FeatureSet,
|
||||||
|
@ -326,7 +309,7 @@ pub fn create_ebpf_vm<'a, 'b>(
|
||||||
regions: Vec<MemoryRegion>,
|
regions: Vec<MemoryRegion>,
|
||||||
orig_account_lengths: Vec<usize>,
|
orig_account_lengths: Vec<usize>,
|
||||||
invoke_context: &'a mut InvokeContext<'b>,
|
invoke_context: &'a mut InvokeContext<'b>,
|
||||||
) -> Result<EbpfVm<'a, RequisiteVerifier, InvokeContext<'b>>, EbpfError> {
|
) -> Result<EbpfVm<'a, RequisiteVerifier, InvokeContext<'b>>, Box<dyn std::error::Error>> {
|
||||||
let round_up_heap_size = invoke_context
|
let round_up_heap_size = invoke_context
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&round_up_heap_size::id());
|
.is_active(&round_up_heap_size::id());
|
||||||
|
@ -336,7 +319,7 @@ pub fn create_ebpf_vm<'a, 'b>(
|
||||||
round_up_heap_size,
|
round_up_heap_size,
|
||||||
));
|
));
|
||||||
if round_up_heap_size {
|
if round_up_heap_size {
|
||||||
heap_cost_result.map_err(SyscallError::InstructionError)?;
|
heap_cost_result?;
|
||||||
}
|
}
|
||||||
let check_aligned = bpf_loader_deprecated::id()
|
let check_aligned = bpf_loader_deprecated::id()
|
||||||
!= invoke_context
|
!= invoke_context
|
||||||
|
@ -346,20 +329,17 @@ pub fn create_ebpf_vm<'a, 'b>(
|
||||||
instruction_context
|
instruction_context
|
||||||
.try_borrow_last_program_account(invoke_context.transaction_context)
|
.try_borrow_last_program_account(invoke_context.transaction_context)
|
||||||
})
|
})
|
||||||
.map(|program_account| *program_account.get_owner())
|
.map(|program_account| *program_account.get_owner())?;
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
let check_size = invoke_context
|
let check_size = invoke_context
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&check_slice_translation_size::id());
|
.is_active(&check_slice_translation_size::id());
|
||||||
let allocator = Rc::new(RefCell::new(BpfAllocator::new(heap, MM_HEAP_START)));
|
let allocator = Rc::new(RefCell::new(BpfAllocator::new(heap, MM_HEAP_START)));
|
||||||
invoke_context
|
invoke_context.set_syscall_context(
|
||||||
.set_syscall_context(
|
check_aligned,
|
||||||
check_aligned,
|
check_size,
|
||||||
check_size,
|
orig_account_lengths,
|
||||||
orig_account_lengths,
|
allocator.clone(),
|
||||||
allocator.clone(),
|
)?;
|
||||||
)
|
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
let stack_len = stack.len();
|
let stack_len = stack.len();
|
||||||
let memory_mapping = create_memory_mapping(
|
let memory_mapping = create_memory_mapping(
|
||||||
program.get_executable(),
|
program.get_executable(),
|
||||||
|
@ -369,7 +349,12 @@ pub fn create_ebpf_vm<'a, 'b>(
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
EbpfVm::new(program, invoke_context, memory_mapping, stack_len)
|
Ok(EbpfVm::new(
|
||||||
|
program,
|
||||||
|
invoke_context,
|
||||||
|
memory_mapping,
|
||||||
|
stack_len,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -406,7 +391,7 @@ fn create_memory_mapping<'a, 'b, C: ContextObject>(
|
||||||
heap: &'b mut AlignedMemory<{ HOST_ALIGN }>,
|
heap: &'b mut AlignedMemory<{ HOST_ALIGN }>,
|
||||||
additional_regions: Vec<MemoryRegion>,
|
additional_regions: Vec<MemoryRegion>,
|
||||||
cow_cb: Option<MemoryCowCallback>,
|
cow_cb: Option<MemoryCowCallback>,
|
||||||
) -> Result<MemoryMapping<'a>, EbpfError> {
|
) -> Result<MemoryMapping<'a>, Box<dyn std::error::Error>> {
|
||||||
let config = executable.get_config();
|
let config = executable.get_config();
|
||||||
let regions: Vec<MemoryRegion> = vec![
|
let regions: Vec<MemoryRegion> = vec![
|
||||||
executable.get_ro_region(),
|
executable.get_ro_region(),
|
||||||
|
@ -432,18 +417,22 @@ fn create_memory_mapping<'a, 'b, C: ContextObject>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
pub fn process_instruction(
|
||||||
process_instruction_common(invoke_context, false)
|
invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
process_instruction_inner(invoke_context, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_instruction_jit(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
pub fn process_instruction_jit(
|
||||||
process_instruction_common(invoke_context, true)
|
invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
process_instruction_inner(invoke_context, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_instruction_common(
|
fn process_instruction_inner(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
use_jit: bool,
|
use_jit: bool,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let log_collector = invoke_context.get_log_collector();
|
let log_collector = invoke_context.get_log_collector();
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
|
@ -518,7 +507,7 @@ fn process_instruction_common(
|
||||||
)?;
|
)?;
|
||||||
if first_account.is_executable() {
|
if first_account.is_executable() {
|
||||||
ic_logger_msg!(log_collector, "BPF loader is executable");
|
ic_logger_msg!(log_collector, "BPF loader is executable");
|
||||||
return Err(InstructionError::IncorrectProgramId);
|
return Err(Box::new(InstructionError::IncorrectProgramId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -554,13 +543,14 @@ fn process_instruction_common(
|
||||||
} else {
|
} else {
|
||||||
ic_logger_msg!(log_collector, "Invalid BPF loader id");
|
ic_logger_msg!(log_collector, "Invalid BPF loader id");
|
||||||
Err(InstructionError::IncorrectProgramId)
|
Err(InstructionError::IncorrectProgramId)
|
||||||
};
|
}
|
||||||
|
.map_err(|error| Box::new(error) as Box<dyn std::error::Error>);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Program Invocation
|
// Program Invocation
|
||||||
if !program_account.is_executable() {
|
if !program_account.is_executable() {
|
||||||
ic_logger_msg!(log_collector, "Program is not executable");
|
ic_logger_msg!(log_collector, "Program is not executable");
|
||||||
return Err(InstructionError::IncorrectProgramId);
|
return Err(Box::new(InstructionError::IncorrectProgramId));
|
||||||
}
|
}
|
||||||
|
|
||||||
let programdata_account = if bpf_loader_upgradeable::check_id(program_account.get_owner()) {
|
let programdata_account = if bpf_loader_upgradeable::check_id(program_account.get_owner()) {
|
||||||
|
@ -601,10 +591,10 @@ fn process_instruction_common(
|
||||||
match &executor.program {
|
match &executor.program {
|
||||||
LoadedProgramType::FailedVerification
|
LoadedProgramType::FailedVerification
|
||||||
| LoadedProgramType::Closed
|
| LoadedProgramType::Closed
|
||||||
| LoadedProgramType::DelayVisibility => Err(InstructionError::InvalidAccountData),
|
| LoadedProgramType::DelayVisibility => Err(Box::new(InstructionError::InvalidAccountData)),
|
||||||
LoadedProgramType::LegacyV0(executable) => execute(executable, invoke_context),
|
LoadedProgramType::LegacyV0(executable) => execute(executable, invoke_context),
|
||||||
LoadedProgramType::LegacyV1(executable) => execute(executable, invoke_context),
|
LoadedProgramType::LegacyV1(executable) => execute(executable, invoke_context),
|
||||||
_ => Err(InstructionError::IncorrectProgramId),
|
_ => Err(Box::new(InstructionError::IncorrectProgramId)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1525,9 +1515,8 @@ fn process_loader_instruction(
|
||||||
fn execute<'a, 'b: 'a>(
|
fn execute<'a, 'b: 'a>(
|
||||||
executable: &'a VerifiedExecutable<RequisiteVerifier, InvokeContext<'static>>,
|
executable: &'a VerifiedExecutable<RequisiteVerifier, InvokeContext<'static>>,
|
||||||
invoke_context: &'a mut InvokeContext<'b>,
|
invoke_context: &'a mut InvokeContext<'b>,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let log_collector = invoke_context.get_log_collector();
|
let log_collector = invoke_context.get_log_collector();
|
||||||
let stack_height = invoke_context.get_stack_height();
|
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let program_id = *instruction_context.get_last_program_key(transaction_context)?;
|
let program_id = *instruction_context.get_last_program_key(transaction_context)?;
|
||||||
|
@ -1537,7 +1526,7 @@ fn execute<'a, 'b: 'a>(
|
||||||
let use_jit = executable.get_executable().get_compiled_program().is_some();
|
let use_jit = executable.get_executable().get_compiled_program().is_some();
|
||||||
|
|
||||||
let mut serialize_time = Measure::start("serialize");
|
let mut serialize_time = Measure::start("serialize");
|
||||||
let (parameter_bytes, regions, account_lengths) = serialize_parameters(
|
let (parameter_bytes, regions, account_lengths) = serialization::serialize_parameters(
|
||||||
invoke_context.transaction_context,
|
invoke_context.transaction_context,
|
||||||
instruction_context,
|
instruction_context,
|
||||||
invoke_context
|
invoke_context
|
||||||
|
@ -1569,13 +1558,12 @@ fn execute<'a, 'b: 'a>(
|
||||||
Ok(info) => info,
|
Ok(info) => info,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
ic_logger_msg!(log_collector, "Failed to create SBF VM: {}", e);
|
ic_logger_msg!(log_collector, "Failed to create SBF VM: {}", e);
|
||||||
return Err(InstructionError::ProgramEnvironmentSetupFailure);
|
return Err(Box::new(InstructionError::ProgramEnvironmentSetupFailure));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
create_vm_time.stop();
|
create_vm_time.stop();
|
||||||
|
|
||||||
execute_time = Measure::start("execute");
|
execute_time = Measure::start("execute");
|
||||||
stable_log::program_invoke(&log_collector, &program_id, stack_height);
|
|
||||||
let (compute_units_consumed, result) = vm.execute_program(!use_jit);
|
let (compute_units_consumed, result) = vm.execute_program(!use_jit);
|
||||||
drop(vm);
|
drop(vm);
|
||||||
ic_logger_msg!(
|
ic_logger_msg!(
|
||||||
|
@ -1609,50 +1597,32 @@ fn execute<'a, 'b: 'a>(
|
||||||
} else {
|
} else {
|
||||||
status.into()
|
status.into()
|
||||||
};
|
};
|
||||||
stable_log::program_failure(&log_collector, &program_id, &error);
|
Err(Box::new(error) as Box<dyn std::error::Error>)
|
||||||
Err(error)
|
|
||||||
}
|
|
||||||
ProgramResult::Err(error) => {
|
|
||||||
let error = match error {
|
|
||||||
/*EbpfError::UserError(user_error) if let BpfError::SyscallError(
|
|
||||||
SyscallError::InstructionError(instruction_error),
|
|
||||||
) = user_error.downcast_ref::<BpfError>().unwrap() => instruction_error.clone(),*/
|
|
||||||
EbpfError::UserError(user_error)
|
|
||||||
if matches!(
|
|
||||||
user_error.downcast_ref::<BpfError>().unwrap(),
|
|
||||||
BpfError::SyscallError(SyscallError::InstructionError(_)),
|
|
||||||
) =>
|
|
||||||
{
|
|
||||||
match user_error.downcast_ref::<BpfError>().unwrap() {
|
|
||||||
BpfError::SyscallError(SyscallError::InstructionError(
|
|
||||||
instruction_error,
|
|
||||||
)) => instruction_error.clone(),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err => {
|
|
||||||
ic_logger_msg!(log_collector, "Program failed to complete: {}", err);
|
|
||||||
InstructionError::ProgramFailedToComplete
|
|
||||||
}
|
|
||||||
};
|
|
||||||
stable_log::program_failure(&log_collector, &program_id, &error);
|
|
||||||
Err(error)
|
|
||||||
}
|
}
|
||||||
|
ProgramResult::Err(error) => Err(error),
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
execute_time.stop();
|
execute_time.stop();
|
||||||
|
|
||||||
let mut deserialize_time = Measure::start("deserialize");
|
fn deserialize_parameters(
|
||||||
let execute_or_deserialize_result = execution_result.and_then(|_| {
|
invoke_context: &mut InvokeContext,
|
||||||
deserialize_parameters(
|
parameter_bytes: &[u8],
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
|
serialization::deserialize_parameters(
|
||||||
invoke_context.transaction_context,
|
invoke_context.transaction_context,
|
||||||
invoke_context
|
invoke_context
|
||||||
.transaction_context
|
.transaction_context
|
||||||
.get_current_instruction_context()?,
|
.get_current_instruction_context()?,
|
||||||
parameter_bytes.as_slice(),
|
parameter_bytes,
|
||||||
invoke_context.get_orig_account_lengths()?,
|
invoke_context.get_orig_account_lengths()?,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut deserialize_time = Measure::start("deserialize");
|
||||||
|
let execute_or_deserialize_result = execution_result.and_then(|_| {
|
||||||
|
deserialize_parameters(invoke_context, parameter_bytes.as_slice())
|
||||||
|
.map_err(|error| Box::new(error) as Box<dyn std::error::Error>)
|
||||||
});
|
});
|
||||||
deserialize_time.stop();
|
deserialize_time.stop();
|
||||||
|
|
||||||
|
@ -1665,9 +1635,6 @@ fn execute<'a, 'b: 'a>(
|
||||||
.deserialize_us
|
.deserialize_us
|
||||||
.saturating_add(deserialize_time.as_us());
|
.saturating_add(deserialize_time.as_us());
|
||||||
|
|
||||||
if execute_or_deserialize_result.is_ok() {
|
|
||||||
stable_log::program_success(&log_collector, &program_id);
|
|
||||||
}
|
|
||||||
execute_or_deserialize_result
|
execute_or_deserialize_result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1680,7 +1647,7 @@ mod tests {
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
ebpf::MM_INPUT_START,
|
ebpf::MM_INPUT_START,
|
||||||
elf::Executable,
|
elf::Executable,
|
||||||
verifier::Verifier,
|
verifier::{Verifier, VerifierError},
|
||||||
vm::{BuiltInProgram, Config, ContextObject, FunctionRegistry},
|
vm::{BuiltInProgram, Config, ContextObject, FunctionRegistry},
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
|
@ -1755,7 +1722,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "ExceededMaxInstructions(31, 10)")]
|
#[should_panic(expected = "ExceededMaxInstructions(31)")]
|
||||||
fn test_bpf_loader_non_terminating_program() {
|
fn test_bpf_loader_non_terminating_program() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let program = &[
|
let program = &[
|
||||||
|
@ -1798,8 +1765,7 @@ mod tests {
|
||||||
&mut context_object,
|
&mut context_object,
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
stack_len,
|
stack_len,
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
vm.execute_program(true).1.unwrap();
|
vm.execute_program(true).1.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ impl<'a> CallerAccount<'a> {
|
||||||
_vm_addr: u64,
|
_vm_addr: u64,
|
||||||
account_info: &AccountInfo,
|
account_info: &AccountInfo,
|
||||||
original_data_len: usize,
|
original_data_len: usize,
|
||||||
) -> Result<CallerAccount<'a>, EbpfError> {
|
) -> Result<CallerAccount<'a>, Error> {
|
||||||
// account_info points to host memory. The addresses used internally are
|
// account_info points to host memory. The addresses used internally are
|
||||||
// in vm space so they need to be translated.
|
// in vm space so they need to be translated.
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ impl<'a> CallerAccount<'a> {
|
||||||
vm_addr: u64,
|
vm_addr: u64,
|
||||||
account_info: &SolAccountInfo,
|
account_info: &SolAccountInfo,
|
||||||
original_data_len: usize,
|
original_data_len: usize,
|
||||||
) -> Result<CallerAccount<'a>, EbpfError> {
|
) -> Result<CallerAccount<'a>, Error> {
|
||||||
// account_info points to host memory. The addresses used internally are
|
// account_info points to host memory. The addresses used internally are
|
||||||
// in vm space so they need to be translated.
|
// in vm space so they need to be translated.
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ trait SyscallInvokeSigned {
|
||||||
addr: u64,
|
addr: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<StableInstruction, EbpfError>;
|
) -> Result<StableInstruction, Error>;
|
||||||
fn translate_accounts<'a>(
|
fn translate_accounts<'a>(
|
||||||
instruction_accounts: &[InstructionAccount],
|
instruction_accounts: &[InstructionAccount],
|
||||||
program_indices: &[IndexOfAccount],
|
program_indices: &[IndexOfAccount],
|
||||||
|
@ -220,14 +220,14 @@ trait SyscallInvokeSigned {
|
||||||
account_infos_len: u64,
|
account_infos_len: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<TranslatedAccounts<'a>, EbpfError>;
|
) -> Result<TranslatedAccounts<'a>, Error>;
|
||||||
fn translate_signers(
|
fn translate_signers(
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
signers_seeds_addr: u64,
|
signers_seeds_addr: u64,
|
||||||
signers_seeds_len: u64,
|
signers_seeds_len: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
invoke_context: &InvokeContext,
|
invoke_context: &InvokeContext,
|
||||||
) -> Result<Vec<Pubkey>, EbpfError>;
|
) -> Result<Vec<Pubkey>, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_syscall!(
|
declare_syscall!(
|
||||||
|
@ -241,7 +241,7 @@ declare_syscall!(
|
||||||
signers_seeds_addr: u64,
|
signers_seeds_addr: u64,
|
||||||
signers_seeds_len: u64,
|
signers_seeds_len: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
cpi_common::<Self>(
|
cpi_common::<Self>(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
instruction_addr,
|
instruction_addr,
|
||||||
|
@ -259,7 +259,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
|
||||||
addr: u64,
|
addr: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<StableInstruction, EbpfError> {
|
) -> Result<StableInstruction, Error> {
|
||||||
let ix = translate_type::<StableInstruction>(
|
let ix = translate_type::<StableInstruction>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
addr,
|
addr,
|
||||||
|
@ -312,7 +312,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
|
||||||
account_infos_len: u64,
|
account_infos_len: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<TranslatedAccounts<'a>, EbpfError> {
|
) -> Result<TranslatedAccounts<'a>, Error> {
|
||||||
let (account_infos, account_info_keys) = translate_account_infos(
|
let (account_infos, account_info_keys) = translate_account_infos(
|
||||||
account_infos_addr,
|
account_infos_addr,
|
||||||
account_infos_len,
|
account_infos_len,
|
||||||
|
@ -339,7 +339,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
|
||||||
signers_seeds_len: u64,
|
signers_seeds_len: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
invoke_context: &InvokeContext,
|
invoke_context: &InvokeContext,
|
||||||
) -> Result<Vec<Pubkey>, EbpfError> {
|
) -> Result<Vec<Pubkey>, Error> {
|
||||||
let mut signers = Vec::new();
|
let mut signers = Vec::new();
|
||||||
if signers_seeds_len > 0 {
|
if signers_seeds_len > 0 {
|
||||||
let signers_seeds = translate_slice::<&[&[u8]]>(
|
let signers_seeds = translate_slice::<&[&[u8]]>(
|
||||||
|
@ -350,7 +350,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
|
||||||
invoke_context.get_check_size(),
|
invoke_context.get_check_size(),
|
||||||
)?;
|
)?;
|
||||||
if signers_seeds.len() > MAX_SIGNERS {
|
if signers_seeds.len() > MAX_SIGNERS {
|
||||||
return Err(SyscallError::TooManySigners.into());
|
return Err(Box::new(SyscallError::TooManySigners));
|
||||||
}
|
}
|
||||||
for signer_seeds in signers_seeds.iter() {
|
for signer_seeds in signers_seeds.iter() {
|
||||||
let untranslated_seeds = translate_slice::<&[u8]>(
|
let untranslated_seeds = translate_slice::<&[u8]>(
|
||||||
|
@ -361,10 +361,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
|
||||||
invoke_context.get_check_size(),
|
invoke_context.get_check_size(),
|
||||||
)?;
|
)?;
|
||||||
if untranslated_seeds.len() > MAX_SEEDS {
|
if untranslated_seeds.len() > MAX_SEEDS {
|
||||||
return Err(SyscallError::InstructionError(
|
return Err(Box::new(InstructionError::MaxSeedLengthExceeded));
|
||||||
InstructionError::MaxSeedLengthExceeded,
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
let seeds = untranslated_seeds
|
let seeds = untranslated_seeds
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -377,7 +374,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
|
||||||
invoke_context.get_check_size(),
|
invoke_context.get_check_size(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, EbpfError>>()?;
|
.collect::<Result<Vec<_>, Error>>()?;
|
||||||
let signer = Pubkey::create_program_address(&seeds, program_id)
|
let signer = Pubkey::create_program_address(&seeds, program_id)
|
||||||
.map_err(SyscallError::BadSeeds)?;
|
.map_err(SyscallError::BadSeeds)?;
|
||||||
signers.push(signer);
|
signers.push(signer);
|
||||||
|
@ -453,7 +450,7 @@ declare_syscall!(
|
||||||
signers_seeds_addr: u64,
|
signers_seeds_addr: u64,
|
||||||
signers_seeds_len: u64,
|
signers_seeds_len: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
cpi_common::<Self>(
|
cpi_common::<Self>(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
instruction_addr,
|
instruction_addr,
|
||||||
|
@ -471,7 +468,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
|
||||||
addr: u64,
|
addr: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<StableInstruction, EbpfError> {
|
) -> Result<StableInstruction, Error> {
|
||||||
let ix_c = translate_type::<SolInstruction>(
|
let ix_c = translate_type::<SolInstruction>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
addr,
|
addr,
|
||||||
|
@ -530,7 +527,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
|
||||||
is_writable: meta_c.is_writable,
|
is_writable: meta_c.is_writable,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<AccountMeta>, EbpfError>>()?;
|
.collect::<Result<Vec<AccountMeta>, Error>>()?;
|
||||||
|
|
||||||
Ok(StableInstruction {
|
Ok(StableInstruction {
|
||||||
accounts: accounts.into(),
|
accounts: accounts.into(),
|
||||||
|
@ -546,7 +543,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
|
||||||
account_infos_len: u64,
|
account_infos_len: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<TranslatedAccounts<'a>, EbpfError> {
|
) -> Result<TranslatedAccounts<'a>, Error> {
|
||||||
let (account_infos, account_info_keys) = translate_account_infos(
|
let (account_infos, account_info_keys) = translate_account_infos(
|
||||||
account_infos_addr,
|
account_infos_addr,
|
||||||
account_infos_len,
|
account_infos_len,
|
||||||
|
@ -573,7 +570,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
|
||||||
signers_seeds_len: u64,
|
signers_seeds_len: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
invoke_context: &InvokeContext,
|
invoke_context: &InvokeContext,
|
||||||
) -> Result<Vec<Pubkey>, EbpfError> {
|
) -> Result<Vec<Pubkey>, Error> {
|
||||||
if signers_seeds_len > 0 {
|
if signers_seeds_len > 0 {
|
||||||
let signers_seeds = translate_slice::<SolSignerSeedsC>(
|
let signers_seeds = translate_slice::<SolSignerSeedsC>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
|
@ -583,7 +580,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
|
||||||
invoke_context.get_check_size(),
|
invoke_context.get_check_size(),
|
||||||
)?;
|
)?;
|
||||||
if signers_seeds.len() > MAX_SIGNERS {
|
if signers_seeds.len() > MAX_SIGNERS {
|
||||||
return Err(SyscallError::TooManySigners.into());
|
return Err(Box::new(SyscallError::TooManySigners));
|
||||||
}
|
}
|
||||||
Ok(signers_seeds
|
Ok(signers_seeds
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -596,10 +593,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
|
||||||
invoke_context.get_check_size(),
|
invoke_context.get_check_size(),
|
||||||
)?;
|
)?;
|
||||||
if seeds.len() > MAX_SEEDS {
|
if seeds.len() > MAX_SEEDS {
|
||||||
return Err(SyscallError::InstructionError(
|
return Err(Box::new(InstructionError::MaxSeedLengthExceeded) as Error);
|
||||||
InstructionError::MaxSeedLengthExceeded,
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
let seeds_bytes = seeds
|
let seeds_bytes = seeds
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -612,11 +606,11 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
|
||||||
invoke_context.get_check_size(),
|
invoke_context.get_check_size(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, EbpfError>>()?;
|
.collect::<Result<Vec<_>, Error>>()?;
|
||||||
Pubkey::create_program_address(&seeds_bytes, program_id)
|
Pubkey::create_program_address(&seeds_bytes, program_id)
|
||||||
.map_err(|err| SyscallError::BadSeeds(err).into())
|
.map_err(|err| Box::new(SyscallError::BadSeeds(err)) as Error)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, EbpfError>>()?)
|
.collect::<Result<Vec<_>, Error>>()?)
|
||||||
} else {
|
} else {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
@ -629,7 +623,7 @@ fn translate_account_infos<'a, T, F>(
|
||||||
key_addr: F,
|
key_addr: F,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(&'a [T], Vec<&'a Pubkey>), EbpfError>
|
) -> Result<(&'a [T], Vec<&'a Pubkey>), Error>
|
||||||
where
|
where
|
||||||
F: Fn(&T) -> u64,
|
F: Fn(&T) -> u64,
|
||||||
{
|
{
|
||||||
|
@ -650,7 +644,7 @@ where
|
||||||
invoke_context.get_check_aligned(),
|
invoke_context.get_check_aligned(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, EbpfError>>()?;
|
.collect::<Result<Vec<_>, Error>>()?;
|
||||||
|
|
||||||
Ok((account_infos, account_info_keys))
|
Ok((account_infos, account_info_keys))
|
||||||
}
|
}
|
||||||
|
@ -666,21 +660,17 @@ fn translate_and_update_accounts<'a, T, F>(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
memory_mapping: &MemoryMapping,
|
memory_mapping: &MemoryMapping,
|
||||||
do_translate: F,
|
do_translate: F,
|
||||||
) -> Result<TranslatedAccounts<'a>, EbpfError>
|
) -> Result<TranslatedAccounts<'a>, Error>
|
||||||
where
|
where
|
||||||
F: Fn(&InvokeContext, &MemoryMapping, u64, &T, usize) -> Result<CallerAccount<'a>, EbpfError>,
|
F: Fn(&InvokeContext, &MemoryMapping, u64, &T, usize) -> Result<CallerAccount<'a>, Error>,
|
||||||
{
|
{
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
.get_current_instruction_context()
|
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
let mut accounts = Vec::with_capacity(instruction_accounts.len().saturating_add(1));
|
let mut accounts = Vec::with_capacity(instruction_accounts.len().saturating_add(1));
|
||||||
|
|
||||||
let program_account_index = program_indices
|
let program_account_index = program_indices
|
||||||
.last()
|
.last()
|
||||||
.ok_or(SyscallError::InstructionError(
|
.ok_or_else(|| Box::new(InstructionError::MissingAccount))?;
|
||||||
InstructionError::MissingAccount,
|
|
||||||
))?;
|
|
||||||
accounts.push((*program_account_index, None));
|
accounts.push((*program_account_index, None));
|
||||||
|
|
||||||
// unwrapping here is fine: we're in a syscall and the method below fails
|
// unwrapping here is fine: we're in a syscall and the method below fails
|
||||||
|
@ -693,16 +683,13 @@ where
|
||||||
continue; // Skip duplicate account
|
continue; // Skip duplicate account
|
||||||
}
|
}
|
||||||
|
|
||||||
let callee_account = instruction_context
|
let callee_account = instruction_context.try_borrow_instruction_account(
|
||||||
.try_borrow_instruction_account(
|
transaction_context,
|
||||||
transaction_context,
|
instruction_account.index_in_caller,
|
||||||
instruction_account.index_in_caller,
|
)?;
|
||||||
)
|
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
let account_key = invoke_context
|
let account_key = invoke_context
|
||||||
.transaction_context
|
.transaction_context
|
||||||
.get_key_of_account_at_index(instruction_account.index_in_transaction)
|
.get_key_of_account_at_index(instruction_account.index_in_transaction)?;
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
|
|
||||||
if callee_account.is_executable() {
|
if callee_account.is_executable() {
|
||||||
// Use the known account
|
// Use the known account
|
||||||
|
@ -724,7 +711,7 @@ where
|
||||||
"Internal error: index mismatch for account {}",
|
"Internal error: index mismatch for account {}",
|
||||||
account_key
|
account_key
|
||||||
);
|
);
|
||||||
SyscallError::InstructionError(InstructionError::MissingAccount)
|
Box::new(InstructionError::MissingAccount)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// build the CallerAccount corresponding to this account.
|
// build the CallerAccount corresponding to this account.
|
||||||
|
@ -759,7 +746,7 @@ where
|
||||||
"Instruction references an unknown account {}",
|
"Instruction references an unknown account {}",
|
||||||
account_key
|
account_key
|
||||||
);
|
);
|
||||||
return Err(SyscallError::InstructionError(InstructionError::MissingAccount).into());
|
return Err(Box::new(InstructionError::MissingAccount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,7 +757,7 @@ fn check_instruction_size(
|
||||||
num_accounts: usize,
|
num_accounts: usize,
|
||||||
data_len: usize,
|
data_len: usize,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(), EbpfError> {
|
) -> Result<(), Error> {
|
||||||
if invoke_context
|
if invoke_context
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&feature_set::loosen_cpi_size_restriction::id())
|
.is_active(&feature_set::loosen_cpi_size_restriction::id())
|
||||||
|
@ -778,21 +765,19 @@ fn check_instruction_size(
|
||||||
let data_len = data_len as u64;
|
let data_len = data_len as u64;
|
||||||
let max_data_len = MAX_CPI_INSTRUCTION_DATA_LEN;
|
let max_data_len = MAX_CPI_INSTRUCTION_DATA_LEN;
|
||||||
if data_len > max_data_len {
|
if data_len > max_data_len {
|
||||||
return Err(SyscallError::MaxInstructionDataLenExceeded {
|
return Err(Box::new(SyscallError::MaxInstructionDataLenExceeded {
|
||||||
data_len,
|
data_len,
|
||||||
max_data_len,
|
max_data_len,
|
||||||
}
|
}));
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_accounts = num_accounts as u64;
|
let num_accounts = num_accounts as u64;
|
||||||
let max_accounts = MAX_CPI_INSTRUCTION_ACCOUNTS as u64;
|
let max_accounts = MAX_CPI_INSTRUCTION_ACCOUNTS as u64;
|
||||||
if num_accounts > max_accounts {
|
if num_accounts > max_accounts {
|
||||||
return Err(SyscallError::MaxInstructionAccountsExceeded {
|
return Err(Box::new(SyscallError::MaxInstructionAccountsExceeded {
|
||||||
num_accounts,
|
num_accounts,
|
||||||
max_accounts,
|
max_accounts,
|
||||||
}
|
}));
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let max_size = invoke_context.get_compute_budget().max_cpi_instruction_size;
|
let max_size = invoke_context.get_compute_budget().max_cpi_instruction_size;
|
||||||
|
@ -800,7 +785,7 @@ fn check_instruction_size(
|
||||||
.saturating_mul(size_of::<AccountMeta>())
|
.saturating_mul(size_of::<AccountMeta>())
|
||||||
.saturating_add(data_len);
|
.saturating_add(data_len);
|
||||||
if size > max_size {
|
if size > max_size {
|
||||||
return Err(SyscallError::InstructionTooLarge(size, max_size).into());
|
return Err(Box::new(SyscallError::InstructionTooLarge(size, max_size)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -809,7 +794,7 @@ fn check_instruction_size(
|
||||||
fn check_account_infos(
|
fn check_account_infos(
|
||||||
num_account_infos: usize,
|
num_account_infos: usize,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(), EbpfError> {
|
) -> Result<(), Error> {
|
||||||
if invoke_context
|
if invoke_context
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&feature_set::loosen_cpi_size_restriction::id())
|
.is_active(&feature_set::loosen_cpi_size_restriction::id())
|
||||||
|
@ -825,11 +810,10 @@ fn check_account_infos(
|
||||||
let num_account_infos = num_account_infos as u64;
|
let num_account_infos = num_account_infos as u64;
|
||||||
let max_account_infos = max_cpi_account_infos as u64;
|
let max_account_infos = max_cpi_account_infos as u64;
|
||||||
if num_account_infos > max_account_infos {
|
if num_account_infos > max_account_infos {
|
||||||
return Err(SyscallError::MaxInstructionAccountInfosExceeded {
|
return Err(Box::new(SyscallError::MaxInstructionAccountInfosExceeded {
|
||||||
num_account_infos,
|
num_account_infos,
|
||||||
max_account_infos,
|
max_account_infos,
|
||||||
}
|
}));
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let adjusted_len = num_account_infos.saturating_mul(size_of::<Pubkey>());
|
let adjusted_len = num_account_infos.saturating_mul(size_of::<Pubkey>());
|
||||||
|
@ -837,7 +821,7 @@ fn check_account_infos(
|
||||||
if adjusted_len > invoke_context.get_compute_budget().max_cpi_instruction_size {
|
if adjusted_len > invoke_context.get_compute_budget().max_cpi_instruction_size {
|
||||||
// Cap the number of account_infos a caller can pass to approximate
|
// Cap the number of account_infos a caller can pass to approximate
|
||||||
// maximum that accounts that could be passed in an instruction
|
// maximum that accounts that could be passed in an instruction
|
||||||
return Err(SyscallError::TooManyAccounts.into());
|
return Err(Box::new(SyscallError::TooManyAccounts));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -847,7 +831,7 @@ fn check_authorized_program(
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
invoke_context: &InvokeContext,
|
invoke_context: &InvokeContext,
|
||||||
) -> Result<(), EbpfError> {
|
) -> Result<(), Error> {
|
||||||
if native_loader::check_id(program_id)
|
if native_loader::check_id(program_id)
|
||||||
|| bpf_loader::check_id(program_id)
|
|| bpf_loader::check_id(program_id)
|
||||||
|| bpf_loader_deprecated::check_id(program_id)
|
|| bpf_loader_deprecated::check_id(program_id)
|
||||||
|
@ -865,7 +849,7 @@ fn check_authorized_program(
|
||||||
invoke_context.feature_set.is_active(feature_id)
|
invoke_context.feature_set.is_active(feature_id)
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
return Err(SyscallError::ProgramNotSupported(*program_id).into());
|
return Err(Box::new(SyscallError::ProgramNotSupported(*program_id)));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -879,7 +863,7 @@ fn cpi_common<S: SyscallInvokeSigned>(
|
||||||
signers_seeds_addr: u64,
|
signers_seeds_addr: u64,
|
||||||
signers_seeds_len: u64,
|
signers_seeds_len: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
// CPI entry.
|
// CPI entry.
|
||||||
//
|
//
|
||||||
// Translate the inputs to the syscall and synchronize the caller's account
|
// Translate the inputs to the syscall and synchronize the caller's account
|
||||||
|
@ -891,12 +875,8 @@ fn cpi_common<S: SyscallInvokeSigned>(
|
||||||
|
|
||||||
let instruction = S::translate_instruction(instruction_addr, memory_mapping, invoke_context)?;
|
let instruction = S::translate_instruction(instruction_addr, memory_mapping, invoke_context)?;
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
.get_current_instruction_context()
|
let caller_program_id = instruction_context.get_last_program_key(transaction_context)?;
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
let caller_program_id = instruction_context
|
|
||||||
.get_last_program_key(transaction_context)
|
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
let signers = S::translate_signers(
|
let signers = S::translate_signers(
|
||||||
caller_program_id,
|
caller_program_id,
|
||||||
signers_seeds_addr,
|
signers_seeds_addr,
|
||||||
|
@ -904,9 +884,8 @@ fn cpi_common<S: SyscallInvokeSigned>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
invoke_context,
|
invoke_context,
|
||||||
)?;
|
)?;
|
||||||
let (instruction_accounts, program_indices) = invoke_context
|
let (instruction_accounts, program_indices) =
|
||||||
.prepare_instruction(&instruction, &signers)
|
invoke_context.prepare_instruction(&instruction, &signers)?;
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
check_authorized_program(&instruction.program_id, &instruction.data, invoke_context)?;
|
check_authorized_program(&instruction.program_id, &instruction.data, invoke_context)?;
|
||||||
let mut accounts = S::translate_accounts(
|
let mut accounts = S::translate_accounts(
|
||||||
&instruction_accounts,
|
&instruction_accounts,
|
||||||
|
@ -919,21 +898,17 @@ fn cpi_common<S: SyscallInvokeSigned>(
|
||||||
|
|
||||||
// Process the callee instruction
|
// Process the callee instruction
|
||||||
let mut compute_units_consumed = 0;
|
let mut compute_units_consumed = 0;
|
||||||
invoke_context
|
invoke_context.process_instruction(
|
||||||
.process_instruction(
|
&instruction.data,
|
||||||
&instruction.data,
|
&instruction_accounts,
|
||||||
&instruction_accounts,
|
&program_indices,
|
||||||
&program_indices,
|
&mut compute_units_consumed,
|
||||||
&mut compute_units_consumed,
|
&mut ExecuteTimings::default(),
|
||||||
&mut ExecuteTimings::default(),
|
)?;
|
||||||
)
|
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
|
|
||||||
// re-bind to please the borrow checker
|
// re-bind to please the borrow checker
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
.get_current_instruction_context()
|
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
|
|
||||||
// CPI exit.
|
// CPI exit.
|
||||||
//
|
//
|
||||||
|
@ -941,8 +916,7 @@ fn cpi_common<S: SyscallInvokeSigned>(
|
||||||
for (index_in_caller, caller_account) in accounts.iter_mut() {
|
for (index_in_caller, caller_account) in accounts.iter_mut() {
|
||||||
if let Some(caller_account) = caller_account {
|
if let Some(caller_account) = caller_account {
|
||||||
let callee_account = instruction_context
|
let callee_account = instruction_context
|
||||||
.try_borrow_instruction_account(transaction_context, *index_in_caller)
|
.try_borrow_instruction_account(transaction_context, *index_in_caller)?;
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
update_caller_account(
|
update_caller_account(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
|
@ -967,15 +941,13 @@ fn update_callee_account(
|
||||||
invoke_context: &InvokeContext,
|
invoke_context: &InvokeContext,
|
||||||
caller_account: &CallerAccount,
|
caller_account: &CallerAccount,
|
||||||
mut callee_account: BorrowedAccount<'_>,
|
mut callee_account: BorrowedAccount<'_>,
|
||||||
) -> Result<(), EbpfError> {
|
) -> Result<(), Error> {
|
||||||
let is_disable_cpi_setting_executable_and_rent_epoch_active = invoke_context
|
let is_disable_cpi_setting_executable_and_rent_epoch_active = invoke_context
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&disable_cpi_setting_executable_and_rent_epoch::id());
|
.is_active(&disable_cpi_setting_executable_and_rent_epoch::id());
|
||||||
|
|
||||||
if callee_account.get_lamports() != *caller_account.lamports {
|
if callee_account.get_lamports() != *caller_account.lamports {
|
||||||
callee_account
|
callee_account.set_lamports(*caller_account.lamports)?;
|
||||||
.set_lamports(*caller_account.lamports)
|
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The redundant check helps to avoid the expensive data comparison if we can
|
// The redundant check helps to avoid the expensive data comparison if we can
|
||||||
|
@ -983,13 +955,9 @@ fn update_callee_account(
|
||||||
.can_data_be_resized(caller_account.data.len())
|
.can_data_be_resized(caller_account.data.len())
|
||||||
.and_then(|_| callee_account.can_data_be_changed())
|
.and_then(|_| callee_account.can_data_be_changed())
|
||||||
{
|
{
|
||||||
Ok(()) => callee_account
|
Ok(()) => callee_account.set_data_from_slice(caller_account.data)?,
|
||||||
.set_data_from_slice(caller_account.data)
|
|
||||||
.map_err(SyscallError::InstructionError)?,
|
|
||||||
Err(err) if callee_account.get_data() != caller_account.data => {
|
Err(err) if callee_account.get_data() != caller_account.data => {
|
||||||
return Err(EbpfError::UserError(Box::new(BpfError::SyscallError(
|
return Err(Box::new(err));
|
||||||
SyscallError::InstructionError(err),
|
|
||||||
))));
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -997,16 +965,12 @@ fn update_callee_account(
|
||||||
if !is_disable_cpi_setting_executable_and_rent_epoch_active
|
if !is_disable_cpi_setting_executable_and_rent_epoch_active
|
||||||
&& callee_account.is_executable() != caller_account.executable
|
&& callee_account.is_executable() != caller_account.executable
|
||||||
{
|
{
|
||||||
callee_account
|
callee_account.set_executable(caller_account.executable)?;
|
||||||
.set_executable(caller_account.executable)
|
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change the owner at the end so that we are allowed to change the lamports and data before
|
// Change the owner at the end so that we are allowed to change the lamports and data before
|
||||||
if callee_account.get_owner() != caller_account.owner {
|
if callee_account.get_owner() != caller_account.owner {
|
||||||
callee_account
|
callee_account.set_owner(caller_account.owner.as_ref())?;
|
||||||
.set_owner(caller_account.owner.as_ref())
|
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BorrowedAccount doesn't allow changing the rent epoch. Drop it and use
|
// BorrowedAccount doesn't allow changing the rent epoch. Drop it and use
|
||||||
|
@ -1015,8 +979,7 @@ fn update_callee_account(
|
||||||
drop(callee_account);
|
drop(callee_account);
|
||||||
let callee_account = invoke_context
|
let callee_account = invoke_context
|
||||||
.transaction_context
|
.transaction_context
|
||||||
.get_account_at_index(index_in_transaction)
|
.get_account_at_index(index_in_transaction)?;
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
if !is_disable_cpi_setting_executable_and_rent_epoch_active
|
if !is_disable_cpi_setting_executable_and_rent_epoch_active
|
||||||
&& callee_account.borrow().rent_epoch() != caller_account.rent_epoch
|
&& callee_account.borrow().rent_epoch() != caller_account.rent_epoch
|
||||||
{
|
{
|
||||||
|
@ -1024,7 +987,7 @@ fn update_callee_account(
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&enable_early_verification_of_account_modifications::id())
|
.is_active(&enable_early_verification_of_account_modifications::id())
|
||||||
{
|
{
|
||||||
return Err(SyscallError::InstructionError(InstructionError::RentEpochModified).into());
|
return Err(Box::new(InstructionError::RentEpochModified));
|
||||||
} else {
|
} else {
|
||||||
callee_account
|
callee_account
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
|
@ -1048,7 +1011,7 @@ fn update_caller_account(
|
||||||
memory_mapping: &MemoryMapping,
|
memory_mapping: &MemoryMapping,
|
||||||
caller_account: &mut CallerAccount,
|
caller_account: &mut CallerAccount,
|
||||||
callee_account: &BorrowedAccount<'_>,
|
callee_account: &BorrowedAccount<'_>,
|
||||||
) -> Result<(), EbpfError> {
|
) -> Result<(), Error> {
|
||||||
*caller_account.lamports = callee_account.get_lamports();
|
*caller_account.lamports = callee_account.get_lamports();
|
||||||
*caller_account.owner = *callee_account.get_owner();
|
*caller_account.owner = *callee_account.get_owner();
|
||||||
let new_len = callee_account.get_data().len();
|
let new_len = callee_account.get_data().len();
|
||||||
|
@ -1063,15 +1026,13 @@ fn update_caller_account(
|
||||||
"Account data size realloc limited to {} in inner instructions",
|
"Account data size realloc limited to {} in inner instructions",
|
||||||
MAX_PERMITTED_DATA_INCREASE
|
MAX_PERMITTED_DATA_INCREASE
|
||||||
);
|
);
|
||||||
return Err(SyscallError::InstructionError(InstructionError::InvalidRealloc).into());
|
return Err(Box::new(InstructionError::InvalidRealloc));
|
||||||
}
|
}
|
||||||
if new_len < caller_account.data.len() {
|
if new_len < caller_account.data.len() {
|
||||||
caller_account
|
caller_account
|
||||||
.data
|
.data
|
||||||
.get_mut(new_len..)
|
.get_mut(new_len..)
|
||||||
.ok_or(SyscallError::InstructionError(
|
.ok_or_else(|| Box::new(InstructionError::AccountDataTooSmall))?
|
||||||
InstructionError::AccountDataTooSmall,
|
|
||||||
))?
|
|
||||||
.fill(0);
|
.fill(0);
|
||||||
}
|
}
|
||||||
caller_account.data = translate_slice_mut::<u8>(
|
caller_account.data = translate_slice_mut::<u8>(
|
||||||
|
@ -1109,7 +1070,7 @@ fn update_caller_account(
|
||||||
.get(0..new_len)
|
.get(0..new_len)
|
||||||
.ok_or(SyscallError::InvalidLength)?;
|
.ok_or(SyscallError::InvalidLength)?;
|
||||||
if to_slice.len() != from_slice.len() {
|
if to_slice.len() != from_slice.len() {
|
||||||
return Err(SyscallError::InstructionError(InstructionError::AccountDataTooSmall).into());
|
return Err(Box::new(InstructionError::AccountDataTooSmall));
|
||||||
}
|
}
|
||||||
to_slice.copy_from_slice(from_slice);
|
to_slice.copy_from_slice(from_slice);
|
||||||
|
|
||||||
|
@ -1449,9 +1410,7 @@ mod tests {
|
||||||
&mut caller_account,
|
&mut caller_account,
|
||||||
&callee_account,
|
&callee_account,
|
||||||
),
|
),
|
||||||
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::InvalidRealloc,
|
||||||
SyscallError::InstructionError(InstructionError::InvalidRealloc)
|
|
||||||
)
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let cost = invoke_context
|
let cost = invoke_context
|
||||||
.get_compute_budget()
|
.get_compute_budget()
|
||||||
.syscall_base_cost
|
.syscall_base_cost
|
||||||
|
@ -47,7 +47,7 @@ declare_syscall!(
|
||||||
arg4: u64,
|
arg4: u64,
|
||||||
arg5: u64,
|
arg5: u64,
|
||||||
_memory_mapping: &mut MemoryMapping,
|
_memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let cost = invoke_context.get_compute_budget().log_64_units;
|
let cost = invoke_context.get_compute_budget().log_64_units;
|
||||||
consume_compute_meter(invoke_context, cost)?;
|
consume_compute_meter(invoke_context, cost)?;
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
_memory_mapping: &mut MemoryMapping,
|
_memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let cost = invoke_context.get_compute_budget().syscall_base_cost;
|
let cost = invoke_context.get_compute_budget().syscall_base_cost;
|
||||||
consume_compute_meter(invoke_context, cost)?;
|
consume_compute_meter(invoke_context, cost)?;
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let cost = invoke_context.get_compute_budget().log_pubkey_units;
|
let cost = invoke_context.get_compute_budget().log_pubkey_units;
|
||||||
consume_compute_meter(invoke_context, cost)?;
|
consume_compute_meter(invoke_context, cost)?;
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let budget = invoke_context.get_compute_budget();
|
let budget = invoke_context.get_compute_budget();
|
||||||
|
|
||||||
consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
|
consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use {super::*, crate::declare_syscall};
|
use {super::*, crate::declare_syscall};
|
||||||
|
|
||||||
fn mem_op_consume(invoke_context: &mut InvokeContext, n: u64) -> Result<(), EbpfError> {
|
fn mem_op_consume(invoke_context: &mut InvokeContext, n: u64) -> Result<(), Error> {
|
||||||
let compute_budget = invoke_context.get_compute_budget();
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
let cost = compute_budget
|
let cost = compute_budget
|
||||||
.mem_op_base_cost
|
.mem_op_base_cost
|
||||||
|
@ -19,7 +19,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
mem_op_consume(invoke_context, n)?;
|
mem_op_consume(invoke_context, n)?;
|
||||||
|
|
||||||
if !is_nonoverlapping(src_addr, n, dst_addr, n) {
|
if !is_nonoverlapping(src_addr, n, dst_addr, n) {
|
||||||
|
@ -66,7 +66,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
mem_op_consume(invoke_context, n)?;
|
mem_op_consume(invoke_context, n)?;
|
||||||
|
|
||||||
let dst = translate_slice_mut::<u8>(
|
let dst = translate_slice_mut::<u8>(
|
||||||
|
@ -101,7 +101,7 @@ declare_syscall!(
|
||||||
cmp_result_addr: u64,
|
cmp_result_addr: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
mem_op_consume(invoke_context, n)?;
|
mem_op_consume(invoke_context, n)?;
|
||||||
|
|
||||||
let s1 = translate_slice::<u8>(
|
let s1 = translate_slice::<u8>(
|
||||||
|
@ -149,7 +149,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
mem_op_consume(invoke_context, n)?;
|
mem_op_consume(invoke_context, n)?;
|
||||||
|
|
||||||
let s = translate_slice_mut::<u8>(
|
let s = translate_slice_mut::<u8>(
|
||||||
|
|
|
@ -11,13 +11,11 @@ pub use self::{
|
||||||
};
|
};
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
use {
|
use {
|
||||||
crate::BpfError,
|
|
||||||
solana_program_runtime::{
|
solana_program_runtime::{
|
||||||
compute_budget::ComputeBudget, ic_logger_msg, ic_msg, invoke_context::InvokeContext,
|
compute_budget::ComputeBudget, ic_logger_msg, ic_msg, invoke_context::InvokeContext,
|
||||||
stable_log, timings::ExecuteTimings,
|
stable_log, timings::ExecuteTimings,
|
||||||
},
|
},
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
error::EbpfError,
|
|
||||||
memory_region::{AccessType, MemoryMapping},
|
memory_region::{AccessType, MemoryMapping},
|
||||||
vm::{BuiltInProgram, Config, ProgramResult, PROGRAM_ENVIRONMENT_KEY_SHIFT},
|
vm::{BuiltInProgram, Config, ProgramResult, PROGRAM_ENVIRONMENT_KEY_SHIFT},
|
||||||
},
|
},
|
||||||
|
@ -94,8 +92,6 @@ pub enum SyscallError {
|
||||||
BadSeeds(PubkeyError),
|
BadSeeds(PubkeyError),
|
||||||
#[error("Program {0} not supported by inner instructions")]
|
#[error("Program {0} not supported by inner instructions")]
|
||||||
ProgramNotSupported(Pubkey),
|
ProgramNotSupported(Pubkey),
|
||||||
#[error("{0}")]
|
|
||||||
InstructionError(InstructionError),
|
|
||||||
#[error("Unaligned pointer")]
|
#[error("Unaligned pointer")]
|
||||||
UnalignedPointer,
|
UnalignedPointer,
|
||||||
#[error("Too many signers")]
|
#[error("Too many signers")]
|
||||||
|
@ -127,16 +123,11 @@ pub enum SyscallError {
|
||||||
#[error("InvalidAttribute")]
|
#[error("InvalidAttribute")]
|
||||||
InvalidAttribute,
|
InvalidAttribute,
|
||||||
}
|
}
|
||||||
impl From<SyscallError> for EbpfError {
|
|
||||||
fn from(error: SyscallError) -> Self {
|
|
||||||
EbpfError::UserError(Box::<BpfError>::new(error.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn consume_compute_meter(invoke_context: &InvokeContext, amount: u64) -> Result<(), EbpfError> {
|
type Error = Box<dyn std::error::Error>;
|
||||||
invoke_context
|
|
||||||
.consume_checked(amount)
|
fn consume_compute_meter(invoke_context: &InvokeContext, amount: u64) -> Result<(), Error> {
|
||||||
.map_err(SyscallError::InstructionError)?;
|
invoke_context.consume_checked(amount)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +147,7 @@ pub fn create_loader<'a>(
|
||||||
reject_deployment_of_broken_elfs: bool,
|
reject_deployment_of_broken_elfs: bool,
|
||||||
disable_deploy_of_alloc_free_syscall: bool,
|
disable_deploy_of_alloc_free_syscall: bool,
|
||||||
debugging_features: bool,
|
debugging_features: bool,
|
||||||
) -> Result<Arc<BuiltInProgram<InvokeContext<'a>>>, EbpfError> {
|
) -> Result<Arc<BuiltInProgram<InvokeContext<'a>>>, Error> {
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
let config = Config {
|
let config = Config {
|
||||||
max_call_depth: compute_budget.max_call_depth,
|
max_call_depth: compute_budget.max_call_depth,
|
||||||
|
@ -330,7 +321,7 @@ fn translate(
|
||||||
access_type: AccessType,
|
access_type: AccessType,
|
||||||
vm_addr: u64,
|
vm_addr: u64,
|
||||||
len: u64,
|
len: u64,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
memory_mapping.map(access_type, vm_addr, len, 0).into()
|
memory_mapping.map(access_type, vm_addr, len, 0).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +330,7 @@ fn translate_type_inner<'a, T>(
|
||||||
access_type: AccessType,
|
access_type: AccessType,
|
||||||
vm_addr: u64,
|
vm_addr: u64,
|
||||||
check_aligned: bool,
|
check_aligned: bool,
|
||||||
) -> Result<&'a mut T, EbpfError> {
|
) -> Result<&'a mut T, Error> {
|
||||||
let host_addr = translate(memory_mapping, access_type, vm_addr, size_of::<T>() as u64)?;
|
let host_addr = translate(memory_mapping, access_type, vm_addr, size_of::<T>() as u64)?;
|
||||||
|
|
||||||
if check_aligned && (host_addr as *mut T as usize).wrapping_rem(align_of::<T>()) != 0 {
|
if check_aligned && (host_addr as *mut T as usize).wrapping_rem(align_of::<T>()) != 0 {
|
||||||
|
@ -351,14 +342,14 @@ fn translate_type_mut<'a, T>(
|
||||||
memory_mapping: &MemoryMapping,
|
memory_mapping: &MemoryMapping,
|
||||||
vm_addr: u64,
|
vm_addr: u64,
|
||||||
check_aligned: bool,
|
check_aligned: bool,
|
||||||
) -> Result<&'a mut T, EbpfError> {
|
) -> Result<&'a mut T, Error> {
|
||||||
translate_type_inner::<T>(memory_mapping, AccessType::Store, vm_addr, check_aligned)
|
translate_type_inner::<T>(memory_mapping, AccessType::Store, vm_addr, check_aligned)
|
||||||
}
|
}
|
||||||
fn translate_type<'a, T>(
|
fn translate_type<'a, T>(
|
||||||
memory_mapping: &MemoryMapping,
|
memory_mapping: &MemoryMapping,
|
||||||
vm_addr: u64,
|
vm_addr: u64,
|
||||||
check_aligned: bool,
|
check_aligned: bool,
|
||||||
) -> Result<&'a T, EbpfError> {
|
) -> Result<&'a T, Error> {
|
||||||
translate_type_inner::<T>(memory_mapping, AccessType::Load, vm_addr, check_aligned)
|
translate_type_inner::<T>(memory_mapping, AccessType::Load, vm_addr, check_aligned)
|
||||||
.map(|value| &*value)
|
.map(|value| &*value)
|
||||||
}
|
}
|
||||||
|
@ -370,7 +361,7 @@ fn translate_slice_inner<'a, T>(
|
||||||
len: u64,
|
len: u64,
|
||||||
check_aligned: bool,
|
check_aligned: bool,
|
||||||
check_size: bool,
|
check_size: bool,
|
||||||
) -> Result<&'a mut [T], EbpfError> {
|
) -> Result<&'a mut [T], Error> {
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Ok(&mut []);
|
return Ok(&mut []);
|
||||||
}
|
}
|
||||||
|
@ -393,7 +384,7 @@ fn translate_slice_mut<'a, T>(
|
||||||
len: u64,
|
len: u64,
|
||||||
check_aligned: bool,
|
check_aligned: bool,
|
||||||
check_size: bool,
|
check_size: bool,
|
||||||
) -> Result<&'a mut [T], EbpfError> {
|
) -> Result<&'a mut [T], Error> {
|
||||||
translate_slice_inner::<T>(
|
translate_slice_inner::<T>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
AccessType::Store,
|
AccessType::Store,
|
||||||
|
@ -409,7 +400,7 @@ fn translate_slice<'a, T>(
|
||||||
len: u64,
|
len: u64,
|
||||||
check_aligned: bool,
|
check_aligned: bool,
|
||||||
check_size: bool,
|
check_size: bool,
|
||||||
) -> Result<&'a [T], EbpfError> {
|
) -> Result<&'a [T], Error> {
|
||||||
translate_slice_inner::<T>(
|
translate_slice_inner::<T>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
AccessType::Load,
|
AccessType::Load,
|
||||||
|
@ -430,8 +421,8 @@ fn translate_string_and_do(
|
||||||
check_aligned: bool,
|
check_aligned: bool,
|
||||||
check_size: bool,
|
check_size: bool,
|
||||||
stop_truncating_strings_in_syscalls: bool,
|
stop_truncating_strings_in_syscalls: bool,
|
||||||
work: &mut dyn FnMut(&str) -> Result<u64, EbpfError>,
|
work: &mut dyn FnMut(&str) -> Result<u64, Error>,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let buf = translate_slice::<u8>(memory_mapping, addr, len, check_aligned, check_size)?;
|
let buf = translate_slice::<u8>(memory_mapping, addr, len, check_aligned, check_size)?;
|
||||||
let msg = if stop_truncating_strings_in_syscalls {
|
let msg = if stop_truncating_strings_in_syscalls {
|
||||||
buf
|
buf
|
||||||
|
@ -488,7 +479,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
_memory_mapping: &mut MemoryMapping,
|
_memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
Err(SyscallError::Abort.into())
|
Err(SyscallError::Abort.into())
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -505,7 +496,7 @@ declare_syscall!(
|
||||||
column: u64,
|
column: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
consume_compute_meter(invoke_context, len)?;
|
consume_compute_meter(invoke_context, len)?;
|
||||||
|
|
||||||
translate_string_and_do(
|
translate_string_and_do(
|
||||||
|
@ -538,10 +529,8 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
_memory_mapping: &mut MemoryMapping,
|
_memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let allocator = invoke_context
|
let allocator = invoke_context.get_allocator()?;
|
||||||
.get_allocator()
|
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
let mut allocator = allocator
|
let mut allocator = allocator
|
||||||
.try_borrow_mut()
|
.try_borrow_mut()
|
||||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed)?;
|
.map_err(|_| SyscallError::InvokeContextBorrowFailed)?;
|
||||||
|
@ -576,7 +565,7 @@ fn translate_and_check_program_address_inputs<'a>(
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
check_aligned: bool,
|
check_aligned: bool,
|
||||||
check_size: bool,
|
check_size: bool,
|
||||||
) -> Result<(Vec<&'a [u8]>, &'a Pubkey), EbpfError> {
|
) -> Result<(Vec<&'a [u8]>, &'a Pubkey), Error> {
|
||||||
let untranslated_seeds = translate_slice::<&[&u8]>(
|
let untranslated_seeds = translate_slice::<&[&u8]>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
seeds_addr,
|
seeds_addr,
|
||||||
|
@ -601,7 +590,7 @@ fn translate_and_check_program_address_inputs<'a>(
|
||||||
check_size,
|
check_size,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, EbpfError>>()?;
|
.collect::<Result<Vec<_>, Error>>()?;
|
||||||
let program_id = translate_type::<Pubkey>(memory_mapping, program_id_addr, check_aligned)?;
|
let program_id = translate_type::<Pubkey>(memory_mapping, program_id_addr, check_aligned)?;
|
||||||
Ok((seeds, program_id))
|
Ok((seeds, program_id))
|
||||||
}
|
}
|
||||||
|
@ -617,7 +606,7 @@ declare_syscall!(
|
||||||
address_addr: u64,
|
address_addr: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let cost = invoke_context
|
let cost = invoke_context
|
||||||
.get_compute_budget()
|
.get_compute_budget()
|
||||||
.create_program_address_units;
|
.create_program_address_units;
|
||||||
|
@ -661,7 +650,7 @@ declare_syscall!(
|
||||||
address_addr: u64,
|
address_addr: u64,
|
||||||
bump_seed_addr: u64,
|
bump_seed_addr: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let cost = invoke_context
|
let cost = invoke_context
|
||||||
.get_compute_budget()
|
.get_compute_budget()
|
||||||
.create_program_address_units;
|
.create_program_address_units;
|
||||||
|
@ -731,7 +720,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let compute_budget = invoke_context.get_compute_budget();
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
if compute_budget.sha256_max_slices < vals_len {
|
if compute_budget.sha256_max_slices < vals_len {
|
||||||
ic_msg!(
|
ic_msg!(
|
||||||
|
@ -794,7 +783,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let compute_budget = invoke_context.get_compute_budget();
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
if compute_budget.sha256_max_slices < vals_len {
|
if compute_budget.sha256_max_slices < vals_len {
|
||||||
ic_msg!(
|
ic_msg!(
|
||||||
|
@ -857,7 +846,7 @@ declare_syscall!(
|
||||||
result_addr: u64,
|
result_addr: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let cost = invoke_context.get_compute_budget().secp256k1_recover_cost;
|
let cost = invoke_context.get_compute_budget().secp256k1_recover_cost;
|
||||||
consume_compute_meter(invoke_context, cost)?;
|
consume_compute_meter(invoke_context, cost)?;
|
||||||
|
|
||||||
|
@ -949,7 +938,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
use solana_zk_token_sdk::curve25519::{curve_syscall_traits::*, edwards, ristretto};
|
use solana_zk_token_sdk::curve25519::{curve_syscall_traits::*, edwards, ristretto};
|
||||||
match curve_id {
|
match curve_id {
|
||||||
CURVE25519_EDWARDS => {
|
CURVE25519_EDWARDS => {
|
||||||
|
@ -1006,7 +995,7 @@ declare_syscall!(
|
||||||
right_input_addr: u64,
|
right_input_addr: u64,
|
||||||
result_point_addr: u64,
|
result_point_addr: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
use solana_zk_token_sdk::curve25519::{
|
use solana_zk_token_sdk::curve25519::{
|
||||||
curve_syscall_traits::*, edwards, ristretto, scalar,
|
curve_syscall_traits::*, edwards, ristretto, scalar,
|
||||||
};
|
};
|
||||||
|
@ -1207,7 +1196,7 @@ declare_syscall!(
|
||||||
points_len: u64,
|
points_len: u64,
|
||||||
result_point_addr: u64,
|
result_point_addr: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
use solana_zk_token_sdk::curve25519::{
|
use solana_zk_token_sdk::curve25519::{
|
||||||
curve_syscall_traits::*, edwards, ristretto, scalar,
|
curve_syscall_traits::*, edwards, ristretto, scalar,
|
||||||
};
|
};
|
||||||
|
@ -1310,7 +1299,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let compute_budget = invoke_context.get_compute_budget();
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
if compute_budget.sha256_max_slices < vals_len {
|
if compute_budget.sha256_max_slices < vals_len {
|
||||||
ic_msg!(
|
ic_msg!(
|
||||||
|
@ -1373,7 +1362,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let budget = invoke_context.get_compute_budget();
|
let budget = invoke_context.get_compute_budget();
|
||||||
|
|
||||||
let cost = len
|
let cost = len
|
||||||
|
@ -1402,12 +1391,9 @@ declare_syscall!(
|
||||||
.get_current_instruction_context()
|
.get_current_instruction_context()
|
||||||
.and_then(|instruction_context| {
|
.and_then(|instruction_context| {
|
||||||
instruction_context.get_last_program_key(transaction_context)
|
instruction_context.get_last_program_key(transaction_context)
|
||||||
})
|
})?;
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
|
|
||||||
transaction_context
|
transaction_context.set_return_data(program_id, return_data)?;
|
||||||
.set_return_data(program_id, return_data)
|
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
|
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
@ -1424,7 +1410,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let budget = invoke_context.get_compute_budget();
|
let budget = invoke_context.get_compute_budget();
|
||||||
|
|
||||||
consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
|
consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
|
||||||
|
@ -1491,7 +1477,7 @@ declare_syscall!(
|
||||||
data_addr: u64,
|
data_addr: u64,
|
||||||
accounts_addr: u64,
|
accounts_addr: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let budget = invoke_context.get_compute_budget();
|
let budget = invoke_context.get_compute_budget();
|
||||||
|
|
||||||
consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
|
consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
|
||||||
|
@ -1510,8 +1496,7 @@ declare_syscall!(
|
||||||
for index_in_trace in (0..instruction_trace_length).rev() {
|
for index_in_trace in (0..instruction_trace_length).rev() {
|
||||||
let instruction_context = invoke_context
|
let instruction_context = invoke_context
|
||||||
.transaction_context
|
.transaction_context
|
||||||
.get_instruction_context_at_index_in_trace(index_in_trace)
|
.get_instruction_context_at_index_in_trace(index_in_trace)?;
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
if (stop_sibling_instruction_search_at_parent
|
if (stop_sibling_instruction_search_at_parent
|
||||||
|| instruction_context.get_stack_height() == TRANSACTION_LEVEL_STACK_HEIGHT)
|
|| instruction_context.get_stack_height() == TRANSACTION_LEVEL_STACK_HEIGHT)
|
||||||
&& instruction_context.get_stack_height() < stack_height
|
&& instruction_context.get_stack_height() < stack_height
|
||||||
|
@ -1599,8 +1584,7 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
|
|
||||||
*program_id = *instruction_context
|
*program_id = *instruction_context
|
||||||
.get_last_program_key(invoke_context.transaction_context)
|
.get_last_program_key(invoke_context.transaction_context)?;
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
data.clone_from_slice(instruction_context.get_instruction_data());
|
data.clone_from_slice(instruction_context.get_instruction_data());
|
||||||
let account_metas = (0..instruction_context.get_number_of_instruction_accounts())
|
let account_metas = (0..instruction_context.get_number_of_instruction_accounts())
|
||||||
.map(|instruction_account_index| {
|
.map(|instruction_account_index| {
|
||||||
|
@ -1619,8 +1603,7 @@ declare_syscall!(
|
||||||
.is_instruction_account_writable(instruction_account_index)?,
|
.is_instruction_account_writable(instruction_account_index)?,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, InstructionError>>()
|
.collect::<Result<Vec<_>, InstructionError>>()?;
|
||||||
.map_err(SyscallError::InstructionError)?;
|
|
||||||
accounts.clone_from_slice(account_metas.as_slice());
|
accounts.clone_from_slice(account_metas.as_slice());
|
||||||
}
|
}
|
||||||
result_header.data_len = instruction_context.get_instruction_data().len() as u64;
|
result_header.data_len = instruction_context.get_instruction_data().len() as u64;
|
||||||
|
@ -1643,7 +1626,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
_memory_mapping: &mut MemoryMapping,
|
_memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let budget = invoke_context.get_compute_budget();
|
let budget = invoke_context.get_compute_budget();
|
||||||
|
|
||||||
consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
|
consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
|
||||||
|
@ -1663,7 +1646,7 @@ declare_syscall!(
|
||||||
result_addr: u64,
|
result_addr: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
use solana_sdk::alt_bn128::prelude::{ALT_BN128_ADD, ALT_BN128_MUL, ALT_BN128_PAIRING};
|
use solana_sdk::alt_bn128::prelude::{ALT_BN128_ADD, ALT_BN128_MUL, ALT_BN128_PAIRING};
|
||||||
let budget = invoke_context.get_compute_budget();
|
let budget = invoke_context.get_compute_budget();
|
||||||
let (cost, output): (u64, usize) = match group_op {
|
let (cost, output): (u64, usize) = match group_op {
|
||||||
|
@ -1748,7 +1731,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
let params = &translate_slice::<BigModExpParams>(
|
let params = &translate_slice::<BigModExpParams>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
params,
|
params,
|
||||||
|
@ -1825,6 +1808,7 @@ mod tests {
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
aligned_memory::AlignedMemory,
|
aligned_memory::AlignedMemory,
|
||||||
ebpf::{self, HOST_ALIGN},
|
ebpf::{self, HOST_ALIGN},
|
||||||
|
error::EbpfError,
|
||||||
memory_region::MemoryRegion,
|
memory_region::MemoryRegion,
|
||||||
vm::{BuiltInFunction, Config},
|
vm::{BuiltInFunction, Config},
|
||||||
},
|
},
|
||||||
|
@ -1843,11 +1827,10 @@ mod tests {
|
||||||
|
|
||||||
macro_rules! assert_access_violation {
|
macro_rules! assert_access_violation {
|
||||||
($result:expr, $va:expr, $len:expr) => {
|
($result:expr, $va:expr, $len:expr) => {
|
||||||
match $result {
|
match $result.unwrap_err().downcast_ref::<EbpfError>().unwrap() {
|
||||||
ProgramResult::Err(EbpfError::AccessViolation(_, _, va, len, _))
|
EbpfError::AccessViolation(_, _, va, len, _) if $va == *va && $len == *len => {}
|
||||||
if $va == va && $len == len => {}
|
EbpfError::StackAccessViolation(_, _, va, len, _) if $va == *va && $len == *len => {
|
||||||
ProgramResult::Err(EbpfError::StackAccessViolation(_, _, va, len, _))
|
}
|
||||||
if $va == va && $len == len => {}
|
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2066,7 +2049,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "UserError(SyscallError(Abort))")]
|
#[should_panic(expected = "Abort")]
|
||||||
fn test_syscall_abort() {
|
fn test_syscall_abort() {
|
||||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
|
@ -2086,7 +2069,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")]
|
#[should_panic(expected = "Panic(\"Gaggablaghblagh!\", 42, 84)")]
|
||||||
fn test_syscall_sol_panic() {
|
fn test_syscall_sol_panic() {
|
||||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||||
|
|
||||||
|
@ -2112,9 +2095,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
|
||||||
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
|
|
||||||
invoke_context.mock_set_remaining(string.len() as u64);
|
invoke_context.mock_set_remaining(string.len() as u64);
|
||||||
|
@ -2195,9 +2176,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
|
||||||
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -2281,9 +2260,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
|
||||||
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
|
|
||||||
invoke_context.mock_set_remaining(cost);
|
invoke_context.mock_set_remaining(cost);
|
||||||
|
@ -2617,7 +2594,7 @@ mod tests {
|
||||||
&mut result,
|
&mut result,
|
||||||
);
|
);
|
||||||
assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64);
|
assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64);
|
||||||
|
let mut result = ProgramResult::Ok(0);
|
||||||
SyscallSha256::call(
|
SyscallSha256::call(
|
||||||
&mut invoke_context,
|
&mut invoke_context,
|
||||||
ro_va,
|
ro_va,
|
||||||
|
@ -2630,9 +2607,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
|
||||||
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2710,9 +2685,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
|
||||||
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2790,9 +2763,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
|
||||||
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2962,9 +2933,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
|
||||||
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3136,9 +3105,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
|
||||||
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3479,7 +3446,7 @@ mod tests {
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
overlap_outputs: bool,
|
overlap_outputs: bool,
|
||||||
syscall: BuiltInFunction<InvokeContext<'b>>,
|
syscall: BuiltInFunction<InvokeContext<'b>>,
|
||||||
) -> Result<(Pubkey, u8), EbpfError> {
|
) -> Result<(Pubkey, u8), Error> {
|
||||||
const SEEDS_VA: u64 = 0x100000000;
|
const SEEDS_VA: u64 = 0x100000000;
|
||||||
const PROGRAM_ID_VA: u64 = 0x200000000;
|
const PROGRAM_ID_VA: u64 = 0x200000000;
|
||||||
const ADDRESS_VA: u64 = 0x300000000;
|
const ADDRESS_VA: u64 = 0x300000000;
|
||||||
|
@ -3526,14 +3493,14 @@ mod tests {
|
||||||
&mut memory_mapping,
|
&mut memory_mapping,
|
||||||
&mut result,
|
&mut result,
|
||||||
);
|
);
|
||||||
Result::<u64, EbpfError>::from(result).map(|_| (address, bump_seed))
|
Result::<u64, Error>::from(result).map(|_| (address, bump_seed))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_program_address(
|
fn create_program_address(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
seeds: &[&[u8]],
|
seeds: &[&[u8]],
|
||||||
address: &Pubkey,
|
address: &Pubkey,
|
||||||
) -> Result<Pubkey, EbpfError> {
|
) -> Result<Pubkey, Error> {
|
||||||
let (address, _) = call_program_address_common(
|
let (address, _) = call_program_address_common(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
seeds,
|
seeds,
|
||||||
|
@ -3548,7 +3515,7 @@ mod tests {
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
seeds: &[&[u8]],
|
seeds: &[&[u8]],
|
||||||
address: &Pubkey,
|
address: &Pubkey,
|
||||||
) -> Result<(Pubkey, u8), EbpfError> {
|
) -> Result<(Pubkey, u8), Error> {
|
||||||
call_program_address_common(
|
call_program_address_common(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
seeds,
|
seeds,
|
||||||
|
@ -3621,9 +3588,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
ProgramResult::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping,
|
||||||
SyscallError::CopyOverlapping
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3775,9 +3740,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
ProgramResult::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping,
|
||||||
SyscallError::CopyOverlapping
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3791,9 +3754,7 @@ mod tests {
|
||||||
let exceeded_seed = &[127; MAX_SEED_LEN + 1];
|
let exceeded_seed = &[127; MAX_SEED_LEN + 1];
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
create_program_address(&mut invoke_context, &[exceeded_seed], &address),
|
create_program_address(&mut invoke_context, &[exceeded_seed], &address),
|
||||||
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded),
|
||||||
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
create_program_address(
|
create_program_address(
|
||||||
|
@ -3801,9 +3762,7 @@ mod tests {
|
||||||
&[b"short_seed", exceeded_seed],
|
&[b"short_seed", exceeded_seed],
|
||||||
&address,
|
&address,
|
||||||
),
|
),
|
||||||
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded),
|
||||||
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
let max_seed = &[0; MAX_SEED_LEN];
|
let max_seed = &[0; MAX_SEED_LEN];
|
||||||
assert!(create_program_address(&mut invoke_context, &[max_seed], &address).is_ok());
|
assert!(create_program_address(&mut invoke_context, &[max_seed], &address).is_ok());
|
||||||
|
@ -3847,9 +3806,7 @@ mod tests {
|
||||||
];
|
];
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
create_program_address(&mut invoke_context, max_seeds, &address),
|
create_program_address(&mut invoke_context, max_seeds, &address),
|
||||||
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded),
|
||||||
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
create_program_address(&mut invoke_context, &[b"", &[1]], &address).unwrap(),
|
create_program_address(&mut invoke_context, &[b"", &[1]], &address).unwrap(),
|
||||||
|
@ -3886,9 +3843,7 @@ mod tests {
|
||||||
invoke_context.mock_set_remaining(0);
|
invoke_context.mock_set_remaining(0);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
create_program_address(&mut invoke_context, &[b"", &[1]], &address),
|
create_program_address(&mut invoke_context, &[b"", &[1]], &address),
|
||||||
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
|
||||||
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3927,18 +3882,14 @@ mod tests {
|
||||||
invoke_context.mock_set_remaining(cost * (max_tries - bump_seed as u64 - 1));
|
invoke_context.mock_set_remaining(cost * (max_tries - bump_seed as u64 - 1));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
try_find_program_address(&mut invoke_context, seeds, &address),
|
try_find_program_address(&mut invoke_context, seeds, &address),
|
||||||
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
|
||||||
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
|
|
||||||
let exceeded_seed = &[127; MAX_SEED_LEN + 1];
|
let exceeded_seed = &[127; MAX_SEED_LEN + 1];
|
||||||
invoke_context.mock_set_remaining(cost * (max_tries - 1));
|
invoke_context.mock_set_remaining(cost * (max_tries - 1));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
try_find_program_address(&mut invoke_context, &[exceeded_seed], &address),
|
try_find_program_address(&mut invoke_context, &[exceeded_seed], &address),
|
||||||
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded),
|
||||||
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
let exceeded_seeds: &[&[u8]] = &[
|
let exceeded_seeds: &[&[u8]] = &[
|
||||||
&[1],
|
&[1],
|
||||||
|
@ -3962,9 +3913,7 @@ mod tests {
|
||||||
invoke_context.mock_set_remaining(cost * (max_tries - 1));
|
invoke_context.mock_set_remaining(cost * (max_tries - 1));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
try_find_program_address(&mut invoke_context, exceeded_seeds, &address),
|
try_find_program_address(&mut invoke_context, exceeded_seeds, &address),
|
||||||
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded),
|
||||||
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
|
@ -3975,9 +3924,7 @@ mod tests {
|
||||||
true,
|
true,
|
||||||
SyscallTryFindProgramAddress::call,
|
SyscallTryFindProgramAddress::call,
|
||||||
),
|
),
|
||||||
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping,
|
||||||
SyscallError::CopyOverlapping
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId + Clone>(
|
||||||
check_aligned: bool,
|
check_aligned: bool,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
consume_compute_meter(
|
consume_compute_meter(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
invoke_context
|
invoke_context
|
||||||
|
@ -16,7 +16,7 @@ fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId + Clone>(
|
||||||
)?;
|
)?;
|
||||||
let var = translate_type_mut::<T>(memory_mapping, var_addr, check_aligned)?;
|
let var = translate_type_mut::<T>(memory_mapping, var_addr, check_aligned)?;
|
||||||
|
|
||||||
let sysvar: Arc<T> = sysvar.map_err(SyscallError::InstructionError)?;
|
let sysvar: Arc<T> = sysvar?;
|
||||||
*var = T::clone(sysvar.as_ref());
|
*var = T::clone(sysvar.as_ref());
|
||||||
|
|
||||||
Ok(SUCCESS)
|
Ok(SUCCESS)
|
||||||
|
@ -33,7 +33,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
get_sysvar(
|
get_sysvar(
|
||||||
invoke_context.get_sysvar_cache().get_clock(),
|
invoke_context.get_sysvar_cache().get_clock(),
|
||||||
var_addr,
|
var_addr,
|
||||||
|
@ -55,7 +55,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
get_sysvar(
|
get_sysvar(
|
||||||
invoke_context.get_sysvar_cache().get_epoch_schedule(),
|
invoke_context.get_sysvar_cache().get_epoch_schedule(),
|
||||||
var_addr,
|
var_addr,
|
||||||
|
@ -77,7 +77,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
{
|
{
|
||||||
get_sysvar(
|
get_sysvar(
|
||||||
|
@ -102,7 +102,7 @@ declare_syscall!(
|
||||||
_arg4: u64,
|
_arg4: u64,
|
||||||
_arg5: u64,
|
_arg5: u64,
|
||||||
memory_mapping: &mut MemoryMapping,
|
memory_mapping: &mut MemoryMapping,
|
||||||
) -> Result<u64, EbpfError> {
|
) -> Result<u64, Error> {
|
||||||
get_sysvar(
|
get_sysvar(
|
||||||
invoke_context.get_sysvar_cache().get_rent(),
|
invoke_context.get_sysvar_cache().get_rent(),
|
||||||
var_addr,
|
var_addr,
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use {
|
use {solana_program_runtime::invoke_context::InvokeContext, solana_sdk::feature_set};
|
||||||
solana_program_runtime::invoke_context::InvokeContext,
|
|
||||||
solana_sdk::{feature_set, instruction::InstructionError},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
pub fn process_instruction(
|
||||||
|
invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
||||||
if invoke_context
|
if invoke_context
|
||||||
.feature_set
|
.feature_set
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use {
|
use {
|
||||||
crate::ConfigKeys,
|
crate::ConfigKeys,
|
||||||
bincode::deserialize,
|
bincode::deserialize,
|
||||||
solana_program_runtime::{ic_msg, invoke_context::InvokeContext},
|
solana_program_runtime::{declare_process_instruction, ic_msg, invoke_context::InvokeContext},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
feature_set, instruction::InstructionError, program_utils::limited_deserialize,
|
feature_set, instruction::InstructionError, program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey, transaction_context::IndexOfAccount,
|
pubkey::Pubkey, transaction_context::IndexOfAccount,
|
||||||
|
@ -11,19 +11,14 @@ use {
|
||||||
std::collections::BTreeSet,
|
std::collections::BTreeSet,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
declare_process_instruction!(450);
|
||||||
|
pub fn process_instruction_inner(
|
||||||
|
invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let data = instruction_context.get_instruction_data();
|
let data = instruction_context.get_instruction_data();
|
||||||
|
|
||||||
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
|
||||||
if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::native_programs_consume_cu::id())
|
|
||||||
{
|
|
||||||
invoke_context.consume_checked(450)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let key_list: ConfigKeys = limited_deserialize(data)?;
|
let key_list: ConfigKeys = limited_deserialize(data)?;
|
||||||
let config_account_key = transaction_context.get_key_of_account_at_index(
|
let config_account_key = transaction_context.get_key_of_account_at_index(
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
||||||
|
|
|
@ -141,7 +141,7 @@ fn calculate_heap_cost(heap_size: u64, heap_cost: u64) -> u64 {
|
||||||
pub fn create_vm<'a, 'b>(
|
pub fn create_vm<'a, 'b>(
|
||||||
invoke_context: &'a mut InvokeContext<'b>,
|
invoke_context: &'a mut InvokeContext<'b>,
|
||||||
program: &'a VerifiedExecutable<RequisiteVerifier, InvokeContext<'b>>,
|
program: &'a VerifiedExecutable<RequisiteVerifier, InvokeContext<'b>>,
|
||||||
) -> Result<EbpfVm<'a, RequisiteVerifier, InvokeContext<'b>>, InstructionError> {
|
) -> Result<EbpfVm<'a, RequisiteVerifier, InvokeContext<'b>>, Box<dyn std::error::Error>> {
|
||||||
let config = program.get_executable().get_config();
|
let config = program.get_executable().get_config();
|
||||||
let compute_budget = invoke_context.get_compute_budget();
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
let heap_size = compute_budget.heap_size.unwrap_or(HEAP_LENGTH);
|
let heap_size = compute_budget.heap_size.unwrap_or(HEAP_LENGTH);
|
||||||
|
@ -160,18 +160,22 @@ pub fn create_vm<'a, 'b>(
|
||||||
MemoryRegion::new_writable(heap.as_slice_mut(), ebpf::MM_HEAP_START),
|
MemoryRegion::new_writable(heap.as_slice_mut(), ebpf::MM_HEAP_START),
|
||||||
];
|
];
|
||||||
let log_collector = invoke_context.get_log_collector();
|
let log_collector = invoke_context.get_log_collector();
|
||||||
MemoryMapping::new(regions, config)
|
let memory_mapping = MemoryMapping::new(regions, config).map_err(|err| {
|
||||||
.and_then(|memory_mapping| EbpfVm::new(program, invoke_context, memory_mapping, stack_len))
|
ic_logger_msg!(log_collector, "Failed to create SBF VM: {}", err);
|
||||||
.map_err(|err| {
|
Box::new(InstructionError::ProgramEnvironmentSetupFailure)
|
||||||
ic_logger_msg!(log_collector, "Failed to create SBF VM: {}", err);
|
})?;
|
||||||
InstructionError::ProgramEnvironmentSetupFailure
|
Ok(EbpfVm::new(
|
||||||
})
|
program,
|
||||||
|
invoke_context,
|
||||||
|
memory_mapping,
|
||||||
|
stack_len,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute(
|
fn execute(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
program: &VerifiedExecutable<RequisiteVerifier, InvokeContext<'static>>,
|
program: &VerifiedExecutable<RequisiteVerifier, InvokeContext<'static>>,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let log_collector = invoke_context.get_log_collector();
|
let log_collector = invoke_context.get_log_collector();
|
||||||
let stack_height = invoke_context.get_stack_height();
|
let stack_height = invoke_context.get_stack_height();
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
|
@ -211,10 +215,10 @@ fn execute(
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
ProgramResult::Ok(status) if status != SUCCESS => {
|
ProgramResult::Ok(status) if status != SUCCESS => {
|
||||||
let error = status.into();
|
let error: InstructionError = status.into();
|
||||||
Err(error)
|
Err(Box::new(error) as Box<dyn std::error::Error>)
|
||||||
}
|
}
|
||||||
ProgramResult::Err(_) => Err(InstructionError::ProgramFailedToComplete),
|
ProgramResult::Err(error) => Err(error),
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -531,7 +535,9 @@ pub fn process_instruction_transfer_authority(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
pub fn process_instruction(
|
||||||
|
invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let use_jit = true;
|
let use_jit = true;
|
||||||
let log_collector = invoke_context.get_log_collector();
|
let log_collector = invoke_context.get_log_collector();
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
|
@ -558,20 +564,21 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
|
||||||
process_instruction_transfer_authority(invoke_context)
|
process_instruction_transfer_authority(invoke_context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.map_err(|err| Box::new(err) as Box<dyn std::error::Error>)
|
||||||
} else {
|
} else {
|
||||||
let program = instruction_context.try_borrow_last_program_account(transaction_context)?;
|
let program = instruction_context.try_borrow_last_program_account(transaction_context)?;
|
||||||
if !loader_v3::check_id(program.get_owner()) {
|
if !loader_v3::check_id(program.get_owner()) {
|
||||||
ic_logger_msg!(log_collector, "Program not owned by loader");
|
ic_logger_msg!(log_collector, "Program not owned by loader");
|
||||||
return Err(InstructionError::InvalidAccountOwner);
|
return Err(Box::new(InstructionError::InvalidAccountOwner));
|
||||||
}
|
}
|
||||||
if program.get_data().is_empty() {
|
if program.get_data().is_empty() {
|
||||||
ic_logger_msg!(log_collector, "Program is uninitialized");
|
ic_logger_msg!(log_collector, "Program is uninitialized");
|
||||||
return Err(InstructionError::InvalidAccountData);
|
return Err(Box::new(InstructionError::InvalidAccountData));
|
||||||
}
|
}
|
||||||
let state = get_state(program.get_data())?;
|
let state = get_state(program.get_data())?;
|
||||||
if !state.is_deployed {
|
if !state.is_deployed {
|
||||||
ic_logger_msg!(log_collector, "Program is not deployed");
|
ic_logger_msg!(log_collector, "Program is not deployed");
|
||||||
return Err(InstructionError::InvalidArgument);
|
return Err(Box::new(InstructionError::InvalidArgument));
|
||||||
}
|
}
|
||||||
let mut get_or_create_executor_time = Measure::start("get_or_create_executor_time");
|
let mut get_or_create_executor_time = Measure::start("get_or_create_executor_time");
|
||||||
let (loaded_program, load_program_metrics) = load_program_from_account(
|
let (loaded_program, load_program_metrics) = load_program_from_account(
|
||||||
|
@ -593,9 +600,11 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
|
||||||
match &loaded_program.program {
|
match &loaded_program.program {
|
||||||
LoadedProgramType::FailedVerification
|
LoadedProgramType::FailedVerification
|
||||||
| LoadedProgramType::Closed
|
| LoadedProgramType::Closed
|
||||||
| LoadedProgramType::DelayVisibility => Err(InstructionError::InvalidAccountData),
|
| LoadedProgramType::DelayVisibility => {
|
||||||
|
Err(Box::new(InstructionError::InvalidAccountData))
|
||||||
|
}
|
||||||
LoadedProgramType::Typed(executable) => execute(invoke_context, executable),
|
LoadedProgramType::Typed(executable) => execute(invoke_context, executable),
|
||||||
_ => Err(InstructionError::IncorrectProgramId),
|
_ => Err(Box::new(InstructionError::IncorrectProgramId)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6497,9 +6497,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana_rbpf"
|
name = "solana_rbpf"
|
||||||
version = "0.2.40"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a5735b8c9defc3723162321a61ef738d34168401eeef213f62a32809739b0f5"
|
checksum = "edb31627f86190e2d97f86988f1de1a757b530caa50694244d9d28812611b063"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.4.3",
|
"byteorder 1.4.3",
|
||||||
"combine",
|
"combine",
|
||||||
|
|
|
@ -24,7 +24,7 @@ num-traits = "0.2"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
solana_rbpf = "=0.2.40"
|
solana_rbpf = "=0.3.0"
|
||||||
solana-account-decoder = { path = "../../account-decoder", version = "=1.16.0" }
|
solana-account-decoder = { path = "../../account-decoder", version = "=1.16.0" }
|
||||||
solana-address-lookup-table-program = { path = "../../programs/address-lookup-table", version = "=1.16.0" }
|
solana-address-lookup-table-program = { path = "../../programs/address-lookup-table", version = "=1.16.0" }
|
||||||
solana-bpf-loader-program = { path = "../bpf_loader", version = "=1.16.0" }
|
solana-bpf-loader-program = { path = "../bpf_loader", version = "=1.16.0" }
|
||||||
|
|
|
@ -918,6 +918,7 @@ fn test_program_sbf_invoke_sanity() {
|
||||||
assert_eq!(result, Err(expected_error));
|
assert_eq!(result, Err(expected_error));
|
||||||
assert_eq!(invoked_programs, expected_invoked_programs);
|
assert_eq!(invoked_programs, expected_invoked_programs);
|
||||||
if let Some(expected_log_messages) = expected_log_messages {
|
if let Some(expected_log_messages) = expected_log_messages {
|
||||||
|
assert_eq!(log_messages.len(), expected_log_messages.len());
|
||||||
expected_log_messages
|
expected_log_messages
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(log_messages)
|
.zip(log_messages)
|
||||||
|
@ -985,8 +986,7 @@ fn test_program_sbf_invoke_sanity() {
|
||||||
format!("Program log: invoke {program_lang} program"),
|
format!("Program log: invoke {program_lang} program"),
|
||||||
"Program log: Test max instruction data len exceeded".into(),
|
"Program log: Test max instruction data len exceeded".into(),
|
||||||
"skip".into(), // don't compare compute consumption logs
|
"skip".into(), // don't compare compute consumption logs
|
||||||
"Program failed to complete: Invoked an instruction with data that is too large (10241 > 10240)".into(),
|
format!("Program {invoke_program_id} failed: Invoked an instruction with data that is too large (10241 > 10240)"),
|
||||||
format!("Program {invoke_program_id} failed: Program failed to complete"),
|
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -999,8 +999,7 @@ fn test_program_sbf_invoke_sanity() {
|
||||||
format!("Program log: invoke {program_lang} program"),
|
format!("Program log: invoke {program_lang} program"),
|
||||||
"Program log: Test max instruction accounts exceeded".into(),
|
"Program log: Test max instruction accounts exceeded".into(),
|
||||||
"skip".into(), // don't compare compute consumption logs
|
"skip".into(), // don't compare compute consumption logs
|
||||||
"Program failed to complete: Invoked an instruction with too many accounts (256 > 255)".into(),
|
format!("Program {invoke_program_id} failed: Invoked an instruction with too many accounts (256 > 255)"),
|
||||||
format!("Program {invoke_program_id} failed: Program failed to complete"),
|
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1013,8 +1012,7 @@ fn test_program_sbf_invoke_sanity() {
|
||||||
format!("Program log: invoke {program_lang} program"),
|
format!("Program log: invoke {program_lang} program"),
|
||||||
"Program log: Test max account infos exceeded".into(),
|
"Program log: Test max account infos exceeded".into(),
|
||||||
"skip".into(), // don't compare compute consumption logs
|
"skip".into(), // don't compare compute consumption logs
|
||||||
"Program failed to complete: Invoked an instruction with too many account info's (129 > 128)".into(),
|
format!("Program {invoke_program_id} failed: Invoked an instruction with too many account info's (129 > 128)"),
|
||||||
format!("Program {invoke_program_id} failed: Program failed to complete"),
|
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ use {
|
||||||
},
|
},
|
||||||
log::*,
|
log::*,
|
||||||
solana_program_runtime::{
|
solana_program_runtime::{
|
||||||
invoke_context::InvokeContext, sysvar_cache::get_sysvar_with_account_check,
|
declare_process_instruction, invoke_context::InvokeContext,
|
||||||
|
sysvar_cache::get_sysvar_with_account_check,
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
clock::Clock,
|
clock::Clock,
|
||||||
|
@ -51,21 +52,16 @@ fn get_optional_pubkey<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
declare_process_instruction!(750);
|
||||||
|
pub fn process_instruction_inner(
|
||||||
|
invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let data = instruction_context.get_instruction_data();
|
let data = instruction_context.get_instruction_data();
|
||||||
|
|
||||||
trace!("process_instruction: {:?}", data);
|
trace!("process_instruction: {:?}", data);
|
||||||
|
|
||||||
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
|
||||||
if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::native_programs_consume_cu::id())
|
|
||||||
{
|
|
||||||
invoke_context.consume_checked(750)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let get_stake_account = || {
|
let get_stake_account = || {
|
||||||
let me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
let me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
if *me.get_owner() != id() {
|
if *me.get_owner() != id() {
|
||||||
|
|
|
@ -5,7 +5,8 @@ use {
|
||||||
log::*,
|
log::*,
|
||||||
solana_program::vote::{instruction::VoteInstruction, program::id, state::VoteAuthorize},
|
solana_program::vote::{instruction::VoteInstruction, program::id, state::VoteAuthorize},
|
||||||
solana_program_runtime::{
|
solana_program_runtime::{
|
||||||
invoke_context::InvokeContext, sysvar_cache::get_sysvar_with_account_check,
|
declare_process_instruction, invoke_context::InvokeContext,
|
||||||
|
sysvar_cache::get_sysvar_with_account_check,
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
feature_set,
|
feature_set,
|
||||||
|
@ -55,23 +56,18 @@ fn process_authorize_with_seed_instruction(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
// Citing `runtime/src/block_cost_limit.rs`, vote has statically defined 2_100
|
||||||
|
// units; can consume based on instructions in the future like `bpf_loader` does.
|
||||||
|
declare_process_instruction!(2_100);
|
||||||
|
pub fn process_instruction_inner(
|
||||||
|
invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let data = instruction_context.get_instruction_data();
|
let data = instruction_context.get_instruction_data();
|
||||||
|
|
||||||
trace!("process_instruction: {:?}", data);
|
trace!("process_instruction: {:?}", data);
|
||||||
|
|
||||||
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
|
||||||
// Citing `runtime/src/block_cost_limit.rs`, vote has statically defined 2_100
|
|
||||||
// units; can consume based on instructions in the future like `bpf_loader` does.
|
|
||||||
if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::native_programs_consume_cu::id())
|
|
||||||
{
|
|
||||||
invoke_context.consume_checked(2_100)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
let mut me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
if *me.get_owner() != id() {
|
if *me.get_owner() != id() {
|
||||||
return Err(InstructionError::InvalidAccountOwner);
|
return Err(InstructionError::InvalidAccountOwner);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
bytemuck::Pod,
|
bytemuck::Pod,
|
||||||
solana_program_runtime::{ic_msg, invoke_context::InvokeContext},
|
solana_program_runtime::{declare_process_instruction, ic_msg, invoke_context::InvokeContext},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
feature_set,
|
feature_set,
|
||||||
instruction::{InstructionError, TRANSACTION_LEVEL_STACK_HEIGHT},
|
instruction::{InstructionError, TRANSACTION_LEVEL_STACK_HEIGHT},
|
||||||
|
@ -114,7 +114,10 @@ fn process_close_proof_context(invoke_context: &mut InvokeContext) -> Result<(),
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
declare_process_instruction!(0);
|
||||||
|
pub fn process_instruction_inner(
|
||||||
|
invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
if invoke_context.get_stack_height() != TRANSACTION_LEVEL_STACK_HEIGHT {
|
if invoke_context.get_stack_height() != TRANSACTION_LEVEL_STACK_HEIGHT {
|
||||||
// Not supported as an inner instruction
|
// Not supported as an inner instruction
|
||||||
return Err(InstructionError::UnsupportedProgramId);
|
return Err(InstructionError::UnsupportedProgramId);
|
||||||
|
@ -137,21 +140,27 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyCloseAccount => {
|
ProofInstruction::VerifyCloseAccount => {
|
||||||
if native_programs_consume_cu {
|
if native_programs_consume_cu {
|
||||||
invoke_context.consume_checked(6_012)?;
|
invoke_context
|
||||||
|
.consume_checked(6_012)
|
||||||
|
.map_err(|_| InstructionError::ComputationalBudgetExceeded)?;
|
||||||
}
|
}
|
||||||
ic_msg!(invoke_context, "VerifyCloseAccount");
|
ic_msg!(invoke_context, "VerifyCloseAccount");
|
||||||
process_verify_proof::<CloseAccountData, CloseAccountProofContext>(invoke_context)
|
process_verify_proof::<CloseAccountData, CloseAccountProofContext>(invoke_context)
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyWithdraw => {
|
ProofInstruction::VerifyWithdraw => {
|
||||||
if native_programs_consume_cu {
|
if native_programs_consume_cu {
|
||||||
invoke_context.consume_checked(112_454)?;
|
invoke_context
|
||||||
|
.consume_checked(112_454)
|
||||||
|
.map_err(|_| InstructionError::ComputationalBudgetExceeded)?;
|
||||||
}
|
}
|
||||||
ic_msg!(invoke_context, "VerifyWithdraw");
|
ic_msg!(invoke_context, "VerifyWithdraw");
|
||||||
process_verify_proof::<WithdrawData, WithdrawProofContext>(invoke_context)
|
process_verify_proof::<WithdrawData, WithdrawProofContext>(invoke_context)
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyWithdrawWithheldTokens => {
|
ProofInstruction::VerifyWithdrawWithheldTokens => {
|
||||||
if native_programs_consume_cu {
|
if native_programs_consume_cu {
|
||||||
invoke_context.consume_checked(7_943)?;
|
invoke_context
|
||||||
|
.consume_checked(7_943)
|
||||||
|
.map_err(|_| InstructionError::ComputationalBudgetExceeded)?;
|
||||||
}
|
}
|
||||||
ic_msg!(invoke_context, "VerifyWithdrawWithheldTokens");
|
ic_msg!(invoke_context, "VerifyWithdrawWithheldTokens");
|
||||||
process_verify_proof::<WithdrawWithheldTokensData, WithdrawWithheldTokensProofContext>(
|
process_verify_proof::<WithdrawWithheldTokensData, WithdrawWithheldTokensProofContext>(
|
||||||
|
@ -160,21 +169,27 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyTransfer => {
|
ProofInstruction::VerifyTransfer => {
|
||||||
if native_programs_consume_cu {
|
if native_programs_consume_cu {
|
||||||
invoke_context.consume_checked(219_290)?;
|
invoke_context
|
||||||
|
.consume_checked(219_290)
|
||||||
|
.map_err(|_| InstructionError::ComputationalBudgetExceeded)?;
|
||||||
}
|
}
|
||||||
ic_msg!(invoke_context, "VerifyTransfer");
|
ic_msg!(invoke_context, "VerifyTransfer");
|
||||||
process_verify_proof::<TransferData, TransferProofContext>(invoke_context)
|
process_verify_proof::<TransferData, TransferProofContext>(invoke_context)
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyTransferWithFee => {
|
ProofInstruction::VerifyTransferWithFee => {
|
||||||
if native_programs_consume_cu {
|
if native_programs_consume_cu {
|
||||||
invoke_context.consume_checked(407_121)?;
|
invoke_context
|
||||||
|
.consume_checked(407_121)
|
||||||
|
.map_err(|_| InstructionError::ComputationalBudgetExceeded)?;
|
||||||
}
|
}
|
||||||
ic_msg!(invoke_context, "VerifyTransferWithFee");
|
ic_msg!(invoke_context, "VerifyTransferWithFee");
|
||||||
process_verify_proof::<TransferWithFeeData, TransferWithFeeProofContext>(invoke_context)
|
process_verify_proof::<TransferWithFeeData, TransferWithFeeProofContext>(invoke_context)
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyPubkeyValidity => {
|
ProofInstruction::VerifyPubkeyValidity => {
|
||||||
if native_programs_consume_cu {
|
if native_programs_consume_cu {
|
||||||
invoke_context.consume_checked(2_619)?;
|
invoke_context
|
||||||
|
.consume_checked(2_619)
|
||||||
|
.map_err(|_| InstructionError::ComputationalBudgetExceeded)?;
|
||||||
}
|
}
|
||||||
ic_msg!(invoke_context, "VerifyPubkeyValidity");
|
ic_msg!(invoke_context, "VerifyPubkeyValidity");
|
||||||
process_verify_proof::<PubkeyValidityData, PubkeyValidityProofContext>(invoke_context)
|
process_verify_proof::<PubkeyValidityData, PubkeyValidityProofContext>(invoke_context)
|
||||||
|
|
|
@ -15,7 +15,6 @@ use {
|
||||||
client::{AsyncClient, SyncClient},
|
client::{AsyncClient, SyncClient},
|
||||||
clock::MAX_RECENT_BLOCKHASHES,
|
clock::MAX_RECENT_BLOCKHASHES,
|
||||||
genesis_config::create_genesis_config,
|
genesis_config::create_genesis_config,
|
||||||
instruction::InstructionError,
|
|
||||||
message::Message,
|
message::Message,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
|
@ -35,8 +34,9 @@ const NOOP_PROGRAM_ID: [u8; 32] = [
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||||
];
|
];
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
fn process_instruction(
|
||||||
fn process_instruction(_invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
_invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1342,7 +1342,7 @@ fn test_rent_complex() {
|
||||||
|
|
||||||
fn mock_process_instruction(
|
fn mock_process_instruction(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -1359,7 +1359,7 @@ fn test_rent_complex() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidInstructionData)
|
Err(Box::new(InstructionError::InvalidInstructionData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5072,14 +5072,14 @@ fn test_add_builtin() {
|
||||||
}
|
}
|
||||||
fn mock_vote_processor(
|
fn mock_vote_processor(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let program_id = instruction_context.get_last_program_key(transaction_context)?;
|
let program_id = instruction_context.get_last_program_key(transaction_context)?;
|
||||||
if mock_vote_program_id() != *program_id {
|
if mock_vote_program_id() != *program_id {
|
||||||
return Err(InstructionError::IncorrectProgramId);
|
return Err(Box::new(InstructionError::IncorrectProgramId));
|
||||||
}
|
}
|
||||||
Err(InstructionError::Custom(42))
|
Err(Box::new(InstructionError::Custom(42)))
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(bank.get_account(&mock_vote_program_id()).is_none());
|
assert!(bank.get_account(&mock_vote_program_id()).is_none());
|
||||||
|
@ -5130,10 +5130,10 @@ fn test_add_duplicate_static_program() {
|
||||||
|
|
||||||
fn mock_vote_processor(
|
fn mock_vote_processor(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
// mock builtin must consume units
|
// mock builtin must consume units
|
||||||
invoke_context.consume_checked(1)?;
|
invoke_context.consume_checked(1)?;
|
||||||
Err(InstructionError::Custom(42))
|
Err(Box::new(InstructionError::Custom(42)))
|
||||||
}
|
}
|
||||||
|
|
||||||
let mock_account = Keypair::new();
|
let mock_account = Keypair::new();
|
||||||
|
@ -5180,10 +5180,10 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() {
|
||||||
|
|
||||||
fn mock_ix_processor(
|
fn mock_ix_processor(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
// mock builtin must consume units
|
// mock builtin must consume units
|
||||||
invoke_context.consume_checked(1)?;
|
invoke_context.consume_checked(1)?;
|
||||||
Err(InstructionError::Custom(42))
|
Err(Box::new(InstructionError::Custom(42)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-builtin loader accounts can not be used for instruction processing
|
// Non-builtin loader accounts can not be used for instruction processing
|
||||||
|
@ -6472,7 +6472,7 @@ fn test_transaction_with_duplicate_accounts_in_instruction() {
|
||||||
|
|
||||||
fn mock_process_instruction(
|
fn mock_process_instruction(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -6533,7 +6533,7 @@ fn test_transaction_with_program_ids_passed_to_programs() {
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn mock_process_instruction(
|
fn mock_process_instruction(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), Box<dyn std::error::Error>> {
|
||||||
// mock builtin must consume units
|
// mock builtin must consume units
|
||||||
invoke_context.consume_checked(1)?;
|
invoke_context.consume_checked(1)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -6753,7 +6753,7 @@ fn test_program_id_as_payer() {
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn mock_ok_vote_processor(
|
fn mock_ok_vote_processor(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
// mock builtin must consume units
|
// mock builtin must consume units
|
||||||
invoke_context.consume_checked(1)?;
|
invoke_context.consume_checked(1)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -7001,7 +7001,7 @@ fn test_bank_hash_consistency() {
|
||||||
fn test_same_program_id_uses_unqiue_executable_accounts() {
|
fn test_same_program_id_uses_unqiue_executable_accounts() {
|
||||||
fn nested_processor(
|
fn nested_processor(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let _ = instruction_context
|
let _ = instruction_context
|
||||||
|
@ -7223,7 +7223,7 @@ fn test_add_builtin_no_overwrite() {
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn mock_ix_processor(
|
fn mock_ix_processor(
|
||||||
_invoke_context: &mut InvokeContext,
|
_invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7254,7 +7254,7 @@ fn test_add_builtin_loader_no_overwrite() {
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn mock_ix_processor(
|
fn mock_ix_processor(
|
||||||
_context: &mut InvokeContext,
|
_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10002,7 +10002,7 @@ fn test_tx_return_data() {
|
||||||
let mock_program_id = Pubkey::from([2u8; 32]);
|
let mock_program_id = Pubkey::from([2u8; 32]);
|
||||||
fn mock_process_instruction(
|
fn mock_process_instruction(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let mock_program_id = Pubkey::from([2u8; 32]);
|
let mock_program_id = Pubkey::from([2u8; 32]);
|
||||||
let transaction_context = &mut invoke_context.transaction_context;
|
let transaction_context = &mut invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
|
@ -10199,7 +10199,7 @@ fn test_transfer_sysvar() {
|
||||||
|
|
||||||
fn mock_ix_processor(
|
fn mock_ix_processor(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
// mock builtin should consume units
|
// mock builtin should consume units
|
||||||
|
@ -10412,7 +10412,7 @@ fn test_compute_budget_program_noop() {
|
||||||
|
|
||||||
fn mock_ix_processor(
|
fn mock_ix_processor(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let compute_budget = invoke_context.get_compute_budget();
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*compute_budget,
|
*compute_budget,
|
||||||
|
@ -10459,7 +10459,7 @@ fn test_compute_request_instruction() {
|
||||||
|
|
||||||
fn mock_ix_processor(
|
fn mock_ix_processor(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let compute_budget = invoke_context.get_compute_budget();
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*compute_budget,
|
*compute_budget,
|
||||||
|
@ -10513,7 +10513,7 @@ fn test_failed_compute_request_instruction() {
|
||||||
|
|
||||||
fn mock_ix_processor(
|
fn mock_ix_processor(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let compute_budget = invoke_context.get_compute_budget();
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*compute_budget,
|
*compute_budget,
|
||||||
|
@ -11078,7 +11078,7 @@ enum MockTransferInstruction {
|
||||||
|
|
||||||
fn mock_transfer_process_instruction(
|
fn mock_transfer_process_instruction(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -11097,7 +11097,7 @@ fn mock_transfer_process_instruction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidInstructionData)
|
Err(Box::new(InstructionError::InvalidInstructionData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11890,7 +11890,7 @@ enum MockReallocInstruction {
|
||||||
|
|
||||||
fn mock_realloc_process_instruction(
|
fn mock_realloc_process_instruction(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), Box<dyn std::error::Error>> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -11929,7 +11929,7 @@ fn mock_realloc_process_instruction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidInstructionData)
|
Err(Box::new(InstructionError::InvalidInstructionData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,7 @@ mod tests {
|
||||||
|
|
||||||
fn mock_system_process_instruction(
|
fn mock_system_process_instruction(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -245,7 +245,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidInstructionData)
|
Err(Box::new(InstructionError::InvalidInstructionData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,7 +432,7 @@ mod tests {
|
||||||
|
|
||||||
fn mock_system_process_instruction(
|
fn mock_system_process_instruction(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -448,7 +448,7 @@ mod tests {
|
||||||
let dup_account = instruction_context
|
let dup_account = instruction_context
|
||||||
.try_borrow_instruction_account(transaction_context, 2)?;
|
.try_borrow_instruction_account(transaction_context, 2)?;
|
||||||
if from_account.get_lamports() != dup_account.get_lamports() {
|
if from_account.get_lamports() != dup_account.get_lamports() {
|
||||||
return Err(InstructionError::InvalidArgument);
|
return Err(Box::new(InstructionError::InvalidArgument));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -460,7 +460,7 @@ mod tests {
|
||||||
.try_borrow_instruction_account(transaction_context, 2)?
|
.try_borrow_instruction_account(transaction_context, 2)?
|
||||||
.get_lamports();
|
.get_lamports();
|
||||||
if lamports_a != lamports_b {
|
if lamports_a != lamports_b {
|
||||||
return Err(InstructionError::InvalidArgument);
|
return Err(Box::new(InstructionError::InvalidArgument));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -479,7 +479,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidInstructionData)
|
Err(Box::new(InstructionError::InvalidInstructionData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,10 +647,10 @@ mod tests {
|
||||||
let mock_program_id = Pubkey::new_unique();
|
let mock_program_id = Pubkey::new_unique();
|
||||||
fn mock_process_instruction(
|
fn mock_process_instruction(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// mock builtin should consume units
|
// mock builtin should consume units
|
||||||
let _ = invoke_context.consume_checked(1);
|
let _ = invoke_context.consume_checked(1);
|
||||||
Err(InstructionError::Custom(0xbabb1e))
|
Err(Box::new(InstructionError::Custom(0xbabb1e)))
|
||||||
}
|
}
|
||||||
let builtin_programs = &[BuiltinProgram {
|
let builtin_programs = &[BuiltinProgram {
|
||||||
program_id: mock_program_id,
|
program_id: mock_program_id,
|
||||||
|
|
|
@ -5,7 +5,8 @@ use {
|
||||||
},
|
},
|
||||||
log::*,
|
log::*,
|
||||||
solana_program_runtime::{
|
solana_program_runtime::{
|
||||||
ic_msg, invoke_context::InvokeContext, sysvar_cache::get_sysvar_with_account_check,
|
declare_process_instruction, ic_msg, invoke_context::InvokeContext,
|
||||||
|
sysvar_cache::get_sysvar_with_account_check,
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::AccountSharedData,
|
account::AccountSharedData,
|
||||||
|
@ -315,7 +316,10 @@ fn transfer_with_seed(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
declare_process_instruction!(150);
|
||||||
|
pub fn process_instruction_inner(
|
||||||
|
invoke_context: &mut InvokeContext,
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -323,14 +327,6 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
|
||||||
|
|
||||||
trace!("process_instruction: {:?}", instruction);
|
trace!("process_instruction: {:?}", instruction);
|
||||||
|
|
||||||
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
|
||||||
if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::native_programs_consume_cu::id())
|
|
||||||
{
|
|
||||||
invoke_context.consume_checked(150)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let signers = instruction_context.get_signers(transaction_context)?;
|
let signers = instruction_context.get_signers(transaction_context)?;
|
||||||
match instruction {
|
match instruction {
|
||||||
SystemInstruction::CreateAccount {
|
SystemInstruction::CreateAccount {
|
||||||
|
|
Loading…
Reference in New Issue