diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index bb36bf1925..53d0cf6e54 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -234,7 +234,7 @@ impl ExecuteTimings { } type BankStatusCache = StatusCache>; -#[frozen_abi(digest = "7bCDimGo11ajw6ZHViBBu8KPfoDZBcwSnumWCU8MMuwr")] +#[frozen_abi(digest = "32EjVUc6shHHVPpsnBAVfyBziMgyFzH8qxisLwmwwdS1")] pub type BankSlotDelta = SlotDelta>; type TransactionAccountRefCells = Vec<(Pubkey, Rc>)>; diff --git a/sdk/src/transaction/error.rs b/sdk/src/transaction/error.rs new file mode 100644 index 0000000000..acf064b9f4 --- /dev/null +++ b/sdk/src/transaction/error.rs @@ -0,0 +1,121 @@ +use { + crate::{ + instruction::InstructionError, message::SanitizeMessageError, sanitize::SanitizeError, + }, + serde::Serialize, + thiserror::Error, +}; + +/// Reasons a transaction might be rejected. +#[derive( + Error, Serialize, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample, AbiEnumVisitor, +)] +pub enum TransactionError { + /// An account is already being processed in another transaction in a way + /// that does not support parallelism + #[error("Account in use")] + AccountInUse, + + /// A `Pubkey` appears twice in the transaction's `account_keys`. Instructions can reference + /// `Pubkey`s more than once but the message must contain a list with no duplicate keys + #[error("Account loaded twice")] + AccountLoadedTwice, + + /// Attempt to debit an account but found no record of a prior credit. + #[error("Attempt to debit an account but found no record of a prior credit.")] + AccountNotFound, + + /// Attempt to load a program that does not exist + #[error("Attempt to load a program that does not exist")] + ProgramAccountNotFound, + + /// The from `Pubkey` does not have sufficient balance to pay the fee to schedule the transaction + #[error("Insufficient funds for fee")] + InsufficientFundsForFee, + + /// This account may not be used to pay transaction fees + #[error("This account may not be used to pay transaction fees")] + InvalidAccountForFee, + + /// The bank has seen this transaction before. This can occur under normal operation + /// when a UDP packet is duplicated, as a user error from a client not updating + /// its `recent_blockhash`, or as a double-spend attack. + #[error("This transaction has already been processed")] + AlreadyProcessed, + + /// The bank has not seen the given `recent_blockhash` or the transaction is too old and + /// the `recent_blockhash` has been discarded. + #[error("Blockhash not found")] + BlockhashNotFound, + + /// An error occurred while processing an instruction. The first element of the tuple + /// indicates the instruction index in which the error occurred. + #[error("Error processing Instruction {0}: {1}")] + InstructionError(u8, InstructionError), + + /// Loader call chain is too deep + #[error("Loader call chain is too deep")] + CallChainTooDeep, + + /// Transaction requires a fee but has no signature present + #[error("Transaction requires a fee but has no signature present")] + MissingSignatureForFee, + + /// Transaction contains an invalid account reference + #[error("Transaction contains an invalid account reference")] + InvalidAccountIndex, + + /// Transaction did not pass signature verification + #[error("Transaction did not pass signature verification")] + SignatureFailure, + + /// This program may not be used for executing instructions + #[error("This program may not be used for executing instructions")] + InvalidProgramForExecution, + + /// Transaction failed to sanitize accounts offsets correctly + /// implies that account locks are not taken for this TX, and should + /// not be unlocked. + #[error("Transaction failed to sanitize accounts offsets correctly")] + SanitizeFailure, + + #[error("Transactions are currently disabled due to cluster maintenance")] + ClusterMaintenance, + + /// Transaction processing left an account with an outstanding borrowed reference + #[error("Transaction processing left an account with an outstanding borrowed reference")] + AccountBorrowOutstanding, + + /// Transaction would exceed max Block Cost Limit + #[error("Transaction would exceed max Block Cost Limit")] + WouldExceedMaxBlockCostLimit, + + /// Transaction version is unsupported + #[error("Transaction version is unsupported")] + UnsupportedVersion, + + /// Transaction loads a writable account that cannot be written + #[error("Transaction loads a writable account that cannot be written")] + InvalidWritableAccount, + + /// Transaction would exceed max account limit within the block + #[error("Transaction would exceed max account limit within the block")] + WouldExceedMaxAccountCostLimit, +} + +impl From for TransactionError { + fn from(_: SanitizeError) -> Self { + Self::SanitizeFailure + } +} + +impl From for TransactionError { + fn from(err: SanitizeMessageError) -> Self { + match err { + SanitizeMessageError::IndexOutOfBounds + | SanitizeMessageError::ValueOutOfBounds + | SanitizeMessageError::InvalidValue => Self::SanitizeFailure, + SanitizeMessageError::DuplicateAccountKey => Self::AccountLoadedTwice, + } + } +} diff --git a/sdk/src/transaction/mod.rs b/sdk/src/transaction/mod.rs index 5ed77660ee..300ebb1fc5 100644 --- a/sdk/src/transaction/mod.rs +++ b/sdk/src/transaction/mod.rs @@ -5,8 +5,8 @@ use { crate::{ hash::Hash, - instruction::{CompiledInstruction, Instruction, InstructionError}, - message::{Message, SanitizeMessageError}, + instruction::{CompiledInstruction, Instruction}, + message::Message, nonce::NONCED_TX_MARKER_IX_INDEX, precompiles::verify_if_precompile, program_utils::limited_deserialize, @@ -20,110 +20,13 @@ use { solana_program::{system_instruction::SystemInstruction, system_program}, solana_sdk::feature_set, std::{result, sync::Arc}, - thiserror::Error, }; +mod error; mod sanitized; mod versioned; -pub use {sanitized::*, versioned::*}; - -/// Reasons a transaction might be rejected. -#[derive( - Error, Serialize, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample, AbiEnumVisitor, -)] -pub enum TransactionError { - /// An account is already being processed in another transaction in a way - /// that does not support parallelism - #[error("Account in use")] - AccountInUse, - - /// A `Pubkey` appears twice in the transaction's `account_keys`. Instructions can reference - /// `Pubkey`s more than once but the message must contain a list with no duplicate keys - #[error("Account loaded twice")] - AccountLoadedTwice, - - /// Attempt to debit an account but found no record of a prior credit. - #[error("Attempt to debit an account but found no record of a prior credit.")] - AccountNotFound, - - /// Attempt to load a program that does not exist - #[error("Attempt to load a program that does not exist")] - ProgramAccountNotFound, - - /// The from `Pubkey` does not have sufficient balance to pay the fee to schedule the transaction - #[error("Insufficient funds for fee")] - InsufficientFundsForFee, - - /// This account may not be used to pay transaction fees - #[error("This account may not be used to pay transaction fees")] - InvalidAccountForFee, - - /// The bank has seen this transaction before. This can occur under normal operation - /// when a UDP packet is duplicated, as a user error from a client not updating - /// its `recent_blockhash`, or as a double-spend attack. - #[error("This transaction has already been processed")] - AlreadyProcessed, - - /// The bank has not seen the given `recent_blockhash` or the transaction is too old and - /// the `recent_blockhash` has been discarded. - #[error("Blockhash not found")] - BlockhashNotFound, - - /// An error occurred while processing an instruction. The first element of the tuple - /// indicates the instruction index in which the error occurred. - #[error("Error processing Instruction {0}: {1}")] - InstructionError(u8, InstructionError), - - /// Loader call chain is too deep - #[error("Loader call chain is too deep")] - CallChainTooDeep, - - /// Transaction requires a fee but has no signature present - #[error("Transaction requires a fee but has no signature present")] - MissingSignatureForFee, - - /// Transaction contains an invalid account reference - #[error("Transaction contains an invalid account reference")] - InvalidAccountIndex, - - /// Transaction did not pass signature verification - #[error("Transaction did not pass signature verification")] - SignatureFailure, - - /// This program may not be used for executing instructions - #[error("This program may not be used for executing instructions")] - InvalidProgramForExecution, - - /// Transaction failed to sanitize accounts offsets correctly - /// implies that account locks are not taken for this TX, and should - /// not be unlocked. - #[error("Transaction failed to sanitize accounts offsets correctly")] - SanitizeFailure, - - #[error("Transactions are currently disabled due to cluster maintenance")] - ClusterMaintenance, - - /// Transaction processing left an account with an outstanding borrowed reference - #[error("Transaction processing left an account with an outstanding borrowed reference")] - AccountBorrowOutstanding, - - /// Transaction would exceed max Block Cost Limit - #[error("Transaction would exceed max Block Cost Limit")] - WouldExceedMaxBlockCostLimit, - - /// Transaction version is unsupported - #[error("Transaction version is unsupported")] - UnsupportedVersion, - - /// Transaction loads a writable account that cannot be written - #[error("Transaction loads a writable account that cannot be written")] - InvalidWritableAccount, - - /// Transaction would exceed max account limit within the block - #[error("Transaction would exceed max account limit within the block")] - WouldExceedMaxAccountCostLimit, -} +pub use {error::*, sanitized::*, versioned::*}; #[derive(PartialEq, Clone, Copy, Debug)] pub enum TransactionVerificationMode { @@ -134,23 +37,6 @@ pub enum TransactionVerificationMode { pub type Result = result::Result; -impl From for TransactionError { - fn from(_: SanitizeError) -> Self { - Self::SanitizeFailure - } -} - -impl From for TransactionError { - fn from(err: SanitizeMessageError) -> Self { - match err { - SanitizeMessageError::IndexOutOfBounds - | SanitizeMessageError::ValueOutOfBounds - | SanitizeMessageError::InvalidValue => Self::SanitizeFailure, - SanitizeMessageError::DuplicateAccountKey => Self::AccountLoadedTwice, - } - } -} - /// An atomic transaction #[frozen_abi(digest = "FZtncnS1Xk8ghHfKiXE5oGiUbw2wJhmfXQuNgQR3K6Mc")] #[derive(Debug, PartialEq, Default, Eq, Clone, Serialize, Deserialize, AbiExample)]