1use std::fmt;
4use std::sync::atomic::{AtomicU64, Ordering};
5
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9static RPC_ID: AtomicU64 = AtomicU64::new(0);
11
12fn next_id() -> u64 {
15 RPC_ID.fetch_add(1, Ordering::SeqCst) + 1
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct Request {
21 pub jsonrpc: String,
23 pub method: String,
25 pub params: Value,
27 pub id: Value,
29}
30
31impl Request {
32 pub fn new(method: impl Into<String>, params: Vec<Value>) -> Request {
36 Request {
37 jsonrpc: "2.0".to_string(),
38 method: method.into(),
39 params: Value::Array(params),
40 id: Value::from(next_id()),
41 }
42 }
43
44 pub fn with_map(method: impl Into<String>, params: serde_json::Map<String, Value>) -> Request {
46 Request {
47 jsonrpc: "2.0".to_string(),
48 method: method.into(),
49 params: Value::Object(params),
50 id: Value::from(next_id()),
51 }
52 }
53
54 pub(crate) fn make_error(&self, e: &crate::Error) -> ResponseIntf {
58 let error = match e {
59 crate::Error::Rpc(eo) => eo.clone(),
60 other => ErrorObject {
61 code: -32603,
62 message: other.to_string(),
63 data: None,
64 },
65 };
66 ResponseIntf {
67 jsonrpc: "2.0".to_string(),
68 result: None,
69 error: Some(error),
70 id: self.id.clone(),
71 }
72 }
73}
74
75#[derive(Debug, Clone, Deserialize)]
77pub struct Response {
78 #[allow(dead_code)]
80 pub jsonrpc: String,
81 #[serde(default)]
83 pub result: Value,
84 #[serde(default)]
86 pub error: Option<ErrorObject>,
87 #[serde(default)]
89 pub id: Value,
90}
91
92#[derive(Debug, Clone, Serialize)]
95pub struct ResponseIntf {
96 pub jsonrpc: String,
98 #[serde(skip_serializing_if = "Option::is_none")]
100 pub result: Option<Value>,
101 #[serde(skip_serializing_if = "Option::is_none")]
103 pub error: Option<ErrorObject>,
104 pub id: Value,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct ErrorObject {
111 pub code: i64,
113 pub message: String,
115 #[serde(default, skip_serializing_if = "Option::is_none")]
117 pub data: Option<Value>,
118}
119
120impl fmt::Display for ErrorObject {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 write!(f, "jsonrpc error {}: {}", self.code, self.message)
123 }
124}
125
126impl std::error::Error for ErrorObject {}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use serde_json::json;
132
133 #[test]
134 fn new_request_empty_params() {
135 let req = Request::new("eth_blockNumber", vec![]);
136 assert_eq!(req.jsonrpc, "2.0");
137 assert_eq!(req.method, "eth_blockNumber");
138 assert_eq!(req.params, json!([]));
139 assert!(req.id.as_u64().unwrap() > 0);
141 }
142
143 #[test]
144 fn new_request_with_params() {
145 let req = Request::new("eth_getBalance", vec![json!("0xdead"), json!("latest")]);
146 assert_eq!(req.params, json!(["0xdead", "latest"]));
147 }
148
149 #[test]
150 fn new_request_map() {
151 let mut m = serde_json::Map::new();
152 m.insert("to".to_string(), json!("0xdead"));
153 let req = Request::with_map("eth_call", m);
154 assert_eq!(req.method, "eth_call");
155 assert_eq!(req.params["to"], json!("0xdead"));
156 }
157
158 #[test]
159 fn ids_are_monotonic() {
160 let a = Request::new("a", vec![]).id.as_u64().unwrap();
161 let b = Request::new("b", vec![]).id.as_u64().unwrap();
162 assert!(b > a);
163 }
164
165 #[test]
166 fn error_object_display() {
167 let e = ErrorObject {
168 code: -32601,
169 message: "Method not found".to_string(),
170 data: None,
171 };
172 assert_eq!(e.to_string(), "jsonrpc error -32601: Method not found");
173 }
174
175 #[test]
176 fn make_error_generic_and_passthrough() {
177 let req = Request::new("eth_test", vec![]);
178 let resp = req.make_error(&crate::Error::Other("something broke".to_string()));
179 let eo = resp.error.unwrap();
180 assert_eq!(eo.code, -32603);
181 assert_eq!(eo.message, "something broke");
182
183 let original = ErrorObject {
184 code: -32601,
185 message: "Method not found".to_string(),
186 data: None,
187 };
188 let resp = req.make_error(&crate::Error::Rpc(original));
189 assert_eq!(resp.error.unwrap().code, -32601);
190 }
191}