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)",
|
"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)",
|
"reqwest 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"solana-sdk 0.24.0",
|
"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]]
|
[[package]]
|
||||||
|
@ -2163,7 +2163,7 @@ name = "solana-rayon-threadlimit"
|
||||||
version = "0.24.0"
|
version = "0.24.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
|
@ -2194,7 +2194,7 @@ dependencies = [
|
||||||
"solana-stake-program 0.24.0",
|
"solana-stake-program 0.24.0",
|
||||||
"solana-storage-program 0.24.0",
|
"solana-storage-program 0.24.0",
|
||||||
"solana-vote-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)",
|
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2398,7 +2398,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sys-info"
|
name = "sys-info"
|
||||||
version = "0.5.8"
|
version = "0.5.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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 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 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 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 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 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"
|
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
|
|
|
@ -2,8 +2,14 @@
|
||||||
|
|
||||||
extern crate solana_sdk;
|
extern crate solana_sdk;
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
|
|
||||||
use solana_sdk::{
|
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;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -20,6 +26,22 @@ impl From<MyError> for ProgramError {
|
||||||
ProgramError::CustomError(e as u32)
|
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);
|
entrypoint!(process_instruction);
|
||||||
fn process_instruction(
|
fn process_instruction(
|
||||||
|
@ -27,6 +49,8 @@ fn process_instruction(
|
||||||
accounts: &[AccountInfo],
|
accounts: &[AccountInfo],
|
||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
) -> Result<(), ProgramError> {
|
) -> Result<(), ProgramError> {
|
||||||
|
ProgramError::CustomError(42).print::<MyError>();
|
||||||
|
|
||||||
match instruction_data[0] {
|
match instruction_data[0] {
|
||||||
1 => {
|
1 => {
|
||||||
info!("return success");
|
info!("return success");
|
||||||
|
|
|
@ -1,36 +1,78 @@
|
||||||
use crate::instruction::InstructionError;
|
use crate::{instruction::InstructionError, instruction_processor_utils::DecodeError};
|
||||||
use num_traits::ToPrimitive;
|
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
|
/// Reasons the program may fail
|
||||||
|
#[derive(Clone, Debug, Deserialize, Eq, Error, PartialEq, Serialize)]
|
||||||
pub enum ProgramError {
|
pub enum ProgramError {
|
||||||
/// Allows on-chain programs to implement program-specific error types and see them returned
|
/// 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
|
/// by the Solana runtime. A program-specific error may be any type that is represented as
|
||||||
/// or serialized to a u32 integer.
|
/// or serialized to a u32 integer.
|
||||||
|
#[error("Custom program error: {0}")]
|
||||||
CustomError(u32),
|
CustomError(u32),
|
||||||
/// The arguments provided to a program instruction where invalid
|
#[error("The arguments provided to a program instruction where invalid")]
|
||||||
InvalidArgument,
|
InvalidArgument,
|
||||||
/// An instruction's data contents was invalid
|
#[error("An instruction's data contents was invalid")]
|
||||||
InvalidInstructionData,
|
InvalidInstructionData,
|
||||||
/// An account's data contents was invalid
|
#[error("An account's data contents was invalid")]
|
||||||
InvalidAccountData,
|
InvalidAccountData,
|
||||||
/// An account's data was too small
|
#[error("An account's data was too small")]
|
||||||
AccountDataTooSmall,
|
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,
|
InsufficientFunds,
|
||||||
/// The account did not have the expected program id
|
#[error("The account did not have the expected program id")]
|
||||||
IncorrectProgramId,
|
IncorrectProgramId,
|
||||||
/// A signature was required but not found
|
#[error("A signature was required but not found")]
|
||||||
MissingRequiredSignature,
|
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,
|
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,
|
UninitializedAccount,
|
||||||
/// The instruction expected additional account keys
|
#[error("The instruction expected additional account keys")]
|
||||||
NotEnoughAccountKeys,
|
NotEnoughAccountKeys,
|
||||||
/// Failed to borrow a reference to account data, already borrowed
|
#[error("Failed to borrow a reference to account data, already borrowed")]
|
||||||
AccountBorrowFailed,
|
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
|
/// Builtin return values occupy the upper 32 bits
|
||||||
const BUILTIN_BIT_SHIFT: usize = 32;
|
const BUILTIN_BIT_SHIFT: usize = 32;
|
||||||
macro_rules! to_builtin {
|
macro_rules! to_builtin {
|
||||||
|
|
Loading…
Reference in New Issue