Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Add missing ProgramError to InstructionError mappings (backport #16231) #17723

Merged
merged 1 commit into from
Jun 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions programs/bpf_loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ use solana_sdk::{
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
clock::Clock,
entrypoint::SUCCESS,
feature_set::upgradeable_close_instruction,
feature_set::{add_missing_program_error_mappings, upgradeable_close_instruction},
ic_logger_msg, ic_msg,
instruction::InstructionError,
keyed_account::{from_keyed_account, keyed_account_at_index},
loader_instruction::LoaderInstruction,
loader_upgradeable_instruction::UpgradeableLoaderInstruction,
process_instruction::{stable_log, ComputeMeter, Executor, InvokeContext},
program_error::{ACCOUNT_NOT_RENT_EXEMPT, BORSH_IO_ERROR},
program_utils::limited_deserialize,
pubkey::Pubkey,
rent::Rent,
Expand Down Expand Up @@ -751,6 +752,8 @@ impl Executor for BpfExecutor {
) -> Result<(), InstructionError> {
let logger = invoke_context.get_logger();
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()?;

Expand Down Expand Up @@ -804,7 +807,14 @@ impl Executor for BpfExecutor {
match result {
Ok(status) => {
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);
return Err(error);
}
Expand Down
2 changes: 2 additions & 0 deletions sdk/program/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ pub enum InstructionError {
/// Unsupported sysvar
#[error("Unsupported sysvar")]
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)]
Expand Down
81 changes: 45 additions & 36 deletions sdk/program/src/program_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ pub const INVALID_SEEDS: u64 = to_builtin!(14);
pub const BORSH_IO_ERROR: u64 = to_builtin!(15);
pub const ACCOUNT_NOT_RENT_EXEMPT: u64 = to_builtin!(16);
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 {
fn from(error: ProgramError) -> Self {
Expand All @@ -131,7 +136,6 @@ impl From<ProgramError> for u64 {
ProgramError::BorshIoError(_) => BORSH_IO_ERROR,
ProgramError::AccountNotRentExempt => ACCOUNT_NOT_RENT_EXEMPT,
ProgramError::UnsupportedSysvar => UNSUPPORTED_SYSVAR,

ProgramError::Custom(error) => {
if error == 0 {
CUSTOM_ZERO
Expand All @@ -146,22 +150,24 @@ impl From<ProgramError> for u64 {
impl From<u64> for ProgramError {
fn from(error: u64) -> Self {
match error {
INVALID_ARGUMENT => ProgramError::InvalidArgument,
INVALID_INSTRUCTION_DATA => ProgramError::InvalidInstructionData,
INVALID_ACCOUNT_DATA => ProgramError::InvalidAccountData,
ACCOUNT_DATA_TOO_SMALL => ProgramError::AccountDataTooSmall,
INSUFFICIENT_FUNDS => ProgramError::InsufficientFunds,
INCORRECT_PROGRAM_ID => ProgramError::IncorrectProgramId,
MISSING_REQUIRED_SIGNATURES => ProgramError::MissingRequiredSignature,
ACCOUNT_ALREADY_INITIALIZED => ProgramError::AccountAlreadyInitialized,
UNINITIALIZED_ACCOUNT => ProgramError::UninitializedAccount,
NOT_ENOUGH_ACCOUNT_KEYS => ProgramError::NotEnoughAccountKeys,
ACCOUNT_BORROW_FAILED => ProgramError::AccountBorrowFailed,
MAX_SEED_LENGTH_EXCEEDED => ProgramError::MaxSeedLengthExceeded,
INVALID_SEEDS => ProgramError::InvalidSeeds,
UNSUPPORTED_SYSVAR => ProgramError::UnsupportedSysvar,
CUSTOM_ZERO => ProgramError::Custom(0),
_ => ProgramError::Custom(error as u32),
CUSTOM_ZERO => Self::Custom(0),
INVALID_ARGUMENT => Self::InvalidArgument,
INVALID_INSTRUCTION_DATA => Self::InvalidInstructionData,
INVALID_ACCOUNT_DATA => Self::InvalidAccountData,
ACCOUNT_DATA_TOO_SMALL => Self::AccountDataTooSmall,
INSUFFICIENT_FUNDS => Self::InsufficientFunds,
INCORRECT_PROGRAM_ID => Self::IncorrectProgramId,
MISSING_REQUIRED_SIGNATURES => Self::MissingRequiredSignature,
ACCOUNT_ALREADY_INITIALIZED => Self::AccountAlreadyInitialized,
UNINITIALIZED_ACCOUNT => Self::UninitializedAccount,
NOT_ENOUGH_ACCOUNT_KEYS => Self::NotEnoughAccountKeys,
ACCOUNT_BORROW_FAILED => Self::AccountBorrowFailed,
MAX_SEED_LENGTH_EXCEEDED => Self::MaxSeedLengthExceeded,
INVALID_SEEDS => Self::InvalidSeeds,
BORSH_IO_ERROR => Self::BorshIoError("Unkown".to_string()),
ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt,
UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar,
_ => Self::Custom(error as u32),
}
}
}
Expand All @@ -184,6 +190,7 @@ impl TryFrom<InstructionError> for ProgramError {
Self::Error::NotEnoughAccountKeys => Ok(Self::NotEnoughAccountKeys),
Self::Error::AccountBorrowFailed => Ok(Self::AccountBorrowFailed),
Self::Error::MaxSeedLengthExceeded => Ok(Self::MaxSeedLengthExceeded),
Self::Error::InvalidSeeds => Ok(Self::InvalidSeeds),
Self::Error::BorshIoError(err) => Ok(Self::BorshIoError(err)),
Self::Error::AccountNotRentExempt => Ok(Self::AccountNotRentExempt),
Self::Error::UnsupportedSysvar => Ok(Self::UnsupportedSysvar),
Expand All @@ -199,25 +206,27 @@ where
fn from(error: T) -> Self {
let error = error.to_u64().unwrap_or(0xbad_c0de);
match error {
CUSTOM_ZERO => InstructionError::Custom(0),
INVALID_ARGUMENT => InstructionError::InvalidArgument,
INVALID_INSTRUCTION_DATA => InstructionError::InvalidInstructionData,
INVALID_ACCOUNT_DATA => InstructionError::InvalidAccountData,
ACCOUNT_DATA_TOO_SMALL => InstructionError::AccountDataTooSmall,
INSUFFICIENT_FUNDS => InstructionError::InsufficientFunds,
INCORRECT_PROGRAM_ID => InstructionError::IncorrectProgramId,
MISSING_REQUIRED_SIGNATURES => InstructionError::MissingRequiredSignature,
ACCOUNT_ALREADY_INITIALIZED => InstructionError::AccountAlreadyInitialized,
UNINITIALIZED_ACCOUNT => InstructionError::UninitializedAccount,
NOT_ENOUGH_ACCOUNT_KEYS => InstructionError::NotEnoughAccountKeys,
ACCOUNT_BORROW_FAILED => InstructionError::AccountBorrowFailed,
MAX_SEED_LENGTH_EXCEEDED => InstructionError::MaxSeedLengthExceeded,
INVALID_SEEDS => InstructionError::InvalidSeeds,
UNSUPPORTED_SYSVAR => InstructionError::UnsupportedSysvar,
CUSTOM_ZERO => Self::Custom(0),
INVALID_ARGUMENT => Self::InvalidArgument,
INVALID_INSTRUCTION_DATA => Self::InvalidInstructionData,
INVALID_ACCOUNT_DATA => Self::InvalidAccountData,
ACCOUNT_DATA_TOO_SMALL => Self::AccountDataTooSmall,
INSUFFICIENT_FUNDS => Self::InsufficientFunds,
INCORRECT_PROGRAM_ID => Self::IncorrectProgramId,
MISSING_REQUIRED_SIGNATURES => Self::MissingRequiredSignature,
ACCOUNT_ALREADY_INITIALIZED => Self::AccountAlreadyInitialized,
UNINITIALIZED_ACCOUNT => Self::UninitializedAccount,
NOT_ENOUGH_ACCOUNT_KEYS => Self::NotEnoughAccountKeys,
ACCOUNT_BORROW_FAILED => Self::AccountBorrowFailed,
MAX_SEED_LENGTH_EXCEEDED => Self::MaxSeedLengthExceeded,
INVALID_SEEDS => Self::InvalidSeeds,
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
if error >> BUILTIN_BIT_SHIFT == 0 {
InstructionError::Custom(error as u32)
Self::Custom(error as u32)
} else {
Self::InvalidError
}
Expand All @@ -229,14 +238,14 @@ where
impl From<PubkeyError> for ProgramError {
fn from(error: PubkeyError) -> Self {
match error {
PubkeyError::MaxSeedLengthExceeded => ProgramError::MaxSeedLengthExceeded,
PubkeyError::InvalidSeeds => ProgramError::InvalidSeeds,
PubkeyError::MaxSeedLengthExceeded => Self::MaxSeedLengthExceeded,
PubkeyError::InvalidSeeds => Self::InvalidSeeds,
}
}
}

impl From<BorshIoError> for ProgramError {
fn from(error: BorshIoError) -> Self {
ProgramError::BorshIoError(format!("{}", error))
Self::BorshIoError(format!("{}", error))
}
}
5 changes: 5 additions & 0 deletions sdk/src/feature_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ pub mod memory_ops_syscalls {
solana_sdk::declare_id!("ENQi37wsVhTvFz2gUiZAAbqFEWGN2jwFsqdEDTE8A4MU");
}

pub mod add_missing_program_error_mappings {
solana_sdk::declare_id!("3QEUpjhgPEt92nz3Mqf6pABkHPGCQwSvKtyGMq4SuQyL");
}

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