subrpcer/
lib.rs

1//! Minimal implementation of Substrate RPC APIs.
2//!
3//! Formatting rule(s):
4//! - All the APIs must be sorted in alphabetic order.
5
6#![deny(missing_docs)]
7#![deny(unused_crate_dependencies)]
8
9// TODO: https://github.com/rust-lang/rust/issues/82715
10// This should be `no_run` eventually
11/// Define a group of APIs.
12///
13/// Require [serde](https://crates.io/crates/serde) and [serde_json](https://crates.io/crates/serde_json) as the dependencies.
14///
15/// # Example
16/// ```ignore
17/// impl_apis! {
18/// 	state {
19/// 		call { params: [name, bytes], opt_params: [hash] }
20/// 		get_keys { params: [prefix], opt_params: [hash] }
21/// 		get_metadata { params: [], opt_params: [hash] }
22/// 		get_pairs { params: [prefix], opt_params: [hash] }
23/// 		get_read_proof { params: [keys], opt_params: [hash] }
24/// 		get_runtime_version { params: [], opt_params: [hash] }
25/// 		get_storage { params: [key], opt_params: [hash] }
26/// 		get_storage_hash { params: [key], opt_params: [hash] }
27/// 		get_storage_size { params: [key], opt_params: [hash] }
28/// 		query_storage { params: [keys, block], opt_params: [hash] }
29/// 		query_storage_at { params: [keys], opt_params: [at] }
30/// 		subscribe_runtime_version { params: [], opt_params: [] }
31/// 		subscribe_storage { params: [], opt_params: [keys] }
32/// 		trace_block { params: [block], opt_params: [targets, storage_keys, methods] }
33/// 		unsubscribe_runtime_version { params: [subscription_id], opt_params: [] }
34/// 		unsubscribe_storage { params: [subscription_id], opt_params: [] }
35/// 	}
36/// }
37/// ```
38#[allow(clippy::tabs_in_doc_comments)]
39#[macro_export]
40macro_rules! impl_apis {
41	{
42		$prefix:ident {
43			$(
44				$method:ident {
45					params: [
46						$(
47							$param:ident
48						),*
49					],
50					opt_params: [
51						$(
52							$opt_param:ident
53						),*
54					]
55				}
56			)+
57		}
58	} => {
59		$(
60			affix::paste! {
61				/// Check module's Substrate reference(s) for the detail.
62				pub fn $method(
63					id: usize,
64					$($param: impl serde::Serialize,)*
65					$($opt_param: Option<impl serde::Serialize>,)*
66				) -> serde_json::Value {
67					$crate::rpc(
68						id,
69						stringify!([<$prefix _ $method:camel>]),
70						serde_json::json!([
71							$($param,)*
72							$($opt_param,)*
73						])
74					)
75				}
76
77				#[doc = concat!("Similar to [`", stringify!($method), "`], but return the method name and parameters directly.")]
78				pub fn [<$method _raw>](
79					$($param: impl serde::Serialize,)*
80					$($opt_param: Option<impl serde::Serialize>,)*
81				) -> (&'static str, serde_json::Value) {
82					(
83						stringify!([<$prefix _ $method:camel>]),
84						serde_json::json!([
85							$($param,)*
86							$($opt_param,)*
87						])
88					)
89				}
90			}
91		)+
92	};
93}
94
95pub mod author;
96pub mod babe;
97pub mod chain;
98pub mod grandpa;
99pub mod net;
100pub mod offchain;
101pub mod payment;
102pub mod rpc;
103pub mod state;
104pub mod system;
105
106#[cfg(any(feature = "reqwest-client", feature = "ureq-client"))] pub mod client;
107
108// TODO: optimize the option param
109
110// crates.io
111use serde_json::Value;
112
113/// Build a JSONRPC 2.0 call.
114pub fn rpc(id: usize, method: &str, params: Value) -> Value {
115	let rpc = serde_json::json!({
116		"jsonrpc": "2.0",
117		"id": id,
118		"method": method,
119		"params": params
120	});
121
122	// This must not fail.
123	//
124	// `unwrap_or_default` is useless actually.
125	#[cfg(feature = "trace")]
126	tracing::trace!("Rpc({:?})", serde_json::to_string(&rpc).unwrap_or_default());
127
128	rpc
129}