Facilitate printing program errors from BPF programs (#8109)
This commit is contained in:
parent
79249360f7
commit
4e595e8e3c
|
@ -2155,7 +2155,7 @@ dependencies = [
|
|||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-sdk 0.24.0",
|
||||
"sys-info 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sys-info 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2163,7 +2163,7 @@ name = "solana-rayon-threadlimit"
|
|||
version = "0.24.0"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sys-info 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sys-info 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2194,7 +2194,7 @@ dependencies = [
|
|||
"solana-stake-program 0.24.0",
|
||||
"solana-storage-program 0.24.0",
|
||||
"solana-vote-program 0.24.0",
|
||||
"sys-info 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sys-info 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -2398,7 +2398,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sys-info"
|
||||
version = "0.5.8"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3271,7 +3271,7 @@ dependencies = [
|
|||
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
|
||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
|
||||
"checksum sys-info 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0079fe39cec2c8215e21b0bc4ccec9031004c160b88358f531b601e96b77f0df"
|
||||
"checksum sys-info 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d4eff5474e55653c77b4470bdc2278c7e22f942d59658d0e8767d1c97e02a7b9"
|
||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
|
|
|
@ -2,8 +2,14 @@
|
|||
|
||||
extern crate solana_sdk;
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use solana_sdk::{
|
||||
account_info::AccountInfo, entrypoint, info, program_error::ProgramError, pubkey::Pubkey,
|
||||
account_info::AccountInfo,
|
||||
entrypoint, info,
|
||||
instruction_processor_utils::DecodeError,
|
||||
program_error::{PrintProgramError, ProgramError},
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -20,6 +26,22 @@ impl From<MyError> for ProgramError {
|
|||
ProgramError::CustomError(e as u32)
|
||||
}
|
||||
}
|
||||
impl<T> DecodeError<T> for MyError {
|
||||
fn type_of() -> &'static str {
|
||||
"MyError"
|
||||
}
|
||||
}
|
||||
impl PrintProgramError for MyError {
|
||||
fn print<E>(&self)
|
||||
where
|
||||
E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive,
|
||||
{
|
||||
match self {
|
||||
MyError::DefaultEnumStart => info!("Error: Default enum start"),
|
||||
MyError::TheAnswer => info!("Error: The Answer"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entrypoint!(process_instruction);
|
||||
fn process_instruction(
|
||||
|
@ -27,6 +49,8 @@ fn process_instruction(
|
|||
accounts: &[AccountInfo],
|
||||
instruction_data: &[u8],
|
||||
) -> Result<(), ProgramError> {
|
||||
ProgramError::CustomError(42).print::<MyError>();
|
||||
|
||||
match instruction_data[0] {
|
||||
1 => {
|
||||
info!("return success");
|
||||
|
|
|
@ -1,36 +1,78 @@
|
|||
use crate::instruction::InstructionError;
|
||||
use num_traits::ToPrimitive;
|
||||
use crate::{instruction::InstructionError, instruction_processor_utils::DecodeError};
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use thiserror::Error;
|
||||
|
||||
#[cfg(feature = "program")]
|
||||
use crate::info;
|
||||
#[cfg(not(feature = "program"))]
|
||||
use log::info;
|
||||
|
||||
/// Reasons the program may fail
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Error, PartialEq, Serialize)]
|
||||
pub enum ProgramError {
|
||||
/// Allows on-chain programs to implement program-specific error types and see them returned
|
||||
/// by the Solana runtime. A program-specific error may be any type that is represented as
|
||||
/// or serialized to a u32 integer.
|
||||
#[error("Custom program error: {0}")]
|
||||
CustomError(u32),
|
||||
/// The arguments provided to a program instruction where invalid
|
||||
#[error("The arguments provided to a program instruction where invalid")]
|
||||
InvalidArgument,
|
||||
/// An instruction's data contents was invalid
|
||||
#[error("An instruction's data contents was invalid")]
|
||||
InvalidInstructionData,
|
||||
/// An account's data contents was invalid
|
||||
#[error("An account's data contents was invalid")]
|
||||
InvalidAccountData,
|
||||
/// An account's data was too small
|
||||
#[error("An account's data was too small")]
|
||||
AccountDataTooSmall,
|
||||
/// An account's balance was too small to complete the instruction
|
||||
#[error("An account's balance was too small to complete the instruction")]
|
||||
InsufficientFunds,
|
||||
/// The account did not have the expected program id
|
||||
#[error("The account did not have the expected program id")]
|
||||
IncorrectProgramId,
|
||||
/// A signature was required but not found
|
||||
#[error("A signature was required but not found")]
|
||||
MissingRequiredSignature,
|
||||
/// An initialize instruction was sent to an account that has already been initialized.
|
||||
#[error("An initialize instruction was sent to an account that has already been initialized")]
|
||||
AccountAlreadyInitialized,
|
||||
/// An attempt to operate on an account that hasn't been initialized.
|
||||
#[error("An attempt to operate on an account that hasn't been initialized")]
|
||||
UninitializedAccount,
|
||||
/// The instruction expected additional account keys
|
||||
#[error("The instruction expected additional account keys")]
|
||||
NotEnoughAccountKeys,
|
||||
/// Failed to borrow a reference to account data, already borrowed
|
||||
#[error("Failed to borrow a reference to account data, already borrowed")]
|
||||
AccountBorrowFailed,
|
||||
}
|
||||
|
||||
pub trait PrintProgramError {
|
||||
fn print<E>(&self)
|
||||
where
|
||||
E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive;
|
||||
}
|
||||
|
||||
impl PrintProgramError for ProgramError {
|
||||
fn print<E>(&self)
|
||||
where
|
||||
E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive,
|
||||
{
|
||||
match self {
|
||||
ProgramError::CustomError(error) => {
|
||||
if let Some(custom_error) = E::decode_custom_error_to_enum(*error) {
|
||||
custom_error.print::<E>();
|
||||
} else {
|
||||
info!("Error: Unknown");
|
||||
}
|
||||
}
|
||||
ProgramError::InvalidArgument => info!("Error: InvalidArgument"),
|
||||
ProgramError::InvalidInstructionData => info!("Error: InvalidInstructionData"),
|
||||
ProgramError::InvalidAccountData => info!("Error: InvalidAccountData"),
|
||||
ProgramError::AccountDataTooSmall => info!("Error: AccountDataTooSmall"),
|
||||
ProgramError::InsufficientFunds => info!("Error: InsufficientFunds"),
|
||||
ProgramError::IncorrectProgramId => info!("Error: IncorrectProgramId"),
|
||||
ProgramError::MissingRequiredSignature => info!("Error: MissingRequiredSignature"),
|
||||
ProgramError::AccountAlreadyInitialized => info!("Error: AccountAlreadyInitialized"),
|
||||
ProgramError::UninitializedAccount => info!("Error: UninitializedAccount"),
|
||||
ProgramError::NotEnoughAccountKeys => info!("Error: NotEnoughAccountKeys"),
|
||||
ProgramError::AccountBorrowFailed => info!("Error: AccountBorrowFailed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Builtin return values occupy the upper 32 bits
|
||||
const BUILTIN_BIT_SHIFT: usize = 32;
|
||||
macro_rules! to_builtin {
|
||||
|
|
Loading…
Reference in New Issue