1#![allow(clippy::arithmetic_side_effects)]
4#![cfg_attr(docsrs, feature(doc_auto_cfg))]
5#![no_std]
6#[cfg(feature = "borsh")]
7use borsh::io::Error as BorshIoError;
8use core::{convert::TryFrom, fmt};
9#[cfg(feature = "serde")]
10use serde_derive::{Deserialize, Serialize};
11
12pub type ProgramResult = core::result::Result<(), ProgramError>;
13
14pub const BUILTIN_BIT_SHIFT: usize = 32;
16macro_rules! to_builtin {
17 ($error:expr) => {
18 ($error as u64) << BUILTIN_BIT_SHIFT
19 };
20}
21
22pub const CUSTOM_ZERO: u64 = to_builtin!(1);
23pub const INVALID_ARGUMENT: u64 = to_builtin!(2);
24pub const INVALID_INSTRUCTION_DATA: u64 = to_builtin!(3);
25pub const INVALID_ACCOUNT_DATA: u64 = to_builtin!(4);
26pub const ACCOUNT_DATA_TOO_SMALL: u64 = to_builtin!(5);
27pub const INSUFFICIENT_FUNDS: u64 = to_builtin!(6);
28pub const INCORRECT_PROGRAM_ID: u64 = to_builtin!(7);
29pub const MISSING_REQUIRED_SIGNATURES: u64 = to_builtin!(8);
30pub const ACCOUNT_ALREADY_INITIALIZED: u64 = to_builtin!(9);
31pub const UNINITIALIZED_ACCOUNT: u64 = to_builtin!(10);
32pub const NOT_ENOUGH_ACCOUNT_KEYS: u64 = to_builtin!(11);
33pub const ACCOUNT_BORROW_FAILED: u64 = to_builtin!(12);
34pub const MAX_SEED_LENGTH_EXCEEDED: u64 = to_builtin!(13);
35pub const INVALID_SEEDS: u64 = to_builtin!(14);
36pub const BORSH_IO_ERROR: u64 = to_builtin!(15);
37pub const ACCOUNT_NOT_RENT_EXEMPT: u64 = to_builtin!(16);
38pub const UNSUPPORTED_SYSVAR: u64 = to_builtin!(17);
39pub const ILLEGAL_OWNER: u64 = to_builtin!(18);
40pub const MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED: u64 = to_builtin!(19);
41pub const INVALID_ACCOUNT_DATA_REALLOC: u64 = to_builtin!(20);
42pub const MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED: u64 = to_builtin!(21);
43pub const BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS: u64 = to_builtin!(22);
44pub const INVALID_ACCOUNT_OWNER: u64 = to_builtin!(23);
45pub const ARITHMETIC_OVERFLOW: u64 = to_builtin!(24);
46pub const IMMUTABLE: u64 = to_builtin!(25);
47pub const INCORRECT_AUTHORITY: u64 = to_builtin!(26);
48#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
56#[derive(Clone, Debug, Eq, PartialEq)]
57pub enum ProgramError {
58 Custom(u32),
62 InvalidArgument,
63 InvalidInstructionData,
64 InvalidAccountData,
65 AccountDataTooSmall,
66 InsufficientFunds,
67 IncorrectProgramId,
68 MissingRequiredSignature,
69 AccountAlreadyInitialized,
70 UninitializedAccount,
71 NotEnoughAccountKeys,
72 AccountBorrowFailed,
73 MaxSeedLengthExceeded,
74 InvalidSeeds,
75 BorshIoError,
76 AccountNotRentExempt,
77 UnsupportedSysvar,
78 IllegalOwner,
79 MaxAccountsDataAllocationsExceeded,
80 InvalidRealloc,
81 MaxInstructionTraceLengthExceeded,
82 BuiltinProgramsMustConsumeComputeUnits,
83 InvalidAccountOwner,
84 ArithmeticOverflow,
85 Immutable,
86 IncorrectAuthority,
87}
88
89impl core::error::Error for ProgramError {}
90
91impl fmt::Display for ProgramError {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 match self {
94 ProgramError::Custom(num) => write!(f,"Custom program error: {num:#x}"),
95 ProgramError::InvalidArgument
96 => f.write_str("The arguments provided to a program instruction were invalid"),
97 ProgramError::InvalidInstructionData
98 => f.write_str("An instruction's data contents was invalid"),
99 ProgramError::InvalidAccountData
100 => f.write_str("An account's data contents was invalid"),
101 ProgramError::AccountDataTooSmall
102 => f.write_str("An account's data was too small"),
103 ProgramError::InsufficientFunds
104 => f.write_str("An account's balance was too small to complete the instruction"),
105 ProgramError::IncorrectProgramId
106 => f.write_str("The account did not have the expected program id"),
107 ProgramError::MissingRequiredSignature
108 => f.write_str("A signature was required but not found"),
109 ProgramError::AccountAlreadyInitialized
110 => f.write_str("An initialize instruction was sent to an account that has already been initialized"),
111 ProgramError::UninitializedAccount
112 => f.write_str("An attempt to operate on an account that hasn't been initialized"),
113 ProgramError::NotEnoughAccountKeys
114 => f.write_str("The instruction expected additional account keys"),
115 ProgramError::AccountBorrowFailed
116 => f.write_str("Failed to borrow a reference to account data, already borrowed"),
117 ProgramError::MaxSeedLengthExceeded
118 => f.write_str("Length of the seed is too long for address generation"),
119 ProgramError::InvalidSeeds
120 => f.write_str("Provided seeds do not result in a valid address"),
121 ProgramError::BorshIoError => f.write_str("IO Error"),
122 ProgramError::AccountNotRentExempt
123 => f.write_str("An account does not have enough lamports to be rent-exempt"),
124 ProgramError::UnsupportedSysvar
125 => f.write_str("Unsupported sysvar"),
126 ProgramError::IllegalOwner
127 => f.write_str("Provided owner is not allowed"),
128 ProgramError::MaxAccountsDataAllocationsExceeded
129 => f.write_str("Accounts data allocations exceeded the maximum allowed per transaction"),
130 ProgramError::InvalidRealloc
131 => f.write_str("Account data reallocation was invalid"),
132 ProgramError::MaxInstructionTraceLengthExceeded
133 => f.write_str("Instruction trace length exceeded the maximum allowed per transaction"),
134 ProgramError::BuiltinProgramsMustConsumeComputeUnits
135 => f.write_str("Builtin programs must consume compute units"),
136 ProgramError::InvalidAccountOwner
137 => f.write_str("Invalid account owner"),
138 ProgramError::ArithmeticOverflow
139 => f.write_str("Program arithmetic overflowed"),
140 ProgramError::Immutable
141 => f.write_str("Account is immutable"),
142 ProgramError::IncorrectAuthority
143 => f.write_str("Incorrect authority provided"),
144 }
145 }
146}
147
148pub trait ToStr {
159 fn to_str(&self) -> &'static str;
160}
161
162impl ProgramError {
163 pub fn to_str<E>(&self) -> &'static str
189 where
190 E: 'static + ToStr + TryFrom<u32>,
191 {
192 match self {
193 Self::Custom(error) => {
194 if let Ok(custom_error) = E::try_from(*error) {
195 custom_error.to_str()
196 } else {
197 "Error: Unknown"
198 }
199 }
200 Self::InvalidArgument => "Error: InvalidArgument",
201 Self::InvalidInstructionData => "Error: InvalidInstructionData",
202 Self::InvalidAccountData => "Error: InvalidAccountData",
203 Self::AccountDataTooSmall => "Error: AccountDataTooSmall",
204 Self::InsufficientFunds => "Error: InsufficientFunds",
205 Self::IncorrectProgramId => "Error: IncorrectProgramId",
206 Self::MissingRequiredSignature => "Error: MissingRequiredSignature",
207 Self::AccountAlreadyInitialized => "Error: AccountAlreadyInitialized",
208 Self::UninitializedAccount => "Error: UninitializedAccount",
209 Self::NotEnoughAccountKeys => "Error: NotEnoughAccountKeys",
210 Self::AccountBorrowFailed => "Error: AccountBorrowFailed",
211 Self::MaxSeedLengthExceeded => "Error: MaxSeedLengthExceeded",
212 Self::InvalidSeeds => "Error: InvalidSeeds",
213 Self::BorshIoError => "Error: BorshIoError",
214 Self::AccountNotRentExempt => "Error: AccountNotRentExempt",
215 Self::UnsupportedSysvar => "Error: UnsupportedSysvar",
216 Self::IllegalOwner => "Error: IllegalOwner",
217 Self::MaxAccountsDataAllocationsExceeded => "Error: MaxAccountsDataAllocationsExceeded",
218 Self::InvalidRealloc => "Error: InvalidRealloc",
219 Self::MaxInstructionTraceLengthExceeded => "Error: MaxInstructionTraceLengthExceeded",
220 Self::BuiltinProgramsMustConsumeComputeUnits => {
221 "Error: BuiltinProgramsMustConsumeComputeUnits"
222 }
223 Self::InvalidAccountOwner => "Error: InvalidAccountOwner",
224 Self::ArithmeticOverflow => "Error: ArithmeticOverflow",
225 Self::Immutable => "Error: Immutable",
226 Self::IncorrectAuthority => "Error: IncorrectAuthority",
227 }
228 }
229}
230
231impl From<ProgramError> for u64 {
232 fn from(error: ProgramError) -> Self {
233 match error {
234 ProgramError::InvalidArgument => INVALID_ARGUMENT,
235 ProgramError::InvalidInstructionData => INVALID_INSTRUCTION_DATA,
236 ProgramError::InvalidAccountData => INVALID_ACCOUNT_DATA,
237 ProgramError::AccountDataTooSmall => ACCOUNT_DATA_TOO_SMALL,
238 ProgramError::InsufficientFunds => INSUFFICIENT_FUNDS,
239 ProgramError::IncorrectProgramId => INCORRECT_PROGRAM_ID,
240 ProgramError::MissingRequiredSignature => MISSING_REQUIRED_SIGNATURES,
241 ProgramError::AccountAlreadyInitialized => ACCOUNT_ALREADY_INITIALIZED,
242 ProgramError::UninitializedAccount => UNINITIALIZED_ACCOUNT,
243 ProgramError::NotEnoughAccountKeys => NOT_ENOUGH_ACCOUNT_KEYS,
244 ProgramError::AccountBorrowFailed => ACCOUNT_BORROW_FAILED,
245 ProgramError::MaxSeedLengthExceeded => MAX_SEED_LENGTH_EXCEEDED,
246 ProgramError::InvalidSeeds => INVALID_SEEDS,
247 ProgramError::BorshIoError => BORSH_IO_ERROR,
248 ProgramError::AccountNotRentExempt => ACCOUNT_NOT_RENT_EXEMPT,
249 ProgramError::UnsupportedSysvar => UNSUPPORTED_SYSVAR,
250 ProgramError::IllegalOwner => ILLEGAL_OWNER,
251 ProgramError::MaxAccountsDataAllocationsExceeded => {
252 MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED
253 }
254 ProgramError::InvalidRealloc => INVALID_ACCOUNT_DATA_REALLOC,
255 ProgramError::MaxInstructionTraceLengthExceeded => {
256 MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED
257 }
258 ProgramError::BuiltinProgramsMustConsumeComputeUnits => {
259 BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS
260 }
261 ProgramError::InvalidAccountOwner => INVALID_ACCOUNT_OWNER,
262 ProgramError::ArithmeticOverflow => ARITHMETIC_OVERFLOW,
263 ProgramError::Immutable => IMMUTABLE,
264 ProgramError::IncorrectAuthority => INCORRECT_AUTHORITY,
265 ProgramError::Custom(error) => {
266 if error == 0 {
267 CUSTOM_ZERO
268 } else {
269 error as u64
270 }
271 }
272 }
273 }
274}
275
276impl From<u64> for ProgramError {
277 fn from(error: u64) -> Self {
278 match error {
279 CUSTOM_ZERO => Self::Custom(0),
280 INVALID_ARGUMENT => Self::InvalidArgument,
281 INVALID_INSTRUCTION_DATA => Self::InvalidInstructionData,
282 INVALID_ACCOUNT_DATA => Self::InvalidAccountData,
283 ACCOUNT_DATA_TOO_SMALL => Self::AccountDataTooSmall,
284 INSUFFICIENT_FUNDS => Self::InsufficientFunds,
285 INCORRECT_PROGRAM_ID => Self::IncorrectProgramId,
286 MISSING_REQUIRED_SIGNATURES => Self::MissingRequiredSignature,
287 ACCOUNT_ALREADY_INITIALIZED => Self::AccountAlreadyInitialized,
288 UNINITIALIZED_ACCOUNT => Self::UninitializedAccount,
289 NOT_ENOUGH_ACCOUNT_KEYS => Self::NotEnoughAccountKeys,
290 ACCOUNT_BORROW_FAILED => Self::AccountBorrowFailed,
291 MAX_SEED_LENGTH_EXCEEDED => Self::MaxSeedLengthExceeded,
292 INVALID_SEEDS => Self::InvalidSeeds,
293 BORSH_IO_ERROR => Self::BorshIoError,
294 ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt,
295 UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar,
296 ILLEGAL_OWNER => Self::IllegalOwner,
297 MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED => Self::MaxAccountsDataAllocationsExceeded,
298 INVALID_ACCOUNT_DATA_REALLOC => Self::InvalidRealloc,
299 MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED => Self::MaxInstructionTraceLengthExceeded,
300 BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS => {
301 Self::BuiltinProgramsMustConsumeComputeUnits
302 }
303 INVALID_ACCOUNT_OWNER => Self::InvalidAccountOwner,
304 ARITHMETIC_OVERFLOW => Self::ArithmeticOverflow,
305 IMMUTABLE => Self::Immutable,
306 INCORRECT_AUTHORITY => Self::IncorrectAuthority,
307 _ => Self::Custom(error as u32),
308 }
309 }
310}
311
312#[cfg(feature = "borsh")]
313impl From<BorshIoError> for ProgramError {
314 fn from(_error: BorshIoError) -> Self {
315 Self::BorshIoError
316 }
317}