1#![allow(clippy::integer_arithmetic)]
2use crate::{decode_error::DecodeError, instruction::InstructionError, msg, pubkey::PubkeyError};
3use borsh::maybestd::io::Error as BorshIoError;
4use num_traits::{FromPrimitive, ToPrimitive};
5use std::convert::TryFrom;
6use thiserror::Error;
7
8#[derive(Clone, Debug, Deserialize, Eq, Error, PartialEq, Serialize)]
10pub enum ProgramError {
11 #[error("Custom program error: {0:#x}")]
15 Custom(u32),
16 #[error("The arguments provided to a program instruction where invalid")]
17 InvalidArgument,
18 #[error("An instruction's data contents was invalid")]
19 InvalidInstructionData,
20 #[error("An account's data contents was invalid")]
21 InvalidAccountData,
22 #[error("An account's data was too small")]
23 AccountDataTooSmall,
24 #[error("An account's balance was too small to complete the instruction")]
25 InsufficientFunds,
26 #[error("The account did not have the expected program id")]
27 IncorrectProgramId,
28 #[error("A signature was required but not found")]
29 MissingRequiredSignature,
30 #[error("An initialize instruction was sent to an account that has already been initialized")]
31 AccountAlreadyInitialized,
32 #[error("An attempt to operate on an account that hasn't been initialized")]
33 UninitializedAccount,
34 #[error("The instruction expected additional account keys")]
35 NotEnoughAccountKeys,
36 #[error("Failed to borrow a reference to account data, already borrowed")]
37 AccountBorrowFailed,
38 #[error("Length of the seed is too long for address generation")]
39 MaxSeedLengthExceeded,
40 #[error("Provided seeds do not result in a valid address")]
41 InvalidSeeds,
42 #[error("IO Error: {0}")]
43 BorshIoError(String),
44 #[error("An account does not have enough carats to be rent-exempt")]
45 AccountNotRentExempt,
46 #[error("Unsupported sysvar")]
47 UnsupportedSysvar,
48 #[error("Provided owner is not allowed")]
49 IllegalOwner,
50}
51
52pub trait PrintProgramError {
53 fn print<E>(&self)
54 where
55 E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive;
56}
57
58impl PrintProgramError for ProgramError {
59 fn print<E>(&self)
60 where
61 E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive,
62 {
63 match self {
64 Self::Custom(error) => {
65 if let Some(custom_error) = E::decode_custom_error_to_enum(*error) {
66 custom_error.print::<E>();
67 } else {
68 msg!("Error: Unknown");
69 }
70 }
71 Self::InvalidArgument => msg!("Error: InvalidArgument"),
72 Self::InvalidInstructionData => msg!("Error: InvalidInstructionData"),
73 Self::InvalidAccountData => msg!("Error: InvalidAccountData"),
74 Self::AccountDataTooSmall => msg!("Error: AccountDataTooSmall"),
75 Self::InsufficientFunds => msg!("Error: InsufficientFunds"),
76 Self::IncorrectProgramId => msg!("Error: IncorrectProgramId"),
77 Self::MissingRequiredSignature => msg!("Error: MissingRequiredSignature"),
78 Self::AccountAlreadyInitialized => msg!("Error: AccountAlreadyInitialized"),
79 Self::UninitializedAccount => msg!("Error: UninitializedAccount"),
80 Self::NotEnoughAccountKeys => msg!("Error: NotEnoughAccountKeys"),
81 Self::AccountBorrowFailed => msg!("Error: AccountBorrowFailed"),
82 Self::MaxSeedLengthExceeded => msg!("Error: MaxSeedLengthExceeded"),
83 Self::InvalidSeeds => msg!("Error: InvalidSeeds"),
84 Self::BorshIoError(_) => msg!("Error: BorshIoError"),
85 Self::AccountNotRentExempt => msg!("Error: AccountNotRentExempt"),
86 Self::UnsupportedSysvar => msg!("Error: UnsupportedSysvar"),
87 Self::IllegalOwner => msg!("Error: IllegalOwner"),
88 }
89 }
90}
91
92const BUILTIN_BIT_SHIFT: usize = 32;
94macro_rules! to_builtin {
95 ($error:expr) => {
96 ($error as u64) << BUILTIN_BIT_SHIFT
97 };
98}
99
100pub const CUSTOM_ZERO: u64 = to_builtin!(1);
101pub const INVALID_ARGUMENT: u64 = to_builtin!(2);
102pub const INVALID_INSTRUCTION_DATA: u64 = to_builtin!(3);
103pub const INVALID_ACCOUNT_DATA: u64 = to_builtin!(4);
104pub const ACCOUNT_DATA_TOO_SMALL: u64 = to_builtin!(5);
105pub const INSUFFICIENT_FUNDS: u64 = to_builtin!(6);
106pub const INCORRECT_PROGRAM_ID: u64 = to_builtin!(7);
107pub const MISSING_REQUIRED_SIGNATURES: u64 = to_builtin!(8);
108pub const ACCOUNT_ALREADY_INITIALIZED: u64 = to_builtin!(9);
109pub const UNINITIALIZED_ACCOUNT: u64 = to_builtin!(10);
110pub const NOT_ENOUGH_ACCOUNT_KEYS: u64 = to_builtin!(11);
111pub const ACCOUNT_BORROW_FAILED: u64 = to_builtin!(12);
112pub const MAX_SEED_LENGTH_EXCEEDED: u64 = to_builtin!(13);
113pub const INVALID_SEEDS: u64 = to_builtin!(14);
114pub const BORSH_IO_ERROR: u64 = to_builtin!(15);
115pub const ACCOUNT_NOT_RENT_EXEMPT: u64 = to_builtin!(16);
116pub const UNSUPPORTED_SYSVAR: u64 = to_builtin!(17);
117pub const ILLEGAL_OWNER: u64 = to_builtin!(18);
118impl From<ProgramError> for u64 {
125 fn from(error: ProgramError) -> Self {
126 match error {
127 ProgramError::InvalidArgument => INVALID_ARGUMENT,
128 ProgramError::InvalidInstructionData => INVALID_INSTRUCTION_DATA,
129 ProgramError::InvalidAccountData => INVALID_ACCOUNT_DATA,
130 ProgramError::AccountDataTooSmall => ACCOUNT_DATA_TOO_SMALL,
131 ProgramError::InsufficientFunds => INSUFFICIENT_FUNDS,
132 ProgramError::IncorrectProgramId => INCORRECT_PROGRAM_ID,
133 ProgramError::MissingRequiredSignature => MISSING_REQUIRED_SIGNATURES,
134 ProgramError::AccountAlreadyInitialized => ACCOUNT_ALREADY_INITIALIZED,
135 ProgramError::UninitializedAccount => UNINITIALIZED_ACCOUNT,
136 ProgramError::NotEnoughAccountKeys => NOT_ENOUGH_ACCOUNT_KEYS,
137 ProgramError::AccountBorrowFailed => ACCOUNT_BORROW_FAILED,
138 ProgramError::MaxSeedLengthExceeded => MAX_SEED_LENGTH_EXCEEDED,
139 ProgramError::InvalidSeeds => INVALID_SEEDS,
140 ProgramError::BorshIoError(_) => BORSH_IO_ERROR,
141 ProgramError::AccountNotRentExempt => ACCOUNT_NOT_RENT_EXEMPT,
142 ProgramError::UnsupportedSysvar => UNSUPPORTED_SYSVAR,
143 ProgramError::IllegalOwner => ILLEGAL_OWNER,
144 ProgramError::Custom(error) => {
145 if error == 0 {
146 CUSTOM_ZERO
147 } else {
148 error as u64
149 }
150 }
151 }
152 }
153}
154
155impl From<u64> for ProgramError {
156 fn from(error: u64) -> Self {
157 match error {
158 CUSTOM_ZERO => Self::Custom(0),
159 INVALID_ARGUMENT => Self::InvalidArgument,
160 INVALID_INSTRUCTION_DATA => Self::InvalidInstructionData,
161 INVALID_ACCOUNT_DATA => Self::InvalidAccountData,
162 ACCOUNT_DATA_TOO_SMALL => Self::AccountDataTooSmall,
163 INSUFFICIENT_FUNDS => Self::InsufficientFunds,
164 INCORRECT_PROGRAM_ID => Self::IncorrectProgramId,
165 MISSING_REQUIRED_SIGNATURES => Self::MissingRequiredSignature,
166 ACCOUNT_ALREADY_INITIALIZED => Self::AccountAlreadyInitialized,
167 UNINITIALIZED_ACCOUNT => Self::UninitializedAccount,
168 NOT_ENOUGH_ACCOUNT_KEYS => Self::NotEnoughAccountKeys,
169 ACCOUNT_BORROW_FAILED => Self::AccountBorrowFailed,
170 MAX_SEED_LENGTH_EXCEEDED => Self::MaxSeedLengthExceeded,
171 INVALID_SEEDS => Self::InvalidSeeds,
172 BORSH_IO_ERROR => Self::BorshIoError("Unkown".to_string()),
173 ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt,
174 UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar,
175 ILLEGAL_OWNER => Self::IllegalOwner,
176 _ => Self::Custom(error as u32),
177 }
178 }
179}
180
181impl TryFrom<InstructionError> for ProgramError {
182 type Error = InstructionError;
183
184 fn try_from(error: InstructionError) -> Result<Self, Self::Error> {
185 match error {
186 Self::Error::Custom(err) => Ok(Self::Custom(err)),
187 Self::Error::InvalidArgument => Ok(Self::InvalidArgument),
188 Self::Error::InvalidInstructionData => Ok(Self::InvalidInstructionData),
189 Self::Error::InvalidAccountData => Ok(Self::InvalidAccountData),
190 Self::Error::AccountDataTooSmall => Ok(Self::AccountDataTooSmall),
191 Self::Error::InsufficientFunds => Ok(Self::InsufficientFunds),
192 Self::Error::IncorrectProgramId => Ok(Self::IncorrectProgramId),
193 Self::Error::MissingRequiredSignature => Ok(Self::MissingRequiredSignature),
194 Self::Error::AccountAlreadyInitialized => Ok(Self::AccountAlreadyInitialized),
195 Self::Error::UninitializedAccount => Ok(Self::UninitializedAccount),
196 Self::Error::NotEnoughAccountKeys => Ok(Self::NotEnoughAccountKeys),
197 Self::Error::AccountBorrowFailed => Ok(Self::AccountBorrowFailed),
198 Self::Error::MaxSeedLengthExceeded => Ok(Self::MaxSeedLengthExceeded),
199 Self::Error::InvalidSeeds => Ok(Self::InvalidSeeds),
200 Self::Error::BorshIoError(err) => Ok(Self::BorshIoError(err)),
201 Self::Error::AccountNotRentExempt => Ok(Self::AccountNotRentExempt),
202 Self::Error::UnsupportedSysvar => Ok(Self::UnsupportedSysvar),
203 Self::Error::IllegalOwner => Ok(Self::IllegalOwner),
204 _ => Err(error),
205 }
206 }
207}
208
209impl<T> From<T> for InstructionError
210where
211 T: ToPrimitive,
212{
213 fn from(error: T) -> Self {
214 let error = error.to_u64().unwrap_or(0xbad_c0de);
215 match error {
216 CUSTOM_ZERO => Self::Custom(0),
217 INVALID_ARGUMENT => Self::InvalidArgument,
218 INVALID_INSTRUCTION_DATA => Self::InvalidInstructionData,
219 INVALID_ACCOUNT_DATA => Self::InvalidAccountData,
220 ACCOUNT_DATA_TOO_SMALL => Self::AccountDataTooSmall,
221 INSUFFICIENT_FUNDS => Self::InsufficientFunds,
222 INCORRECT_PROGRAM_ID => Self::IncorrectProgramId,
223 MISSING_REQUIRED_SIGNATURES => Self::MissingRequiredSignature,
224 ACCOUNT_ALREADY_INITIALIZED => Self::AccountAlreadyInitialized,
225 UNINITIALIZED_ACCOUNT => Self::UninitializedAccount,
226 NOT_ENOUGH_ACCOUNT_KEYS => Self::NotEnoughAccountKeys,
227 ACCOUNT_BORROW_FAILED => Self::AccountBorrowFailed,
228 MAX_SEED_LENGTH_EXCEEDED => Self::MaxSeedLengthExceeded,
229 INVALID_SEEDS => Self::InvalidSeeds,
230 BORSH_IO_ERROR => Self::BorshIoError("Unkown".to_string()),
231 ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt,
232 UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar,
233 ILLEGAL_OWNER => Self::IllegalOwner,
234 _ => {
235 if error >> BUILTIN_BIT_SHIFT == 0 {
237 Self::Custom(error as u32)
238 } else {
239 Self::InvalidError
240 }
241 }
242 }
243 }
244}
245
246impl From<PubkeyError> for ProgramError {
247 fn from(error: PubkeyError) -> Self {
248 match error {
249 PubkeyError::MaxSeedLengthExceeded => Self::MaxSeedLengthExceeded,
250 PubkeyError::InvalidSeeds => Self::InvalidSeeds,
251 PubkeyError::IllegalOwner => Self::IllegalOwner,
252 }
253 }
254}
255
256impl From<BorshIoError> for ProgramError {
257 fn from(error: BorshIoError) -> Self {
258 Self::BorshIoError(format!("{}", error))
259 }
260}