sc_rpc_spec_v2/common/
storage.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//! Storage queries for the RPC-V2 spec.
20
21use std::{marker::PhantomData, sync::Arc};
22
23use sc_client_api::{Backend, ChildInfo, StorageKey, StorageProvider};
24use sp_runtime::traits::Block as BlockT;
25
26use super::events::{StorageResult, StorageResultType};
27use crate::hex_string;
28
29/// Call into the storage of blocks.
30pub struct Storage<Client, Block, BE> {
31	/// Substrate client.
32	client: Arc<Client>,
33	_phandom: PhantomData<(BE, Block)>,
34}
35
36impl<Client, Block, BE> Storage<Client, Block, BE> {
37	/// Constructs a new [`Storage`].
38	pub fn new(client: Arc<Client>) -> Self {
39		Self { client, _phandom: PhantomData }
40	}
41}
42
43/// Query to iterate over storage.
44pub struct QueryIter {
45	/// The key from which the iteration was started.
46	pub query_key: StorageKey,
47	/// The key after which pagination should resume.
48	pub pagination_start_key: Option<StorageKey>,
49	/// The type of the query (either value or hash).
50	pub ty: IterQueryType,
51}
52
53/// The query type of an iteration.
54pub enum IterQueryType {
55	/// Iterating over (key, value) pairs.
56	Value,
57	/// Iterating over (key, hash) pairs.
58	Hash,
59}
60
61/// The result of making a query call.
62pub type QueryResult = Result<Option<StorageResult>, String>;
63
64/// The result of iterating over keys.
65pub type QueryIterResult = Result<(Vec<StorageResult>, Option<QueryIter>), String>;
66
67impl<Client, Block, BE> Storage<Client, Block, BE>
68where
69	Block: BlockT + 'static,
70	BE: Backend<Block> + 'static,
71	Client: StorageProvider<Block, BE> + 'static,
72{
73	/// Fetch the value from storage.
74	pub fn query_value(
75		&self,
76		hash: Block::Hash,
77		key: &StorageKey,
78		child_key: Option<&ChildInfo>,
79	) -> QueryResult {
80		let result = if let Some(child_key) = child_key {
81			self.client.child_storage(hash, child_key, key)
82		} else {
83			self.client.storage(hash, key)
84		};
85
86		result
87			.map(|opt| {
88				QueryResult::Ok(opt.map(|storage_data| StorageResult {
89					key: hex_string(&key.0),
90					result: StorageResultType::Value(hex_string(&storage_data.0)),
91				}))
92			})
93			.unwrap_or_else(|error| QueryResult::Err(error.to_string()))
94	}
95
96	/// Fetch the hash of a value from storage.
97	pub fn query_hash(
98		&self,
99		hash: Block::Hash,
100		key: &StorageKey,
101		child_key: Option<&ChildInfo>,
102	) -> QueryResult {
103		let result = if let Some(child_key) = child_key {
104			self.client.child_storage_hash(hash, child_key, key)
105		} else {
106			self.client.storage_hash(hash, key)
107		};
108
109		result
110			.map(|opt| {
111				QueryResult::Ok(opt.map(|storage_data| StorageResult {
112					key: hex_string(&key.0),
113					result: StorageResultType::Hash(hex_string(&storage_data.as_ref())),
114				}))
115			})
116			.unwrap_or_else(|error| QueryResult::Err(error.to_string()))
117	}
118
119	/// Fetch the closest merkle value.
120	pub fn query_merkle_value(
121		&self,
122		hash: Block::Hash,
123		key: &StorageKey,
124		child_key: Option<&ChildInfo>,
125	) -> QueryResult {
126		let result = if let Some(child_key) = child_key {
127			self.client.child_closest_merkle_value(hash, child_key, key)
128		} else {
129			self.client.closest_merkle_value(hash, key)
130		};
131
132		result
133			.map(|opt| {
134				QueryResult::Ok(opt.map(|storage_data| {
135					let result = match &storage_data {
136						sc_client_api::MerkleValue::Node(data) => hex_string(&data.as_slice()),
137						sc_client_api::MerkleValue::Hash(hash) => hex_string(&hash.as_ref()),
138					};
139
140					StorageResult {
141						key: hex_string(&key.0),
142						result: StorageResultType::ClosestDescendantMerkleValue(result),
143					}
144				}))
145			})
146			.unwrap_or_else(|error| QueryResult::Err(error.to_string()))
147	}
148
149	/// Iterate over at most the provided number of keys.
150	///
151	/// Returns the storage result with a potential next key to resume iteration.
152	pub fn query_iter_pagination(
153		&self,
154		query: QueryIter,
155		hash: Block::Hash,
156		child_key: Option<&ChildInfo>,
157		count: usize,
158	) -> QueryIterResult {
159		let QueryIter { ty, query_key, pagination_start_key } = query;
160
161		let mut keys_iter = if let Some(child_key) = child_key {
162			self.client.child_storage_keys(
163				hash,
164				child_key.to_owned(),
165				Some(&query_key),
166				pagination_start_key.as_ref(),
167			)
168		} else {
169			self.client.storage_keys(hash, Some(&query_key), pagination_start_key.as_ref())
170		}
171		.map_err(|err| err.to_string())?;
172
173		let mut ret = Vec::with_capacity(count);
174		let mut next_pagination_key = None;
175		for _ in 0..count {
176			let Some(key) = keys_iter.next() else { break };
177
178			next_pagination_key = Some(key.clone());
179
180			let result = match ty {
181				IterQueryType::Value => self.query_value(hash, &key, child_key),
182				IterQueryType::Hash => self.query_hash(hash, &key, child_key),
183			}?;
184
185			if let Some(value) = result {
186				ret.push(value);
187			}
188		}
189
190		// Save the next key if any to continue the iteration.
191		let maybe_next_query = keys_iter.next().map(|_| QueryIter {
192			ty,
193			query_key,
194			pagination_start_key: next_pagination_key,
195		});
196		Ok((ret, maybe_next_query))
197	}
198}