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