starknet_devnet_server/rpc_core/
error.rs

1//! JSON-RPC error bindings
2use std::borrow::Cow;
3use std::fmt;
4
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6use serde_json::json;
7
8/// Represents a JSON-RPC error
9#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(deny_unknown_fields)]
11pub struct RpcError {
12    pub code: ErrorCode,
13    /// error message
14    pub message: Cow<'static, str>,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub data: Option<serde_json::Value>,
17}
18
19impl RpcError {
20    /// New [Error] with the given [ErrorCode]
21    pub const fn new(code: ErrorCode) -> Self {
22        RpcError { message: Cow::Borrowed(code.message()), code, data: None }
23    }
24
25    /// Creates a new `ParseError`
26    pub fn parse_error<R>(reason: R) -> Self
27    where
28        R: Into<String>,
29    {
30        RpcError {
31            code: ErrorCode::ParseError,
32            message: Cow::Borrowed(ErrorCode::ParseError.message()),
33            data: Some(json!({ "reason": reason.into() })),
34        }
35    }
36    /// Creates a new `MethodNotFound`
37    pub const fn method_not_found() -> Self {
38        Self::new(ErrorCode::MethodNotFound)
39    }
40
41    /// Creates a new `InvalidRequest`
42    pub const fn invalid_request() -> Self {
43        Self::new(ErrorCode::InvalidRequest)
44    }
45
46    // Creates a new `InvalidRequest` with a message
47    pub fn invalid_request_with_reason<R>(reason: R) -> Self
48    where
49        R: Into<String>,
50    {
51        RpcError {
52            code: ErrorCode::InvalidRequest,
53            message: Cow::Borrowed(ErrorCode::InvalidRequest.message()),
54            data: Some(json!({ "reason": reason.into() })),
55        }
56    }
57
58    /// Creates a new `InternalError`
59    pub const fn internal_error() -> Self {
60        Self::new(ErrorCode::InternalError)
61    }
62
63    /// Creates a new `InvalidParams`
64    pub fn invalid_params<M>(message: M) -> Self
65    where
66        M: Into<String>,
67    {
68        RpcError { code: ErrorCode::InvalidParams, message: message.into().into(), data: None }
69    }
70
71    /// Creates a new `InternalError` with a message
72    pub fn internal_error_with<M>(message: M) -> Self
73    where
74        M: Into<String>,
75    {
76        RpcError { code: ErrorCode::InternalError, message: message.into().into(), data: None }
77    }
78
79    /// Creates a new rpc error for when a transaction was rejected
80    pub fn transaction_rejected<M>(message: M) -> Self
81    where
82        M: Into<String>,
83    {
84        RpcError {
85            code: ErrorCode::TransactionRejected,
86            message: message.into().into(),
87            data: None,
88        }
89    }
90}
91
92impl fmt::Display for RpcError {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        write!(f, "{}: {}", self.code.message(), self.message)
95    }
96}
97
98/// List of JSON-RPC error codes
99#[derive(Clone, Copy, Debug, PartialEq, Eq)]
100pub enum ErrorCode {
101    /// Server received Invalid JSON.
102    /// server side error while parsing JSON
103    ParseError,
104    /// send invalid request object.
105    InvalidRequest,
106    /// method does not exist or valid
107    MethodNotFound,
108    /// invalid method parameter.
109    InvalidParams,
110    /// internal call error
111    InternalError,
112    /// Failed to send transaction, See also <https://github.com/MetaMask/eth-rpc-errors/blob/main/src/error-constants.ts>
113    TransactionRejected,
114    /// Custom geth error code, <https://github.com/vapory-legacy/wiki/blob/master/JSON-RPC-Error-Codes-Improvement-Proposal.md>
115    ExecutionError,
116    /// method is forbidden for execution
117    MethodForbidden,
118    /// Used for server specific errors.
119    ServerError(i64),
120}
121
122impl ErrorCode {
123    /// Returns the error code as `i64`
124    pub fn code(&self) -> i64 {
125        match *self {
126            ErrorCode::ParseError => -32700,
127            ErrorCode::InvalidRequest => -32600,
128            ErrorCode::MethodNotFound => -32601,
129            ErrorCode::InvalidParams => -32602,
130            ErrorCode::InternalError => -32603,
131            ErrorCode::MethodForbidden => -32604,
132            ErrorCode::TransactionRejected => -32003,
133            ErrorCode::ExecutionError => 3,
134            ErrorCode::ServerError(c) => c,
135        }
136    }
137
138    /// Returns the message associated with the error
139    pub const fn message(&self) -> &'static str {
140        match *self {
141            ErrorCode::ParseError => "Parse error",
142            ErrorCode::InvalidRequest => "Invalid request",
143            ErrorCode::MethodNotFound => "Method not found",
144            ErrorCode::InvalidParams => "Invalid params",
145            ErrorCode::InternalError => "Internal error",
146            ErrorCode::TransactionRejected => "Transaction rejected",
147            ErrorCode::ServerError(_) => "Server error",
148            ErrorCode::ExecutionError => "Execution error",
149            ErrorCode::MethodForbidden => "Method forbidden",
150        }
151    }
152}
153
154impl Serialize for ErrorCode {
155    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
156    where
157        S: Serializer,
158    {
159        serializer.serialize_i64(self.code())
160    }
161}
162
163impl<'a> Deserialize<'a> for ErrorCode {
164    fn deserialize<D>(deserializer: D) -> Result<ErrorCode, D::Error>
165    where
166        D: Deserializer<'a>,
167    {
168        i64::deserialize(deserializer).map(Into::into)
169    }
170}
171
172impl From<i64> for ErrorCode {
173    fn from(code: i64) -> Self {
174        match code {
175            -32700 => ErrorCode::ParseError,
176            -32600 => ErrorCode::InvalidRequest,
177            -32601 => ErrorCode::MethodNotFound,
178            -32602 => ErrorCode::InvalidParams,
179            -32603 => ErrorCode::InternalError,
180            -32604 => ErrorCode::MethodForbidden,
181            -32003 => ErrorCode::TransactionRejected,
182            3 => ErrorCode::ExecutionError,
183            _ => ErrorCode::ServerError(code),
184        }
185    }
186}