Facilitate printing program errors from BPF programs (#8109)

This commit is contained in:
Jack May 2020-02-04 09:03:45 -08:00 committed by GitHub
parent 79249360f7
commit 4e595e8e3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 19 deletions

View File

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

View File

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

View File

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