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		key_prefix: StorageKey,
234		block: Option<Block::Hash>,
235	) -> Result<Vec<StorageKey>, Error> {
236		self.backend.storage_keys(block, key_prefix).map_err(Into::into)
237	}
238
239	fn storage_pairs(
240		&self,
241		ext: &Extensions,
242		key_prefix: StorageKey,
243		block: Option<Block::Hash>,
244	) -> Result<Vec<(StorageKey, StorageData)>, Error> {
245		check_if_safe(ext)?;
246		self.backend.storage_pairs(block, key_prefix).map_err(Into::into)
247	}
248
249	fn storage_keys_paged(
250		&self,
251		prefix: Option<StorageKey>,
252		count: u32,
253		start_key: Option<StorageKey>,
254		block: Option<Block::Hash>,
255	) -> Result<Vec<StorageKey>, Error> {
256		if count > STORAGE_KEYS_PAGED_MAX_COUNT {
257			return Err(Error::InvalidCount { value: count, max: STORAGE_KEYS_PAGED_MAX_COUNT });
258		}
259		self.backend
260			.storage_keys_paged(block, prefix, count, start_key)
261			.map_err(Into::into)
262	}
263
264	fn storage(
265		&self,
266		key: StorageKey,
267		block: Option<Block::Hash>,
268	) -> Result<Option<StorageData>, Error> {
269		self.backend.storage(block, key).map_err(Into::into)
270	}
271
272	fn storage_hash(
273		&self,
274		key: StorageKey,
275		block: Option<Block::Hash>,
276	) -> Result<Option<Block::Hash>, Error> {
277		self.backend.storage_hash(block, key).map_err(Into::into)
278	}
279
280	async fn storage_size(
281		&self,
282		ext: &Extensions,
283		key: StorageKey,
284		block: Option<Block::Hash>,
285	) -> Result<Option<u64>, Error> {
286		let deny_unsafe = ext
287			.get::<DenyUnsafe>()
288			.cloned()
289			.expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
290		self.backend.storage_size(block, key, deny_unsafe).await.map_err(Into::into)
291	}
292
293	fn metadata(&self, block: Option<Block::Hash>) -> Result<Bytes, Error> {
294		self.backend.metadata(block).map_err(Into::into)
295	}
296
297	fn runtime_version(&self, at: Option<Block::Hash>) -> Result<RuntimeVersion, Error> {
298		self.backend.runtime_version(at).map_err(Into::into)
299	}
300
301	fn query_storage(
302		&self,
303		ext: &Extensions,
304		keys: Vec<StorageKey>,
305		from: Block::Hash,
306		to: Option<Block::Hash>,
307	) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
308		check_if_safe(ext)?;
309		self.backend.query_storage(from, to, keys).map_err(Into::into)
310	}
311
312	fn query_storage_at(
313		&self,
314		keys: Vec<StorageKey>,
315		at: Option<Block::Hash>,
316	) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
317		self.backend.query_storage_at(keys, at).map_err(Into::into)
318	}
319
320	fn read_proof(
321		&self,
322		keys: Vec<StorageKey>,
323		block: Option<Block::Hash>,
324	) -> Result<ReadProof<Block::Hash>, Error> {
325		self.backend.read_proof(block, keys).map_err(Into::into)
326	}
327
328	/// Re-execute the given block with the tracing targets given in `targets`
329	/// and capture all state changes.
330	///
331	/// Note: requires the node to run with `--rpc-methods=Unsafe`.
332	/// Note: requires runtimes compiled with wasm tracing support, `--features with-tracing`.
333	fn trace_block(
334		&self,
335		ext: &Extensions,
336		block: Block::Hash,
337		targets: Option<String>,
338		storage_keys: Option<String>,
339		methods: Option<String>,
340	) -> Result<sp_rpc::tracing::TraceBlockResponse, Error> {
341		check_if_safe(ext)?;
342		self.backend
343			.trace_block(block, targets, storage_keys, methods)
344			.map_err(Into::into)
345	}
346
347	fn call_recorded(
348		&self,
349		ext: &Extensions,
350		method: String,
351		data: Bytes,
352		block: Block::Hash,
353	) -> Result<Bytes, Error> {
354		check_if_safe(ext).map_err(|_| Error::CallRecordedDenied)?;
355		self.backend.call_recorded(block, method, data).map_err(Into::into)
356	}
357
358	fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink) {
359		self.backend.subscribe_runtime_version(pending)
360	}
361
362	fn subscribe_storage(
363		&self,
364		pending: PendingSubscriptionSink,
365		ext: &Extensions,
366		keys: Option<Vec<StorageKey>>,
367	) {
368		let deny_unsafe = ext
369			.get::<DenyUnsafe>()
370			.cloned()
371			.expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
372		self.backend.subscribe_storage(pending, keys, deny_unsafe)
373	}
374}
375
376/// Child state backend API.
377pub trait ChildStateBackend<Block: BlockT, Client>: Send + Sync + 'static
378where
379	Block: BlockT + 'static,
380	Client: Send + Sync + 'static,
381{
382	/// Returns proof of storage for a child key entries at a specific block's state.
383	fn read_child_proof(
384		&self,
385		block: Option<Block::Hash>,
386		storage_key: PrefixedStorageKey,
387		keys: Vec<StorageKey>,
388	) -> Result<ReadProof<Block::Hash>, Error>;
389
390	/// Returns the keys with prefix from a child storage,
391	/// leave prefix empty to get all the keys.
392	fn storage_keys(
393		&self,
394		block: Option<Block::Hash>,
395		storage_key: PrefixedStorageKey,
396		prefix: StorageKey,
397	) -> Result<Vec<StorageKey>, Error>;
398
399	/// Returns the keys with prefix from a child storage with pagination support.
400	fn storage_keys_paged(
401		&self,
402		block: Option<Block::Hash>,
403		storage_key: PrefixedStorageKey,
404		prefix: Option<StorageKey>,
405		count: u32,
406		start_key: Option<StorageKey>,
407	) -> Result<Vec<StorageKey>, Error>;
408
409	/// Returns a child storage entry at a specific block's state.
410	fn storage(
411		&self,
412		block: Option<Block::Hash>,
413		storage_key: PrefixedStorageKey,
414		key: StorageKey,
415	) -> Result<Option<StorageData>, Error>;
416
417	/// Returns child storage entries at a specific block's state.
418	fn storage_entries(
419		&self,
420		block: Option<Block::Hash>,
421		storage_key: PrefixedStorageKey,
422		keys: Vec<StorageKey>,
423	) -> Result<Vec<Option<StorageData>>, Error>;
424
425	/// Returns the hash of a child storage entry at a block's state.
426	fn storage_hash(
427		&self,
428		block: Option<Block::Hash>,
429		storage_key: PrefixedStorageKey,
430		key: StorageKey,
431	) -> Result<Option<Block::Hash>, Error>;
432
433	/// Returns the size of a child storage entry at a block's state.
434	fn storage_size(
435		&self,
436		block: Option<Block::Hash>,
437		storage_key: PrefixedStorageKey,
438		key: StorageKey,
439	) -> Result<Option<u64>, Error> {
440		self.storage(block, storage_key, key).map(|x| x.map(|x| x.0.len() as u64))
441	}
442}
443
444/// Child state API with subscriptions support.
445pub struct ChildState<Block, Client> {
446	backend: Box<dyn ChildStateBackend<Block, Client>>,
447}
448
449impl<Block, Client> ChildStateApiServer<Block::Hash> for ChildState<Block, Client>
450where
451	Block: BlockT + 'static,
452	Client: Send + Sync + 'static,
453{
454	fn storage_keys(
455		&self,
456		storage_key: PrefixedStorageKey,
457		key_prefix: StorageKey,
458		block: Option<Block::Hash>,
459	) -> Result<Vec<StorageKey>, Error> {
460		self.backend.storage_keys(block, storage_key, key_prefix).map_err(Into::into)
461	}
462
463	fn storage_keys_paged(
464		&self,
465		storage_key: PrefixedStorageKey,
466		prefix: Option<StorageKey>,
467		count: u32,
468		start_key: Option<StorageKey>,
469		block: Option<Block::Hash>,
470	) -> Result<Vec<StorageKey>, Error> {
471		self.backend
472			.storage_keys_paged(block, storage_key, prefix, count, start_key)
473			.map_err(Into::into)
474	}
475
476	fn storage(
477		&self,
478		storage_key: PrefixedStorageKey,
479		key: StorageKey,
480		block: Option<Block::Hash>,
481	) -> Result<Option<StorageData>, Error> {
482		self.backend.storage(block, storage_key, key).map_err(Into::into)
483	}
484
485	fn storage_entries(
486		&self,
487		storage_key: PrefixedStorageKey,
488		keys: Vec<StorageKey>,
489		block: Option<Block::Hash>,
490	) -> Result<Vec<Option<StorageData>>, Error> {
491		self.backend.storage_entries(block, storage_key, keys).map_err(Into::into)
492	}
493
494	fn storage_hash(
495		&self,
496		storage_key: PrefixedStorageKey,
497		key: StorageKey,
498		block: Option<Block::Hash>,
499	) -> Result<Option<Block::Hash>, Error> {
500		self.backend.storage_hash(block, storage_key, key).map_err(Into::into)
501	}
502
503	fn storage_size(
504		&self,
505		storage_key: PrefixedStorageKey,
506		key: StorageKey,
507		block: Option<Block::Hash>,
508	) -> Result<Option<u64>, Error> {
509		self.backend.storage_size(block, storage_key, key).map_err(Into::into)
510	}
511
512	fn read_child_proof(
513		&self,
514		child_storage_key: PrefixedStorageKey,
515		keys: Vec<StorageKey>,
516		block: Option<Block::Hash>,
517	) -> Result<ReadProof<Block::Hash>, Error> {
518		self.backend
519			.read_child_proof(block, child_storage_key, keys)
520			.map_err(Into::into)
521	}
522}
523
524fn client_err(err: sp_blockchain::Error) -> Error {
525	Error::Client(Box::new(err))
526}