Add missing ProgramError to InstructionError mappings (#16231)

* Add missing ProgramError to InstructionError mappings

* add note

* Clarify process of adding new program error
This commit is contained in:
Jack May 2021-06-03 14:59:04 -07:00 committed by GitHub
parent 708bbcb001
commit 83b9a046d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 38 deletions

View File

@ -31,13 +31,14 @@ use solana_sdk::{
bpf_loader_upgradeable::{self, UpgradeableLoaderState}, bpf_loader_upgradeable::{self, UpgradeableLoaderState},
clock::Clock, clock::Clock,
entrypoint::SUCCESS, entrypoint::SUCCESS,
feature_set::upgradeable_close_instruction, feature_set::{add_missing_program_error_mappings, upgradeable_close_instruction},
ic_logger_msg, ic_msg, ic_logger_msg, ic_msg,
instruction::InstructionError, instruction::InstructionError,
keyed_account::{from_keyed_account, keyed_account_at_index}, keyed_account::{from_keyed_account, keyed_account_at_index},
loader_instruction::LoaderInstruction, loader_instruction::LoaderInstruction,
loader_upgradeable_instruction::UpgradeableLoaderInstruction, loader_upgradeable_instruction::UpgradeableLoaderInstruction,
process_instruction::{stable_log, ComputeMeter, Executor, InvokeContext}, process_instruction::{stable_log, ComputeMeter, Executor, InvokeContext},
program_error::{ACCOUNT_NOT_RENT_EXEMPT, BORSH_IO_ERROR},
program_utils::limited_deserialize, program_utils::limited_deserialize,
pubkey::Pubkey, pubkey::Pubkey,
rent::Rent, rent::Rent,
@ -750,6 +751,8 @@ impl Executor for BpfExecutor {
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
let logger = invoke_context.get_logger(); let logger = invoke_context.get_logger();
let invoke_depth = invoke_context.invoke_depth(); let invoke_depth = invoke_context.invoke_depth();
let add_missing_program_error_mappings =
invoke_context.is_feature_active(&add_missing_program_error_mappings::id());
invoke_context.remove_first_keyed_account()?; invoke_context.remove_first_keyed_account()?;
@ -803,7 +806,14 @@ impl Executor for BpfExecutor {
match result { match result {
Ok(status) => { Ok(status) => {
if status != SUCCESS { if status != SUCCESS {
let error: InstructionError = status.into(); let error: InstructionError = if !add_missing_program_error_mappings
&& (status == ACCOUNT_NOT_RENT_EXEMPT || status == BORSH_IO_ERROR)
{
// map originally missing error mappings to InvalidError
InstructionError::InvalidError
} else {
status.into()
};
stable_log::program_failure(&logger, program_id, &error); stable_log::program_failure(&logger, program_id, &error);
return Err(error); return Err(error);
} }

View File

@ -215,6 +215,8 @@ pub enum InstructionError {
/// Unsupported sysvar /// Unsupported sysvar
#[error("Unsupported sysvar")] #[error("Unsupported sysvar")]
UnsupportedSysvar, UnsupportedSysvar,
// Note: For any new error added here an equivilent ProgramError and it's
// conversions must also be added
} }
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]

View File

@ -111,6 +111,11 @@ pub const INVALID_SEEDS: u64 = to_builtin!(14);
pub const BORSH_IO_ERROR: u64 = to_builtin!(15); pub const BORSH_IO_ERROR: u64 = to_builtin!(15);
pub const ACCOUNT_NOT_RENT_EXEMPT: u64 = to_builtin!(16); pub const ACCOUNT_NOT_RENT_EXEMPT: u64 = to_builtin!(16);
pub const UNSUPPORTED_SYSVAR: u64 = to_builtin!(17); pub const UNSUPPORTED_SYSVAR: u64 = to_builtin!(17);
// Warning: Any new program errors added here must also be:
// - Added to the below conversions
// - Added as an equivilent to InstructionError
// - Be featureized in the BPF loader to return `InstructionError::InvalidError`
// until the feature is activated
impl From<ProgramError> for u64 { impl From<ProgramError> for u64 {
fn from(error: ProgramError) -> Self { fn from(error: ProgramError) -> Self {
@ -131,7 +136,6 @@ impl From<ProgramError> for u64 {
ProgramError::BorshIoError(_) => BORSH_IO_ERROR, ProgramError::BorshIoError(_) => BORSH_IO_ERROR,
ProgramError::AccountNotRentExempt => ACCOUNT_NOT_RENT_EXEMPT, ProgramError::AccountNotRentExempt => ACCOUNT_NOT_RENT_EXEMPT,
ProgramError::UnsupportedSysvar => UNSUPPORTED_SYSVAR, ProgramError::UnsupportedSysvar => UNSUPPORTED_SYSVAR,
ProgramError::Custom(error) => { ProgramError::Custom(error) => {
if error == 0 { if error == 0 {
CUSTOM_ZERO CUSTOM_ZERO
@ -146,22 +150,24 @@ impl From<ProgramError> for u64 {
impl From<u64> for ProgramError { impl From<u64> for ProgramError {
fn from(error: u64) -> Self { fn from(error: u64) -> Self {
match error { match error {
INVALID_ARGUMENT => ProgramError::InvalidArgument, CUSTOM_ZERO => Self::Custom(0),
INVALID_INSTRUCTION_DATA => ProgramError::InvalidInstructionData, INVALID_ARGUMENT => Self::InvalidArgument,
INVALID_ACCOUNT_DATA => ProgramError::InvalidAccountData, INVALID_INSTRUCTION_DATA => Self::InvalidInstructionData,
ACCOUNT_DATA_TOO_SMALL => ProgramError::AccountDataTooSmall, INVALID_ACCOUNT_DATA => Self::InvalidAccountData,
INSUFFICIENT_FUNDS => ProgramError::InsufficientFunds, ACCOUNT_DATA_TOO_SMALL => Self::AccountDataTooSmall,
INCORRECT_PROGRAM_ID => ProgramError::IncorrectProgramId, INSUFFICIENT_FUNDS => Self::InsufficientFunds,
MISSING_REQUIRED_SIGNATURES => ProgramError::MissingRequiredSignature, INCORRECT_PROGRAM_ID => Self::IncorrectProgramId,
ACCOUNT_ALREADY_INITIALIZED => ProgramError::AccountAlreadyInitialized, MISSING_REQUIRED_SIGNATURES => Self::MissingRequiredSignature,
UNINITIALIZED_ACCOUNT => ProgramError::UninitializedAccount, ACCOUNT_ALREADY_INITIALIZED => Self::AccountAlreadyInitialized,
NOT_ENOUGH_ACCOUNT_KEYS => ProgramError::NotEnoughAccountKeys, UNINITIALIZED_ACCOUNT => Self::UninitializedAccount,
ACCOUNT_BORROW_FAILED => ProgramError::AccountBorrowFailed, NOT_ENOUGH_ACCOUNT_KEYS => Self::NotEnoughAccountKeys,
MAX_SEED_LENGTH_EXCEEDED => ProgramError::MaxSeedLengthExceeded, ACCOUNT_BORROW_FAILED => Self::AccountBorrowFailed,
INVALID_SEEDS => ProgramError::InvalidSeeds, MAX_SEED_LENGTH_EXCEEDED => Self::MaxSeedLengthExceeded,
UNSUPPORTED_SYSVAR => ProgramError::UnsupportedSysvar, INVALID_SEEDS => Self::InvalidSeeds,
CUSTOM_ZERO => ProgramError::Custom(0), BORSH_IO_ERROR => Self::BorshIoError("Unkown".to_string()),
_ => ProgramError::Custom(error as u32), ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt,
UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar,
_ => Self::Custom(error as u32),
} }
} }
} }
@ -184,6 +190,7 @@ impl TryFrom<InstructionError> for ProgramError {
Self::Error::NotEnoughAccountKeys => Ok(Self::NotEnoughAccountKeys), Self::Error::NotEnoughAccountKeys => Ok(Self::NotEnoughAccountKeys),
Self::Error::AccountBorrowFailed => Ok(Self::AccountBorrowFailed), Self::Error::AccountBorrowFailed => Ok(Self::AccountBorrowFailed),
Self::Error::MaxSeedLengthExceeded => Ok(Self::MaxSeedLengthExceeded), Self::Error::MaxSeedLengthExceeded => Ok(Self::MaxSeedLengthExceeded),
Self::Error::InvalidSeeds => Ok(Self::InvalidSeeds),
Self::Error::BorshIoError(err) => Ok(Self::BorshIoError(err)), Self::Error::BorshIoError(err) => Ok(Self::BorshIoError(err)),
Self::Error::AccountNotRentExempt => Ok(Self::AccountNotRentExempt), Self::Error::AccountNotRentExempt => Ok(Self::AccountNotRentExempt),
Self::Error::UnsupportedSysvar => Ok(Self::UnsupportedSysvar), Self::Error::UnsupportedSysvar => Ok(Self::UnsupportedSysvar),
@ -199,25 +206,27 @@ where
fn from(error: T) -> Self { fn from(error: T) -> Self {
let error = error.to_u64().unwrap_or(0xbad_c0de); let error = error.to_u64().unwrap_or(0xbad_c0de);
match error { match error {
CUSTOM_ZERO => InstructionError::Custom(0), CUSTOM_ZERO => Self::Custom(0),
INVALID_ARGUMENT => InstructionError::InvalidArgument, INVALID_ARGUMENT => Self::InvalidArgument,
INVALID_INSTRUCTION_DATA => InstructionError::InvalidInstructionData, INVALID_INSTRUCTION_DATA => Self::InvalidInstructionData,
INVALID_ACCOUNT_DATA => InstructionError::InvalidAccountData, INVALID_ACCOUNT_DATA => Self::InvalidAccountData,
ACCOUNT_DATA_TOO_SMALL => InstructionError::AccountDataTooSmall, ACCOUNT_DATA_TOO_SMALL => Self::AccountDataTooSmall,
INSUFFICIENT_FUNDS => InstructionError::InsufficientFunds, INSUFFICIENT_FUNDS => Self::InsufficientFunds,
INCORRECT_PROGRAM_ID => InstructionError::IncorrectProgramId, INCORRECT_PROGRAM_ID => Self::IncorrectProgramId,
MISSING_REQUIRED_SIGNATURES => InstructionError::MissingRequiredSignature, MISSING_REQUIRED_SIGNATURES => Self::MissingRequiredSignature,
ACCOUNT_ALREADY_INITIALIZED => InstructionError::AccountAlreadyInitialized, ACCOUNT_ALREADY_INITIALIZED => Self::AccountAlreadyInitialized,
UNINITIALIZED_ACCOUNT => InstructionError::UninitializedAccount, UNINITIALIZED_ACCOUNT => Self::UninitializedAccount,
NOT_ENOUGH_ACCOUNT_KEYS => InstructionError::NotEnoughAccountKeys, NOT_ENOUGH_ACCOUNT_KEYS => Self::NotEnoughAccountKeys,
ACCOUNT_BORROW_FAILED => InstructionError::AccountBorrowFailed, ACCOUNT_BORROW_FAILED => Self::AccountBorrowFailed,
MAX_SEED_LENGTH_EXCEEDED => InstructionError::MaxSeedLengthExceeded, MAX_SEED_LENGTH_EXCEEDED => Self::MaxSeedLengthExceeded,
INVALID_SEEDS => InstructionError::InvalidSeeds, INVALID_SEEDS => Self::InvalidSeeds,
UNSUPPORTED_SYSVAR => InstructionError::UnsupportedSysvar, BORSH_IO_ERROR => Self::BorshIoError("Unkown".to_string()),
ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt,
UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar,
_ => { _ => {
// A valid custom error has no bits set in the upper 32 // A valid custom error has no bits set in the upper 32
if error >> BUILTIN_BIT_SHIFT == 0 { if error >> BUILTIN_BIT_SHIFT == 0 {
InstructionError::Custom(error as u32) Self::Custom(error as u32)
} else { } else {
Self::InvalidError Self::InvalidError
} }
@ -229,14 +238,14 @@ where
impl From<PubkeyError> for ProgramError { impl From<PubkeyError> for ProgramError {
fn from(error: PubkeyError) -> Self { fn from(error: PubkeyError) -> Self {
match error { match error {
PubkeyError::MaxSeedLengthExceeded => ProgramError::MaxSeedLengthExceeded, PubkeyError::MaxSeedLengthExceeded => Self::MaxSeedLengthExceeded,
PubkeyError::InvalidSeeds => ProgramError::InvalidSeeds, PubkeyError::InvalidSeeds => Self::InvalidSeeds,
} }
} }
} }
impl From<BorshIoError> for ProgramError { impl From<BorshIoError> for ProgramError {
fn from(error: BorshIoError) -> Self { fn from(error: BorshIoError) -> Self {
ProgramError::BorshIoError(format!("{}", error)) Self::BorshIoError(format!("{}", error))
} }
} }

View File

@ -139,6 +139,10 @@ pub mod memory_ops_syscalls {
solana_sdk::declare_id!("ENQi37wsVhTvFz2gUiZAAbqFEWGN2jwFsqdEDTE8A4MU"); solana_sdk::declare_id!("ENQi37wsVhTvFz2gUiZAAbqFEWGN2jwFsqdEDTE8A4MU");
} }
pub mod add_missing_program_error_mappings {
solana_sdk::declare_id!("3QEUpjhgPEt92nz3Mqf6pABkHPGCQwSvKtyGMq4SuQyL");
}
lazy_static! { lazy_static! {
/// Map of feature identifiers to user-visible description /// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [ pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -174,6 +178,7 @@ lazy_static! {
(keccak256_syscall_enabled::id(), "keccak256 syscall"), (keccak256_syscall_enabled::id(), "keccak256 syscall"),
(stake_program_v4::id(), "solana_stake_program v4"), (stake_program_v4::id(), "solana_stake_program v4"),
(memory_ops_syscalls::id(), "add syscalls for memory operations"), (memory_ops_syscalls::id(), "add syscalls for memory operations"),
(add_missing_program_error_mappings::id(), "add missing program error mappings"),
/*************** ADD NEW FEATURES HERE ***************/ /*************** ADD NEW FEATURES HERE ***************/
] ]
.iter() .iter()