sc_rpc_spec_v2/archive/
archive_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//! Implementation of the `archive_storage` method.
20
21use std::sync::Arc;
22
23use sc_client_api::{Backend, ChildInfo, StorageKey, StorageProvider};
24use sp_runtime::traits::Block as BlockT;
25
26use crate::common::{
27	events::{ArchiveStorageResult, PaginatedStorageQuery, StorageQueryType},
28	storage::{IterQueryType, QueryIter, Storage},
29};
30
31/// Generates the events of the `archive_storage` method.
32pub struct ArchiveStorage<Client, Block, BE> {
33	/// Storage client.
34	client: Storage<Client, Block, BE>,
35	/// The maximum number of responses the API can return for a descendant query at a time.
36	storage_max_descendant_responses: usize,
37	/// The maximum number of queried items allowed for the `archive_storage` at a time.
38	storage_max_queried_items: usize,
39}
40
41impl<Client, Block, BE> ArchiveStorage<Client, Block, BE> {
42	/// Constructs a new [`ArchiveStorage`].
43	pub fn new(
44		client: Arc<Client>,
45		storage_max_descendant_responses: usize,
46		storage_max_queried_items: usize,
47	) -> Self {
48		Self {
49			client: Storage::new(client),
50			storage_max_descendant_responses,
51			storage_max_queried_items,
52		}
53	}
54}
55
56impl<Client, Block, BE> ArchiveStorage<Client, Block, BE>
57where
58	Block: BlockT + 'static,
59	BE: Backend<Block> + 'static,
60	Client: StorageProvider<Block, BE> + 'static,
61{
62	/// Generate the response of the `archive_storage` method.
63	pub fn handle_query(
64		&self,
65		hash: Block::Hash,
66		mut items: Vec<PaginatedStorageQuery<StorageKey>>,
67		child_key: Option<ChildInfo>,
68	) -> ArchiveStorageResult {
69		let discarded_items = items.len().saturating_sub(self.storage_max_queried_items);
70		items.truncate(self.storage_max_queried_items);
71
72		let mut storage_results = Vec::with_capacity(items.len());
73		for item in items {
74			match item.query_type {
75				StorageQueryType::Value => {
76					match self.client.query_value(hash, &item.key, child_key.as_ref()) {
77						Ok(Some(value)) => storage_results.push(value),
78						Ok(None) => continue,
79						Err(error) => return ArchiveStorageResult::err(error),
80					}
81				},
82				StorageQueryType::Hash =>
83					match self.client.query_hash(hash, &item.key, child_key.as_ref()) {
84						Ok(Some(value)) => storage_results.push(value),
85						Ok(None) => continue,
86						Err(error) => return ArchiveStorageResult::err(error),
87					},
88				StorageQueryType::ClosestDescendantMerkleValue =>
89					match self.client.query_merkle_value(hash, &item.key, child_key.as_ref()) {
90						Ok(Some(value)) => storage_results.push(value),
91						Ok(None) => continue,
92						Err(error) => return ArchiveStorageResult::err(error),
93					},
94				StorageQueryType::DescendantsValues => {
95					match self.client.query_iter_pagination(
96						QueryIter {
97							query_key: item.key,
98							ty: IterQueryType::Value,
99							pagination_start_key: item.pagination_start_key,
100						},
101						hash,
102						child_key.as_ref(),
103						self.storage_max_descendant_responses,
104					) {
105						Ok((results, _)) => storage_results.extend(results),
106						Err(error) => return ArchiveStorageResult::err(error),
107					}
108				},
109				StorageQueryType::DescendantsHashes => {
110					match self.client.query_iter_pagination(
111						QueryIter {
112							query_key: item.key,
113							ty: IterQueryType::Hash,
114							pagination_start_key: item.pagination_start_key,
115						},
116						hash,
117						child_key.as_ref(),
118						self.storage_max_descendant_responses,
119					) {
120						Ok((results, _)) => storage_results.extend(results),
121						Err(error) => return ArchiveStorageResult::err(error),
122					}
123				},
124			};
125		}
126
127		ArchiveStorageResult::ok(storage_results, discarded_items)
128	}
129}