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;
28use std::fmt;
29
30use serde::de::Deserializer;
31use serde::ser::Serializer;
32use serde::{Deserialize, Serialize};
33use serde_json::value::RawValue;
34use std::borrow::{Borrow, Cow as StdCow};
35use thiserror::Error;
36
37/// Owned variant of [`ErrorObject`].
38pub type ErrorObjectOwned = ErrorObject<'static>;
39
40/// [Failed JSON-RPC response object](https://www.jsonrpc.org/specification#response_object).
41#[derive(Debug, Deserialize, Serialize, Clone, thiserror::Error)]
42#[serde(deny_unknown_fields)]
43#[error("{self:?}")]
44pub struct ErrorObject<'a> {
45	/// Code
46	code: ErrorCode,
47	/// Message
48	message: StdCow<'a, str>,
49	/// Optional data
50	#[serde(skip_serializing_if = "Option::is_none")]
51	data: Option<StdCow<'a, RawValue>>,
52}
53
54impl<'a> ErrorObject<'a> {
55	/// Return the error code
56	pub fn code(&self) -> i32 {
57		self.code.code()
58	}
59
60	/// Return the message
61	pub fn message(&self) -> &str {
62		self.message.borrow()
63	}
64
65	/// Return the data associated with this error, if any
66	pub fn data(&self) -> Option<&RawValue> {
67		self.data.as_ref().map(|d| d.borrow())
68	}
69
70	/// Create a new `ErrorObjectOwned` with optional data.
71	pub fn owned<S: Serialize>(code: i32, message: impl Into<String>, data: Option<S>) -> ErrorObject<'static> {
72		let data = data.and_then(|d| serde_json::value::to_raw_value(&d).ok());
73		ErrorObject { code: code.into(), message: message.into().into(), data: data.map(StdCow::Owned) }
74	}
75
76	/// Create a new [`ErrorObject`] with optional data.
77	pub fn borrowed(code: i32, message: &'a str, data: Option<&'a RawValue>) -> ErrorObject<'a> {
78		ErrorObject { code: code.into(), message: StdCow::Borrowed(message), data: data.map(StdCow::Borrowed) }
79	}
80
81	/// Take ownership of the parameters within, if we haven't already.
82	pub fn into_owned(self) -> ErrorObject<'static> {
83		ErrorObject {
84			code: self.code,
85			message: StdCow::Owned(self.message.into_owned()),
86			data: self.data.map(|d| StdCow::Owned(d.into_owned())),
87		}
88	}
89
90	/// Borrow the current [`ErrorObject`].
91	pub fn borrow(&'a self) -> ErrorObject<'a> {
92		ErrorObject {
93			code: self.code,
94			message: StdCow::Borrowed(self.message.borrow()),
95			data: self.data.as_ref().map(|d| StdCow::Borrowed(d.borrow())),
96		}
97	}
98}
99
100impl PartialEq for ErrorObject<'_> {
101	fn eq(&self, other: &Self) -> bool {
102		let this_raw = self.data.as_ref().map(|r| r.get());
103		let other_raw = other.data.as_ref().map(|r| r.get());
104		self.code == other.code && self.message == other.message && this_raw == other_raw
105	}
106}
107
108impl From<ErrorCode> for ErrorObject<'_> {
109	fn from(code: ErrorCode) -> Self {
110		Self { code, message: code.message().into(), data: None }
111	}
112}
113
114impl From<Infallible> for ErrorObject<'_> {
115	fn from(e: Infallible) -> Self {
116		match e {}
117	}
118}
119
120/// Parse error code.
121pub const PARSE_ERROR_CODE: i32 = -32700;
122/// Invalid request error code.
123pub const INVALID_REQUEST_CODE: i32 = -32600;
124/// Method not found error code.
125pub const METHOD_NOT_FOUND_CODE: i32 = -32601;
126/// Invalid params error code.
127pub const INVALID_PARAMS_CODE: i32 = -32602;
128/// Internal error code.
129pub const INTERNAL_ERROR_CODE: i32 = -32603;
130/// Custom server error when a call failed.
131pub const CALL_EXECUTION_FAILED_CODE: i32 = -32000;
132/// Unknown error.
133pub const UNKNOWN_ERROR_CODE: i32 = -32001;
134/// Batched requests are not supported by the server.
135pub const BATCHES_NOT_SUPPORTED_CODE: i32 = -32005;
136/// Subscription limit per connection was exceeded.
137pub const TOO_MANY_SUBSCRIPTIONS_CODE: i32 = -32006;
138/// Oversized request error code.
139pub const OVERSIZED_REQUEST_CODE: i32 = -32007;
140/// Oversized response error code.
141pub const OVERSIZED_RESPONSE_CODE: i32 = -32008;
142/// Server is busy error code.
143pub const SERVER_IS_BUSY_CODE: i32 = -32009;
144/// Batch request limit was exceed.
145pub const TOO_BIG_BATCH_REQUEST_CODE: i32 = -32010;
146/// Batch response limit was exceed.
147pub const TOO_BIG_BATCH_RESPONSE_CODE: i32 = -32011;
148/// Message encryption failed error code.
149pub const ENCRYPTION_ERROR_CODE: i32 = -32012;
150/// Message decryption failed error code.
151pub const DECRYPTION_ERROR_CODE: i32 = -32013;
152
153/// Parse error message
154pub const PARSE_ERROR_MSG: &str = "Parse error";
155/// Oversized request message
156pub const OVERSIZED_REQUEST_MSG: &str = "Request is too big";
157/// Oversized response message
158pub const OVERSIZED_RESPONSE_MSG: &str = "Response is too big";
159/// Internal error message.
160pub const INTERNAL_ERROR_MSG: &str = "Internal error";
161/// Invalid params error message.
162pub const INVALID_PARAMS_MSG: &str = "Invalid params";
163/// Invalid request error message.
164pub const INVALID_REQUEST_MSG: &str = "Invalid request";
165/// Method not found error message.
166pub const METHOD_NOT_FOUND_MSG: &str = "Method not found";
167/// Server is busy error message.
168pub const SERVER_IS_BUSY_MSG: &str = "Server is busy, try again later";
169/// Reserved for implementation-defined server-errors.
170pub const SERVER_ERROR_MSG: &str = "Server error";
171/// Batched requests not supported error message.
172pub const BATCHES_NOT_SUPPORTED_MSG: &str = "Batched requests are not supported by this server";
173/// Subscription limit per connection was exceeded.
174pub const TOO_MANY_SUBSCRIPTIONS_MSG: &str = "Too many subscriptions on the connection";
175/// Batched requests limit was exceed.
176pub const TOO_BIG_BATCH_REQUEST_MSG: &str = "The batch request was too large";
177/// Batch request response limit was exceed.
178pub const TOO_BIG_BATCH_RESPONSE_MSG: &str = "The batch response was too large";
179/// Message encryption failed error message.
180pub const ENCRYPTION_ERROR_MSG: &str = "Message encryption failed";
181/// Message decryption failed error message.
182pub const DECRYPTION_ERROR_MSG: &str = "Message decryption failed";
183
184/// JSONRPC error code
185#[derive(Error, Debug, PartialEq, Eq, Copy, Clone)]
186pub enum ErrorCode {
187	/// Invalid JSON was received by the server.
188	/// An error occurred on the server while parsing the JSON text.
189	ParseError,
190	/// The request was too big.
191	OversizedRequest,
192	/// The JSON sent is not a valid Request object.
193	InvalidRequest,
194	/// The method does not exist / is not available.
195	MethodNotFound,
196	/// Server is busy / resources are at capacity.
197	ServerIsBusy,
198	/// Invalid method parameter(s).
199	InvalidParams,
200	/// Internal JSON-RPC error.
201	InternalError,
202	/// Reserved for implementation-defined server-errors.
203	ServerError(i32),
204}
205
206impl ErrorCode {
207	/// Returns integer code value
208	pub const fn code(&self) -> i32 {
209		use ErrorCode::*;
210		match *self {
211			ParseError => PARSE_ERROR_CODE,
212			OversizedRequest => OVERSIZED_REQUEST_CODE,
213			InvalidRequest => INVALID_REQUEST_CODE,
214			MethodNotFound => METHOD_NOT_FOUND_CODE,
215			ServerIsBusy => SERVER_IS_BUSY_CODE,
216			InvalidParams => INVALID_PARAMS_CODE,
217			InternalError => INTERNAL_ERROR_CODE,
218			ServerError(code) => code,
219		}
220	}
221
222	/// Returns the message for the given error code.
223	pub const fn message(&self) -> &'static str {
224		use ErrorCode::*;
225		match self {
226			ParseError => PARSE_ERROR_MSG,
227			OversizedRequest => OVERSIZED_REQUEST_MSG,
228			InvalidRequest => INVALID_REQUEST_MSG,
229			MethodNotFound => METHOD_NOT_FOUND_MSG,
230			ServerIsBusy => SERVER_IS_BUSY_MSG,
231			InvalidParams => INVALID_PARAMS_MSG,
232			InternalError => INTERNAL_ERROR_MSG,
233			ServerError(_) => SERVER_ERROR_MSG,
234		}
235	}
236}
237
238impl fmt::Display for ErrorCode {
239	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240		write!(f, "{}: {}", self.code(), self.message())
241	}
242}
243
244impl From<i32> for ErrorCode {
245	fn from(code: i32) -> Self {
246		use ErrorCode::*;
247		match code {
248			PARSE_ERROR_CODE => ParseError,
249			OVERSIZED_REQUEST_CODE => OversizedRequest,
250			INVALID_REQUEST_CODE => InvalidRequest,
251			METHOD_NOT_FOUND_CODE => MethodNotFound,
252			INVALID_PARAMS_CODE => InvalidParams,
253			INTERNAL_ERROR_CODE => InternalError,
254			code => ServerError(code),
255		}
256	}
257}
258
259impl<'a> serde::Deserialize<'a> for ErrorCode {
260	fn deserialize<D>(deserializer: D) -> Result<ErrorCode, D::Error>
261	where
262		D: Deserializer<'a>,
263	{
264		let code: i32 = Deserialize::deserialize(deserializer)?;
265		Ok(ErrorCode::from(code))
266	}
267}
268
269impl serde::Serialize for ErrorCode {
270	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
271	where
272		S: Serializer,
273	{
274		serializer.serialize_i32(self.code())
275	}
276}
277
278/// Helper to get a `JSON-RPC` error object when the maximum number of subscriptions have been 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}