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