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	/// New runtime version subscription
153	fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink);
154
155	/// New storage subscription
156	fn subscribe_storage(
157		&self,
158		pending: PendingSubscriptionSink,
159		keys: Option<Vec<StorageKey>>,
160		deny_unsafe: DenyUnsafe,
161	);
162}
163
164/// Create new state API that works on full node.
165pub fn new_full<BE, Block: BlockT, Client>(
166	client: Arc<Client>,
167	executor: SubscriptionTaskExecutor,
168	execute_block: Option<Arc<dyn TracingExecuteBlock<Block>>>,
169) -> (State<Block, Client>, ChildState<Block, Client>)
170where
171	Block: BlockT + 'static,
172	Block::Hash: Unpin,
173	BE: Backend<Block> + 'static,
174	Client: ExecutorProvider<Block>
175		+ StorageProvider<Block, BE>
176		+ ProofProvider<Block>
177		+ HeaderMetadata<Block, Error = sp_blockchain::Error>
178		+ BlockchainEvents<Block>
179		+ CallApiAt<Block>
180		+ HeaderBackend<Block>
181		+ BlockBackend<Block>
182		+ ProvideRuntimeApi<Block>
183		+ Send
184		+ Sync
185		+ 'static,
186	Client::Api: Metadata<Block>,
187{
188	let child_backend = Box::new(self::state_full::FullState::new(
189		client.clone(),
190		executor.clone(),
191		execute_block.clone(),
192	));
193	let backend =
194		Box::new(self::state_full::FullState::new(client, executor, execute_block.clone()));
195	(State { backend }, ChildState { backend: child_backend })
196}
197
198/// State API with subscriptions support.
199pub struct State<Block, Client> {
200	backend: Box<dyn StateBackend<Block, Client>>,
201}
202
203#[async_trait]
204impl<Block, Client> StateApiServer<Block::Hash> for State<Block, Client>
205where
206	Block: BlockT + 'static,
207	Client: Send + Sync + 'static,
208{
209	fn call(
210		&self,
211		method: String,
212		data: Bytes,
213		block: Option<Block::Hash>,
214	) -> Result<Bytes, Error> {
215		self.backend.call(block, method, data).map_err(Into::into)
216	}
217
218	fn storage_keys(
219		&self,
220		key_prefix: StorageKey,
221		block: Option<Block::Hash>,
222	) -> Result<Vec<StorageKey>, Error> {
223		self.backend.storage_keys(block, key_prefix).map_err(Into::into)
224	}
225
226	fn storage_pairs(
227		&self,
228		ext: &Extensions,
229		key_prefix: StorageKey,
230		block: Option<Block::Hash>,
231	) -> Result<Vec<(StorageKey, StorageData)>, Error> {
232		check_if_safe(ext)?;
233		self.backend.storage_pairs(block, key_prefix).map_err(Into::into)
234	}
235
236	fn storage_keys_paged(
237		&self,
238		prefix: Option<StorageKey>,
239		count: u32,
240		start_key: Option<StorageKey>,
241		block: Option<Block::Hash>,
242	) -> Result<Vec<StorageKey>, Error> {
243		if count > STORAGE_KEYS_PAGED_MAX_COUNT {
244			return Err(Error::InvalidCount { value: count, max: STORAGE_KEYS_PAGED_MAX_COUNT })
245		}
246		self.backend
247			.storage_keys_paged(block, prefix, count, start_key)
248			.map_err(Into::into)
249	}
250
251	fn storage(
252		&self,
253		key: StorageKey,
254		block: Option<Block::Hash>,
255	) -> Result<Option<StorageData>, Error> {
256		self.backend.storage(block, key).map_err(Into::into)
257	}
258
259	fn storage_hash(
260		&self,
261		key: StorageKey,
262		block: Option<Block::Hash>,
263	) -> Result<Option<Block::Hash>, Error> {
264		self.backend.storage_hash(block, key).map_err(Into::into)
265	}
266
267	async fn storage_size(
268		&self,
269		ext: &Extensions,
270		key: StorageKey,
271		block: Option<Block::Hash>,
272	) -> Result<Option<u64>, Error> {
273		let deny_unsafe = ext
274			.get::<DenyUnsafe>()
275			.cloned()
276			.expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
277		self.backend.storage_size(block, key, deny_unsafe).await.map_err(Into::into)
278	}
279
280	fn metadata(&self, block: Option<Block::Hash>) -> Result<Bytes, Error> {
281		self.backend.metadata(block).map_err(Into::into)
282	}
283
284	fn runtime_version(&self, at: Option<Block::Hash>) -> Result<RuntimeVersion, Error> {
285		self.backend.runtime_version(at).map_err(Into::into)
286	}
287
288	fn query_storage(
289		&self,
290		ext: &Extensions,
291		keys: Vec<StorageKey>,
292		from: Block::Hash,
293		to: Option<Block::Hash>,
294	) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
295		check_if_safe(ext)?;
296		self.backend.query_storage(from, to, keys).map_err(Into::into)
297	}
298
299	fn query_storage_at(
300		&self,
301		keys: Vec<StorageKey>,
302		at: Option<Block::Hash>,
303	) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
304		self.backend.query_storage_at(keys, at).map_err(Into::into)
305	}
306
307	fn read_proof(
308		&self,
309		keys: Vec<StorageKey>,
310		block: Option<Block::Hash>,
311	) -> Result<ReadProof<Block::Hash>, Error> {
312		self.backend.read_proof(block, keys).map_err(Into::into)
313	}
314
315	/// Re-execute the given block with the tracing targets given in `targets`
316	/// and capture all state changes.
317	///
318	/// Note: requires the node to run with `--rpc-methods=Unsafe`.
319	/// Note: requires runtimes compiled with wasm tracing support, `--features with-tracing`.
320	fn trace_block(
321		&self,
322		ext: &Extensions,
323		block: Block::Hash,
324		targets: Option<String>,
325		storage_keys: Option<String>,
326		methods: Option<String>,
327	) -> Result<sp_rpc::tracing::TraceBlockResponse, Error> {
328		check_if_safe(ext)?;
329		self.backend
330			.trace_block(block, targets, storage_keys, methods)
331			.map_err(Into::into)
332	}
333
334	fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink) {
335		self.backend.subscribe_runtime_version(pending)
336	}
337
338	fn subscribe_storage(
339		&self,
340		pending: PendingSubscriptionSink,
341		ext: &Extensions,
342		keys: Option<Vec<StorageKey>>,
343	) {
344		let deny_unsafe = ext
345			.get::<DenyUnsafe>()
346			.cloned()
347			.expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
348		self.backend.subscribe_storage(pending, keys, deny_unsafe)
349	}
350}
351
352/// Child state backend API.
353pub trait ChildStateBackend<Block: BlockT, Client>: Send + Sync + 'static
354where
355	Block: BlockT + 'static,
356	Client: Send + Sync + 'static,
357{
358	/// Returns proof of storage for a child key entries at a specific block's state.
359	fn read_child_proof(
360		&self,
361		block: Option<Block::Hash>,
362		storage_key: PrefixedStorageKey,
363		keys: Vec<StorageKey>,
364	) -> Result<ReadProof<Block::Hash>, Error>;
365
366	/// Returns the keys with prefix from a child storage,
367	/// leave prefix empty to get all the keys.
368	fn storage_keys(
369		&self,
370		block: Option<Block::Hash>,
371		storage_key: PrefixedStorageKey,
372		prefix: StorageKey,
373	) -> Result<Vec<StorageKey>, Error>;
374
375	/// Returns the keys with prefix from a child storage with pagination support.
376	fn storage_keys_paged(
377		&self,
378		block: Option<Block::Hash>,
379		storage_key: PrefixedStorageKey,
380		prefix: Option<StorageKey>,
381		count: u32,
382		start_key: Option<StorageKey>,
383	) -> Result<Vec<StorageKey>, Error>;
384
385	/// Returns a child storage entry at a specific block's state.
386	fn storage(
387		&self,
388		block: Option<Block::Hash>,
389		storage_key: PrefixedStorageKey,
390		key: StorageKey,
391	) -> Result<Option<StorageData>, Error>;
392
393	/// Returns child storage entries at a specific block's state.
394	fn storage_entries(
395		&self,
396		block: Option<Block::Hash>,
397		storage_key: PrefixedStorageKey,
398		keys: Vec<StorageKey>,
399	) -> Result<Vec<Option<StorageData>>, Error>;
400
401	/// Returns the hash of a child storage entry at a block's state.
402	fn storage_hash(
403		&self,
404		block: Option<Block::Hash>,
405		storage_key: PrefixedStorageKey,
406		key: StorageKey,
407	) -> Result<Option<Block::Hash>, Error>;
408
409	/// Returns the size of a child storage entry at a block's state.
410	fn storage_size(
411		&self,
412		block: Option<Block::Hash>,
413		storage_key: PrefixedStorageKey,
414		key: StorageKey,
415	) -> Result<Option<u64>, Error> {
416		self.storage(block, storage_key, key).map(|x| x.map(|x| x.0.len() as u64))
417	}
418}
419
420/// Child state API with subscriptions support.
421pub struct ChildState<Block, Client> {
422	backend: Box<dyn ChildStateBackend<Block, Client>>,
423}
424
425impl<Block, Client> ChildStateApiServer<Block::Hash> for ChildState<Block, Client>
426where
427	Block: BlockT + 'static,
428	Client: Send + Sync + 'static,
429{
430	fn storage_keys(
431		&self,
432		storage_key: PrefixedStorageKey,
433		key_prefix: StorageKey,
434		block: Option<Block::Hash>,
435	) -> Result<Vec<StorageKey>, Error> {
436		self.backend.storage_keys(block, storage_key, key_prefix).map_err(Into::into)
437	}
438
439	fn storage_keys_paged(
440		&self,
441		storage_key: PrefixedStorageKey,
442		prefix: Option<StorageKey>,
443		count: u32,
444		start_key: Option<StorageKey>,
445		block: Option<Block::Hash>,
446	) -> Result<Vec<StorageKey>, Error> {
447		self.backend
448			.storage_keys_paged(block, storage_key, prefix, count, start_key)
449			.map_err(Into::into)
450	}
451
452	fn storage(
453		&self,
454		storage_key: PrefixedStorageKey,
455		key: StorageKey,
456		block: Option<Block::Hash>,
457	) -> Result<Option<StorageData>, Error> {
458		self.backend.storage(block, storage_key, key).map_err(Into::into)
459	}
460
461	fn storage_entries(
462		&self,
463		storage_key: PrefixedStorageKey,
464		keys: Vec<StorageKey>,
465		block: Option<Block::Hash>,
466	) -> Result<Vec<Option<StorageData>>, Error> {
467		self.backend.storage_entries(block, storage_key, keys).map_err(Into::into)
468	}
469
470	fn storage_hash(
471		&self,
472		storage_key: PrefixedStorageKey,
473		key: StorageKey,
474		block: Option<Block::Hash>,
475	) -> Result<Option<Block::Hash>, Error> {
476		self.backend.storage_hash(block, storage_key, key).map_err(Into::into)
477	}
478
479	fn storage_size(
480		&self,
481		storage_key: PrefixedStorageKey,
482		key: StorageKey,
483		block: Option<Block::Hash>,
484	) -> Result<Option<u64>, Error> {
485		self.backend.storage_size(block, storage_key, key).map_err(Into::into)
486	}
487
488	fn read_child_proof(
489		&self,
490		child_storage_key: PrefixedStorageKey,
491		keys: Vec<StorageKey>,
492		block: Option<Block::Hash>,
493	) -> Result<ReadProof<Block::Hash>, Error> {
494		self.backend
495			.read_child_proof(block, child_storage_key, keys)
496			.map_err(Into::into)
497	}
498}
499
500fn client_err(err: sp_blockchain::Error) -> Error {
501	Error::Client(Box::new(err))
502}