clone_solana_system_interface/
error.rs1use {
2 clone_solana_decode_error::DecodeError,
3 clone_solana_msg::msg,
4 clone_solana_program_error::{PrintProgramError, ProgramError},
5 num_traits::{FromPrimitive, ToPrimitive},
6};
7
8#[cfg_attr(test, derive(strum_macros::FromRepr, strum_macros::EnumIter))]
11#[cfg_attr(
12 feature = "serde",
13 derive(serde_derive::Deserialize, serde_derive::Serialize)
14)]
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub enum SystemError {
17 AccountAlreadyInUse,
19 ResultWithNegativeLamports,
21 InvalidProgramId,
23 InvalidAccountDataLength,
25 MaxSeedLengthExceeded,
27 AddressWithSeedMismatch,
29 NonceNoRecentBlockhashes,
31 NonceBlockhashNotExpired,
33 NonceUnexpectedBlockhashValue,
35}
36
37impl FromPrimitive for SystemError {
38 #[inline]
39 fn from_i64(n: i64) -> Option<Self> {
40 if n == Self::AccountAlreadyInUse as i64 {
41 Some(Self::AccountAlreadyInUse)
42 } else if n == Self::ResultWithNegativeLamports as i64 {
43 Some(Self::ResultWithNegativeLamports)
44 } else if n == Self::InvalidProgramId as i64 {
45 Some(Self::InvalidProgramId)
46 } else if n == Self::InvalidAccountDataLength as i64 {
47 Some(Self::InvalidAccountDataLength)
48 } else if n == Self::MaxSeedLengthExceeded as i64 {
49 Some(Self::MaxSeedLengthExceeded)
50 } else if n == Self::AddressWithSeedMismatch as i64 {
51 Some(Self::AddressWithSeedMismatch)
52 } else if n == Self::NonceNoRecentBlockhashes as i64 {
53 Some(Self::NonceNoRecentBlockhashes)
54 } else if n == Self::NonceBlockhashNotExpired as i64 {
55 Some(Self::NonceBlockhashNotExpired)
56 } else if n == Self::NonceUnexpectedBlockhashValue as i64 {
57 Some(Self::NonceUnexpectedBlockhashValue)
58 } else {
59 None
60 }
61 }
62 #[inline]
63 fn from_u64(n: u64) -> Option<Self> {
64 Self::from_i64(n as i64)
65 }
66}
67
68impl ToPrimitive for SystemError {
69 #[inline]
70 fn to_i64(&self) -> Option<i64> {
71 Some(match *self {
72 Self::AccountAlreadyInUse => Self::AccountAlreadyInUse as i64,
73 Self::ResultWithNegativeLamports => Self::ResultWithNegativeLamports as i64,
74 Self::InvalidProgramId => Self::InvalidProgramId as i64,
75 Self::InvalidAccountDataLength => Self::InvalidAccountDataLength as i64,
76 Self::MaxSeedLengthExceeded => Self::MaxSeedLengthExceeded as i64,
77 Self::AddressWithSeedMismatch => Self::AddressWithSeedMismatch as i64,
78 Self::NonceNoRecentBlockhashes => Self::NonceNoRecentBlockhashes as i64,
79 Self::NonceBlockhashNotExpired => Self::NonceBlockhashNotExpired as i64,
80 Self::NonceUnexpectedBlockhashValue => Self::NonceUnexpectedBlockhashValue as i64,
81 })
82 }
83 #[inline]
84 fn to_u64(&self) -> Option<u64> {
85 self.to_i64().map(|x| x as u64)
86 }
87}
88
89impl std::error::Error for SystemError {}
90
91impl core::fmt::Display for SystemError {
92 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
93 match self {
94 SystemError::AccountAlreadyInUse => {
95 f.write_str("an account with the same address already exists")
96 }
97 SystemError::ResultWithNegativeLamports => {
98 f.write_str("account does not have enough SOL to perform the operation")
99 }
100 SystemError::InvalidProgramId => {
101 f.write_str("cannot assign account to this program id")
102 }
103 SystemError::InvalidAccountDataLength => {
104 f.write_str("cannot allocate account data of this length")
105 }
106 SystemError::MaxSeedLengthExceeded => {
107 f.write_str("length of requested seed is too long")
108 }
109 SystemError::AddressWithSeedMismatch => {
110 f.write_str("provided address does not match addressed derived from seed")
111 }
112 SystemError::NonceNoRecentBlockhashes => {
113 f.write_str("advancing stored nonce requires a populated RecentBlockhashes sysvar")
114 }
115 SystemError::NonceBlockhashNotExpired => {
116 f.write_str("stored nonce is still in recent_blockhashes")
117 }
118 SystemError::NonceUnexpectedBlockhashValue => {
119 f.write_str("specified nonce does not match stored nonce")
120 }
121 }
122 }
123}
124
125impl PrintProgramError for SystemError {
126 fn print<E>(&self) {
127 msg!(&self.to_string());
128 }
129}
130
131impl From<SystemError> for ProgramError {
132 fn from(e: SystemError) -> Self {
133 Self::Custom(e as u32)
134 }
135}
136
137impl<T> DecodeError<T> for SystemError {
138 fn type_of() -> &'static str {
139 "SystemError"
140 }
141}
142
143impl From<u64> for SystemError {
144 fn from(error: u64) -> Self {
145 match error {
146 0 => SystemError::AccountAlreadyInUse,
147 1 => SystemError::ResultWithNegativeLamports,
148 2 => SystemError::InvalidProgramId,
149 3 => SystemError::InvalidAccountDataLength,
150 4 => SystemError::MaxSeedLengthExceeded,
151 5 => SystemError::AddressWithSeedMismatch,
152 6 => SystemError::NonceNoRecentBlockhashes,
153 7 => SystemError::NonceBlockhashNotExpired,
154 8 => SystemError::NonceUnexpectedBlockhashValue,
155 _ => panic!("Unsupported SystemError"),
156 }
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use {super::SystemError, num_traits::FromPrimitive, strum::IntoEnumIterator};
163
164 #[test]
165 fn test_system_error_from_primitive_exhaustive() {
166 for variant in SystemError::iter() {
167 let variant_i64 = variant.clone() as i64;
168 assert_eq!(
169 SystemError::from_repr(variant_i64 as usize),
170 SystemError::from_i64(variant_i64)
171 );
172 assert_eq!(SystemError::from(variant_i64 as u64), variant);
173 }
174 }
175}