referrerpolicy=no-referrer-when-downgrade

pallet_revive_eth_rpc/
block_info_provider.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use crate::{
19	client::{SubscriptionType, SubstrateBlock, SubstrateBlockNumber},
20	subxt_client::SrcChainConfig,
21	ClientError,
22};
23use jsonrpsee::core::async_trait;
24use sp_core::H256;
25use std::sync::Arc;
26use subxt::{backend::legacy::LegacyRpcMethods, OnlineClient};
27use tokio::sync::RwLock;
28
29/// BlockInfoProvider cache and retrieves information about blocks.
30#[async_trait]
31pub trait BlockInfoProvider: Send + Sync {
32	/// Update the latest block
33	async fn update_latest(&self, block: SubstrateBlock, subscription_type: SubscriptionType);
34
35	/// Return the latest finalized block.
36	async fn latest_finalized_block(&self) -> Arc<SubstrateBlock>;
37
38	/// Return the latest block.
39	async fn latest_block(&self) -> Arc<SubstrateBlock>;
40
41	/// Return the latest block number
42	async fn latest_block_number(&self) -> SubstrateBlockNumber {
43		return self.latest_block().await.number()
44	}
45
46	/// Get block by block_number.
47	async fn block_by_number(
48		&self,
49		block_number: SubstrateBlockNumber,
50	) -> Result<Option<Arc<SubstrateBlock>>, ClientError>;
51
52	/// Get block by block hash.
53	async fn block_by_hash(&self, hash: &H256) -> Result<Option<Arc<SubstrateBlock>>, ClientError>;
54}
55
56/// Provides information about blocks.
57#[derive(Clone)]
58pub struct SubxtBlockInfoProvider {
59	/// The latest block.
60	latest_block: Arc<RwLock<Arc<SubstrateBlock>>>,
61
62	/// The latest finalized block.
63	latest_finalized_block: Arc<RwLock<Arc<SubstrateBlock>>>,
64
65	/// The rpc client, used to fetch blocks not in the cache.
66	rpc: LegacyRpcMethods<SrcChainConfig>,
67
68	/// The api client, used to fetch blocks not in the cache.
69	api: OnlineClient<SrcChainConfig>,
70}
71
72impl SubxtBlockInfoProvider {
73	pub async fn new(
74		api: OnlineClient<SrcChainConfig>,
75		rpc: LegacyRpcMethods<SrcChainConfig>,
76	) -> Result<Self, ClientError> {
77		let latest = Arc::new(api.blocks().at_latest().await?);
78		Ok(Self {
79			api,
80			rpc,
81			latest_block: Arc::new(RwLock::new(latest.clone())),
82			latest_finalized_block: Arc::new(RwLock::new(latest)),
83		})
84	}
85}
86
87#[async_trait]
88impl BlockInfoProvider for SubxtBlockInfoProvider {
89	async fn update_latest(&self, block: SubstrateBlock, subscription_type: SubscriptionType) {
90		let mut latest = match subscription_type {
91			SubscriptionType::FinalizedBlocks => self.latest_finalized_block.write().await,
92			SubscriptionType::BestBlocks => self.latest_block.write().await,
93		};
94		*latest = Arc::new(block);
95	}
96
97	async fn latest_block(&self) -> Arc<SubstrateBlock> {
98		self.latest_block.read().await.clone()
99	}
100
101	async fn latest_finalized_block(&self) -> Arc<SubstrateBlock> {
102		self.latest_finalized_block.read().await.clone()
103	}
104
105	async fn block_by_number(
106		&self,
107		block_number: SubstrateBlockNumber,
108	) -> Result<Option<Arc<SubstrateBlock>>, ClientError> {
109		let latest = self.latest_block().await;
110		if block_number == latest.number() {
111			return Ok(Some(latest));
112		}
113
114		let latest_finalized = self.latest_finalized_block().await;
115		if block_number == latest_finalized.number() {
116			return Ok(Some(latest_finalized));
117		}
118
119		let Some(hash) = self.rpc.chain_get_block_hash(Some(block_number.into())).await? else {
120			return Ok(None);
121		};
122
123		match self.api.blocks().at(hash).await {
124			Ok(block) => Ok(Some(Arc::new(block))),
125			Err(subxt::Error::Block(subxt::error::BlockError::NotFound(_))) => Ok(None),
126			Err(err) => Err(err.into()),
127		}
128	}
129
130	async fn block_by_hash(&self, hash: &H256) -> Result<Option<Arc<SubstrateBlock>>, ClientError> {
131		let latest = self.latest_block().await;
132		if hash == &latest.hash() {
133			return Ok(Some(latest));
134		}
135
136		let latest_finalized = self.latest_finalized_block().await;
137		if hash == &latest_finalized.hash() {
138			return Ok(Some(latest_finalized));
139		}
140
141		match self.api.blocks().at(*hash).await {
142			Ok(block) => Ok(Some(Arc::new(block))),
143			Err(subxt::Error::Block(subxt::error::BlockError::NotFound(_))) => Ok(None),
144			Err(err) => Err(err.into()),
145		}
146	}
147}
148
149#[cfg(test)]
150pub mod test {
151	use super::*;
152	use crate::BlockInfo;
153
154	/// A Noop BlockInfoProvider used to test [`db::ReceiptProvider`].
155	pub struct MockBlockInfoProvider;
156
157	pub struct MockBlockInfo {
158		pub number: SubstrateBlockNumber,
159		pub hash: H256,
160	}
161
162	impl BlockInfo for MockBlockInfo {
163		fn hash(&self) -> H256 {
164			self.hash
165		}
166		fn number(&self) -> SubstrateBlockNumber {
167			self.number
168		}
169	}
170
171	#[async_trait]
172	impl BlockInfoProvider for MockBlockInfoProvider {
173		async fn update_latest(
174			&self,
175			_block: SubstrateBlock,
176			_subscription_type: SubscriptionType,
177		) {
178		}
179
180		async fn latest_finalized_block(&self) -> Arc<SubstrateBlock> {
181			unimplemented!()
182		}
183
184		async fn latest_block(&self) -> Arc<SubstrateBlock> {
185			unimplemented!()
186		}
187
188		async fn latest_block_number(&self) -> SubstrateBlockNumber {
189			2u32
190		}
191
192		async fn block_by_number(
193			&self,
194			_block_number: SubstrateBlockNumber,
195		) -> Result<Option<Arc<SubstrateBlock>>, ClientError> {
196			Ok(None)
197		}
198
199		async fn block_by_hash(
200			&self,
201			_hash: &H256,
202		) -> Result<Option<Arc<SubstrateBlock>>, ClientError> {
203			Ok(None)
204		}
205	}
206}