From 485b3d64a165db982cd2d7bfb3728d59216bedf2 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 16 Dec 2020 03:50:04 +0000 Subject: [PATCH] Add Program loader/environment instruction errors (#14120) (#14143) (cherry picked from commit d513b0c4ca0bd89e3651bda8a42e1509c3ba5b37) Co-authored-by: Jack May --- programs/bpf/tests/programs.rs | 8 +++---- programs/bpf_loader/src/lib.rs | 42 ++++++++++++++-------------------- runtime/src/bank.rs | 2 +- sdk/program/src/instruction.rs | 9 ++++++++ 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index c11f218cb2..934711b789 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -890,7 +890,7 @@ fn test_program_bpf_invoke() { assert_eq!(invoked_programs, vec![]); assert_eq!( result.unwrap_err(), - TransactionError::InstructionError(0, InstructionError::Custom(194969602)) + TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete) ); // Check final state @@ -1033,7 +1033,7 @@ fn test_program_bpf_ro_modify() { let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message); assert_eq!( result.unwrap_err().unwrap(), - TransactionError::InstructionError(0, InstructionError::Custom(0xb9f0002)) + TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete) ); let instruction = Instruction::new(program_pubkey, &[3_u8], account_metas.clone()); @@ -1041,7 +1041,7 @@ fn test_program_bpf_ro_modify() { let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message); assert_eq!( result.unwrap_err().unwrap(), - TransactionError::InstructionError(0, InstructionError::Custom(0xb9f0002)) + TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete) ); let instruction = Instruction::new(program_pubkey, &[4_u8], account_metas.clone()); @@ -1049,7 +1049,7 @@ fn test_program_bpf_ro_modify() { let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message); assert_eq!( result.unwrap_err().unwrap(), - TransactionError::InstructionError(0, InstructionError::Custom(0xb9f0002)) + TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete) ); } diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 5c57244815..6e9c52455d 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -13,7 +13,6 @@ use crate::{ serialization::{deserialize_parameters, serialize_parameters}, syscalls::SyscallError, }; -use num_derive::{FromPrimitive, ToPrimitive}; use solana_rbpf::{ ebpf::MM_HEAP_START, error::{EbpfError, UserDefinedError}, @@ -26,7 +25,6 @@ use solana_sdk::{ bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, clock::Clock, - decode_error::DecodeError, entrypoint::SUCCESS, feature_set::bpf_compute_budget_balancing, instruction::InstructionError, @@ -48,22 +46,6 @@ solana_sdk::declare_builtin!( solana_bpf_loader_program::process_instruction ); -/// Errors returned by the BPFLoader if the VM fails to run the program -#[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)] -pub enum BPFLoaderError { - #[error("failed to create virtual machine")] - VirtualMachineCreationFailed = 0x0b9f_0001, - #[error("virtual machine failed to run the program to completion")] - VirtualMachineFailedToRunProgram = 0x0b9f_0002, - #[error("failed to compile program")] - JustInTimeCompilationFailed = 0x0b9f_0003, -} -impl DecodeError for BPFLoaderError { - fn type_of() -> &'static str { - "BPFLoaderError" - } -} - /// Errors returned by functions the BPF Loader registers with the VM #[derive(Debug, Error, PartialEq)] pub enum BPFError { @@ -107,6 +89,8 @@ pub fn create_and_cache_executor( invoke_context: &mut dyn InvokeContext, use_jit: bool, ) -> Result, InstructionError> { + let logger = invoke_context.get_logger(); + let bpf_compute_budget = invoke_context.get_bpf_compute_budget(); let mut program = Executable::::from_elf( data, @@ -127,11 +111,16 @@ pub fn create_and_cache_executor( !invoke_context.is_feature_active(&bpf_compute_budget_balancing::id()), ) .map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?; - let syscall_registry = syscalls::register_syscalls(invoke_context) - .map_err(|e| map_ebpf_error(invoke_context, e))?; + let syscall_registry = syscalls::register_syscalls(invoke_context).map_err(|e| { + log!(logger, "Failed to register syscalls: {}", e); + InstructionError::ProgramEnvironmentSetupFailure + })?; program.set_syscall_registry(syscall_registry); - if use_jit && program.jit_compile().is_err() { - return Err(BPFLoaderError::JustInTimeCompilationFailed.into()); + if use_jit { + if let Err(err) = program.jit_compile() { + log!(logger, "Failed to compile program {:?}", err); + return Err(InstructionError::ProgramFailedToCompile); + } } let executor = Arc::new(BPFExecutor { program }); invoke_context.add_executor(key, executor.clone()); @@ -682,7 +671,7 @@ impl Executor for BPFExecutor { Ok(info) => info, Err(e) => { log!(logger, "Failed to create BPF VM: {}", e); - return Err(BPFLoaderError::VirtualMachineCreationFailed.into()); + return Err(InstructionError::ProgramEnvironmentSetupFailure); } }; @@ -721,7 +710,10 @@ impl Executor for BPFExecutor { EbpfError::UserError(BPFError::SyscallError( SyscallError::InstructionError(error), )) => error, - _ => BPFLoaderError::VirtualMachineFailedToRunProgram.into(), + err => { + log!(logger, "Program failed to complete: {:?}", err); + InstructionError::ProgramFailedToComplete + } }; stable_log::program_failure(&logger, program.unsigned_key(), &error); @@ -1010,7 +1002,7 @@ mod tests { Arc::new(FeatureSet::default()), ); assert_eq!( - Err(InstructionError::Custom(194969602)), + Err(InstructionError::ProgramFailedToComplete), process_instruction(&bpf_loader::id(), &keyed_accounts, &[], &mut invoke_context) ); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 378e9dfca6..de3ebdafcb 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -114,7 +114,7 @@ pub const SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0; pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5; type BankStatusCache = StatusCache>; -#[frozen_abi(digest = "9b9RfyiGPNGcMyP78YSD799ghJSTsGvqHTsJtQo8uqGX")] +#[frozen_abi(digest = "GSPuprru1pomsgvopKG7XRWiXdqdXJdLPkgJ2arPbkXM")] pub type BankSlotDelta = SlotDelta>; type TransactionAccountRefCells = Vec>>; type TransactionLoaderRefCells = Vec)>>; diff --git a/sdk/program/src/instruction.rs b/sdk/program/src/instruction.rs index 8ccb10b0cf..4eb3974e66 100644 --- a/sdk/program/src/instruction.rs +++ b/sdk/program/src/instruction.rs @@ -171,6 +171,15 @@ pub enum InstructionError { /// Cross-program invocation with unauthorized signer or writable account #[error("Cross-program invocation with unauthorized signer or writable account")] PrivilegeEscalation, + + #[error("Failed to create program execution environment")] + ProgramEnvironmentSetupFailure, + + #[error("Program failed to complete")] + ProgramFailedToComplete, + + #[error("Program failed to compile")] + ProgramFailedToCompile, } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]