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::{
28 frozen_abi, AbiEnumVisitor, AbiExample, StableAbi, StableAbiSample,
29 };
30
31 #[cfg_attr(
39 feature = "frozen-abi",
40 derive(AbiExample, AbiEnumVisitor, StableAbi, StableAbiSample),
41 frozen_abi(
42 abi_digest = "FeTxh6dMDyYG1EdnenTpe8vpH37xDRvfksy83XKBN671",
43 abi_serializer = ["bincode", "wincode"],
44 test_roundtrip = "eq_and_wire"
45 )
46 )]
47 #[cfg_attr(
48 feature = "serde",
49 derive(serde_derive::Serialize, serde_derive::Deserialize)
50 )]
51 #[cfg_attr(feature = "wincode", derive(wincode::SchemaWrite, wincode::SchemaRead))]
52 #[cfg_attr(test, derive(strum_macros::EnumIter))]
53 #[derive(Debug, PartialEq, Eq, Clone)]
54 #[non_exhaustive]
55 pub enum InstructionError {
56 GenericError,
59
60 InvalidArgument,
62
63 InvalidInstructionData,
65
66 InvalidAccountData,
68
69 AccountDataTooSmall,
71
72 InsufficientFunds,
74
75 IncorrectProgramId,
77
78 MissingRequiredSignature,
80
81 AccountAlreadyInitialized,
83
84 UninitializedAccount,
86
87 UnbalancedInstruction,
89
90 ModifiedProgramId,
92
93 ExternalAccountLamportSpend,
95
96 ExternalAccountDataModified,
98
99 ReadonlyLamportChange,
101
102 ReadonlyDataModified,
104
105 DuplicateAccountIndex,
108
109 ExecutableModified,
111
112 RentEpochModified,
114
115 #[deprecated(since = "2.1.0", note = "Use InstructionError::MissingAccount instead")]
117 NotEnoughAccountKeys,
118
119 AccountDataSizeChanged,
121
122 AccountNotExecutable,
124
125 AccountBorrowFailed,
127
128 AccountBorrowOutstanding,
130
131 DuplicateAccountOutOfSync,
135
136 Custom(u32),
140
141 InvalidError,
144
145 ExecutableDataModified,
147
148 ExecutableLamportChange,
150
151 ExecutableAccountNotRentExempt,
153
154 UnsupportedProgramId,
156
157 CallDepth,
159
160 MissingAccount,
162
163 ReentrancyNotAllowed,
165
166 MaxSeedLengthExceeded,
168
169 InvalidSeeds,
171
172 InvalidRealloc,
174
175 ComputationalBudgetExceeded,
177
178 PrivilegeEscalation,
180
181 ProgramEnvironmentSetupFailure,
183
184 ProgramFailedToComplete,
186
187 ProgramFailedToCompile,
189
190 Immutable,
192
193 IncorrectAuthority,
195
196 BorshIoError,
198
199 AccountNotRentExempt,
201
202 InvalidAccountOwner,
204
205 ArithmeticOverflow,
207
208 UnsupportedSysvar,
210
211 IllegalOwner,
213
214 MaxAccountsDataAllocationsExceeded,
216
217 MaxAccountsExceeded,
219
220 MaxInstructionTraceLengthExceeded,
222
223 BuiltinProgramsMustConsumeComputeUnits,
225
226 BailOut,
230 }
233}
234
235impl InstructionError {
236 #[allow(deprecated)]
237 pub const VARIANTS: [Self; 55] = [
238 Self::GenericError,
239 Self::InvalidArgument,
240 Self::InvalidInstructionData,
241 Self::InvalidAccountData,
242 Self::AccountDataTooSmall,
243 Self::InsufficientFunds,
244 Self::IncorrectProgramId,
245 Self::MissingRequiredSignature,
246 Self::AccountAlreadyInitialized,
247 Self::UninitializedAccount,
248 Self::UnbalancedInstruction,
249 Self::ModifiedProgramId,
250 Self::ExternalAccountLamportSpend,
251 Self::ExternalAccountDataModified,
252 Self::ReadonlyLamportChange,
253 Self::ReadonlyDataModified,
254 Self::DuplicateAccountIndex,
255 Self::ExecutableModified,
256 Self::RentEpochModified,
257 Self::NotEnoughAccountKeys,
258 Self::AccountDataSizeChanged,
259 Self::AccountNotExecutable,
260 Self::AccountBorrowFailed,
261 Self::AccountBorrowOutstanding,
262 Self::DuplicateAccountOutOfSync,
263 Self::Custom(0),
264 Self::InvalidError,
265 Self::ExecutableDataModified,
266 Self::ExecutableLamportChange,
267 Self::ExecutableAccountNotRentExempt,
268 Self::UnsupportedProgramId,
269 Self::CallDepth,
270 Self::MissingAccount,
271 Self::ReentrancyNotAllowed,
272 Self::MaxSeedLengthExceeded,
273 Self::InvalidSeeds,
274 Self::InvalidRealloc,
275 Self::ComputationalBudgetExceeded,
276 Self::PrivilegeEscalation,
277 Self::ProgramEnvironmentSetupFailure,
278 Self::ProgramFailedToComplete,
279 Self::ProgramFailedToCompile,
280 Self::Immutable,
281 Self::IncorrectAuthority,
282 Self::BorshIoError,
283 Self::AccountNotRentExempt,
284 Self::InvalidAccountOwner,
285 Self::ArithmeticOverflow,
286 Self::UnsupportedSysvar,
287 Self::IllegalOwner,
288 Self::MaxAccountsDataAllocationsExceeded,
289 Self::MaxAccountsExceeded,
290 Self::MaxInstructionTraceLengthExceeded,
291 Self::BuiltinProgramsMustConsumeComputeUnits,
292 Self::BailOut,
293 ];
294}
295
296impl core::default::Default for InstructionError {
297 fn default() -> Self {
298 Self::Custom(0)
299 }
300}
301
302impl core::error::Error for InstructionError {}
303
304impl fmt::Display for InstructionError {
305 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
306 match self {
307 InstructionError::GenericError => f.write_str("generic instruction error"),
308 InstructionError::InvalidArgument => f.write_str("invalid program argument"),
309 InstructionError::InvalidInstructionData => f.write_str("invalid instruction data"),
310 InstructionError::InvalidAccountData => {
311 f.write_str("invalid account data for instruction")
312 }
313 InstructionError::AccountDataTooSmall => {
314 f.write_str("account data too small for instruction")
315 }
316 InstructionError::InsufficientFunds => {
317 f.write_str("insufficient funds for instruction")
318 }
319 InstructionError::IncorrectProgramId => {
320 f.write_str("incorrect program id for instruction")
321 }
322 InstructionError::MissingRequiredSignature => {
323 f.write_str("missing required signature for instruction")
324 }
325 InstructionError::AccountAlreadyInitialized => {
326 f.write_str("instruction requires an uninitialized account")
327 }
328 InstructionError::UninitializedAccount => {
329 f.write_str("instruction requires an initialized account")
330 }
331 InstructionError::UnbalancedInstruction => {
332 f.write_str("sum of account balances before and after instruction do not match")
333 }
334 InstructionError::ModifiedProgramId => {
335 f.write_str("instruction illegally modified the program id of an account")
336 }
337 InstructionError::ExternalAccountLamportSpend => {
338 f.write_str("instruction spent from the balance of an account it does not own")
339 }
340 InstructionError::ExternalAccountDataModified => {
341 f.write_str("instruction modified data of an account it does not own")
342 }
343 InstructionError::ReadonlyLamportChange => {
344 f.write_str("instruction changed the balance of a read-only account")
345 }
346 InstructionError::ReadonlyDataModified => {
347 f.write_str("instruction modified data of a read-only account")
348 }
349 InstructionError::DuplicateAccountIndex => {
350 f.write_str("instruction contains duplicate accounts")
351 }
352 InstructionError::ExecutableModified => {
353 f.write_str("instruction changed executable bit of an account")
354 }
355 InstructionError::RentEpochModified => {
356 f.write_str("instruction modified rent epoch of an account")
357 }
358 #[allow(deprecated)]
359 InstructionError::NotEnoughAccountKeys => {
360 f.write_str("insufficient account keys for instruction")
361 }
362 InstructionError::AccountDataSizeChanged => f.write_str(
363 "program other than the account's owner changed the size of the account data",
364 ),
365 InstructionError::AccountNotExecutable => {
366 f.write_str("instruction expected an executable account")
367 }
368 InstructionError::AccountBorrowFailed => f.write_str(
369 "instruction tries to borrow reference for an account which is already borrowed",
370 ),
371 InstructionError::AccountBorrowOutstanding => {
372 f.write_str("instruction left account with an outstanding borrowed reference")
373 }
374 InstructionError::DuplicateAccountOutOfSync => {
375 f.write_str("instruction modifications of multiply-passed account differ")
376 }
377 InstructionError::Custom(num) => {
378 write!(f, "custom program error: {num:#x}")
379 }
380 InstructionError::InvalidError => f.write_str("program returned invalid error code"),
381 InstructionError::ExecutableDataModified => {
382 f.write_str("instruction changed executable accounts data")
383 }
384 InstructionError::ExecutableLamportChange => {
385 f.write_str("instruction changed the balance of an executable account")
386 }
387 InstructionError::ExecutableAccountNotRentExempt => {
388 f.write_str("executable accounts must be rent exempt")
389 }
390 InstructionError::UnsupportedProgramId => f.write_str("Unsupported program id"),
391 InstructionError::CallDepth => {
392 f.write_str("Cross-program invocation call depth too deep")
393 }
394 InstructionError::MissingAccount => {
395 f.write_str("An account required by the instruction is missing")
396 }
397 InstructionError::ReentrancyNotAllowed => {
398 f.write_str("Cross-program invocation reentrancy not allowed for this instruction")
399 }
400 InstructionError::MaxSeedLengthExceeded => {
401 f.write_str("Length of the seed is too long for address generation")
402 }
403 InstructionError::InvalidSeeds => {
404 f.write_str("Provided seeds do not result in a valid address")
405 }
406 InstructionError::InvalidRealloc => f.write_str("Failed to reallocate account data"),
407 InstructionError::ComputationalBudgetExceeded => {
408 f.write_str("Computational budget exceeded")
409 }
410 InstructionError::PrivilegeEscalation => {
411 f.write_str("Cross-program invocation with unauthorized signer or writable account")
412 }
413 InstructionError::ProgramEnvironmentSetupFailure => {
414 f.write_str("Failed to create program execution environment")
415 }
416 InstructionError::ProgramFailedToComplete => f.write_str("Program failed to complete"),
417 InstructionError::ProgramFailedToCompile => f.write_str("Program failed to compile"),
418 InstructionError::Immutable => f.write_str("Account is immutable"),
419 InstructionError::IncorrectAuthority => f.write_str("Incorrect authority provided"),
420 InstructionError::BorshIoError => {
421 f.write_str("Failed to serialize or deserialize account data")
422 }
423 InstructionError::AccountNotRentExempt => {
424 f.write_str("An account does not have enough lamports to be rent-exempt")
425 }
426 InstructionError::InvalidAccountOwner => f.write_str("Invalid account owner"),
427 InstructionError::ArithmeticOverflow => f.write_str("Program arithmetic overflowed"),
428 InstructionError::UnsupportedSysvar => f.write_str("Unsupported sysvar"),
429 InstructionError::IllegalOwner => f.write_str("Provided owner is not allowed"),
430 InstructionError::MaxAccountsDataAllocationsExceeded => f.write_str(
431 "Accounts data allocations exceeded the maximum allowed per transaction",
432 ),
433 InstructionError::MaxAccountsExceeded => f.write_str("Max accounts exceeded"),
434 InstructionError::MaxInstructionTraceLengthExceeded => {
435 f.write_str("Max instruction trace length exceeded")
436 }
437 InstructionError::BuiltinProgramsMustConsumeComputeUnits => {
438 f.write_str("Builtin programs must consume compute units")
439 }
440 InstructionError::BailOut => f.write_str("Block production bailed out"),
441 }
442 }
443}
444
445#[cfg(feature = "num-traits")]
446impl<T> From<T> for InstructionError
447where
448 T: ToPrimitive,
449{
450 fn from(error: T) -> Self {
451 let error = error.to_u64().unwrap_or(0xbad_c0de);
452 match error {
453 CUSTOM_ZERO => Self::Custom(0),
454 INVALID_ARGUMENT => Self::InvalidArgument,
455 INVALID_INSTRUCTION_DATA => Self::InvalidInstructionData,
456 INVALID_ACCOUNT_DATA => Self::InvalidAccountData,
457 ACCOUNT_DATA_TOO_SMALL => Self::AccountDataTooSmall,
458 INSUFFICIENT_FUNDS => Self::InsufficientFunds,
459 INCORRECT_PROGRAM_ID => Self::IncorrectProgramId,
460 MISSING_REQUIRED_SIGNATURES => Self::MissingRequiredSignature,
461 ACCOUNT_ALREADY_INITIALIZED => Self::AccountAlreadyInitialized,
462 UNINITIALIZED_ACCOUNT => Self::UninitializedAccount,
463 #[allow(deprecated)]
464 NOT_ENOUGH_ACCOUNT_KEYS => Self::NotEnoughAccountKeys,
465 ACCOUNT_BORROW_FAILED => Self::AccountBorrowFailed,
466 MAX_SEED_LENGTH_EXCEEDED => Self::MaxSeedLengthExceeded,
467 INVALID_SEEDS => Self::InvalidSeeds,
468 BORSH_IO_ERROR => Self::BorshIoError,
469 ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt,
470 UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar,
471 ILLEGAL_OWNER => Self::IllegalOwner,
472 MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED => Self::MaxAccountsDataAllocationsExceeded,
473 INVALID_ACCOUNT_DATA_REALLOC => Self::InvalidRealloc,
474 MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED => Self::MaxInstructionTraceLengthExceeded,
475 BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS => {
476 Self::BuiltinProgramsMustConsumeComputeUnits
477 }
478 INVALID_ACCOUNT_OWNER => Self::InvalidAccountOwner,
479 ARITHMETIC_OVERFLOW => Self::ArithmeticOverflow,
480 IMMUTABLE => Self::Immutable,
481 INCORRECT_AUTHORITY => Self::IncorrectAuthority,
482 _ => {
483 if error >> solana_program_error::BUILTIN_BIT_SHIFT == 0 {
485 Self::Custom(error as u32)
486 } else {
487 Self::InvalidError
488 }
489 }
490 }
491 }
492}
493
494#[derive(Debug)]
495#[cfg_attr(test, derive(strum_macros::EnumIter, PartialEq))]
496#[non_exhaustive]
497pub enum LamportsError {
498 ArithmeticUnderflow,
500 ArithmeticOverflow,
502}
503
504impl LamportsError {
505 pub const VARIANTS: [Self; 2] = [Self::ArithmeticUnderflow, Self::ArithmeticOverflow];
506}
507
508impl core::error::Error for LamportsError {}
509
510impl fmt::Display for LamportsError {
511 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
512 match self {
513 Self::ArithmeticUnderflow => f.write_str("Arithmetic underflowed"),
514 Self::ArithmeticOverflow => f.write_str("Arithmetic overflowed"),
515 }
516 }
517}
518
519impl From<LamportsError> for InstructionError {
520 fn from(error: LamportsError) -> Self {
521 match error {
522 LamportsError::ArithmeticOverflow => InstructionError::ArithmeticOverflow,
523 LamportsError::ArithmeticUnderflow => InstructionError::ArithmeticOverflow,
524 }
525 }
526}
527
528impl TryFrom<InstructionError> for ProgramError {
529 type Error = InstructionError;
530
531 fn try_from(error: InstructionError) -> Result<Self, Self::Error> {
532 match error {
533 Self::Error::Custom(err) => Ok(Self::Custom(err)),
534 Self::Error::InvalidArgument => Ok(Self::InvalidArgument),
535 Self::Error::InvalidInstructionData => Ok(Self::InvalidInstructionData),
536 Self::Error::InvalidAccountData => Ok(Self::InvalidAccountData),
537 Self::Error::AccountDataTooSmall => Ok(Self::AccountDataTooSmall),
538 Self::Error::InsufficientFunds => Ok(Self::InsufficientFunds),
539 Self::Error::IncorrectProgramId => Ok(Self::IncorrectProgramId),
540 Self::Error::MissingRequiredSignature => Ok(Self::MissingRequiredSignature),
541 Self::Error::AccountAlreadyInitialized => Ok(Self::AccountAlreadyInitialized),
542 Self::Error::UninitializedAccount => Ok(Self::UninitializedAccount),
543 #[allow(deprecated)]
544 Self::Error::NotEnoughAccountKeys => Ok(Self::NotEnoughAccountKeys),
545 Self::Error::MissingAccount => Ok(Self::NotEnoughAccountKeys),
546 Self::Error::AccountBorrowFailed => Ok(Self::AccountBorrowFailed),
547 Self::Error::MaxSeedLengthExceeded => Ok(Self::MaxSeedLengthExceeded),
548 Self::Error::InvalidSeeds => Ok(Self::InvalidSeeds),
549 Self::Error::BorshIoError => Ok(Self::BorshIoError),
550 Self::Error::AccountNotRentExempt => Ok(Self::AccountNotRentExempt),
551 Self::Error::UnsupportedSysvar => Ok(Self::UnsupportedSysvar),
552 Self::Error::IllegalOwner => Ok(Self::IllegalOwner),
553 Self::Error::MaxAccountsDataAllocationsExceeded => {
554 Ok(Self::MaxAccountsDataAllocationsExceeded)
555 }
556 Self::Error::InvalidRealloc => Ok(Self::InvalidRealloc),
557 Self::Error::MaxInstructionTraceLengthExceeded => {
558 Ok(Self::MaxInstructionTraceLengthExceeded)
559 }
560 Self::Error::BuiltinProgramsMustConsumeComputeUnits => {
561 Ok(Self::BuiltinProgramsMustConsumeComputeUnits)
562 }
563 Self::Error::InvalidAccountOwner => Ok(Self::InvalidAccountOwner),
564 Self::Error::ArithmeticOverflow => Ok(Self::ArithmeticOverflow),
565 Self::Error::Immutable => Ok(Self::Immutable),
566 Self::Error::IncorrectAuthority => Ok(Self::IncorrectAuthority),
567 _ => Err(error),
568 }
569 }
570}
571
572#[cfg(test)]
573mod tests {
574 use {
575 super::{InstructionError, LamportsError},
576 strum::IntoEnumIterator,
577 };
578
579 #[test]
580 fn test_lamports_error_variants_exhaustive() {
581 for variant in LamportsError::iter() {
582 assert!(LamportsError::VARIANTS.contains(&variant));
583 }
584 }
585
586 #[test]
587 fn test_instruction_error_variants_exhaustive() {
588 for variant in InstructionError::iter() {
589 assert!(InstructionError::VARIANTS.contains(&variant));
590 }
591 }
592}