referrerpolicy=no-referrer-when-downgrade

sc_rpc/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
21mod state_full;
22mod utils;
23
24#[cfg(test)]
25mod tests;
26
27use crate::SubscriptionTaskExecutor;
28use jsonrpsee::{core::async_trait, Extensions, PendingSubscriptionSink};
29use sc_client_api::{
30	Backend, BlockBackend, BlockchainEvents, ExecutorProvider, ProofProvider, StorageProvider,
31};
32use sc_rpc_api::{check_if_safe, DenyUnsafe};
33use sc_tracing::block::TracingExecuteBlock;
34use sp_api::{CallApiAt, Metadata, ProvideRuntimeApi};
35use sp_blockchain::{HeaderBackend, HeaderMetadata};
36use sp_core::{
37	storage::{PrefixedStorageKey, StorageChangeSet, StorageData, StorageKey},
38	Bytes,
39};
40use sp_runtime::traits::Block as BlockT;
41use sp_version::RuntimeVersion;
42use std::sync::Arc;
43
44pub use sc_rpc_api::{child_state::*, state::*};
45
46const STORAGE_KEYS_PAGED_MAX_COUNT: u32 = 1000;
47
48/// State backend API.
49#[async_trait]
50pub trait StateBackend<Block: BlockT, Client>: Send + Sync + 'static
51where
52	Block: BlockT + 'static,
53	Client: Send + Sync + 'static,
54{
55	/// Call runtime method at given block.
56	fn call(
57		&self,
58		block: Option<Block::Hash>,
59		method: String,
60		call_data: Bytes,
61	) -> Result<Bytes, Error>;
62
63	/// Returns the keys with prefix, leave empty to get all the keys.
64	fn storage_keys(
65		&self,
66		block: Option<Block::Hash>,
67		prefix: StorageKey,
68	) -> Result<Vec<StorageKey>, Error>;
69
70	/// Returns the keys with prefix along with their values, leave empty to get all the pairs.
71	fn storage_pairs(
72		&self,
73		block: Option<Block::Hash>,
74		prefix: StorageKey,
75	) -> Result<Vec<(StorageKey, StorageData)>, Error>;
76
77	/// Returns the keys with prefix with pagination support.
78	fn storage_keys_paged(
79		&self,
80		block: Option<Block::Hash>,
81		prefix: Option<StorageKey>,
82		count: u32,
83		start_key: Option<StorageKey>,
84	) -> Result<Vec<StorageKey>, Error>;
85
86	/// Returns a storage entry at a specific block's state.
87	fn storage(
88		&self,
89		block: Option<Block::Hash>,
90		key: StorageKey,
91	) -> Result<Option<StorageData>, Error>;
92
93	/// Returns the hash of a storage entry at a block's state.
94	fn storage_hash(
95		&self,
96		block: Option<Block::Hash>,
97		key: StorageKey,
98	) -> Result<Option<Block::Hash>, Error>;
99
100	/// Returns the size of a storage entry at a block's state.
101	///
102	/// If data is available at `key`, it is returned. Else, the sum of values who's key has `key`
103	/// prefix is returned, i.e. all the storage (double) maps that have this prefix.
104	async fn storage_size(
105		&self,
106		block: Option<Block::Hash>,
107		key: StorageKey,
108		deny_unsafe: DenyUnsafe,
109	) -> Result<Option<u64>, Error>;
110
111	/// Returns the runtime metadata as an opaque blob.
112	fn metadata(&self, block: Option<Block::Hash>) -> Result<Bytes, Error>;
113
114	/// Get the runtime version.
115	fn runtime_version(&self, block: Option<Block::Hash>) -> Result<RuntimeVersion, Error>;
116
117	/// Query historical storage entries (by key) starting from a block given as the second
118	/// parameter.
119	///
120	/// NOTE This first returned result contains the initial state of storage for all keys.
121	/// Subsequent values in the vector represent changes to the previous state (diffs).
122	fn query_storage(
123		&self,
124		from: Block::Hash,
125		to: Option<Block::Hash>,
126		keys: Vec<StorageKey>,
127	) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error>;
128
129	/// Query storage entries (by key) starting at block hash given as the second parameter.
130	fn query_storage_at(
131		&self,
132		keys: Vec<StorageKey>,
133		at: Option<Block::Hash>,
134	) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error>;
135
136	/// Returns proof of storage entries at a specific block's state.
137	fn read_proof(
138		&self,
139		block: Option<Block::Hash>,
140		keys: Vec<StorageKey>,
141	) -> Result<ReadProof<Block::Hash>, Error>;
142
143	/// Trace storage changes for block
144	fn trace_block(
145		&self,
146		block: Block::Hash,
147		targets: Option<String>,
148		storage_keys: Option<String>,
149		methods: Option<String>,
150	) -> Result<sp_rpc::tracing::TraceBlockResponse, Error>;
151
152	/// Run `method` re-enacting `block` at its parent state with a proof-size recorder, replaying
153	/// `block`'s stored recording when available.
154	fn call_recorded(
155		&self,
156		block: Block::Hash,
157		method: String,
158		call_data: Bytes,
159	) -> Result<Bytes, Error>;
160
161	/// New runtime version subscription
162	fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink);
163
164	/// New storage subscription
165	fn subscribe_storage(
166		&self,
167		pending: PendingSubscriptionSink,
168		keys: Option<Vec<StorageKey>>,
169		deny_unsafe: DenyUnsafe,
170	);
171}
172
173/// Create new state API that works on full node.
174///
175/// `execute_block` is the optional proof-size-recording block executor (`Some` on parachains).
176/// When `None`, `state_traceBlock` runs without recording and `state_callRecorded` reports
177/// `CallRecordedUnsupported`.
178pub fn new_full<BE, Block: BlockT, Client>(
179	client: Arc<Client>,
180	executor: SubscriptionTaskExecutor,
181	execute_block: Option<Arc<dyn TracingExecuteBlock<Block>>>,
182) -> (State<Block, Client>, ChildState<Block, Client>)
183where
184	Block: BlockT + 'static,
185	Block::Hash: Unpin,
186	BE: Backend<Block> + 'static,
187	Client: ExecutorProvider<Block>
188		+ StorageProvider<Block, BE>
189		+ ProofProvider<Block>
190		+ HeaderMetadata<Block, Error = sp_blockchain::Error>
191		+ BlockchainEvents<Block>
192		+ CallApiAt<Block>
193		+ HeaderBackend<Block>
194		+ BlockBackend<Block>
195		+ ProvideRuntimeApi<Block>
196		+ Send
197		+ Sync
198		+ 'static,
199	Client::Api: Metadata<Block>,
200{
201	let child_backend = Box::new(self::state_full::FullState::new(
202		client.clone(),
203		executor.clone(),
204		execute_block.clone(),
205	));
206	let backend =
207		Box::new(self::state_full::FullState::new(client, executor, execute_block.clone()));
208	(State { backend }, ChildState { backend: child_backend })
209}
210
211/// State API with subscriptions support.
212pub struct State<Block, Client> {
213	backend: Box<dyn StateBackend<Block, Client>>,
214}
215
216#[async_trait]
217impl<Block, Client> StateApiServer<Block::Hash> for State<Block, Client>
218where
219	Block: BlockT + 'static,
220	Client: Send + Sync + 'static,
221{
222	fn call(
223		&self,
224		method: String,
225		data: Bytes,
226		block: Option<Block::Hash>,
227	) -> Result<Bytes, Error> {
228		self.backend.call(block, method, data).map_err(Into::into)
229	}
230
231	fn storage_keys(
232		&self,
233		ext: &Extensions,
234		key_prefix: StorageKey,
235		block: Option<Block::Hash>,
236	) -> Result<Vec<StorageKey>, Error> {
237		check_if_safe(ext)?;
238		self.backend.storage_keys(block, key_prefix).map_err(Into::into)
239	}
240
241	fn storage_pairs(
242		&self,
243		ext: &Extensions,
244		key_prefix: StorageKey,
245		block: Option<Block::Hash>,
246	) -> Result<Vec<(StorageKey, StorageData)>, Error> {
247		check_if_safe(ext)?;
248		self.backend.storage_pairs(block, key_prefix).map_err(Into::into)
249	}
250
251	fn storage_keys_paged(
252		&self,
253		prefix: Option<StorageKey>,
254		count: u32,
255		start_key: Option<StorageKey>,
256		block: Option<Block::Hash>,
257	) -> Result<Vec<StorageKey>, Error> {
258		if count > STORAGE_KEYS_PAGED_MAX_COUNT {
259			return Err(Error::InvalidCount { value: count, max: STORAGE_KEYS_PAGED_MAX_COUNT });
260		}
261		self.backend
262			.storage_keys_paged(block, prefix, count, start_key)
263			.map_err(Into::into)
264	}
265
266	fn storage(
267		&self,
268		key: StorageKey,
269		block: Option<Block::Hash>,
270	) -> Result<Option<StorageData>, Error> {
271		self.backend.storage(block, key).map_err(Into::into)
272	}
273
274	fn storage_hash(
275		&self,
276		key: StorageKey,
277		block: Option<Block::Hash>,
278	) -> Result<Option<Block::Hash>, Error> {
279		self.backend.storage_hash(block, key).map_err(Into::into)
280	}
281
282	async fn storage_size(
283		&self,
284		ext: &Extensions,
285		key: StorageKey,
286		block: Option<Block::Hash>,
287	) -> Result<Option<u64>, Error> {
288		let deny_unsafe = ext
289			.get::<DenyUnsafe>()
290			.cloned()
291			.expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
292		self.backend.storage_size(block, key, deny_unsafe).await.map_err(Into::into)
293	}
294
295	fn metadata(&self, block: Option<Block::Hash>) -> Result<Bytes, Error> {
296		self.backend.metadata(block).map_err(Into::into)
297	}
298
299	fn runtime_version(&self, at: Option<Block::Hash>) -> Result<RuntimeVersion, Error> {
300		self.backend.runtime_version(at).map_err(Into::into)
301	}
302
303	fn query_storage(
304		&self,
305		ext: &Extensions,
306		keys: Vec<StorageKey>,
307		from: Block::Hash,
308		to: Option<Block::Hash>,
309	) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
310		check_if_safe(ext)?;
311		self.backend.query_storage(from, to, keys).map_err(Into::into)
312	}
313
314	fn query_storage_at(
315		&self,
316		keys: Vec<StorageKey>,
317		at: Option<Block::Hash>,
318	) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
319		self.backend.query_storage_at(keys, at).map_err(Into::into)
320	}
321
322	fn read_proof(
323		&self,
324		keys: Vec<StorageKey>,
325		block: Option<Block::Hash>,
326	) -> Result<ReadProof<Block::Hash>, Error> {
327		self.backend.read_proof(block, keys).map_err(Into::into)
328	}
329
330	/// Re-execute the given block with the tracing targets given in `targets`
331	/// and capture all state changes.
332	///
333	/// Note: requires the node to run with `--rpc-methods=Unsafe`.
334	/// Note: requires runtimes compiled with wasm tracing support, `--features with-tracing`.
335	fn trace_block(
336		&self,
337		ext: &Extensions,
338		block: Block::Hash,
339		targets: Option<String>,
340		storage_keys: Option<String>,
341		methods: Option<String>,
342	) -> Result<sp_rpc::tracing::TraceBlockResponse, Error> {
343		check_if_safe(ext)?;
344		self.backend
345			.trace_block(block, targets, storage_keys, methods)
346			.map_err(Into::into)
347	}
348
349	fn call_recorded(
350		&self,
351		ext: &Extensions,
352		method: String,
353		data: Bytes,
354		block: Block::Hash,
355	) -> Result<Bytes, Error> {
356		check_if_safe(ext).map_err(|_| Error::CallRecordedDenied)?;
357		self.backend.call_recorded(block, method, data).map_err(Into::into)
358	}
359
360	fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink) {
361		self.backend.subscribe_runtime_version(pending)
362	}
363
364	fn subscribe_storage(
365		&self,
366		pending: PendingSubscriptionSink,
367		ext: &Extensions,
368		keys: Option<Vec<StorageKey>>,
369	) {
370		let deny_unsafe = ext
371			.get::<DenyUnsafe>()
372			.cloned()
373			.expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
374		self.backend.subscribe_storage(pending, keys, deny_unsafe)
375	}
376}
377
378/// Child state backend API.
379pub trait ChildStateBackend<Block: BlockT, Client>: Send + Sync + 'static
380where
381	Block: BlockT + 'static,
382	Client: Send + Sync + 'static,
383{
384	/// Returns proof of storage for a child key entries at a specific block's state.
385	fn read_child_proof(
386		&self,
387		block: Option<Block::Hash>,
388		storage_key: PrefixedStorageKey,
389		keys: Vec<StorageKey>,
390	) -> Result<ReadProof<Block::Hash>, Error>;
391
392	/// Returns the keys with prefix from a child storage,
393	/// leave prefix empty to get all the keys.
394	fn storage_keys(
395		&self,
396		block: Option<Block::Hash>,
397		storage_key: PrefixedStorageKey,
398		prefix: StorageKey,
399	) -> Result<Vec<StorageKey>, Error>;
400
401	/// Returns the keys with prefix from a child storage with pagination support.
402	fn storage_keys_paged(
403		&self,
404		block: Option<Block::Hash>,
405		storage_key: PrefixedStorageKey,
406		prefix: Option<StorageKey>,
407		count: u32,
408		start_key: Option<StorageKey>,
409	) -> Result<Vec<StorageKey>, Error>;
410
411	/// Returns a child storage entry at a specific block's state.
412	fn storage(
413		&self,
414		block: Option<Block::Hash>,
415		storage_key: PrefixedStorageKey,
416		key: StorageKey,
417	) -> Result<Option<StorageData>, Error>;
418
419	/// Returns child storage entries at a specific block's state.
420	fn storage_entries(
421		&self,
422		block: Option<Block::Hash>,
423		storage_key: PrefixedStorageKey,
424		keys: Vec<StorageKey>,
425	) -> Result<Vec<Option<StorageData>>, Error>;
426
427	/// Returns the hash of a child storage entry at a block's state.
428	fn storage_hash(
429		&self,
430		block: Option<Block::Hash>,
431		storage_key: PrefixedStorageKey,
432		key: StorageKey,
433	) -> Result<Option<Block::Hash>, Error>;
434
435	/// Returns the size of a child storage entry at a block's state.
436	fn storage_size(
437		&self,
438		block: Option<Block::Hash>,
439		storage_key: PrefixedStorageKey,
440		key: StorageKey,
441	) -> Result<Option<u64>, Error> {
442		self.storage(block, storage_key, key).map(|x| x.map(|x| x.0.len() as u64))
443	}
444}
445
446/// Child state API with subscriptions support.
447pub struct ChildState<Block, Client> {
448	backend: Box<dyn ChildStateBackend<Block, Client>>,
449}
450
451impl<Block, Client> ChildStateApiServer<Block::Hash> for ChildState<Block, Client>
452where
453	Block: BlockT + 'static,
454	Client: Send + Sync + 'static,
455{
456	fn storage_keys(
457		&self,
458		ext: &Extensions,
459		storage_key: PrefixedStorageKey,
460		key_prefix: StorageKey,
461		block: Option<Block::Hash>,
462	) -> Result<Vec<StorageKey>, Error> {
463		check_if_safe(ext)?;
464		self.backend.storage_keys(block, storage_key, key_prefix).map_err(Into::into)
465	}
466
467	fn storage_keys_paged(
468		&self,
469		storage_key: PrefixedStorageKey,
470		prefix: Option<StorageKey>,
471		count: u32,
472		start_key: Option<StorageKey>,
473		block: Option<Block::Hash>,
474	) -> Result<Vec<StorageKey>, Error> {
475		self.backend
476			.storage_keys_paged(block, storage_key, prefix, count, start_key)
477			.map_err(Into::into)
478	}
479
480	fn storage(
481		&self,
482		storage_key: PrefixedStorageKey,
483		key: StorageKey,
484		block: Option<Block::Hash>,
485	) -> Result<Option<StorageData>, Error> {
486		self.backend.storage(block, storage_key, key).map_err(Into::into)
487	}
488
489	fn storage_entries(
490		&self,
491		storage_key: PrefixedStorageKey,
492		keys: Vec<StorageKey>,
493		block: Option<Block::Hash>,
494	) -> Result<Vec<Option<StorageData>>, Error> {
495		self.backend.storage_entries(block, storage_key, keys).map_err(Into::into)
496	}
497
498	fn storage_hash(
499		&self,
500		storage_key: PrefixedStorageKey,
501		key: StorageKey,
502		block: Option<Block::Hash>,
503	) -> Result<Option<Block::Hash>, Error> {
504		self.backend.storage_hash(block, storage_key, key).map_err(Into::into)
505	}
506
507	fn storage_size(
508		&self,
509		storage_key: PrefixedStorageKey,
510		key: StorageKey,
511		block: Option<Block::Hash>,
512	) -> Result<Option<u64>, Error> {
513		self.backend.storage_size(block, storage_key, key).map_err(Into::into)
514	}
515
516	fn read_child_proof(
517		&self,
518		child_storage_key: PrefixedStorageKey,
519		keys: Vec<StorageKey>,
520		block: Option<Block::Hash>,
521	) -> Result<ReadProof<Block::Hash>, Error> {
522		self.backend
523			.read_child_proof(block, child_storage_key, keys)
524			.map_err(Into::into)
525	}
526}
527
528fn client_err(err: sp_blockchain::Error) -> Error {
529	Error::Client(Box::new(err))
530}