referrerpolicy=no-referrer-when-downgrade

sc_rpc_spec_v2/chain_head/
chain_head_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 `chainHead_storage` method.
20
21use std::{marker::PhantomData, sync::Arc};
22
23use sc_client_api::{Backend, ChildInfo, StorageKey, StorageProvider};
24use sp_runtime::traits::Block as BlockT;
25use tokio::sync::mpsc;
26
27use crate::common::{
28	events::{StorageQuery, StorageQueryType},
29	storage::{IterQueryType, QueryIter, QueryResult, Storage},
30};
31
32/// Generates the events of the `chainHead_storage` method.
33pub struct ChainHeadStorage<Client, Block, BE> {
34	/// Storage client.
35	client: Storage<Client, Block, BE>,
36	_phandom: PhantomData<(BE, Block)>,
37}
38
39impl<Client, Block, BE> Clone for ChainHeadStorage<Client, Block, BE> {
40	fn clone(&self) -> Self {
41		Self { client: self.client.clone(), _phandom: PhantomData }
42	}
43}
44
45impl<Client, Block, BE> ChainHeadStorage<Client, Block, BE> {
46	/// Constructs a new [`ChainHeadStorage`].
47	pub fn new(client: Arc<Client>) -> Self {
48		Self { client: Storage::new(client), _phandom: PhantomData }
49	}
50}
51
52impl<Client, Block, BE> ChainHeadStorage<Client, Block, BE>
53where
54	Block: BlockT + 'static,
55	BE: Backend<Block> + 'static,
56	Client: StorageProvider<Block, BE> + Send + Sync + 'static,
57{
58	/// Generate the block events for the `chainHead_storage` method.
59	pub async fn generate_events(
60		&mut self,
61		hash: Block::Hash,
62		items: Vec<StorageQuery<StorageKey>>,
63		child_key: Option<ChildInfo>,
64		tx: mpsc::Sender<QueryResult>,
65	) -> Result<(), tokio::task::JoinError> {
66		let this = self.clone();
67
68		tokio::task::spawn_blocking(move || {
69			for item in items {
70				match item.query_type {
71					StorageQueryType::Value => {
72						let rp = this.client.query_value(hash, &item.key, child_key.as_ref());
73						if tx.blocking_send(rp).is_err() {
74							break;
75						}
76					},
77					StorageQueryType::Hash => {
78						let rp = this.client.query_hash(hash, &item.key, child_key.as_ref());
79						if tx.blocking_send(rp).is_err() {
80							break;
81						}
82					},
83					StorageQueryType::ClosestDescendantMerkleValue => {
84						let rp =
85							this.client.query_merkle_value(hash, &item.key, child_key.as_ref());
86						if tx.blocking_send(rp).is_err() {
87							break;
88						}
89					},
90					StorageQueryType::DescendantsValues => {
91						let query = QueryIter {
92							query_key: item.key,
93							ty: IterQueryType::Value,
94							pagination_start_key: None,
95						};
96						this.client.query_iter_pagination_with_producer(
97							query,
98							hash,
99							child_key.as_ref(),
100							&tx,
101						)
102					},
103					StorageQueryType::DescendantsHashes => {
104						let query = QueryIter {
105							query_key: item.key,
106							ty: IterQueryType::Hash,
107							pagination_start_key: None,
108						};
109						this.client.query_iter_pagination_with_producer(
110							query,
111							hash,
112							child_key.as_ref(),
113							&tx,
114						)
115					},
116				}
117			}
118		})
119		.await?;
120
121		Ok(())
122	}
123}