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:
Alexander Meißner 2023-04-05 15:50:34 +02:00 committed by GitHub
parent 06461fb348
commit 24a87f33a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 404 additions and 510 deletions

4
Cargo.lock generated
View File

@ -7343,9 +7343,9 @@ dependencies = [
[[package]]
name = "solana_rbpf"
version = "0.2.40"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a5735b8c9defc3723162321a61ef738d34168401eeef213f62a32809739b0f5"
checksum = "edb31627f86190e2d97f86988f1de1a757b530caa50694244d9d28812611b063"
dependencies = [
"byteorder",
"combine",

View File

@ -289,7 +289,7 @@ signal-hook = "0.3.14"
smpl_jwt = "0.7.1"
socket2 = "0.4.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-address-lookup-table-program = { path = "programs/address-lookup-table", version = "=1.16.0" }
solana-banks-client = { path = "banks-client", version = "=1.16.0" }

View File

@ -2975,7 +2975,7 @@ pub mod tests {
fn mock_processor_ok(
invoke_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
invoke_context.consume_checked(1)?;
Ok(())
}
@ -3006,7 +3006,7 @@ pub mod tests {
fn mock_processor_err(
invoke_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
let instruction_errors = get_instruction_errors();
invoke_context.consume_checked(1)?;
@ -3017,10 +3017,12 @@ pub mod tests {
.get_instruction_data()
.first()
.expect("Failed to get instruction data");
Err(instruction_errors
.get(*err as usize)
.expect("Invalid error index")
.clone())
Err(Box::new(
instruction_errors
.get(*err as usize)
.expect("Invalid error index")
.clone(),
))
}
let mut bankhash_err = None;

View File

@ -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)]
pub struct BuiltinProgram {
@ -50,7 +70,7 @@ impl std::fmt::Debug for BuiltinProgram {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
// These are just type aliases for work around of Debug-ing above pointers
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
// https://github.com/rust-lang/rust/issues/50280
@ -689,26 +709,25 @@ impl<'a> InvokeContext<'a> {
self.transaction_context
.set_return_data(program_id, Vec::new())?;
let is_builtin_program = builtin_id == program_id;
let pre_remaining_units = self.get_remaining();
let result = if is_builtin_program {
let logger = self.get_log_collector();
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
(entry.process_instruction)(self)
.map(|()| {
stable_log::program_success(&logger, &program_id);
})
.map_err(|err| {
stable_log::program_failure(&logger, &program_id, &err);
err
})
} else {
(entry.process_instruction)(self)
};
let logger = self.get_log_collector();
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
let result = (entry.process_instruction)(self)
.map(|()| {
stable_log::program_success(&logger, &program_id);
})
.map_err(|err| {
stable_log::program_failure(&logger, &program_id, err.as_ref());
if let Some(err) = err.downcast_ref::<InstructionError>() {
err.clone()
} else {
InstructionError::ProgramFailedToComplete
}
});
let post_remaining_units = self.get_remaining();
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);
if is_builtin_program
if builtin_id == program_id
&& result.is_ok()
&& *compute_units_consumed == 0
&& self
@ -739,13 +758,13 @@ impl<'a> InvokeContext<'a> {
}
/// 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);
let mut compute_meter = self.compute_meter.borrow_mut();
let exceeded = *compute_meter < amount;
*compute_meter = compute_meter.saturating_sub(amount);
if exceeded {
return Err(InstructionError::ComputationalBudgetExceeded);
return Err(Box::new(InstructionError::ComputationalBudgetExceeded));
}
Ok(())
}
@ -986,14 +1005,14 @@ mod tests {
#[test]
fn test_program_entry_debug() {
#[allow(clippy::unnecessary_wraps)]
fn mock_process_instruction(
_invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
) -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
#[allow(clippy::unnecessary_wraps)]
fn mock_ix_processor(_invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
fn mock_ix_processor(
_invoke_context: &mut InvokeContext,
) -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
let builtin_programs = &[
@ -1014,7 +1033,7 @@ mod tests {
#[allow(clippy::integer_arithmetic)]
fn mock_process_instruction(
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
) -> Result<(), Box<dyn std::error::Error>> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
@ -1048,7 +1067,7 @@ mod tests {
if let Ok(instruction) = bincode::deserialize(instruction_data) {
match instruction {
MockInstruction::NoopSuccess => (),
MockInstruction::NoopFail => return Err(InstructionError::GenericError),
MockInstruction::NoopFail => return Err(Box::new(InstructionError::GenericError)),
MockInstruction::ModifyOwned => instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.set_data_from_slice(&[1])?,
@ -1098,14 +1117,15 @@ mod tests {
desired_result,
} => {
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
.try_borrow_instruction_account(transaction_context, 0)?
.set_data(vec![0; new_len as usize])?,
}
} else {
return Err(InstructionError::InvalidInstructionData);
return Err(Box::new(InstructionError::InvalidInstructionData));
}
Ok(())
}

View File

@ -137,7 +137,7 @@ impl LoadedProgram {
account_size: usize,
use_jit: bool,
metrics: &mut LoadProgramMetrics,
) -> Result<Self, EbpfError> {
) -> Result<Self, Box<dyn std::error::Error>> {
let mut load_elf_time = Measure::start("load_elf_time");
let executable = Executable::load(elf_bytes, loader.clone())?;
load_elf_time.stop();

View File

@ -5,7 +5,7 @@
use {
crate::{ic_logger_msg, log_collector::LogCollector},
itertools::Itertools,
solana_sdk::{instruction::InstructionError, pubkey::Pubkey},
solana_sdk::pubkey::Pubkey,
std::{cell::RefCell, rc::Rc},
};
@ -103,7 +103,7 @@ pub fn program_success(log_collector: &Option<Rc<RefCell<LogCollector>>>, progra
pub fn program_failure(
log_collector: &Option<Rc<RefCell<LogCollector>>>,
program_id: &Pubkey,
err: &InstructionError,
err: &dyn std::error::Error,
) {
ic_logger_msg!(log_collector, "Program {} failed: {}", program_id, err);
}

View File

@ -100,7 +100,7 @@ fn get_invoke_context<'a, 'b>() -> &'a mut InvokeContext<'b> {
pub fn builtin_process_instruction(
process_instruction: solana_sdk::entrypoint::ProcessInstruction,
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
) -> Result<(), Box<dyn std::error::Error>> {
set_invoke_context(invoke_context);
let transaction_context = &invoke_context.transaction_context;
@ -134,8 +134,8 @@ pub fn builtin_process_instruction(
// Execute the program
process_instruction(program_id, &account_infos, instruction_data).map_err(|err| {
let err = u64::from(err);
stable_log::program_failure(&log_collector, program_id, &err.into());
let err: Box<dyn std::error::Error> = Box::new(InstructionError::from(u64::from(err)));
stable_log::program_failure(&log_collector, program_id, err.as_ref());
err
})?;
stable_log::program_success(&log_collector, program_id);

View File

@ -6,7 +6,7 @@ use {
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::{
clock::Slot,
feature_set,
@ -18,14 +18,10 @@ use {
std::convert::TryFrom,
};
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
// 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)?;
}
declare_process_instruction!(750);
pub fn process_instruction_inner(
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();

View File

@ -10,11 +10,7 @@ pub mod upgradeable_with_jit;
pub mod with_jit;
use {
crate::{
allocator_bump::BpfAllocator,
serialization::{deserialize_parameters, serialize_parameters},
syscalls::SyscallError,
},
crate::allocator_bump::BpfAllocator,
solana_measure::measure::Measure,
solana_program_runtime::{
compute_budget::ComputeBudget,
@ -30,9 +26,8 @@ use {
aligned_memory::AlignedMemory,
ebpf::{self, HOST_ALIGN, MM_HEAP_START},
elf::Executable,
error::{EbpfError, UserDefinedError},
memory_region::{MemoryCowCallback, MemoryMapping, MemoryRegion},
verifier::{RequisiteVerifier, VerifierError},
verifier::RequisiteVerifier,
vm::{ContextObject, EbpfVm, ProgramResult, VerifiedExecutable},
},
solana_sdk::{
@ -65,12 +60,10 @@ use {
},
std::{
cell::{RefCell, RefMut},
fmt::Debug,
mem,
rc::Rc,
sync::{atomic::Ordering, Arc},
},
thiserror::Error,
};
solana_sdk::declare_builtin!(
@ -79,16 +72,6 @@ solana_sdk::declare_builtin!(
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)]
pub fn load_program_from_bytes(
feature_set: &FeatureSet,
@ -326,7 +309,7 @@ pub fn create_ebpf_vm<'a, 'b>(
regions: Vec<MemoryRegion>,
orig_account_lengths: Vec<usize>,
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
.feature_set
.is_active(&round_up_heap_size::id());
@ -336,7 +319,7 @@ pub fn create_ebpf_vm<'a, 'b>(
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()
!= invoke_context
@ -346,20 +329,17 @@ pub fn create_ebpf_vm<'a, 'b>(
instruction_context
.try_borrow_last_program_account(invoke_context.transaction_context)
})
.map(|program_account| *program_account.get_owner())
.map_err(SyscallError::InstructionError)?;
.map(|program_account| *program_account.get_owner())?;
let check_size = invoke_context
.feature_set
.is_active(&check_slice_translation_size::id());
let allocator = Rc::new(RefCell::new(BpfAllocator::new(heap, MM_HEAP_START)));
invoke_context
.set_syscall_context(
check_aligned,
check_size,
orig_account_lengths,
allocator.clone(),
)
.map_err(SyscallError::InstructionError)?;
invoke_context.set_syscall_context(
check_aligned,
check_size,
orig_account_lengths,
allocator.clone(),
)?;
let stack_len = stack.len();
let memory_mapping = create_memory_mapping(
program.get_executable(),
@ -369,7 +349,12 @@ pub fn create_ebpf_vm<'a, 'b>(
None,
)?;
EbpfVm::new(program, invoke_context, memory_mapping, stack_len)
Ok(EbpfVm::new(
program,
invoke_context,
memory_mapping,
stack_len,
))
}
#[macro_export]
@ -406,7 +391,7 @@ fn create_memory_mapping<'a, 'b, C: ContextObject>(
heap: &'b mut AlignedMemory<{ HOST_ALIGN }>,
additional_regions: Vec<MemoryRegion>,
cow_cb: Option<MemoryCowCallback>,
) -> Result<MemoryMapping<'a>, EbpfError> {
) -> Result<MemoryMapping<'a>, Box<dyn std::error::Error>> {
let config = executable.get_config();
let regions: Vec<MemoryRegion> = vec![
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> {
process_instruction_common(invoke_context, false)
pub fn process_instruction(
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> {
process_instruction_common(invoke_context, true)
pub fn process_instruction_jit(
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,
use_jit: bool,
) -> Result<(), InstructionError> {
) -> Result<(), Box<dyn std::error::Error>> {
let log_collector = invoke_context.get_log_collector();
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
@ -518,7 +507,7 @@ fn process_instruction_common(
)?;
if first_account.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 {
ic_logger_msg!(log_collector, "Invalid BPF loader id");
Err(InstructionError::IncorrectProgramId)
};
}
.map_err(|error| Box::new(error) as Box<dyn std::error::Error>);
}
// Program Invocation
if !program_account.is_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()) {
@ -601,10 +591,10 @@ fn process_instruction_common(
match &executor.program {
LoadedProgramType::FailedVerification
| LoadedProgramType::Closed
| LoadedProgramType::DelayVisibility => Err(InstructionError::InvalidAccountData),
| LoadedProgramType::DelayVisibility => Err(Box::new(InstructionError::InvalidAccountData)),
LoadedProgramType::LegacyV0(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>(
executable: &'a VerifiedExecutable<RequisiteVerifier, InvokeContext<'static>>,
invoke_context: &'a mut InvokeContext<'b>,
) -> Result<(), InstructionError> {
) -> Result<(), Box<dyn std::error::Error>> {
let log_collector = invoke_context.get_log_collector();
let stack_height = invoke_context.get_stack_height();
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_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 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,
instruction_context,
invoke_context
@ -1569,13 +1558,12 @@ fn execute<'a, 'b: 'a>(
Ok(info) => info,
Err(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();
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);
drop(vm);
ic_logger_msg!(
@ -1609,50 +1597,32 @@ fn execute<'a, 'b: 'a>(
} else {
status.into()
};
stable_log::program_failure(&log_collector, &program_id, &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)
Err(Box::new(error) as Box<dyn std::error::Error>)
}
ProgramResult::Err(error) => Err(error),
_ => Ok(()),
}
};
execute_time.stop();
let mut deserialize_time = Measure::start("deserialize");
let execute_or_deserialize_result = execution_result.and_then(|_| {
deserialize_parameters(
fn deserialize_parameters(
invoke_context: &mut InvokeContext,
parameter_bytes: &[u8],
) -> Result<(), InstructionError> {
serialization::deserialize_parameters(
invoke_context.transaction_context,
invoke_context
.transaction_context
.get_current_instruction_context()?,
parameter_bytes.as_slice(),
parameter_bytes,
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();
@ -1665,9 +1635,6 @@ fn execute<'a, 'b: 'a>(
.deserialize_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
}
@ -1680,7 +1647,7 @@ mod tests {
solana_rbpf::{
ebpf::MM_INPUT_START,
elf::Executable,
verifier::Verifier,
verifier::{Verifier, VerifierError},
vm::{BuiltInProgram, Config, ContextObject, FunctionRegistry},
},
solana_sdk::{
@ -1755,7 +1722,7 @@ mod tests {
}
#[test]
#[should_panic(expected = "ExceededMaxInstructions(31, 10)")]
#[should_panic(expected = "ExceededMaxInstructions(31)")]
fn test_bpf_loader_non_terminating_program() {
#[rustfmt::skip]
let program = &[
@ -1798,8 +1765,7 @@ mod tests {
&mut context_object,
memory_mapping,
stack_len,
)
.unwrap();
);
vm.execute_program(true).1.unwrap();
}

View File

@ -39,7 +39,7 @@ impl<'a> CallerAccount<'a> {
_vm_addr: u64,
account_info: &AccountInfo,
original_data_len: usize,
) -> Result<CallerAccount<'a>, EbpfError> {
) -> Result<CallerAccount<'a>, Error> {
// account_info points to host memory. The addresses used internally are
// in vm space so they need to be translated.
@ -129,7 +129,7 @@ impl<'a> CallerAccount<'a> {
vm_addr: u64,
account_info: &SolAccountInfo,
original_data_len: usize,
) -> Result<CallerAccount<'a>, EbpfError> {
) -> Result<CallerAccount<'a>, Error> {
// account_info points to host memory. The addresses used internally are
// in vm space so they need to be translated.
@ -212,7 +212,7 @@ trait SyscallInvokeSigned {
addr: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<StableInstruction, EbpfError>;
) -> Result<StableInstruction, Error>;
fn translate_accounts<'a>(
instruction_accounts: &[InstructionAccount],
program_indices: &[IndexOfAccount],
@ -220,14 +220,14 @@ trait SyscallInvokeSigned {
account_infos_len: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<TranslatedAccounts<'a>, EbpfError>;
) -> Result<TranslatedAccounts<'a>, Error>;
fn translate_signers(
program_id: &Pubkey,
signers_seeds_addr: u64,
signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<Vec<Pubkey>, EbpfError>;
) -> Result<Vec<Pubkey>, Error>;
}
declare_syscall!(
@ -241,7 +241,7 @@ declare_syscall!(
signers_seeds_addr: u64,
signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
cpi_common::<Self>(
invoke_context,
instruction_addr,
@ -259,7 +259,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
addr: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<StableInstruction, EbpfError> {
) -> Result<StableInstruction, Error> {
let ix = translate_type::<StableInstruction>(
memory_mapping,
addr,
@ -312,7 +312,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
account_infos_len: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<TranslatedAccounts<'a>, EbpfError> {
) -> Result<TranslatedAccounts<'a>, Error> {
let (account_infos, account_info_keys) = translate_account_infos(
account_infos_addr,
account_infos_len,
@ -339,7 +339,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<Vec<Pubkey>, EbpfError> {
) -> Result<Vec<Pubkey>, Error> {
let mut signers = Vec::new();
if signers_seeds_len > 0 {
let signers_seeds = translate_slice::<&[&[u8]]>(
@ -350,7 +350,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
invoke_context.get_check_size(),
)?;
if signers_seeds.len() > MAX_SIGNERS {
return Err(SyscallError::TooManySigners.into());
return Err(Box::new(SyscallError::TooManySigners));
}
for signer_seeds in signers_seeds.iter() {
let untranslated_seeds = translate_slice::<&[u8]>(
@ -361,10 +361,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
invoke_context.get_check_size(),
)?;
if untranslated_seeds.len() > MAX_SEEDS {
return Err(SyscallError::InstructionError(
InstructionError::MaxSeedLengthExceeded,
)
.into());
return Err(Box::new(InstructionError::MaxSeedLengthExceeded));
}
let seeds = untranslated_seeds
.iter()
@ -377,7 +374,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
invoke_context.get_check_size(),
)
})
.collect::<Result<Vec<_>, EbpfError>>()?;
.collect::<Result<Vec<_>, Error>>()?;
let signer = Pubkey::create_program_address(&seeds, program_id)
.map_err(SyscallError::BadSeeds)?;
signers.push(signer);
@ -453,7 +450,7 @@ declare_syscall!(
signers_seeds_addr: u64,
signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
cpi_common::<Self>(
invoke_context,
instruction_addr,
@ -471,7 +468,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
addr: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<StableInstruction, EbpfError> {
) -> Result<StableInstruction, Error> {
let ix_c = translate_type::<SolInstruction>(
memory_mapping,
addr,
@ -530,7 +527,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
is_writable: meta_c.is_writable,
})
})
.collect::<Result<Vec<AccountMeta>, EbpfError>>()?;
.collect::<Result<Vec<AccountMeta>, Error>>()?;
Ok(StableInstruction {
accounts: accounts.into(),
@ -546,7 +543,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
account_infos_len: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<TranslatedAccounts<'a>, EbpfError> {
) -> Result<TranslatedAccounts<'a>, Error> {
let (account_infos, account_info_keys) = translate_account_infos(
account_infos_addr,
account_infos_len,
@ -573,7 +570,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &InvokeContext,
) -> Result<Vec<Pubkey>, EbpfError> {
) -> Result<Vec<Pubkey>, Error> {
if signers_seeds_len > 0 {
let signers_seeds = translate_slice::<SolSignerSeedsC>(
memory_mapping,
@ -583,7 +580,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
invoke_context.get_check_size(),
)?;
if signers_seeds.len() > MAX_SIGNERS {
return Err(SyscallError::TooManySigners.into());
return Err(Box::new(SyscallError::TooManySigners));
}
Ok(signers_seeds
.iter()
@ -596,10 +593,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
invoke_context.get_check_size(),
)?;
if seeds.len() > MAX_SEEDS {
return Err(SyscallError::InstructionError(
InstructionError::MaxSeedLengthExceeded,
)
.into());
return Err(Box::new(InstructionError::MaxSeedLengthExceeded) as Error);
}
let seeds_bytes = seeds
.iter()
@ -612,11 +606,11 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
invoke_context.get_check_size(),
)
})
.collect::<Result<Vec<_>, EbpfError>>()?;
.collect::<Result<Vec<_>, Error>>()?;
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 {
Ok(vec![])
}
@ -629,7 +623,7 @@ fn translate_account_infos<'a, T, F>(
key_addr: F,
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<(&'a [T], Vec<&'a Pubkey>), EbpfError>
) -> Result<(&'a [T], Vec<&'a Pubkey>), Error>
where
F: Fn(&T) -> u64,
{
@ -650,7 +644,7 @@ where
invoke_context.get_check_aligned(),
)
})
.collect::<Result<Vec<_>, EbpfError>>()?;
.collect::<Result<Vec<_>, Error>>()?;
Ok((account_infos, account_info_keys))
}
@ -666,21 +660,17 @@ fn translate_and_update_accounts<'a, T, F>(
invoke_context: &mut InvokeContext,
memory_mapping: &MemoryMapping,
do_translate: F,
) -> Result<TranslatedAccounts<'a>, EbpfError>
) -> Result<TranslatedAccounts<'a>, Error>
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 instruction_context = transaction_context
.get_current_instruction_context()
.map_err(SyscallError::InstructionError)?;
let instruction_context = transaction_context.get_current_instruction_context()?;
let mut accounts = Vec::with_capacity(instruction_accounts.len().saturating_add(1));
let program_account_index = program_indices
.last()
.ok_or(SyscallError::InstructionError(
InstructionError::MissingAccount,
))?;
.ok_or_else(|| Box::new(InstructionError::MissingAccount))?;
accounts.push((*program_account_index, None));
// unwrapping here is fine: we're in a syscall and the method below fails
@ -693,16 +683,13 @@ where
continue; // Skip duplicate account
}
let callee_account = instruction_context
.try_borrow_instruction_account(
transaction_context,
instruction_account.index_in_caller,
)
.map_err(SyscallError::InstructionError)?;
let callee_account = instruction_context.try_borrow_instruction_account(
transaction_context,
instruction_account.index_in_caller,
)?;
let account_key = invoke_context
.transaction_context
.get_key_of_account_at_index(instruction_account.index_in_transaction)
.map_err(SyscallError::InstructionError)?;
.get_key_of_account_at_index(instruction_account.index_in_transaction)?;
if callee_account.is_executable() {
// Use the known account
@ -724,7 +711,7 @@ where
"Internal error: index mismatch for account {}",
account_key
);
SyscallError::InstructionError(InstructionError::MissingAccount)
Box::new(InstructionError::MissingAccount)
})?;
// build the CallerAccount corresponding to this account.
@ -759,7 +746,7 @@ where
"Instruction references an unknown account {}",
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,
data_len: usize,
invoke_context: &mut InvokeContext,
) -> Result<(), EbpfError> {
) -> Result<(), Error> {
if invoke_context
.feature_set
.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 max_data_len = MAX_CPI_INSTRUCTION_DATA_LEN;
if data_len > max_data_len {
return Err(SyscallError::MaxInstructionDataLenExceeded {
return Err(Box::new(SyscallError::MaxInstructionDataLenExceeded {
data_len,
max_data_len,
}
.into());
}));
}
let num_accounts = num_accounts as u64;
let max_accounts = MAX_CPI_INSTRUCTION_ACCOUNTS as u64;
if num_accounts > max_accounts {
return Err(SyscallError::MaxInstructionAccountsExceeded {
return Err(Box::new(SyscallError::MaxInstructionAccountsExceeded {
num_accounts,
max_accounts,
}
.into());
}));
}
} else {
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_add(data_len);
if size > max_size {
return Err(SyscallError::InstructionTooLarge(size, max_size).into());
return Err(Box::new(SyscallError::InstructionTooLarge(size, max_size)));
}
}
Ok(())
@ -809,7 +794,7 @@ fn check_instruction_size(
fn check_account_infos(
num_account_infos: usize,
invoke_context: &mut InvokeContext,
) -> Result<(), EbpfError> {
) -> Result<(), Error> {
if invoke_context
.feature_set
.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 max_account_infos = max_cpi_account_infos as u64;
if num_account_infos > max_account_infos {
return Err(SyscallError::MaxInstructionAccountInfosExceeded {
return Err(Box::new(SyscallError::MaxInstructionAccountInfosExceeded {
num_account_infos,
max_account_infos,
}
.into());
}));
}
} else {
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 {
// Cap the number of account_infos a caller can pass to approximate
// maximum that accounts that could be passed in an instruction
return Err(SyscallError::TooManyAccounts.into());
return Err(Box::new(SyscallError::TooManyAccounts));
};
}
Ok(())
@ -847,7 +831,7 @@ fn check_authorized_program(
program_id: &Pubkey,
instruction_data: &[u8],
invoke_context: &InvokeContext,
) -> Result<(), EbpfError> {
) -> Result<(), Error> {
if native_loader::check_id(program_id)
|| bpf_loader::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)
})
{
return Err(SyscallError::ProgramNotSupported(*program_id).into());
return Err(Box::new(SyscallError::ProgramNotSupported(*program_id)));
}
Ok(())
}
@ -879,7 +863,7 @@ fn cpi_common<S: SyscallInvokeSigned>(
signers_seeds_addr: u64,
signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
// CPI entry.
//
// 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 transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context
.get_current_instruction_context()
.map_err(SyscallError::InstructionError)?;
let caller_program_id = instruction_context
.get_last_program_key(transaction_context)
.map_err(SyscallError::InstructionError)?;
let instruction_context = transaction_context.get_current_instruction_context()?;
let caller_program_id = instruction_context.get_last_program_key(transaction_context)?;
let signers = S::translate_signers(
caller_program_id,
signers_seeds_addr,
@ -904,9 +884,8 @@ fn cpi_common<S: SyscallInvokeSigned>(
memory_mapping,
invoke_context,
)?;
let (instruction_accounts, program_indices) = invoke_context
.prepare_instruction(&instruction, &signers)
.map_err(SyscallError::InstructionError)?;
let (instruction_accounts, program_indices) =
invoke_context.prepare_instruction(&instruction, &signers)?;
check_authorized_program(&instruction.program_id, &instruction.data, invoke_context)?;
let mut accounts = S::translate_accounts(
&instruction_accounts,
@ -919,21 +898,17 @@ fn cpi_common<S: SyscallInvokeSigned>(
// Process the callee instruction
let mut compute_units_consumed = 0;
invoke_context
.process_instruction(
&instruction.data,
&instruction_accounts,
&program_indices,
&mut compute_units_consumed,
&mut ExecuteTimings::default(),
)
.map_err(SyscallError::InstructionError)?;
invoke_context.process_instruction(
&instruction.data,
&instruction_accounts,
&program_indices,
&mut compute_units_consumed,
&mut ExecuteTimings::default(),
)?;
// re-bind to please the borrow checker
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context
.get_current_instruction_context()
.map_err(SyscallError::InstructionError)?;
let instruction_context = transaction_context.get_current_instruction_context()?;
// CPI exit.
//
@ -941,8 +916,7 @@ fn cpi_common<S: SyscallInvokeSigned>(
for (index_in_caller, caller_account) in accounts.iter_mut() {
if let Some(caller_account) = caller_account {
let callee_account = instruction_context
.try_borrow_instruction_account(transaction_context, *index_in_caller)
.map_err(SyscallError::InstructionError)?;
.try_borrow_instruction_account(transaction_context, *index_in_caller)?;
update_caller_account(
invoke_context,
memory_mapping,
@ -967,15 +941,13 @@ fn update_callee_account(
invoke_context: &InvokeContext,
caller_account: &CallerAccount,
mut callee_account: BorrowedAccount<'_>,
) -> Result<(), EbpfError> {
) -> Result<(), Error> {
let is_disable_cpi_setting_executable_and_rent_epoch_active = invoke_context
.feature_set
.is_active(&disable_cpi_setting_executable_and_rent_epoch::id());
if callee_account.get_lamports() != *caller_account.lamports {
callee_account
.set_lamports(*caller_account.lamports)
.map_err(SyscallError::InstructionError)?;
callee_account.set_lamports(*caller_account.lamports)?;
}
// 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())
.and_then(|_| callee_account.can_data_be_changed())
{
Ok(()) => callee_account
.set_data_from_slice(caller_account.data)
.map_err(SyscallError::InstructionError)?,
Ok(()) => callee_account.set_data_from_slice(caller_account.data)?,
Err(err) if callee_account.get_data() != caller_account.data => {
return Err(EbpfError::UserError(Box::new(BpfError::SyscallError(
SyscallError::InstructionError(err),
))));
return Err(Box::new(err));
}
_ => {}
}
@ -997,16 +965,12 @@ fn update_callee_account(
if !is_disable_cpi_setting_executable_and_rent_epoch_active
&& callee_account.is_executable() != caller_account.executable
{
callee_account
.set_executable(caller_account.executable)
.map_err(SyscallError::InstructionError)?;
callee_account.set_executable(caller_account.executable)?;
}
// 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 {
callee_account
.set_owner(caller_account.owner.as_ref())
.map_err(SyscallError::InstructionError)?;
callee_account.set_owner(caller_account.owner.as_ref())?;
}
// BorrowedAccount doesn't allow changing the rent epoch. Drop it and use
@ -1015,8 +979,7 @@ fn update_callee_account(
drop(callee_account);
let callee_account = invoke_context
.transaction_context
.get_account_at_index(index_in_transaction)
.map_err(SyscallError::InstructionError)?;
.get_account_at_index(index_in_transaction)?;
if !is_disable_cpi_setting_executable_and_rent_epoch_active
&& callee_account.borrow().rent_epoch() != caller_account.rent_epoch
{
@ -1024,7 +987,7 @@ fn update_callee_account(
.feature_set
.is_active(&enable_early_verification_of_account_modifications::id())
{
return Err(SyscallError::InstructionError(InstructionError::RentEpochModified).into());
return Err(Box::new(InstructionError::RentEpochModified));
} else {
callee_account
.borrow_mut()
@ -1048,7 +1011,7 @@ fn update_caller_account(
memory_mapping: &MemoryMapping,
caller_account: &mut CallerAccount,
callee_account: &BorrowedAccount<'_>,
) -> Result<(), EbpfError> {
) -> Result<(), Error> {
*caller_account.lamports = callee_account.get_lamports();
*caller_account.owner = *callee_account.get_owner();
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",
MAX_PERMITTED_DATA_INCREASE
);
return Err(SyscallError::InstructionError(InstructionError::InvalidRealloc).into());
return Err(Box::new(InstructionError::InvalidRealloc));
}
if new_len < caller_account.data.len() {
caller_account
.data
.get_mut(new_len..)
.ok_or(SyscallError::InstructionError(
InstructionError::AccountDataTooSmall,
))?
.ok_or_else(|| Box::new(InstructionError::AccountDataTooSmall))?
.fill(0);
}
caller_account.data = translate_slice_mut::<u8>(
@ -1109,7 +1070,7 @@ fn update_caller_account(
.get(0..new_len)
.ok_or(SyscallError::InvalidLength)?;
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);
@ -1449,9 +1410,7 @@ mod tests {
&mut caller_account,
&callee_account,
),
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::InstructionError(InstructionError::InvalidRealloc)
)
Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::InvalidRealloc,
));
}

View File

@ -11,7 +11,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let cost = invoke_context
.get_compute_budget()
.syscall_base_cost
@ -47,7 +47,7 @@ declare_syscall!(
arg4: u64,
arg5: u64,
_memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let cost = invoke_context.get_compute_budget().log_64_units;
consume_compute_meter(invoke_context, cost)?;
@ -70,7 +70,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
_memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let cost = invoke_context.get_compute_budget().syscall_base_cost;
consume_compute_meter(invoke_context, cost)?;
@ -94,7 +94,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let cost = invoke_context.get_compute_budget().log_pubkey_units;
consume_compute_meter(invoke_context, cost)?;
@ -119,7 +119,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let budget = invoke_context.get_compute_budget();
consume_compute_meter(invoke_context, budget.syscall_base_cost)?;

View File

@ -1,6 +1,6 @@
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 cost = compute_budget
.mem_op_base_cost
@ -19,7 +19,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
mem_op_consume(invoke_context, n)?;
if !is_nonoverlapping(src_addr, n, dst_addr, n) {
@ -66,7 +66,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
mem_op_consume(invoke_context, n)?;
let dst = translate_slice_mut::<u8>(
@ -101,7 +101,7 @@ declare_syscall!(
cmp_result_addr: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
mem_op_consume(invoke_context, n)?;
let s1 = translate_slice::<u8>(
@ -149,7 +149,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
mem_op_consume(invoke_context, n)?;
let s = translate_slice_mut::<u8>(

View File

@ -11,13 +11,11 @@ pub use self::{
};
#[allow(deprecated)]
use {
crate::BpfError,
solana_program_runtime::{
compute_budget::ComputeBudget, ic_logger_msg, ic_msg, invoke_context::InvokeContext,
stable_log, timings::ExecuteTimings,
},
solana_rbpf::{
error::EbpfError,
memory_region::{AccessType, MemoryMapping},
vm::{BuiltInProgram, Config, ProgramResult, PROGRAM_ENVIRONMENT_KEY_SHIFT},
},
@ -94,8 +92,6 @@ pub enum SyscallError {
BadSeeds(PubkeyError),
#[error("Program {0} not supported by inner instructions")]
ProgramNotSupported(Pubkey),
#[error("{0}")]
InstructionError(InstructionError),
#[error("Unaligned pointer")]
UnalignedPointer,
#[error("Too many signers")]
@ -127,16 +123,11 @@ pub enum SyscallError {
#[error("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> {
invoke_context
.consume_checked(amount)
.map_err(SyscallError::InstructionError)?;
type Error = Box<dyn std::error::Error>;
fn consume_compute_meter(invoke_context: &InvokeContext, amount: u64) -> Result<(), Error> {
invoke_context.consume_checked(amount)?;
Ok(())
}
@ -156,7 +147,7 @@ pub fn create_loader<'a>(
reject_deployment_of_broken_elfs: bool,
disable_deploy_of_alloc_free_syscall: bool,
debugging_features: bool,
) -> Result<Arc<BuiltInProgram<InvokeContext<'a>>>, EbpfError> {
) -> Result<Arc<BuiltInProgram<InvokeContext<'a>>>, Error> {
use rand::Rng;
let config = Config {
max_call_depth: compute_budget.max_call_depth,
@ -330,7 +321,7 @@ fn translate(
access_type: AccessType,
vm_addr: u64,
len: u64,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
memory_mapping.map(access_type, vm_addr, len, 0).into()
}
@ -339,7 +330,7 @@ fn translate_type_inner<'a, T>(
access_type: AccessType,
vm_addr: u64,
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)?;
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,
vm_addr: u64,
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)
}
fn translate_type<'a, T>(
memory_mapping: &MemoryMapping,
vm_addr: u64,
check_aligned: bool,
) -> Result<&'a T, EbpfError> {
) -> Result<&'a T, Error> {
translate_type_inner::<T>(memory_mapping, AccessType::Load, vm_addr, check_aligned)
.map(|value| &*value)
}
@ -370,7 +361,7 @@ fn translate_slice_inner<'a, T>(
len: u64,
check_aligned: bool,
check_size: bool,
) -> Result<&'a mut [T], EbpfError> {
) -> Result<&'a mut [T], Error> {
if len == 0 {
return Ok(&mut []);
}
@ -393,7 +384,7 @@ fn translate_slice_mut<'a, T>(
len: u64,
check_aligned: bool,
check_size: bool,
) -> Result<&'a mut [T], EbpfError> {
) -> Result<&'a mut [T], Error> {
translate_slice_inner::<T>(
memory_mapping,
AccessType::Store,
@ -409,7 +400,7 @@ fn translate_slice<'a, T>(
len: u64,
check_aligned: bool,
check_size: bool,
) -> Result<&'a [T], EbpfError> {
) -> Result<&'a [T], Error> {
translate_slice_inner::<T>(
memory_mapping,
AccessType::Load,
@ -430,8 +421,8 @@ fn translate_string_and_do(
check_aligned: bool,
check_size: bool,
stop_truncating_strings_in_syscalls: bool,
work: &mut dyn FnMut(&str) -> Result<u64, EbpfError>,
) -> Result<u64, EbpfError> {
work: &mut dyn FnMut(&str) -> Result<u64, Error>,
) -> Result<u64, Error> {
let buf = translate_slice::<u8>(memory_mapping, addr, len, check_aligned, check_size)?;
let msg = if stop_truncating_strings_in_syscalls {
buf
@ -488,7 +479,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
_memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
Err(SyscallError::Abort.into())
}
);
@ -505,7 +496,7 @@ declare_syscall!(
column: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
consume_compute_meter(invoke_context, len)?;
translate_string_and_do(
@ -538,10 +529,8 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
_memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
let allocator = invoke_context
.get_allocator()
.map_err(SyscallError::InstructionError)?;
) -> Result<u64, Error> {
let allocator = invoke_context.get_allocator()?;
let mut allocator = allocator
.try_borrow_mut()
.map_err(|_| SyscallError::InvokeContextBorrowFailed)?;
@ -576,7 +565,7 @@ fn translate_and_check_program_address_inputs<'a>(
memory_mapping: &mut MemoryMapping,
check_aligned: bool,
check_size: bool,
) -> Result<(Vec<&'a [u8]>, &'a Pubkey), EbpfError> {
) -> Result<(Vec<&'a [u8]>, &'a Pubkey), Error> {
let untranslated_seeds = translate_slice::<&[&u8]>(
memory_mapping,
seeds_addr,
@ -601,7 +590,7 @@ fn translate_and_check_program_address_inputs<'a>(
check_size,
)
})
.collect::<Result<Vec<_>, EbpfError>>()?;
.collect::<Result<Vec<_>, Error>>()?;
let program_id = translate_type::<Pubkey>(memory_mapping, program_id_addr, check_aligned)?;
Ok((seeds, program_id))
}
@ -617,7 +606,7 @@ declare_syscall!(
address_addr: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let cost = invoke_context
.get_compute_budget()
.create_program_address_units;
@ -661,7 +650,7 @@ declare_syscall!(
address_addr: u64,
bump_seed_addr: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let cost = invoke_context
.get_compute_budget()
.create_program_address_units;
@ -731,7 +720,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let compute_budget = invoke_context.get_compute_budget();
if compute_budget.sha256_max_slices < vals_len {
ic_msg!(
@ -794,7 +783,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let compute_budget = invoke_context.get_compute_budget();
if compute_budget.sha256_max_slices < vals_len {
ic_msg!(
@ -857,7 +846,7 @@ declare_syscall!(
result_addr: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let cost = invoke_context.get_compute_budget().secp256k1_recover_cost;
consume_compute_meter(invoke_context, cost)?;
@ -949,7 +938,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
use solana_zk_token_sdk::curve25519::{curve_syscall_traits::*, edwards, ristretto};
match curve_id {
CURVE25519_EDWARDS => {
@ -1006,7 +995,7 @@ declare_syscall!(
right_input_addr: u64,
result_point_addr: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
use solana_zk_token_sdk::curve25519::{
curve_syscall_traits::*, edwards, ristretto, scalar,
};
@ -1207,7 +1196,7 @@ declare_syscall!(
points_len: u64,
result_point_addr: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
use solana_zk_token_sdk::curve25519::{
curve_syscall_traits::*, edwards, ristretto, scalar,
};
@ -1310,7 +1299,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let compute_budget = invoke_context.get_compute_budget();
if compute_budget.sha256_max_slices < vals_len {
ic_msg!(
@ -1373,7 +1362,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let budget = invoke_context.get_compute_budget();
let cost = len
@ -1402,12 +1391,9 @@ declare_syscall!(
.get_current_instruction_context()
.and_then(|instruction_context| {
instruction_context.get_last_program_key(transaction_context)
})
.map_err(SyscallError::InstructionError)?;
})?;
transaction_context
.set_return_data(program_id, return_data)
.map_err(SyscallError::InstructionError)?;
transaction_context.set_return_data(program_id, return_data)?;
Ok(0)
}
@ -1424,7 +1410,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let budget = invoke_context.get_compute_budget();
consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
@ -1491,7 +1477,7 @@ declare_syscall!(
data_addr: u64,
accounts_addr: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let budget = invoke_context.get_compute_budget();
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() {
let instruction_context = invoke_context
.transaction_context
.get_instruction_context_at_index_in_trace(index_in_trace)
.map_err(SyscallError::InstructionError)?;
.get_instruction_context_at_index_in_trace(index_in_trace)?;
if (stop_sibling_instruction_search_at_parent
|| instruction_context.get_stack_height() == TRANSACTION_LEVEL_STACK_HEIGHT)
&& instruction_context.get_stack_height() < stack_height
@ -1599,8 +1584,7 @@ declare_syscall!(
}
*program_id = *instruction_context
.get_last_program_key(invoke_context.transaction_context)
.map_err(SyscallError::InstructionError)?;
.get_last_program_key(invoke_context.transaction_context)?;
data.clone_from_slice(instruction_context.get_instruction_data());
let account_metas = (0..instruction_context.get_number_of_instruction_accounts())
.map(|instruction_account_index| {
@ -1619,8 +1603,7 @@ declare_syscall!(
.is_instruction_account_writable(instruction_account_index)?,
})
})
.collect::<Result<Vec<_>, InstructionError>>()
.map_err(SyscallError::InstructionError)?;
.collect::<Result<Vec<_>, InstructionError>>()?;
accounts.clone_from_slice(account_metas.as_slice());
}
result_header.data_len = instruction_context.get_instruction_data().len() as u64;
@ -1643,7 +1626,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
_memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let budget = invoke_context.get_compute_budget();
consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
@ -1663,7 +1646,7 @@ declare_syscall!(
result_addr: u64,
_arg5: u64,
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};
let budget = invoke_context.get_compute_budget();
let (cost, output): (u64, usize) = match group_op {
@ -1748,7 +1731,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
let params = &translate_slice::<BigModExpParams>(
memory_mapping,
params,
@ -1825,6 +1808,7 @@ mod tests {
solana_rbpf::{
aligned_memory::AlignedMemory,
ebpf::{self, HOST_ALIGN},
error::EbpfError,
memory_region::MemoryRegion,
vm::{BuiltInFunction, Config},
},
@ -1843,11 +1827,10 @@ mod tests {
macro_rules! assert_access_violation {
($result:expr, $va:expr, $len:expr) => {
match $result {
ProgramResult::Err(EbpfError::AccessViolation(_, _, va, len, _))
if $va == va && $len == len => {}
ProgramResult::Err(EbpfError::StackAccessViolation(_, _, va, len, _))
if $va == va && $len == len => {}
match $result.unwrap_err().downcast_ref::<EbpfError>().unwrap() {
EbpfError::AccessViolation(_, _, va, len, _) if $va == *va && $len == *len => {}
EbpfError::StackAccessViolation(_, _, va, len, _) if $va == *va && $len == *len => {
}
_ => panic!(),
}
};
@ -2066,7 +2049,7 @@ mod tests {
}
#[test]
#[should_panic(expected = "UserError(SyscallError(Abort))")]
#[should_panic(expected = "Abort")]
fn test_syscall_abort() {
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
let config = Config::default();
@ -2086,7 +2069,7 @@ mod tests {
}
#[test]
#[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")]
#[should_panic(expected = "Panic(\"Gaggablaghblagh!\", 42, 84)")]
fn test_syscall_sol_panic() {
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
@ -2112,9 +2095,7 @@ mod tests {
);
assert!(matches!(
result,
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
),
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
));
invoke_context.mock_set_remaining(string.len() as u64);
@ -2195,9 +2176,7 @@ mod tests {
);
assert!(matches!(
result,
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
),
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
));
assert_eq!(
@ -2281,9 +2260,7 @@ mod tests {
);
assert!(matches!(
result,
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
),
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
));
invoke_context.mock_set_remaining(cost);
@ -2617,7 +2594,7 @@ mod tests {
&mut result,
);
assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64);
let mut result = ProgramResult::Ok(0);
SyscallSha256::call(
&mut invoke_context,
ro_va,
@ -2630,9 +2607,7 @@ mod tests {
);
assert!(matches!(
result,
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
),
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
));
}
@ -2710,9 +2685,7 @@ mod tests {
);
assert!(matches!(
result,
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
),
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
));
}
@ -2790,9 +2763,7 @@ mod tests {
);
assert!(matches!(
result,
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
),
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
));
}
@ -2962,9 +2933,7 @@ mod tests {
);
assert!(matches!(
result,
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
),
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
));
}
@ -3136,9 +3105,7 @@ mod tests {
);
assert!(matches!(
result,
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
),
ProgramResult::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
));
}
@ -3479,7 +3446,7 @@ mod tests {
program_id: &Pubkey,
overlap_outputs: bool,
syscall: BuiltInFunction<InvokeContext<'b>>,
) -> Result<(Pubkey, u8), EbpfError> {
) -> Result<(Pubkey, u8), Error> {
const SEEDS_VA: u64 = 0x100000000;
const PROGRAM_ID_VA: u64 = 0x200000000;
const ADDRESS_VA: u64 = 0x300000000;
@ -3526,14 +3493,14 @@ mod tests {
&mut memory_mapping,
&mut result,
);
Result::<u64, EbpfError>::from(result).map(|_| (address, bump_seed))
Result::<u64, Error>::from(result).map(|_| (address, bump_seed))
}
fn create_program_address(
invoke_context: &mut InvokeContext,
seeds: &[&[u8]],
address: &Pubkey,
) -> Result<Pubkey, EbpfError> {
) -> Result<Pubkey, Error> {
let (address, _) = call_program_address_common(
invoke_context,
seeds,
@ -3548,7 +3515,7 @@ mod tests {
invoke_context: &mut InvokeContext,
seeds: &[&[u8]],
address: &Pubkey,
) -> Result<(Pubkey, u8), EbpfError> {
) -> Result<(Pubkey, u8), Error> {
call_program_address_common(
invoke_context,
seeds,
@ -3621,9 +3588,7 @@ mod tests {
);
assert!(matches!(
result,
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::CopyOverlapping
),
ProgramResult::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping,
));
}
@ -3775,9 +3740,7 @@ mod tests {
);
assert!(matches!(
result,
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::CopyOverlapping
),
ProgramResult::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping,
));
}
@ -3791,9 +3754,7 @@ mod tests {
let exceeded_seed = &[127; MAX_SEED_LEN + 1];
assert!(matches!(
create_program_address(&mut invoke_context, &[exceeded_seed], &address),
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
),
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded),
));
assert!(matches!(
create_program_address(
@ -3801,9 +3762,7 @@ mod tests {
&[b"short_seed", exceeded_seed],
&address,
),
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
),
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded),
));
let max_seed = &[0; MAX_SEED_LEN];
assert!(create_program_address(&mut invoke_context, &[max_seed], &address).is_ok());
@ -3847,9 +3806,7 @@ mod tests {
];
assert!(matches!(
create_program_address(&mut invoke_context, max_seeds, &address),
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
),
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded),
));
assert_eq!(
create_program_address(&mut invoke_context, &[b"", &[1]], &address).unwrap(),
@ -3886,9 +3843,7 @@ mod tests {
invoke_context.mock_set_remaining(0);
assert!(matches!(
create_program_address(&mut invoke_context, &[b"", &[1]], &address),
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
),
Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
));
}
@ -3927,18 +3882,14 @@ mod tests {
invoke_context.mock_set_remaining(cost * (max_tries - bump_seed as u64 - 1));
assert!(matches!(
try_find_program_address(&mut invoke_context, seeds, &address),
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
),
Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded,
));
let exceeded_seed = &[127; MAX_SEED_LEN + 1];
invoke_context.mock_set_remaining(cost * (max_tries - 1));
assert!(matches!(
try_find_program_address(&mut invoke_context, &[exceeded_seed], &address),
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
),
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded),
));
let exceeded_seeds: &[&[u8]] = &[
&[1],
@ -3962,9 +3913,7 @@ mod tests {
invoke_context.mock_set_remaining(cost * (max_tries - 1));
assert!(matches!(
try_find_program_address(&mut invoke_context, exceeded_seeds, &address),
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
),
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded),
));
assert!(matches!(
@ -3975,9 +3924,7 @@ mod tests {
true,
SyscallTryFindProgramAddress::call,
),
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
SyscallError::CopyOverlapping
),
Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping,
));
}

View File

@ -6,7 +6,7 @@ fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId + Clone>(
check_aligned: bool,
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
consume_compute_meter(
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 sysvar: Arc<T> = sysvar.map_err(SyscallError::InstructionError)?;
let sysvar: Arc<T> = sysvar?;
*var = T::clone(sysvar.as_ref());
Ok(SUCCESS)
@ -33,7 +33,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
get_sysvar(
invoke_context.get_sysvar_cache().get_clock(),
var_addr,
@ -55,7 +55,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
get_sysvar(
invoke_context.get_sysvar_cache().get_epoch_schedule(),
var_addr,
@ -77,7 +77,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
#[allow(deprecated)]
{
get_sysvar(
@ -102,7 +102,7 @@ declare_syscall!(
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError> {
) -> Result<u64, Error> {
get_sysvar(
invoke_context.get_sysvar_cache().get_rent(),
var_addr,

View File

@ -1,9 +1,8 @@
use {
solana_program_runtime::invoke_context::InvokeContext,
solana_sdk::{feature_set, instruction::InstructionError},
};
use {solana_program_runtime::invoke_context::InvokeContext, solana_sdk::feature_set};
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,
if invoke_context
.feature_set

View File

@ -3,7 +3,7 @@
use {
crate::ConfigKeys,
bincode::deserialize,
solana_program_runtime::{ic_msg, invoke_context::InvokeContext},
solana_program_runtime::{declare_process_instruction, ic_msg, invoke_context::InvokeContext},
solana_sdk::{
feature_set, instruction::InstructionError, program_utils::limited_deserialize,
pubkey::Pubkey, transaction_context::IndexOfAccount,
@ -11,19 +11,14 @@ use {
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 instruction_context = transaction_context.get_current_instruction_context()?;
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 config_account_key = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(0)?,

View File

@ -141,7 +141,7 @@ fn calculate_heap_cost(heap_size: u64, heap_cost: u64) -> u64 {
pub fn create_vm<'a, 'b>(
invoke_context: &'a mut 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 compute_budget = invoke_context.get_compute_budget();
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),
];
let log_collector = invoke_context.get_log_collector();
MemoryMapping::new(regions, config)
.and_then(|memory_mapping| EbpfVm::new(program, invoke_context, memory_mapping, stack_len))
.map_err(|err| {
ic_logger_msg!(log_collector, "Failed to create SBF VM: {}", err);
InstructionError::ProgramEnvironmentSetupFailure
})
let memory_mapping = MemoryMapping::new(regions, config).map_err(|err| {
ic_logger_msg!(log_collector, "Failed to create SBF VM: {}", err);
Box::new(InstructionError::ProgramEnvironmentSetupFailure)
})?;
Ok(EbpfVm::new(
program,
invoke_context,
memory_mapping,
stack_len,
))
}
fn execute(
invoke_context: &mut InvokeContext,
program: &VerifiedExecutable<RequisiteVerifier, InvokeContext<'static>>,
) -> Result<(), InstructionError> {
) -> Result<(), Box<dyn std::error::Error>> {
let log_collector = invoke_context.get_log_collector();
let stack_height = invoke_context.get_stack_height();
let transaction_context = &invoke_context.transaction_context;
@ -211,10 +215,10 @@ fn execute(
match result {
ProgramResult::Ok(status) if status != SUCCESS => {
let error = status.into();
Err(error)
let error: InstructionError = status.into();
Err(Box::new(error) as Box<dyn std::error::Error>)
}
ProgramResult::Err(_) => Err(InstructionError::ProgramFailedToComplete),
ProgramResult::Err(error) => Err(error),
_ => Ok(()),
}
}
@ -531,7 +535,9 @@ pub fn process_instruction_transfer_authority(
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 log_collector = invoke_context.get_log_collector();
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)
}
}
.map_err(|err| Box::new(err) as Box<dyn std::error::Error>)
} else {
let program = instruction_context.try_borrow_last_program_account(transaction_context)?;
if !loader_v3::check_id(program.get_owner()) {
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() {
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())?;
if !state.is_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 (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 {
LoadedProgramType::FailedVerification
| LoadedProgramType::Closed
| LoadedProgramType::DelayVisibility => Err(InstructionError::InvalidAccountData),
| LoadedProgramType::DelayVisibility => {
Err(Box::new(InstructionError::InvalidAccountData))
}
LoadedProgramType::Typed(executable) => execute(invoke_context, executable),
_ => Err(InstructionError::IncorrectProgramId),
_ => Err(Box::new(InstructionError::IncorrectProgramId)),
}
}
}

View File

@ -6497,9 +6497,9 @@ dependencies = [
[[package]]
name = "solana_rbpf"
version = "0.2.40"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a5735b8c9defc3723162321a61ef738d34168401eeef213f62a32809739b0f5"
checksum = "edb31627f86190e2d97f86988f1de1a757b530caa50694244d9d28812611b063"
dependencies = [
"byteorder 1.4.3",
"combine",

View File

@ -24,7 +24,7 @@ num-traits = "0.2"
rand = "0.7"
serde = "1.0.112"
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-address-lookup-table-program = { path = "../../programs/address-lookup-table", version = "=1.16.0" }
solana-bpf-loader-program = { path = "../bpf_loader", version = "=1.16.0" }

View File

@ -918,6 +918,7 @@ fn test_program_sbf_invoke_sanity() {
assert_eq!(result, Err(expected_error));
assert_eq!(invoked_programs, expected_invoked_programs);
if let Some(expected_log_messages) = expected_log_messages {
assert_eq!(log_messages.len(), expected_log_messages.len());
expected_log_messages
.into_iter()
.zip(log_messages)
@ -985,8 +986,7 @@ fn test_program_sbf_invoke_sanity() {
format!("Program log: invoke {program_lang} program"),
"Program log: Test max instruction data len exceeded".into(),
"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: Program failed to complete"),
format!("Program {invoke_program_id} failed: Invoked an instruction with data that is too large (10241 > 10240)"),
]),
);
@ -999,8 +999,7 @@ fn test_program_sbf_invoke_sanity() {
format!("Program log: invoke {program_lang} program"),
"Program log: Test max instruction accounts exceeded".into(),
"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: Program failed to complete"),
format!("Program {invoke_program_id} failed: Invoked an instruction with too many accounts (256 > 255)"),
]),
);
@ -1013,8 +1012,7 @@ fn test_program_sbf_invoke_sanity() {
format!("Program log: invoke {program_lang} program"),
"Program log: Test max account infos exceeded".into(),
"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: Program failed to complete"),
format!("Program {invoke_program_id} failed: Invoked an instruction with too many account info's (129 > 128)"),
]),
);

View File

@ -8,7 +8,8 @@ use {
},
log::*,
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::{
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 instruction_context = transaction_context.get_current_instruction_context()?;
let data = instruction_context.get_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 me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
if *me.get_owner() != id() {

View File

@ -5,7 +5,8 @@ use {
log::*,
solana_program::vote::{instruction::VoteInstruction, program::id, state::VoteAuthorize},
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::{
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 instruction_context = transaction_context.get_current_instruction_context()?;
let data = instruction_context.get_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)?;
if *me.get_owner() != id() {
return Err(InstructionError::InvalidAccountOwner);

View File

@ -2,7 +2,7 @@
use {
bytemuck::Pod,
solana_program_runtime::{ic_msg, invoke_context::InvokeContext},
solana_program_runtime::{declare_process_instruction, ic_msg, invoke_context::InvokeContext},
solana_sdk::{
feature_set,
instruction::{InstructionError, TRANSACTION_LEVEL_STACK_HEIGHT},
@ -114,7 +114,10 @@ fn process_close_proof_context(invoke_context: &mut InvokeContext) -> Result<(),
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 {
// Not supported as an inner instruction
return Err(InstructionError::UnsupportedProgramId);
@ -137,21 +140,27 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
}
ProofInstruction::VerifyCloseAccount => {
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");
process_verify_proof::<CloseAccountData, CloseAccountProofContext>(invoke_context)
}
ProofInstruction::VerifyWithdraw => {
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");
process_verify_proof::<WithdrawData, WithdrawProofContext>(invoke_context)
}
ProofInstruction::VerifyWithdrawWithheldTokens => {
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");
process_verify_proof::<WithdrawWithheldTokensData, WithdrawWithheldTokensProofContext>(
@ -160,21 +169,27 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
}
ProofInstruction::VerifyTransfer => {
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");
process_verify_proof::<TransferData, TransferProofContext>(invoke_context)
}
ProofInstruction::VerifyTransferWithFee => {
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");
process_verify_proof::<TransferWithFeeData, TransferWithFeeProofContext>(invoke_context)
}
ProofInstruction::VerifyPubkeyValidity => {
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");
process_verify_proof::<PubkeyValidityData, PubkeyValidityProofContext>(invoke_context)

View File

@ -15,7 +15,6 @@ use {
client::{AsyncClient, SyncClient},
clock::MAX_RECENT_BLOCKHASHES,
genesis_config::create_genesis_config,
instruction::InstructionError,
message::Message,
pubkey::Pubkey,
signature::{Keypair, Signer},
@ -35,8 +34,9 @@ const NOOP_PROGRAM_ID: [u8; 32] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
];
#[allow(clippy::unnecessary_wraps)]
fn process_instruction(_invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
fn process_instruction(
_invoke_context: &mut InvokeContext,
) -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

View File

@ -1342,7 +1342,7 @@ fn test_rent_complex() {
fn mock_process_instruction(
invoke_context: &mut InvokeContext,
) -> result::Result<(), InstructionError> {
) -> result::Result<(), Box<dyn std::error::Error>> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
@ -1359,7 +1359,7 @@ fn test_rent_complex() {
}
}
} else {
Err(InstructionError::InvalidInstructionData)
Err(Box::new(InstructionError::InvalidInstructionData))
}
}
@ -5072,14 +5072,14 @@ fn test_add_builtin() {
}
fn mock_vote_processor(
invoke_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let program_id = instruction_context.get_last_program_key(transaction_context)?;
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());
@ -5130,10 +5130,10 @@ fn test_add_duplicate_static_program() {
fn mock_vote_processor(
invoke_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
// mock builtin must consume units
invoke_context.consume_checked(1)?;
Err(InstructionError::Custom(42))
Err(Box::new(InstructionError::Custom(42)))
}
let mock_account = Keypair::new();
@ -5180,10 +5180,10 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() {
fn mock_ix_processor(
invoke_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
// mock builtin must consume units
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
@ -6472,7 +6472,7 @@ fn test_transaction_with_duplicate_accounts_in_instruction() {
fn mock_process_instruction(
invoke_context: &mut InvokeContext,
) -> result::Result<(), InstructionError> {
) -> result::Result<(), Box<dyn std::error::Error>> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
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)]
fn mock_process_instruction(
invoke_context: &mut InvokeContext,
) -> result::Result<(), InstructionError> {
) -> result::Result<(), Box<dyn std::error::Error>> {
// mock builtin must consume units
invoke_context.consume_checked(1)?;
Ok(())
@ -6753,7 +6753,7 @@ fn test_program_id_as_payer() {
#[allow(clippy::unnecessary_wraps)]
fn mock_ok_vote_processor(
invoke_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
// mock builtin must consume units
invoke_context.consume_checked(1)?;
Ok(())
@ -7001,7 +7001,7 @@ fn test_bank_hash_consistency() {
fn test_same_program_id_uses_unqiue_executable_accounts() {
fn nested_processor(
invoke_context: &mut InvokeContext,
) -> result::Result<(), InstructionError> {
) -> result::Result<(), Box<dyn std::error::Error>> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let _ = instruction_context
@ -7223,7 +7223,7 @@ fn test_add_builtin_no_overwrite() {
#[allow(clippy::unnecessary_wraps)]
fn mock_ix_processor(
_invoke_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
Ok(())
}
@ -7254,7 +7254,7 @@ fn test_add_builtin_loader_no_overwrite() {
#[allow(clippy::unnecessary_wraps)]
fn mock_ix_processor(
_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
Ok(())
}
@ -10002,7 +10002,7 @@ fn test_tx_return_data() {
let mock_program_id = Pubkey::from([2u8; 32]);
fn mock_process_instruction(
invoke_context: &mut InvokeContext,
) -> result::Result<(), InstructionError> {
) -> result::Result<(), Box<dyn std::error::Error>> {
let mock_program_id = Pubkey::from([2u8; 32]);
let transaction_context = &mut invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
@ -10199,7 +10199,7 @@ fn test_transfer_sysvar() {
fn mock_ix_processor(
invoke_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
// mock builtin should consume units
@ -10412,7 +10412,7 @@ fn test_compute_budget_program_noop() {
fn mock_ix_processor(
invoke_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
let compute_budget = invoke_context.get_compute_budget();
assert_eq!(
*compute_budget,
@ -10459,7 +10459,7 @@ fn test_compute_request_instruction() {
fn mock_ix_processor(
invoke_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
let compute_budget = invoke_context.get_compute_budget();
assert_eq!(
*compute_budget,
@ -10513,7 +10513,7 @@ fn test_failed_compute_request_instruction() {
fn mock_ix_processor(
invoke_context: &mut InvokeContext,
) -> std::result::Result<(), InstructionError> {
) -> std::result::Result<(), Box<dyn std::error::Error>> {
let compute_budget = invoke_context.get_compute_budget();
assert_eq!(
*compute_budget,
@ -11078,7 +11078,7 @@ enum MockTransferInstruction {
fn mock_transfer_process_instruction(
invoke_context: &mut InvokeContext,
) -> result::Result<(), InstructionError> {
) -> result::Result<(), Box<dyn std::error::Error>> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
@ -11097,7 +11097,7 @@ fn mock_transfer_process_instruction(
}
}
} else {
Err(InstructionError::InvalidInstructionData)
Err(Box::new(InstructionError::InvalidInstructionData))
}
}
@ -11890,7 +11890,7 @@ enum MockReallocInstruction {
fn mock_realloc_process_instruction(
invoke_context: &mut InvokeContext,
) -> result::Result<(), InstructionError> {
) -> result::Result<(), Box<dyn std::error::Error>> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
@ -11929,7 +11929,7 @@ fn mock_realloc_process_instruction(
}
}
} else {
Err(InstructionError::InvalidInstructionData)
Err(Box::new(InstructionError::InvalidInstructionData))
}
}

View File

@ -219,7 +219,7 @@ mod tests {
fn mock_system_process_instruction(
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
) -> Result<(), Box<dyn std::error::Error>> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
@ -245,7 +245,7 @@ mod tests {
}
}
} else {
Err(InstructionError::InvalidInstructionData)
Err(Box::new(InstructionError::InvalidInstructionData))
}
}
@ -432,7 +432,7 @@ mod tests {
fn mock_system_process_instruction(
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
) -> Result<(), Box<dyn std::error::Error>> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
@ -448,7 +448,7 @@ mod tests {
let dup_account = instruction_context
.try_borrow_instruction_account(transaction_context, 2)?;
if from_account.get_lamports() != dup_account.get_lamports() {
return Err(InstructionError::InvalidArgument);
return Err(Box::new(InstructionError::InvalidArgument));
}
Ok(())
}
@ -460,7 +460,7 @@ mod tests {
.try_borrow_instruction_account(transaction_context, 2)?
.get_lamports();
if lamports_a != lamports_b {
return Err(InstructionError::InvalidArgument);
return Err(Box::new(InstructionError::InvalidArgument));
}
Ok(())
}
@ -479,7 +479,7 @@ mod tests {
}
}
} else {
Err(InstructionError::InvalidInstructionData)
Err(Box::new(InstructionError::InvalidInstructionData))
}
}
@ -647,10 +647,10 @@ mod tests {
let mock_program_id = Pubkey::new_unique();
fn mock_process_instruction(
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
) -> Result<(), Box<dyn std::error::Error>> {
// mock builtin should consume units
let _ = invoke_context.consume_checked(1);
Err(InstructionError::Custom(0xbabb1e))
Err(Box::new(InstructionError::Custom(0xbabb1e)))
}
let builtin_programs = &[BuiltinProgram {
program_id: mock_program_id,

View File

@ -5,7 +5,8 @@ use {
},
log::*,
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::{
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 instruction_context = transaction_context.get_current_instruction_context()?;
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);
// 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)?;
match instruction {
SystemInstruction::CreateAccount {