Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
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
2 changes: 1 addition & 1 deletion runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ impl ExecuteTimings {
}

type BankStatusCache = StatusCache<Result<()>>;
#[frozen_abi(digest = "7bCDimGo11ajw6ZHViBBu8KPfoDZBcwSnumWCU8MMuwr")]
#[frozen_abi(digest = "32EjVUc6shHHVPpsnBAVfyBziMgyFzH8qxisLwmwwdS1")]
pub type BankSlotDelta = SlotDelta<Result<()>>;
type TransactionAccountRefCells = Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>;

Expand Down
121 changes: 121 additions & 0 deletions sdk/src/transaction/error.rs
Original file line number Diff line number Diff line change
@@ -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<SanitizeError> for TransactionError {
fn from(_: SanitizeError) -> Self {
Self::SanitizeFailure
}
}

impl From<SanitizeMessageError> for TransactionError {
fn from(err: SanitizeMessageError) -> Self {
match err {
SanitizeMessageError::IndexOutOfBounds
| SanitizeMessageError::ValueOutOfBounds
| SanitizeMessageError::InvalidValue => Self::SanitizeFailure,
SanitizeMessageError::DuplicateAccountKey => Self::AccountLoadedTwice,
}
}
}
122 changes: 4 additions & 118 deletions sdk/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 {
Expand All @@ -134,23 +37,6 @@ pub enum TransactionVerificationMode {

pub type Result<T> = result::Result<T, TransactionError>;

impl From<SanitizeError> for TransactionError {
fn from(_: SanitizeError) -> Self {
Self::SanitizeFailure
}
}

impl From<SanitizeMessageError> 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)]
Expand Down