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