1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
4#[cfg(feature = "num-traits")]
5use num_traits::ToPrimitive;
6#[cfg(feature = "frozen-abi")]
7extern crate std;
8use {core::fmt, solana_program_error::ProgramError};
9pub use {
10 instruction_error_module::*,
11 solana_program_error::{
12 ACCOUNT_ALREADY_INITIALIZED, ACCOUNT_BORROW_FAILED, ACCOUNT_DATA_TOO_SMALL,
13 ACCOUNT_NOT_RENT_EXEMPT, ARITHMETIC_OVERFLOW, BORSH_IO_ERROR,
14 BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS, CUSTOM_ZERO, ILLEGAL_OWNER, IMMUTABLE,
15 INCORRECT_AUTHORITY, INCORRECT_PROGRAM_ID, INSUFFICIENT_FUNDS, INVALID_ACCOUNT_DATA,
16 INVALID_ACCOUNT_DATA_REALLOC, INVALID_ACCOUNT_OWNER, INVALID_ARGUMENT,
17 INVALID_INSTRUCTION_DATA, INVALID_SEEDS, MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED,
18 MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED, MAX_SEED_LENGTH_EXCEEDED,
19 MISSING_REQUIRED_SIGNATURES, NOT_ENOUGH_ACCOUNT_KEYS, UNINITIALIZED_ACCOUNT,
20 UNSUPPORTED_SYSVAR,
21 },
22};
23
24#[allow(deprecated)]
25mod instruction_error_module {
26 #[cfg(feature = "frozen-abi")]
27 use solana_frozen_abi_macro::{AbiEnumVisitor, AbiExample};
28
29 #[cfg_attr(feature = "frozen-abi", derive(AbiExample, AbiEnumVisitor))]
37 #[cfg_attr(
38 feature = "serde",
39 derive(serde_derive::Serialize, serde_derive::Deserialize)
40 )]
41 #[cfg_attr(feature = "wincode", derive(wincode::SchemaWrite, wincode::SchemaRead))]
42 #[derive(Debug, PartialEq, Eq, Clone)]
43 pub enum InstructionError {
44 GenericError,
47
48 InvalidArgument,
50
51 InvalidInstructionData,
53
54 InvalidAccountData,
56
57 AccountDataTooSmall,
59
60 InsufficientFunds,
62
63 IncorrectProgramId,
65
66 MissingRequiredSignature,
68
69 AccountAlreadyInitialized,
71
72 UninitializedAccount,
74
75 UnbalancedInstruction,
77
78 ModifiedProgramId,
80
81 ExternalAccountLamportSpend,
83
84 ExternalAccountDataModified,
86
87 ReadonlyLamportChange,
89
90 ReadonlyDataModified,
92
93 DuplicateAccountIndex,
96
97 ExecutableModified,
99
100 RentEpochModified,
102
103 #[deprecated(since = "2.1.0", note = "Use InstructionError::MissingAccount instead")]
105 NotEnoughAccountKeys,
106
107 AccountDataSizeChanged,
109
110 AccountNotExecutable,
112
113 AccountBorrowFailed,
115
116 AccountBorrowOutstanding,
118
119 DuplicateAccountOutOfSync,
123
124 Custom(u32),
128
129 InvalidError,
132
133 ExecutableDataModified,
135
136 ExecutableLamportChange,
138
139 ExecutableAccountNotRentExempt,
141
142 UnsupportedProgramId,
144
145 CallDepth,
147
148 MissingAccount,
150
151 ReentrancyNotAllowed,
153
154 MaxSeedLengthExceeded,
156
157 InvalidSeeds,
159
160 InvalidRealloc,
162
163 ComputationalBudgetExceeded,
165
166 PrivilegeEscalation,
168
169 ProgramEnvironmentSetupFailure,
171
172 ProgramFailedToComplete,
174
175 ProgramFailedToCompile,
177
178 Immutable,
180
181 IncorrectAuthority,
183
184 BorshIoError,
186
187 AccountNotRentExempt,
189
190 InvalidAccountOwner,
192
193 ArithmeticOverflow,
195
196 UnsupportedSysvar,
198
199 IllegalOwner,
201
202 MaxAccountsDataAllocationsExceeded,
204
205 MaxAccountsExceeded,
207
208 MaxInstructionTraceLengthExceeded,
210
211 BuiltinProgramsMustConsumeComputeUnits,
213 }
216}
217
218impl core::error::Error for InstructionError {}
219
220impl fmt::Display for InstructionError {
221 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
222 match self {
223 InstructionError::GenericError => f.write_str("generic instruction error"),
224 InstructionError::InvalidArgument => f.write_str("invalid program argument"),
225 InstructionError::InvalidInstructionData => f.write_str("invalid instruction data"),
226 InstructionError::InvalidAccountData => {
227 f.write_str("invalid account data for instruction")
228 }
229 InstructionError::AccountDataTooSmall => {
230 f.write_str("account data too small for instruction")
231 }
232 InstructionError::InsufficientFunds => {
233 f.write_str("insufficient funds for instruction")
234 }
235 InstructionError::IncorrectProgramId => {
236 f.write_str("incorrect program id for instruction")
237 }
238 InstructionError::MissingRequiredSignature => {
239 f.write_str("missing required signature for instruction")
240 }
241 InstructionError::AccountAlreadyInitialized => {
242 f.write_str("instruction requires an uninitialized account")
243 }
244 InstructionError::UninitializedAccount => {
245 f.write_str("instruction requires an initialized account")
246 }
247 InstructionError::UnbalancedInstruction => {
248 f.write_str("sum of account balances before and after instruction do not match")
249 }
250 InstructionError::ModifiedProgramId => {
251 f.write_str("instruction illegally modified the program id of an account")
252 }
253 InstructionError::ExternalAccountLamportSpend => {
254 f.write_str("instruction spent from the balance of an account it does not own")
255 }
256 InstructionError::ExternalAccountDataModified => {
257 f.write_str("instruction modified data of an account it does not own")
258 }
259 InstructionError::ReadonlyLamportChange => {
260 f.write_str("instruction changed the balance of a read-only account")
261 }
262 InstructionError::ReadonlyDataModified => {
263 f.write_str("instruction modified data of a read-only account")
264 }
265 InstructionError::DuplicateAccountIndex => {
266 f.write_str("instruction contains duplicate accounts")
267 }
268 InstructionError::ExecutableModified => {
269 f.write_str("instruction changed executable bit of an account")
270 }
271 InstructionError::RentEpochModified => {
272 f.write_str("instruction modified rent epoch of an account")
273 }
274 #[allow(deprecated)]
275 InstructionError::NotEnoughAccountKeys => {
276 f.write_str("insufficient account keys for instruction")
277 }
278 InstructionError::AccountDataSizeChanged => f.write_str(
279 "program other than the account's owner changed the size of the account data",
280 ),
281 InstructionError::AccountNotExecutable => {
282 f.write_str("instruction expected an executable account")
283 }
284 InstructionError::AccountBorrowFailed => f.write_str(
285 "instruction tries to borrow reference for an account which is already borrowed",
286 ),
287 InstructionError::AccountBorrowOutstanding => {
288 f.write_str("instruction left account with an outstanding borrowed reference")
289 }
290 InstructionError::DuplicateAccountOutOfSync => {
291 f.write_str("instruction modifications of multiply-passed account differ")
292 }
293 InstructionError::Custom(num) => {
294 write!(f, "custom program error: {num:#x}")
295 }
296 InstructionError::InvalidError => f.write_str("program returned invalid error code"),
297 InstructionError::ExecutableDataModified => {
298 f.write_str("instruction changed executable accounts data")
299 }
300 InstructionError::ExecutableLamportChange => {
301 f.write_str("instruction changed the balance of an executable account")
302 }
303 InstructionError::ExecutableAccountNotRentExempt => {
304 f.write_str("executable accounts must be rent exempt")
305 }
306 InstructionError::UnsupportedProgramId => f.write_str("Unsupported program id"),
307 InstructionError::CallDepth => {
308 f.write_str("Cross-program invocation call depth too deep")
309 }
310 InstructionError::MissingAccount => {
311 f.write_str("An account required by the instruction is missing")
312 }
313 InstructionError::ReentrancyNotAllowed => {
314 f.write_str("Cross-program invocation reentrancy not allowed for this instruction")
315 }
316 InstructionError::MaxSeedLengthExceeded => {
317 f.write_str("Length of the seed is too long for address generation")
318 }
319 InstructionError::InvalidSeeds => {
320 f.write_str("Provided seeds do not result in a valid address")
321 }
322 InstructionError::InvalidRealloc => f.write_str("Failed to reallocate account data"),
323 InstructionError::ComputationalBudgetExceeded => {
324 f.write_str("Computational budget exceeded")
325 }
326 InstructionError::PrivilegeEscalation => {
327 f.write_str("Cross-program invocation with unauthorized signer or writable account")
328 }
329 InstructionError::ProgramEnvironmentSetupFailure => {
330 f.write_str("Failed to create program execution environment")
331 }
332 InstructionError::ProgramFailedToComplete => f.write_str("Program failed to complete"),
333 InstructionError::ProgramFailedToCompile => f.write_str("Program failed to compile"),
334 InstructionError::Immutable => f.write_str("Account is immutable"),
335 InstructionError::IncorrectAuthority => f.write_str("Incorrect authority provided"),
336 InstructionError::BorshIoError => {
337 f.write_str("Failed to serialize or deserialize account data")
338 }
339 InstructionError::AccountNotRentExempt => {
340 f.write_str("An account does not have enough lamports to be rent-exempt")
341 }
342 InstructionError::InvalidAccountOwner => f.write_str("Invalid account owner"),
343 InstructionError::ArithmeticOverflow => f.write_str("Program arithmetic overflowed"),
344 InstructionError::UnsupportedSysvar => f.write_str("Unsupported sysvar"),
345 InstructionError::IllegalOwner => f.write_str("Provided owner is not allowed"),
346 InstructionError::MaxAccountsDataAllocationsExceeded => f.write_str(
347 "Accounts data allocations exceeded the maximum allowed per transaction",
348 ),
349 InstructionError::MaxAccountsExceeded => f.write_str("Max accounts exceeded"),
350 InstructionError::MaxInstructionTraceLengthExceeded => {
351 f.write_str("Max instruction trace length exceeded")
352 }
353 InstructionError::BuiltinProgramsMustConsumeComputeUnits => {
354 f.write_str("Builtin programs must consume compute units")
355 }
356 }
357 }
358}
359
360#[cfg(feature = "num-traits")]
361impl<T> From<T> for InstructionError
362where
363 T: ToPrimitive,
364{
365 fn from(error: T) -> Self {
366 let error = error.to_u64().unwrap_or(0xbad_c0de);
367 match error {
368 CUSTOM_ZERO => Self::Custom(0),
369 INVALID_ARGUMENT => Self::InvalidArgument,
370 INVALID_INSTRUCTION_DATA => Self::InvalidInstructionData,
371 INVALID_ACCOUNT_DATA => Self::InvalidAccountData,
372 ACCOUNT_DATA_TOO_SMALL => Self::AccountDataTooSmall,
373 INSUFFICIENT_FUNDS => Self::InsufficientFunds,
374 INCORRECT_PROGRAM_ID => Self::IncorrectProgramId,
375 MISSING_REQUIRED_SIGNATURES => Self::MissingRequiredSignature,
376 ACCOUNT_ALREADY_INITIALIZED => Self::AccountAlreadyInitialized,
377 UNINITIALIZED_ACCOUNT => Self::UninitializedAccount,
378 #[allow(deprecated)]
379 NOT_ENOUGH_ACCOUNT_KEYS => Self::NotEnoughAccountKeys,
380 ACCOUNT_BORROW_FAILED => Self::AccountBorrowFailed,
381 MAX_SEED_LENGTH_EXCEEDED => Self::MaxSeedLengthExceeded,
382 INVALID_SEEDS => Self::InvalidSeeds,
383 BORSH_IO_ERROR => Self::BorshIoError,
384 ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt,
385 UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar,
386 ILLEGAL_OWNER => Self::IllegalOwner,
387 MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED => Self::MaxAccountsDataAllocationsExceeded,
388 INVALID_ACCOUNT_DATA_REALLOC => Self::InvalidRealloc,
389 MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED => Self::MaxInstructionTraceLengthExceeded,
390 BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS => {
391 Self::BuiltinProgramsMustConsumeComputeUnits
392 }
393 INVALID_ACCOUNT_OWNER => Self::InvalidAccountOwner,
394 ARITHMETIC_OVERFLOW => Self::ArithmeticOverflow,
395 IMMUTABLE => Self::Immutable,
396 INCORRECT_AUTHORITY => Self::IncorrectAuthority,
397 _ => {
398 if error >> solana_program_error::BUILTIN_BIT_SHIFT == 0 {
400 Self::Custom(error as u32)
401 } else {
402 Self::InvalidError
403 }
404 }
405 }
406 }
407}
408
409#[derive(Debug)]
410pub enum LamportsError {
411 ArithmeticUnderflow,
413 ArithmeticOverflow,
415}
416
417impl core::error::Error for LamportsError {}
418
419impl fmt::Display for LamportsError {
420 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
421 match self {
422 Self::ArithmeticUnderflow => f.write_str("Arithmetic underflowed"),
423 Self::ArithmeticOverflow => f.write_str("Arithmetic overflowed"),
424 }
425 }
426}
427
428impl From<LamportsError> for InstructionError {
429 fn from(error: LamportsError) -> Self {
430 match error {
431 LamportsError::ArithmeticOverflow => InstructionError::ArithmeticOverflow,
432 LamportsError::ArithmeticUnderflow => InstructionError::ArithmeticOverflow,
433 }
434 }
435}
436
437impl TryFrom<InstructionError> for ProgramError {
438 type Error = InstructionError;
439
440 fn try_from(error: InstructionError) -> Result<Self, Self::Error> {
441 match error {
442 Self::Error::Custom(err) => Ok(Self::Custom(err)),
443 Self::Error::InvalidArgument => Ok(Self::InvalidArgument),
444 Self::Error::InvalidInstructionData => Ok(Self::InvalidInstructionData),
445 Self::Error::InvalidAccountData => Ok(Self::InvalidAccountData),
446 Self::Error::AccountDataTooSmall => Ok(Self::AccountDataTooSmall),
447 Self::Error::InsufficientFunds => Ok(Self::InsufficientFunds),
448 Self::Error::IncorrectProgramId => Ok(Self::IncorrectProgramId),
449 Self::Error::MissingRequiredSignature => Ok(Self::MissingRequiredSignature),
450 Self::Error::AccountAlreadyInitialized => Ok(Self::AccountAlreadyInitialized),
451 Self::Error::UninitializedAccount => Ok(Self::UninitializedAccount),
452 #[allow(deprecated)]
453 Self::Error::NotEnoughAccountKeys => Ok(Self::NotEnoughAccountKeys),
454 Self::Error::MissingAccount => Ok(Self::NotEnoughAccountKeys),
455 Self::Error::AccountBorrowFailed => Ok(Self::AccountBorrowFailed),
456 Self::Error::MaxSeedLengthExceeded => Ok(Self::MaxSeedLengthExceeded),
457 Self::Error::InvalidSeeds => Ok(Self::InvalidSeeds),
458 Self::Error::BorshIoError => Ok(Self::BorshIoError),
459 Self::Error::AccountNotRentExempt => Ok(Self::AccountNotRentExempt),
460 Self::Error::UnsupportedSysvar => Ok(Self::UnsupportedSysvar),
461 Self::Error::IllegalOwner => Ok(Self::IllegalOwner),
462 Self::Error::MaxAccountsDataAllocationsExceeded => {
463 Ok(Self::MaxAccountsDataAllocationsExceeded)
464 }
465 Self::Error::InvalidRealloc => Ok(Self::InvalidRealloc),
466 Self::Error::MaxInstructionTraceLengthExceeded => {
467 Ok(Self::MaxInstructionTraceLengthExceeded)
468 }
469 Self::Error::BuiltinProgramsMustConsumeComputeUnits => {
470 Ok(Self::BuiltinProgramsMustConsumeComputeUnits)
471 }
472 Self::Error::InvalidAccountOwner => Ok(Self::InvalidAccountOwner),
473 Self::Error::ArithmeticOverflow => Ok(Self::ArithmeticOverflow),
474 Self::Error::Immutable => Ok(Self::Immutable),
475 Self::Error::IncorrectAuthority => Ok(Self::IncorrectAuthority),
476 _ => Err(error),
477 }
478 }
479}