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]] [[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",

View File

@ -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" }

View File

@ -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;

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)] #[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(())
} }

View File

@ -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();

View File

@ -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);
} }

View File

@ -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);

View File

@ -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();

View File

@ -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();
} }

View File

@ -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)
)
)); ));
} }

View File

@ -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)?;

View File

@ -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>(

View File

@ -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
),
)); ));
} }

View File

@ -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,

View File

@ -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

View File

@ -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)?,

View File

@ -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)),
} }
} }
} }

View File

@ -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",

View File

@ -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" }

View File

@ -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"),
]), ]),
); );

View File

@ -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() {

View File

@ -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);

View File

@ -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)

View File

@ -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(())
} }

View File

@ -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))
} }
} }

View File

@ -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,

View File

@ -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 {