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}