switchboard_common/
error.rs

1use serde_json::Error as SerdeJsonError;
2use std::error::Error as StdError;
3use std::fmt;
4use std::fmt::Debug;
5use std::sync::Arc;
6
7type ParentError = Arc<dyn StdError + Send + Sync + 'static>;
8
9/// Switchboard Functions error suite
10#[derive(Clone, Debug)]
11pub enum SbError {
12    // Generics
13    Generic,
14    Message(&'static str),
15    CustomMessage(String),
16    CustomError {
17        message: String,
18        source: ParentError,
19    },
20    Unexpected,
21    // Environment Errors
22    EnvVariableMissing(String),
23    InvalidKeypairFile,
24    KeyParseError,
25    CheckSizeError,
26
27    IoError(ParentError),
28
29    // SGX Errors
30    SgxError,
31    SgxWriteError,
32
33    // Network Errors
34    NetworkError,
35
36    // Quote Errors
37    QuoteParseError,
38    InvalidQuoteError,
39
40    // QvnErrors
41    QvnError(Arc<String>),
42
43    // Docker/Container Errors
44    DockerError,
45    DockerFetchError,
46    FunctionImageTooBigError,
47    ContainerErrorMessage(String),
48    ContainerError(ParentError),
49    ContainerStartError(ParentError),
50    ContainerCreateError(ParentError),
51    ContainerNeedsUpdate,
52    // ContainerCreateError,
53    ContainerResultParseError,
54    AttachError,
55    ContainerTimeout,
56    ContainerActive,
57    ContainerBackoff(u64),
58    FunctionErrorCountExceeded(u32),
59
60    // Function Errors
61    FunctionResultParseError,
62    IllegalFunctionOutput,
63    FunctionVerifyFailure,
64    FunctionResultIllegalAccount,
65    FunctionResultAccountsMismatch,
66    FunctionResultInvalidData,
67    FunctionResultInvalidPid,
68    FunctionResultEmptyInstructions,
69
70    // Transaction Errors
71    TxFailure,
72    TxCompileErr,
73    TxDeserializationError,
74    QvnTxSendFailure,
75    InvalidInstructionError,
76
77    // Chain specific Errors
78    InvalidChain,
79    AnchorParse,
80    AnchorParseError,
81    EvmError,
82
83    // Misc
84    IpfsParseError,
85    IpfsNetworkError,
86    HeartbeatRoutineFailure,
87    EventListenerRoutineFailure,
88    DecryptError,
89    ParseError,
90    MrEnclaveMismatch,
91    FunctionResultIxIncorrectTargetChain,
92    InvalidSignature,
93
94    // Solana
95    /// Failed to fetch a network resource
96    SolanaFetchError(String),
97    /// Failed to fetch a blockhash from the cluster
98    SolanaBlockhashError,
99    /// Failed to fetch a blockhash from the cluster
100    SolanaBlockhashFetchError(ParentError),
101    /// THe provided payer does not match the payer of the transaction
102    /// Expected vs actual
103    SolanaPayerMismatch(String, String),
104    SolanaPayerSignerMissing(String),
105    /// A required Solana signer is missing
106    SolanaMissingSigner(String),
107    SolanaSignError(ParentError, String),
108    SolanaInstructionsEmpty,
109    SolanaInstructionOverflow,
110    FunctionResultIxMissingDiscriminator,
111    FunctionResultError(&'static str),
112    FunctionResultIxError(&'static str),
113    // An error which should fail to send the user generated transaction and should emit an error code
114    FunctionResultFailoverError(u8, ParentError),
115    // An error which should not be retried and should be dropped by the QVN.
116    FunctionResultNonRetryableError(ParentError),
117
118    AccountNotFound,
119}
120
121impl fmt::Display for SbError {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        match self {
124            SbError::EnvVariableMissing(message) => {
125                write!(f, "Env variable missing: {}", message.as_str())
126            }
127            SbError::Message(message) => write!(f, "error: {}", message),
128            SbError::CustomMessage(message) => write!(f, "error: {}", message.as_str()),
129            SbError::CustomError {
130                message, source, ..
131            } => write!(f, "error: {} - {:?}", message.as_str(), source),
132            SbError::FunctionResultError(message) => {
133                write!(f, "error: FunctionResultError - {}", message)
134            }
135            SbError::FunctionResultIxError(message) => {
136                write!(f, "error: FunctionResultIxError - {}", message)
137            }
138            SbError::FunctionResultFailoverError(code, source) => {
139                write!(
140                    f,
141                    "error: FunctionResultFailoverError ({}) - {:?}",
142                    code, source
143                )
144            }
145            SbError::FunctionResultNonRetryableError(source) => {
146                write!(f, "error: FunctionResultNonRetryableError - {:?}", source)
147            }
148            SbError::SolanaPayerMismatch(expected, actual) => {
149                write!(
150                    f,
151                    "error: SolanaPayerMismatch - expected: {}, actual: {}",
152                    expected, actual
153                )
154            }
155            SbError::SolanaMissingSigner(missing_signer) => {
156                write!(f, "error: Missing required signer: {}", missing_signer)
157            }
158            SbError::SolanaInstructionsEmpty => write!(
159                f,
160                "error: The attempted action requires at least one instruction but none were provided"
161            ),
162            SbError::SolanaInstructionOverflow => write!(
163                f,
164                "error: The transaction exceeded the maximum number of instructions (10)"
165            ),
166            SbError::SolanaPayerSignerMissing(payer) => write!(
167                f,
168                "error: The payer keypair is missing from the provided signers: {}",
169                payer
170            ),
171            SbError::SolanaBlockhashFetchError(source) => write!(
172                f,
173                "error: Failed to fetch blockhash from the cluster. Please try again. - {:?}", source
174            ),
175            // Handle other error variants as needed
176            _ => write!(f, "{:#?}", self),
177        }
178    }
179}
180
181impl From<&str> for SbError {
182    fn from(error: &str) -> Self {
183        SbError::CustomMessage(error.to_string())
184    }
185}
186impl From<String> for SbError {
187    fn from(error: String) -> Self {
188        SbError::CustomMessage(error)
189    }
190}
191
192impl From<hex::FromHexError> for SbError {
193    fn from(error: hex::FromHexError) -> Self {
194        SbError::CustomError {
195            message: "hex error".to_string(),
196            source: Arc::new(error),
197        }
198    }
199}
200
201impl StdError for SbError {
202    fn source(&self) -> Option<&(dyn StdError + 'static)> {
203        match self {
204            SbError::CustomError { source, .. } => Some(source.as_ref()), // Handle other error variants as needed
205            SbError::ContainerError(source) => Some(source.as_ref()),
206            SbError::ContainerStartError(source) => Some(source.as_ref()),
207            SbError::SolanaSignError(source, ..) => Some(source.as_ref()),
208            SbError::FunctionResultFailoverError(_code, source, ..) => Some(source.as_ref()),
209            SbError::FunctionResultNonRetryableError(source, ..) => Some(source.as_ref()),
210            _ => None,
211        }
212    }
213}
214
215impl From<SerdeJsonError> for SbError {
216    fn from(error: SerdeJsonError) -> Self {
217        SbError::CustomError {
218            message: "serde_json error".to_string(),
219            source: Arc::new(error),
220        }
221    }
222}
223
224impl From<std::io::Error> for SbError {
225    fn from(val: std::io::Error) -> Self {
226        SbError::IoError(std::sync::Arc::new(val))
227    }
228}
229
230#[cfg(test)]
231mod tests {
232    use super::*;
233
234    #[test]
235    fn display_generic() {
236        let error = SbError::Generic;
237        assert_eq!(format!("{}", error), "Generic");
238    }
239
240    #[test]
241    fn display_custom_message() {
242        let error = SbError::CustomMessage("my custom message".to_string());
243        assert_eq!(format!("{}", error), "error: my custom message");
244    }
245
246    #[test]
247    fn display_env_variable_missing() {
248        let error = SbError::EnvVariableMissing("MY_ENV_VAR".to_string());
249        assert_eq!(format!("{}", error), "Env variable missing: MY_ENV_VAR");
250    }
251
252    #[test]
253    fn from_str() {
254        let error: SbError = "my custom message".into();
255        assert_eq!(format!("{}", error), "error: my custom message");
256    }
257
258    #[test]
259    fn from_hex_error() {
260        let hex_error = hex::FromHexError::OddLength;
261        let error: SbError = hex_error.into();
262        assert_eq!(format!("{}", error), "error: hex error - OddLength");
263    }
264
265    #[test]
266    fn from_serde_json_error() {
267        let json = "\"";
268        let serde_json_error = serde_json::from_str::<serde_json::Value>(json).unwrap_err();
269        let error: SbError = serde_json_error.into();
270        assert!(format!("{}", error).starts_with("error: serde_json error - "));
271    }
272}