Skip to main content

quasar_svm/
error.rs

1use core::fmt;
2use solana_instruction_error::InstructionError;
3
4/// Errors returned by program execution in QuasarSVM.
5///
6/// Maps from the runtime's `InstructionError` into a clean enum for
7/// assertions in tests:
8///
9/// ```ignore
10/// let result = svm.process_instruction(&ix, &accounts);
11/// assert_eq!(result.error(), Some(ProgramError::InvalidAccountData));
12/// ```
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum ProgramError {
15    // -- Common program errors (what you actually hit in tests) --
16    /// The arguments provided were invalid.
17    InvalidArgument,
18    /// The instruction data was invalid.
19    InvalidInstructionData,
20    /// The account data was invalid.
21    InvalidAccountData,
22    /// Account data was too small.
23    AccountDataTooSmall,
24    /// Insufficient lamports.
25    InsufficientFunds,
26    /// Wrong program id.
27    IncorrectProgramId,
28    /// A required signature was missing.
29    MissingRequiredSignature,
30    /// Account was already initialized.
31    AccountAlreadyInitialized,
32    /// Account was not initialized.
33    UninitializedAccount,
34    /// An account required by the instruction is missing.
35    MissingAccount,
36    /// Invalid PDA seeds.
37    InvalidSeeds,
38    /// Arithmetic overflow.
39    ArithmeticOverflow,
40    /// Account is not rent-exempt.
41    AccountNotRentExempt,
42    /// Invalid account owner.
43    InvalidAccountOwner,
44    /// Incorrect authority.
45    IncorrectAuthority,
46    /// Account is immutable.
47    Immutable,
48    /// Borsh serialization/deserialization failed.
49    BorshIoError,
50    /// Computational budget exceeded.
51    ComputeBudgetExceeded,
52    /// Program-specific error code.
53    Custom(u32),
54
55    // -- Catch-all for runtime-internal errors --
56    /// An `InstructionError` variant that doesn't map to a common program
57    /// error. The string contains the debug representation.
58    Runtime(String),
59}
60
61impl From<InstructionError> for ProgramError {
62    fn from(err: InstructionError) -> Self {
63        #[allow(deprecated)]
64        match err {
65            InstructionError::InvalidArgument => Self::InvalidArgument,
66            InstructionError::InvalidInstructionData => Self::InvalidInstructionData,
67            InstructionError::InvalidAccountData => Self::InvalidAccountData,
68            InstructionError::AccountDataTooSmall => Self::AccountDataTooSmall,
69            InstructionError::InsufficientFunds => Self::InsufficientFunds,
70            InstructionError::IncorrectProgramId => Self::IncorrectProgramId,
71            InstructionError::MissingRequiredSignature => Self::MissingRequiredSignature,
72            InstructionError::AccountAlreadyInitialized => Self::AccountAlreadyInitialized,
73            InstructionError::UninitializedAccount => Self::UninitializedAccount,
74            InstructionError::MissingAccount | InstructionError::NotEnoughAccountKeys => {
75                Self::MissingAccount
76            }
77            InstructionError::InvalidSeeds => Self::InvalidSeeds,
78            InstructionError::ArithmeticOverflow => Self::ArithmeticOverflow,
79            InstructionError::AccountNotRentExempt => Self::AccountNotRentExempt,
80            InstructionError::InvalidAccountOwner => Self::InvalidAccountOwner,
81            InstructionError::IncorrectAuthority => Self::IncorrectAuthority,
82            InstructionError::Immutable => Self::Immutable,
83            InstructionError::BorshIoError => Self::BorshIoError,
84            InstructionError::ComputationalBudgetExceeded => Self::ComputeBudgetExceeded,
85            InstructionError::Custom(code) => Self::Custom(code),
86            other => Self::Runtime(format!("{other:?}")),
87        }
88    }
89}
90
91impl fmt::Display for ProgramError {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        match self {
94            Self::InvalidArgument => write!(f, "invalid argument"),
95            Self::InvalidInstructionData => write!(f, "invalid instruction data"),
96            Self::InvalidAccountData => write!(f, "invalid account data"),
97            Self::AccountDataTooSmall => write!(f, "account data too small"),
98            Self::InsufficientFunds => write!(f, "insufficient funds"),
99            Self::IncorrectProgramId => write!(f, "incorrect program id"),
100            Self::MissingRequiredSignature => write!(f, "missing required signature"),
101            Self::AccountAlreadyInitialized => write!(f, "account already initialized"),
102            Self::UninitializedAccount => write!(f, "uninitialized account"),
103            Self::MissingAccount => write!(f, "missing account"),
104            Self::InvalidSeeds => write!(f, "invalid seeds"),
105            Self::ArithmeticOverflow => write!(f, "arithmetic overflow"),
106            Self::AccountNotRentExempt => write!(f, "account not rent-exempt"),
107            Self::InvalidAccountOwner => write!(f, "invalid account owner"),
108            Self::IncorrectAuthority => write!(f, "incorrect authority"),
109            Self::Immutable => write!(f, "account is immutable"),
110            Self::BorshIoError => write!(f, "borsh serialization error"),
111            Self::ComputeBudgetExceeded => write!(f, "compute budget exceeded"),
112            Self::Custom(code) => write!(f, "custom program error: {code} ({code:#x})"),
113            Self::Runtime(msg) => write!(f, "runtime error: {msg}"),
114        }
115    }
116}