Skip to main content

jsonrpsee_types/
error.rs

1// Copyright 2019-2021 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any
4// person obtaining a copy of this software and associated
5// documentation files (the "Software"), to deal in the
6// Software without restriction, including without
7// limitation the rights to use, copy, modify, merge,
8// publish, distribute, sublicense, and/or sell copies of
9// the Software, and to permit persons to whom the Software
10// is furnished to do so, subject to the following
11// conditions:
12//
13// The above copyright notice and this permission notice
14// shall be included in all copies or substantial portions
15// of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25// DEALINGS IN THE SOFTWARE.
26
27use std::{convert::Infallible, fmt};
28
29use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
30use serde_json::value::RawValue;
31use std::borrow::{Borrow, Cow as StdCow};
32use thiserror::Error;
33
34/// Owned variant of [`ErrorObject`].
35pub type ErrorObjectOwned = ErrorObject<'static>;
36
37/// [Failed JSON-RPC response object](https://www.jsonrpc.org/specification#response_object).
38#[derive(Debug, Deserialize, Serialize, Clone, thiserror::Error)]
39#[serde(deny_unknown_fields)]
40#[error("{self:?}")]
41pub struct ErrorObject<'a> {
42    /// Code
43    code: ErrorCode,
44    /// Message
45    message: StdCow<'a, str>,
46    /// Optional data
47    #[serde(skip_serializing_if = "Option::is_none")]
48    data: Option<StdCow<'a, RawValue>>,
49}
50
51impl<'a> ErrorObject<'a> {
52    /// Return the error code
53    pub fn code(&self) -> i32 {
54        self.code.code()
55    }
56
57    /// Return the message
58    pub fn message(&self) -> &str {
59        self.message.borrow()
60    }
61
62    /// Return the data associated with this error, if any
63    pub fn data(&self) -> Option<&RawValue> {
64        self.data.as_ref().map(|d| d.borrow())
65    }
66
67    /// Create a new `ErrorObjectOwned` with optional data.
68    pub fn owned<S: Serialize>(
69        code: i32,
70        message: impl Into<String>,
71        data: Option<S>,
72    ) -> ErrorObject<'static> {
73        let data = data.and_then(|d| serde_json::value::to_raw_value(&d).ok());
74        ErrorObject {
75            code: code.into(),
76            message: message.into().into(),
77            data: data.map(StdCow::Owned),
78        }
79    }
80
81    /// Create a new [`ErrorObject`] with optional data.
82    pub fn borrowed(code: i32, message: &'a str, data: Option<&'a RawValue>) -> ErrorObject<'a> {
83        ErrorObject {
84            code: code.into(),
85            message: StdCow::Borrowed(message),
86            data: data.map(StdCow::Borrowed),
87        }
88    }
89
90    /// Take ownership of the parameters within, if we haven't already.
91    pub fn into_owned(self) -> ErrorObject<'static> {
92        ErrorObject {
93            code: self.code,
94            message: StdCow::Owned(self.message.into_owned()),
95            data: self.data.map(|d| StdCow::Owned(d.into_owned())),
96        }
97    }
98
99    /// Borrow the current [`ErrorObject`].
100    pub fn borrow(&'a self) -> ErrorObject<'a> {
101        ErrorObject {
102            code: self.code,
103            message: StdCow::Borrowed(self.message.borrow()),
104            data: self.data.as_ref().map(|d| StdCow::Borrowed(d.borrow())),
105        }
106    }
107}
108
109impl PartialEq for ErrorObject<'_> {
110    fn eq(&self, other: &Self) -> bool {
111        let this_raw = self.data.as_ref().map(|r| r.get());
112        let other_raw = other.data.as_ref().map(|r| r.get());
113        self.code == other.code && self.message == other.message && this_raw == other_raw
114    }
115}
116
117impl From<ErrorCode> for ErrorObject<'_> {
118    fn from(code: ErrorCode) -> Self {
119        Self { code, message: code.message().into(), data: None }
120    }
121}
122
123impl From<Infallible> for ErrorObject<'_> {
124    fn from(e: Infallible) -> Self {
125        match e {}
126    }
127}
128
129/// Parse error code.
130pub const PARSE_ERROR_CODE: i32 = -32700;
131/// Invalid request error code.
132pub const INVALID_REQUEST_CODE: i32 = -32600;
133/// Method not found error code.
134pub const METHOD_NOT_FOUND_CODE: i32 = -32601;
135/// Invalid params error code.
136pub const INVALID_PARAMS_CODE: i32 = -32602;
137/// Internal error code.
138pub const INTERNAL_ERROR_CODE: i32 = -32603;
139/// Custom server error when a call failed.
140pub const CALL_EXECUTION_FAILED_CODE: i32 = -32000;
141/// Batched requests are not supported by the server.
142pub const BATCHES_NOT_SUPPORTED_CODE: i32 = -32005;
143/// Subscription limit per connection was exceeded.
144pub const TOO_MANY_SUBSCRIPTIONS_CODE: i32 = -32006;
145/// Oversized request error code.
146pub const OVERSIZED_REQUEST_CODE: i32 = -32007;
147/// Oversized response error code.
148pub const OVERSIZED_RESPONSE_CODE: i32 = -32008;
149/// Server is busy error code.
150pub const SERVER_IS_BUSY_CODE: i32 = -32009;
151/// Batch request limit was exceed.
152pub const TOO_BIG_BATCH_REQUEST_CODE: i32 = -32010;
153/// Batch response limit was exceed.
154pub const TOO_BIG_BATCH_RESPONSE_CODE: i32 = -32011;
155
156/// Parse error message
157pub const PARSE_ERROR_MSG: &str = "Parse error";
158/// Oversized request message
159pub const OVERSIZED_REQUEST_MSG: &str = "Request is too big";
160/// Oversized response message
161pub const OVERSIZED_RESPONSE_MSG: &str = "Response is too big";
162/// Internal error message.
163pub const INTERNAL_ERROR_MSG: &str = "Internal error";
164/// Invalid params error message.
165pub const INVALID_PARAMS_MSG: &str = "Invalid params";
166/// Invalid request error message.
167pub const INVALID_REQUEST_MSG: &str = "Invalid request";
168/// Method not found error message.
169pub const METHOD_NOT_FOUND_MSG: &str = "Method not found";
170/// Server is busy error message.
171pub const SERVER_IS_BUSY_MSG: &str = "Server is busy, try again later";
172/// Reserved for implementation-defined server-errors.
173pub const SERVER_ERROR_MSG: &str = "Server error";
174/// Batched requests not supported error message.
175pub const BATCHES_NOT_SUPPORTED_MSG: &str = "Batched requests are not supported by this server";
176/// Subscription limit per connection was exceeded.
177pub const TOO_MANY_SUBSCRIPTIONS_MSG: &str = "Too many subscriptions on the connection";
178/// Batched requests limit was exceed.
179pub const TOO_BIG_BATCH_REQUEST_MSG: &str = "The batch request was too large";
180/// Batch request response limit was exceed.
181pub const TOO_BIG_BATCH_RESPONSE_MSG: &str = "The batch response was too large";
182
183/// JSONRPC error code
184#[derive(Error, Debug, PartialEq, Eq, Copy, Clone)]
185pub enum ErrorCode {
186    /// Invalid JSON was received by the server.
187    /// An error occurred on the server while parsing the JSON text.
188    ParseError,
189    /// The request was too big.
190    OversizedRequest,
191    /// The JSON sent is not a valid Request object.
192    InvalidRequest,
193    /// The method does not exist / is not available.
194    MethodNotFound,
195    /// Server is busy / resources are at capacity.
196    ServerIsBusy,
197    /// Invalid method parameter(s).
198    InvalidParams,
199    /// Internal JSON-RPC error.
200    InternalError,
201    /// Reserved for implementation-defined server-errors.
202    ServerError(i32),
203}
204
205impl ErrorCode {
206    /// Returns integer code value
207    pub const fn code(&self) -> i32 {
208        use ErrorCode::*;
209        match *self {
210            ParseError => PARSE_ERROR_CODE,
211            OversizedRequest => OVERSIZED_REQUEST_CODE,
212            InvalidRequest => INVALID_REQUEST_CODE,
213            MethodNotFound => METHOD_NOT_FOUND_CODE,
214            ServerIsBusy => SERVER_IS_BUSY_CODE,
215            InvalidParams => INVALID_PARAMS_CODE,
216            InternalError => INTERNAL_ERROR_CODE,
217            ServerError(code) => code,
218        }
219    }
220
221    /// Returns the message for the given error code.
222    pub const fn message(&self) -> &'static str {
223        use ErrorCode::*;
224        match self {
225            ParseError => PARSE_ERROR_MSG,
226            OversizedRequest => OVERSIZED_REQUEST_MSG,
227            InvalidRequest => INVALID_REQUEST_MSG,
228            MethodNotFound => METHOD_NOT_FOUND_MSG,
229            ServerIsBusy => SERVER_IS_BUSY_MSG,
230            InvalidParams => INVALID_PARAMS_MSG,
231            InternalError => INTERNAL_ERROR_MSG,
232            ServerError(_) => SERVER_ERROR_MSG,
233        }
234    }
235}
236
237impl fmt::Display for ErrorCode {
238    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239        write!(f, "{}: {}", self.code(), self.message())
240    }
241}
242
243impl From<i32> for ErrorCode {
244    fn from(code: i32) -> Self {
245        use ErrorCode::*;
246        match code {
247            PARSE_ERROR_CODE => ParseError,
248            OVERSIZED_REQUEST_CODE => OversizedRequest,
249            INVALID_REQUEST_CODE => InvalidRequest,
250            METHOD_NOT_FOUND_CODE => MethodNotFound,
251            INVALID_PARAMS_CODE => InvalidParams,
252            INTERNAL_ERROR_CODE => InternalError,
253            code => ServerError(code),
254        }
255    }
256}
257
258impl<'a> serde::Deserialize<'a> for ErrorCode {
259    fn deserialize<D>(deserializer: D) -> Result<ErrorCode, D::Error>
260    where
261        D: Deserializer<'a>,
262    {
263        let code: i32 = Deserialize::deserialize(deserializer)?;
264        Ok(ErrorCode::from(code))
265    }
266}
267
268impl serde::Serialize for ErrorCode {
269    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
270    where
271        S: Serializer,
272    {
273        serializer.serialize_i32(self.code())
274    }
275}
276
277/// Helper to get a `JSON-RPC` error object when the maximum number of subscriptions have been
278/// exceeded.
279pub fn reject_too_many_subscriptions(limit: u32) -> ErrorObjectOwned {
280    ErrorObjectOwned::owned(
281        TOO_MANY_SUBSCRIPTIONS_CODE,
282        TOO_MANY_SUBSCRIPTIONS_MSG,
283        Some(format!("Exceeded max limit of {limit}")),
284    )
285}
286
287/// Helper to get a `JSON-RPC` error object when the maximum request size limit have been exceeded.
288pub fn reject_too_big_request(limit: u32) -> ErrorObjectOwned {
289    ErrorObjectOwned::owned(
290        OVERSIZED_REQUEST_CODE,
291        OVERSIZED_REQUEST_MSG,
292        Some(format!("Exceeded max limit of {limit}")),
293    )
294}
295
296/// Helper to get a `JSON-RPC` error object when the maximum batch request size have been exceeded.
297pub fn reject_too_big_batch_request(limit: usize) -> ErrorObjectOwned {
298    ErrorObjectOwned::owned(
299        TOO_BIG_BATCH_REQUEST_CODE,
300        TOO_BIG_BATCH_REQUEST_MSG,
301        Some(format!("Exceeded max limit of {limit}")),
302    )
303}
304
305/// Helper to get a `JSON-RPC` error object when the maximum batch response size have been exceeded.
306pub fn reject_too_big_batch_response(limit: usize) -> ErrorObjectOwned {
307    ErrorObjectOwned::owned(
308        TOO_BIG_BATCH_RESPONSE_CODE,
309        TOO_BIG_BATCH_RESPONSE_MSG,
310        Some(format!("Exceeded max limit of {limit}")),
311    )
312}
313
314#[cfg(test)]
315mod tests {
316    use super::{ErrorCode, ErrorObject};
317
318    #[test]
319    fn deserialize_works() {
320        let ser = r#"{"code":-32700,"message":"Parse error"}"#;
321        let exp: ErrorObject = ErrorCode::ParseError.into();
322        let err: ErrorObject = serde_json::from_str(ser).unwrap();
323        assert_eq!(exp, err);
324    }
325
326    #[test]
327    fn deserialize_with_optional_data() {
328        let ser = r#"{"code":-32700,"message":"Parse error", "data":"vegan"}"#;
329        let data = serde_json::value::to_raw_value(&"vegan").unwrap();
330        let exp = ErrorObject::owned(ErrorCode::ParseError.code(), "Parse error", Some(data));
331        let err: ErrorObject = serde_json::from_str(ser).unwrap();
332        assert_eq!(exp, err);
333    }
334
335    #[test]
336    fn deserialized_error_with_quoted_str() {
337        let raw = r#"{
338                "code": 1002,
339                "message": "desc: \"Could not decode `ChargeAssetTxPayment::asset_id`\" } })",
340                "data": "\\\"validate_transaction\\\""
341        }"#;
342        let err: ErrorObject = serde_json::from_str(raw).unwrap();
343
344        let data = serde_json::value::to_raw_value(&"\\\"validate_transaction\\\"").unwrap();
345        let exp = ErrorObject::borrowed(
346            1002,
347            "desc: \"Could not decode `ChargeAssetTxPayment::asset_id`\" } })",
348            Some(&*data),
349        );
350
351        assert_eq!(err, exp);
352    }
353
354    #[test]
355    fn serialize_works() {
356        let exp = r#"{"code":-32603,"message":"Internal error"}"#;
357        let err: ErrorObject = ErrorCode::InternalError.into();
358        let ser = serde_json::to_string(&err).unwrap();
359        assert_eq!(exp, ser);
360    }
361
362    #[test]
363    fn serialize_optional_data_works() {
364        let exp = r#"{"code":-32699,"message":"food","data":"not vegan"}"#;
365        let data = serde_json::value::to_raw_value(&"not vegan").unwrap();
366        let ser = serde_json::to_string(&ErrorObject::owned(-32699, "food", Some(data))).unwrap();
367        assert_eq!(exp, ser);
368    }
369}