1use std::fmt::Debug;
2
3use parity_scale_codec::Decode;
4pub use serde::de::DeserializeOwned;
5use serde::{Deserialize, Serialize};
6use serde_json::{json, to_value, Value};
7use sp_core::H256;
8use sp_storage::StorageKey;
9
10use crate::client::{ClientError, Result};
11use crate::utils::FromHexString;
12
13pub trait RpcClient {
14 fn post(&self, json_req: Value) -> Result<JsonRpcResponse>;
15
16 fn send_extrinsic(&self, xt: &str) -> Result<String> {
17 let json = author_submit_extrinsic(xt);
18 self.post(json)?.into_result()
19 }
20}
21
22#[derive(Debug, Deserialize)]
23#[serde(untagged)]
24pub enum JsonRpcResponse {
25 Success(JsonRpcSuccess),
26 Error(JsonRpcError),
27 String(String),
28}
29
30impl JsonRpcResponse {
31 pub fn into_result<T: DeserializeOwned>(self) -> Result<T, ClientError> {
32 match self {
33 JsonRpcResponse::Success(s) => Ok(serde_json::from_value::<T>(s.result)?),
34 JsonRpcResponse::Error(e) => Err(ClientError::JsonRpcError(e)),
35 JsonRpcResponse::String(s) => Ok(serde_json::from_str(&s)?),
36 }
37 }
38
39 pub fn decode_into<T: Decode>(self) -> Result<Option<T>, ClientError> {
40 match self {
41 JsonRpcResponse::Success(s) => {
42 if !s.result.is_null() {
43 let v = Vec::from_hex(s.result.to_string())?;
44 let t = Decode::decode(&mut v.as_slice())?;
45 Ok(Some(t))
46 } else {
47 Ok(None)
48 }
49 }
50 JsonRpcResponse::Error(e) => Err(ClientError::JsonRpcError(e)),
51 JsonRpcResponse::String(s) => Ok(Some(Decode::decode(&mut s.as_bytes())?)),
52 }
53 }
54}
55
56#[derive(Debug, Deserialize)]
57pub struct JsonRpcSuccess {
58 pub result: Value,
59 pub jsonrpc: String,
60 pub id: String,
61}
62
63#[derive(Debug, Deserialize, thiserror::Error)]
64#[error("{error}")]
65pub struct JsonRpcError {
66 pub jsonrpc: String,
67 pub id: String,
68 pub error: RpcError,
69}
70
71#[derive(Debug, Deserialize, thiserror::Error)]
72#[error("Json RPC error: [code: {code}, message: {message}, data: {data:?}]")]
73pub struct RpcError {
74 pub code: i64,
75 pub message: String,
76 pub data: Option<Value>,
77}
78
79pub fn chain_get_block(hash: Option<H256>) -> Value {
82 chain_get_block_with_id(hash, 1)
83}
84
85pub fn chain_get_block_hash(number: Option<u32>) -> Value {
86 chain_get_block_hash_with_id(number, 1)
87}
88
89pub fn chain_get_genesis_hash() -> Value {
90 chain_get_block_hash(Some(0))
91}
92
93pub fn chain_get_block_with_id(hash: Option<H256>, id: u32) -> Value {
94 json_req("chain_getBlock", vec![hash], id)
95}
96
97pub fn chain_get_block_hash_with_id(number: Option<u32>, id: u32) -> Value {
98 json_req("chain_getBlockHash", vec![number], id)
99}
100
101pub fn state_get_runtime_version() -> Value {
102 state_get_runtime_version_with_id(1)
103}
104
105pub fn state_get_runtime_version_with_id(id: u32) -> Value {
106 json_req("state_getRuntimeVersion", vec![Value::Null], id)
107}
108
109pub(crate) fn state_get_storage(key: StorageKey, at_block: Option<H256>) -> Value {
110 json_req(
111 "state_getStorage",
112 vec![to_value(key).unwrap(), to_value(at_block).unwrap()],
113 1,
114 )
115}
116
117pub fn payment_query_fee_details(xt_hex_prefixed: &str, at_block: Option<H256>) -> Value {
118 json_req(
119 "payment_queryFeeDetails",
120 vec![
121 to_value(xt_hex_prefixed).unwrap(),
122 to_value(at_block).unwrap(),
123 ],
124 1,
125 )
126}
127
128pub fn author_submit_extrinsic(xt_hex_prefixed: &str) -> Value {
129 author_submit_extrinsic_with_id(xt_hex_prefixed, 3)
130}
131
132pub fn author_submit_extrinsic_with_id(xt_hex_prefixed: &str, id: u32) -> Value {
133 json_req("author_submitExtrinsic", vec![xt_hex_prefixed], id)
134}
135
136fn json_req<S: Serialize>(method: &str, params: S, id: u32) -> Value {
137 json!({
138 "method": method,
139 "params": params,
140 "jsonrpc": "2.0",
141 "id": id.to_string(),
142 })
143}