tendermint_rpc/
response_error.rs

1use core::fmt::Display;
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5use crate::prelude::*;
6
7#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
8pub struct ResponseError {
9    /// Error code
10    code: Code,
11
12    /// Error message
13    message: String,
14
15    /// Additional data about the error
16    data: Option<String>,
17}
18
19// /// Tendermint RPC error codes.
20// ///
21/// See `func RPC*Error()` definitions in:
22/// <https://github.com/tendermint/tendermint/blob/main/rpc/jsonrpc/types/types.go>
23#[derive(Copy, Clone, Debug, Eq, thiserror::Error, Hash, PartialEq, PartialOrd, Ord)]
24pub enum Code {
25    /// Low-level HTTP error
26    #[error("HTTP error")]
27    HttpError,
28
29    /// Low-level WebSocket error
30    #[error("WebSocket Error")]
31    WebSocketError,
32
33    /// An internal error occurred within the client.
34    ///
35    /// This is an error unique to this client, and is not available in the
36    /// [Go client].
37    ///
38    /// [Go client]: https://github.com/tendermint/tendermint/tree/main/rpc/jsonrpc/client
39    #[error("Client internal error")]
40    ClientInternalError,
41
42    /// Parse error i.e. invalid JSON (-32700)
43    #[error("Parse error. Invalid JSON")]
44    ParseError,
45
46    /// Invalid request (-32600)
47    #[error("Invalid Request")]
48    InvalidRequest,
49
50    /// Method not found error (-32601)
51    #[error("Method not found")]
52    MethodNotFound,
53
54    /// Invalid parameters (-32602)
55    #[error("Invalid params")]
56    InvalidParams,
57
58    /// Internal RPC server error (-32603)
59    #[error("Internal error")]
60    InternalError,
61
62    /// Server error (-32000)
63    #[error("Server error")]
64    ServerError,
65
66    /// Other error types
67    #[error("Error (code: {})", 0)]
68    Other(i32),
69}
70
71impl Code {
72    /// Get the integer error value for this code
73    pub fn value(self) -> i32 {
74        i32::from(self)
75    }
76}
77
78impl From<i32> for Code {
79    fn from(value: i32) -> Code {
80        match value {
81            0 => Code::HttpError,
82            1 => Code::WebSocketError,
83            2 => Code::ClientInternalError,
84            -32700 => Code::ParseError,
85            -32600 => Code::InvalidRequest,
86            -32601 => Code::MethodNotFound,
87            -32602 => Code::InvalidParams,
88            -32603 => Code::InternalError,
89            -32000 => Code::ServerError,
90            other => Code::Other(other),
91        }
92    }
93}
94
95impl From<Code> for i32 {
96    fn from(code: Code) -> i32 {
97        match code {
98            Code::HttpError => 0,
99            Code::WebSocketError => 1,
100            Code::ClientInternalError => 2,
101            Code::ParseError => -32700,
102            Code::InvalidRequest => -32600,
103            Code::MethodNotFound => -32601,
104            Code::InvalidParams => -32602,
105            Code::InternalError => -32603,
106            Code::ServerError => -32000,
107            Code::Other(other) => other,
108        }
109    }
110}
111
112impl Display for ResponseError {
113    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
114        match &self.data {
115            Some(data) => write!(
116                f,
117                "{}: {} (code: {})",
118                self.message,
119                data,
120                self.code.value()
121            ),
122            None => write!(f, "{} (code: {})", self.message, self.code.value()),
123        }
124    }
125}
126
127impl ResponseError {
128    /// Create a new RPC error
129    pub fn new(code: Code, data: Option<String>) -> ResponseError {
130        let message = code.to_string();
131
132        ResponseError {
133            code,
134            message,
135            data,
136        }
137    }
138
139    // / Create a low-level HTTP error
140    pub fn http_error(message: impl Into<String>) -> ResponseError {
141        ResponseError {
142            code: Code::HttpError,
143            message: message.into(),
144            data: None,
145        }
146    }
147
148    /// Create a new invalid parameter error
149    pub fn invalid_params(data: &str) -> ResponseError {
150        ResponseError::new(Code::InvalidParams, Some(data.to_string()))
151    }
152
153    /// Create a new websocket error
154    pub fn websocket_error(cause: impl Into<String>) -> ResponseError {
155        ResponseError::new(Code::WebSocketError, Some(cause.into()))
156    }
157
158    /// Create a new method-not-found error
159    pub fn method_not_found(name: &str) -> ResponseError {
160        ResponseError::new(Code::MethodNotFound, Some(name.to_string()))
161    }
162
163    /// Create a new parse error
164    pub fn parse_error<E>(error: E) -> ResponseError
165    where
166        E: Display,
167    {
168        ResponseError::new(Code::ParseError, Some(error.to_string()))
169    }
170
171    /// Create a new server error
172    pub fn server_error<D>(data: D) -> ResponseError
173    where
174        D: Display,
175    {
176        ResponseError::new(Code::ServerError, Some(data.to_string()))
177    }
178
179    /// An internal error occurred within the client.
180    pub fn client_internal_error(cause: impl Into<String>) -> ResponseError {
181        ResponseError::new(Code::ClientInternalError, Some(cause.into()))
182    }
183
184    /// Obtain the `rpc::error::Code` for this error
185    pub fn code(&self) -> Code {
186        self.code
187    }
188
189    /// Borrow the error message (if available)
190    pub fn message(&self) -> &str {
191        &self.message
192    }
193
194    /// Optional additional error message (if available)
195    pub fn data(&self) -> Option<&str> {
196        self.data.as_ref().map(AsRef::as_ref)
197    }
198}
199
200impl<'de> Deserialize<'de> for Code {
201    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
202        Ok(Code::from(i32::deserialize(deserializer)?))
203    }
204}
205
206impl Serialize for Code {
207    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
208        self.value().serialize(serializer)
209    }
210}