sc_rpc_api/state/
mod.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Substrate state API.
20
21use jsonrpsee::proc_macros::rpc;
22use sp_core::{
23	storage::{StorageChangeSet, StorageData, StorageKey},
24	Bytes,
25};
26use sp_version::RuntimeVersion;
27
28pub mod error;
29pub mod helpers;
30
31pub use self::helpers::ReadProof;
32pub use error::Error;
33
34/// Substrate state API
35#[rpc(client, server)]
36pub trait StateApi<Hash> {
37	/// Call a method from the runtime API at a block's state.
38	#[method(name = "state_call", aliases = ["state_callAt"], blocking)]
39	fn call(&self, name: String, bytes: Bytes, hash: Option<Hash>) -> Result<Bytes, Error>;
40
41	/// Returns the keys with prefix, leave empty to get all the keys.
42	#[method(name = "state_getKeys", blocking)]
43	#[deprecated(since = "2.0.0", note = "Please use `getKeysPaged` with proper paging support")]
44	fn storage_keys(
45		&self,
46		prefix: StorageKey,
47		hash: Option<Hash>,
48	) -> Result<Vec<StorageKey>, Error>;
49
50	/// Returns the keys with prefix, leave empty to get all the keys
51	#[method(name = "state_getPairs", blocking, with_extensions)]
52	fn storage_pairs(
53		&self,
54		prefix: StorageKey,
55		hash: Option<Hash>,
56	) -> Result<Vec<(StorageKey, StorageData)>, Error>;
57
58	/// Returns the keys with prefix with pagination support.
59	/// Up to `count` keys will be returned.
60	/// If `start_key` is passed, return next keys in storage in lexicographic order.
61	#[method(name = "state_getKeysPaged", aliases = ["state_getKeysPagedAt"], blocking)]
62	fn storage_keys_paged(
63		&self,
64		prefix: Option<StorageKey>,
65		count: u32,
66		start_key: Option<StorageKey>,
67		hash: Option<Hash>,
68	) -> Result<Vec<StorageKey>, Error>;
69
70	/// Returns a storage entry at a specific block's state.
71	#[method(name = "state_getStorage", aliases = ["state_getStorageAt"], blocking)]
72	fn storage(&self, key: StorageKey, hash: Option<Hash>) -> Result<Option<StorageData>, Error>;
73
74	/// Returns the hash of a storage entry at a block's state.
75	#[method(name = "state_getStorageHash", aliases = ["state_getStorageHashAt"], blocking)]
76	fn storage_hash(&self, key: StorageKey, hash: Option<Hash>) -> Result<Option<Hash>, Error>;
77
78	/// Returns the size of a storage entry at a block's state.
79	#[method(name = "state_getStorageSize", aliases = ["state_getStorageSizeAt"], with_extensions)]
80	async fn storage_size(&self, key: StorageKey, hash: Option<Hash>)
81		-> Result<Option<u64>, Error>;
82
83	/// Returns the runtime metadata as an opaque blob.
84	#[method(name = "state_getMetadata", blocking)]
85	fn metadata(&self, hash: Option<Hash>) -> Result<Bytes, Error>;
86
87	/// Get the runtime version.
88	#[method(name = "state_getRuntimeVersion", aliases = ["chain_getRuntimeVersion"], blocking)]
89	fn runtime_version(&self, hash: Option<Hash>) -> Result<RuntimeVersion, Error>;
90
91	/// Query historical storage entries (by key) starting from a block given as the second
92	/// parameter.
93	///
94	/// NOTE: The first returned result contains the initial state of storage for all keys.
95	/// Subsequent values in the vector represent changes to the previous state (diffs).
96	/// WARNING: The time complexity of this query is O(|keys|*dist(block, hash)), and the
97	/// memory complexity is O(dist(block, hash)) -- use with caution.
98	#[method(name = "state_queryStorage", blocking, with_extensions)]
99	fn query_storage(
100		&self,
101		keys: Vec<StorageKey>,
102		block: Hash,
103		hash: Option<Hash>,
104	) -> Result<Vec<StorageChangeSet<Hash>>, Error>;
105
106	/// Query storage entries (by key) at a block hash given as the second parameter.
107	/// NOTE: Each StorageChangeSet in the result corresponds to exactly one element --
108	/// the storage value under an input key at the input block hash.
109	#[method(name = "state_queryStorageAt", blocking)]
110	fn query_storage_at(
111		&self,
112		keys: Vec<StorageKey>,
113		at: Option<Hash>,
114	) -> Result<Vec<StorageChangeSet<Hash>>, Error>;
115
116	/// Returns proof of storage entries at a specific block's state.
117	#[method(name = "state_getReadProof", blocking)]
118	fn read_proof(
119		&self,
120		keys: Vec<StorageKey>,
121		hash: Option<Hash>,
122	) -> Result<ReadProof<Hash>, Error>;
123
124	/// New runtime version subscription
125	#[subscription(
126		name = "state_subscribeRuntimeVersion" => "state_runtimeVersion",
127		unsubscribe = "state_unsubscribeRuntimeVersion",
128		aliases = ["chain_subscribeRuntimeVersion"],
129		unsubscribe_aliases = ["chain_unsubscribeRuntimeVersion"],
130		item = RuntimeVersion,
131	)]
132	fn subscribe_runtime_version(&self);
133
134	/// New storage subscription
135	#[subscription(
136		name = "state_subscribeStorage" => "state_storage",
137		unsubscribe = "state_unsubscribeStorage",
138		item = StorageChangeSet<Hash>,
139		with_extensions,
140	)]
141	fn subscribe_storage(&self, keys: Option<Vec<StorageKey>>);
142
143	/// The `traceBlock` RPC provides a way to trace the re-execution of a single
144	/// block, collecting Spans and Events from both the client and the relevant WASM runtime.
145	/// The Spans and Events are conceptually equivalent to those from the [Tracing][1] crate.
146	///
147	/// The structure of the traces follows that of the block execution pipeline, so meaningful
148	/// interpretation of the traces requires an understanding of the Substrate chain's block
149	/// execution.
150	///
151	/// [Link to conceptual map of trace structure for Polkadot and Kusama block execution.][2]
152	///
153	/// [1]: https://crates.io/crates/tracing
154	/// [2]: https://docs.google.com/drawings/d/1vZoJo9jaXlz0LmrdTOgHck9_1LsfuQPRmTr-5g1tOis/edit?usp=sharing
155	///
156	/// ## Node requirements
157	///
158	/// - Fully synced archive node (i.e. a node that is not actively doing a "major" sync).
159	/// - [Tracing enabled WASM runtimes](#creating-tracing-enabled-wasm-runtimes) for all runtime
160	///   versions
161	/// for which tracing is desired.
162	///
163	/// ## Node recommendations
164	///
165	/// - Use fast SSD disk storage.
166	/// - Run node flags to increase DB read speed (i.e. `--state-cache-size`, `--db-cache`).
167	///
168	/// ## Creating tracing enabled WASM runtimes
169	///
170	/// - Checkout commit of chain version to compile with WASM traces
171	/// - [diener][1] can help to peg commit of substrate to what the chain expects.
172	/// - Navigate to the `runtime` folder/package of the chain
173	/// - Add feature `with-tracing = ["frame-executive/with-tracing", "sp-io/with-tracing"]`
174	/// under `[features]` to the `runtime` packages' `Cargo.toml`.
175	/// - Compile the runtime with `cargo build --release --features with-tracing`
176	/// - Tracing-enabled WASM runtime should be found in
177	///   `./target/release/wbuild/{{chain}}-runtime`
178	/// and be called something like `{{your_chain}}_runtime.compact.wasm`. This can be
179	/// renamed/modified however you like, as long as it retains the `.wasm` extension.
180	/// - Run the node with the wasm blob overrides by placing them in a folder with all your
181	///   runtimes,
182	/// and passing the path of this folder to your chain, e.g.:
183	/// - `./target/release/polkadot --wasm-runtime-overrides /home/user/my-custom-wasm-runtimes`
184	///
185	/// You can also find some pre-built tracing enabled wasm runtimes in [substrate-archive][2]
186	///
187	/// [Source.][3]
188	///
189	/// [1]: https://crates.io/crates/diener
190	/// [2]: https://github.com/paritytech/substrate-archive/tree/master/wasm-tracing
191	/// [3]: https://github.com/paritytech/substrate-archive/wiki
192	///
193	/// ## RPC Usage
194	///
195	/// The RPC allows for two filtering mechanisms: tracing targets and storage key prefixes.
196	/// The filtering of spans and events takes place after they are all collected; so while filters
197	/// do not reduce time for actual block re-execution, they reduce the response payload size.
198	///
199	/// Note: storage events primarily come from _primitives/state-machine/src/ext.rs_.
200	/// The default filters can be overridden, see the [params section](#params) for details.
201	///
202	/// ### `curl` example
203	///
204	/// - Get tracing spans and events
205	/// ```text
206	/// curl \
207	/// 	-H "Content-Type: application/json" \
208	/// 	-d '{"id":1, "jsonrpc":"2.0", "method": "state_traceBlock", \
209	/// 		"params": ["0xb246acf1adea1f801ce15c77a5fa7d8f2eb8fed466978bcee172cc02cf64e264", "pallet,frame,state", "", ""]}' \
210	/// 	http://localhost:9933/
211	/// ```
212	///
213	/// - Get tracing events with all `storage_keys`
214	/// ```text
215	/// curl \
216	/// 	-H "Content-Type: application/json" \
217	/// 	-d '{"id":1, "jsonrpc":"2.0", "method": "state_traceBlock", \
218	/// 		"params": ["0xb246acf1adea1f801ce15c77a5fa7d8f2eb8fed466978bcee172cc02cf64e264", "state", "", ""]}' \
219	/// 	http://localhost:9933/
220	/// ```
221	///
222	/// - Get tracing events with `storage_keys` ('f0c365c3cf59d671eb72da0e7a4113c4')
223	/// ```text
224	/// curl \
225	/// 	-H "Content-Type: application/json" \
226	/// 	-d '{"id":1, "jsonrpc":"2.0", "method": "state_traceBlock", \
227	/// 		"params": ["0xb246acf1adea1f801ce15c77a5fa7d8f2eb8fed466978bcee172cc02cf64e264", "state", "f0c365c3cf59d671eb72da0e7a4113c4", ""]}' \
228	/// 	http://localhost:9933/
229	/// ```
230	///
231	/// - Get tracing events with `storage_keys` ('f0c365c3cf59d671eb72da0e7a4113c4') and method
232	///   ('Put')
233	/// ```text
234	/// curl \
235	/// 	-H "Content-Type: application/json" \
236	/// 	-d '{"id":1, "jsonrpc":"2.0", "method": "state_traceBlock", \
237	/// 		"params": ["0xb246acf1adea1f801ce15c77a5fa7d8f2eb8fed466978bcee172cc02cf64e264", "state", "f0c365c3cf59d671eb72da0e7a4113c4", "Put"]}' \
238	/// 	http://localhost:9933/
239	/// ```
240	///
241	/// - Get tracing events with all `storage_keys` and method ('Put')
242	/// ```text
243	/// curl \
244	/// 	-H "Content-Type: application/json" \
245	/// 	-d '{"id":1, "jsonrpc":"2.0", "method": "state_traceBlock", \
246	/// 		"params": ["0xb246acf1adea1f801ce15c77a5fa7d8f2eb8fed466978bcee172cc02cf64e264", "state", "", "Put"]}' \
247	/// 	http://localhost:9933/
248	/// ```
249	///
250	/// ### Params
251	///
252	/// - `block` (param index 0): Hash of the block to trace.
253	/// - `targets` (param index 1): String of comma separated (no spaces) targets. Specified
254	/// targets match with trace targets by prefix (i.e if a target is in the beginning
255	/// of a trace target it is considered a match). If an empty string is specified no
256	/// targets will be filtered out. The majority of targets correspond to Rust module names,
257	/// and the ones that do not are typically "hardcoded" into span or event location
258	/// somewhere in the Substrate source code. ("Non-hardcoded" targets typically come from frame
259	/// support macros.)
260	/// - `storage_keys` (param index 2): String of comma separated (no spaces) hex encoded
261	/// (no `0x` prefix) storage keys. If an empty string is specified no events will
262	/// be filtered out. If anything other than an empty string is specified, events
263	/// will be filtered by storage key (so non-storage events will **not** show up).
264	/// You can specify any length of a storage key prefix (i.e. if a specified storage
265	/// key is in the beginning of an events storage key it is considered a match).
266	/// Example: for balance tracking on Polkadot & Kusama you would likely want
267	/// to track changes to account balances with the frame_system::Account storage item,
268	/// which is a map from `AccountId` to `AccountInfo`. The key filter for this would be
269	/// the storage prefix for the map:
270	/// `26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9`
271	/// - `methods` (param index 3): String of comma separated (no spaces) tracing event method.
272	/// If an empty string is specified no events will be filtered out. If anything other than
273	/// an empty string is specified, events will be filtered by method (so non-method events will
274	/// **not** show up).
275	///
276	/// Additionally you would want to track the extrinsic index, which is under the
277	/// `:extrinsic_index` key. The key for this would be the aforementioned string as bytes
278	/// in hex: `3a65787472696e7369635f696e646578`.
279	/// The following are some resources to learn more about storage keys in substrate:
280	/// [substrate storage][1], [transparent keys in substrate][2],
281	/// [querying substrate storage via rpc][3].
282	///
283	/// [1]: https://docs.substrate.io/main-docs/fundamentals/state-transitions-and-storage/
284	/// [2]: https://www.shawntabrizi.com/blog/substrate/transparent-keys-in-substrate/
285	/// [3]: https://www.shawntabrizi.com/blog/substrate/querying-substrate-storage-via-rpc/
286	///
287	/// ### Maximum payload size
288	///
289	/// The maximum payload size allowed is 15mb. Payloads over this size will return a
290	/// object with a simple error message. If you run into issues with payload size you can
291	/// narrow down the traces using a smaller set of targets and/or storage keys.
292	///
293	/// If you are having issues with maximum payload size you can use the flag
294	/// `-ltracing=trace` to get some logging during tracing.
295	#[method(name = "state_traceBlock", blocking, with_extensions)]
296	fn trace_block(
297		&self,
298		block: Hash,
299		targets: Option<String>,
300		storage_keys: Option<String>,
301		methods: Option<String>,
302	) -> Result<sp_rpc::tracing::TraceBlockResponse, Error>;
303}