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