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	ClientError, LOG_TARGET,
20	client::{SubscriptionType, SubstrateBlock, SubstrateBlockNumber},
21	subxt_client::SrcChainConfig,
22};
23use jsonrpsee::core::async_trait;
24use sp_core::H256;
25use std::sync::Arc;
26use subxt::{OnlineClient, backend::legacy::LegacyRpcMethods};
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: Arc<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: Arc<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 = 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(_))) => {
144				log::trace!(target: LOG_TARGET, "block_by_hash: block {hash:?} not found");
145				Ok(None)
146			},
147			Err(err) => {
148				log::trace!(target: LOG_TARGET, "block_by_hash: failed to fetch block {hash:?}: {err:?}");
149				Err(err.into())
150			},
151		}
152	}
153}
154
155#[cfg(test)]
156pub mod test {
157	use super::*;
158	use crate::BlockInfo;
159
160	/// A Noop BlockInfoProvider used to test [`db::ReceiptProvider`].
161	pub struct MockBlockInfoProvider;
162
163	pub struct MockBlockInfo {
164		pub number: SubstrateBlockNumber,
165		pub hash: H256,
166	}
167
168	impl BlockInfo for MockBlockInfo {
169		fn hash(&self) -> H256 {
170			self.hash
171		}
172		fn number(&self) -> SubstrateBlockNumber {
173			self.number
174		}
175	}
176
177	#[async_trait]
178	impl BlockInfoProvider for MockBlockInfoProvider {
179		async fn update_latest(
180			&self,
181			_block: Arc<SubstrateBlock>,
182			_subscription_type: SubscriptionType,
183		) {
184		}
185
186		async fn latest_finalized_block(&self) -> Arc<SubstrateBlock> {
187			unimplemented!()
188		}
189
190		async fn latest_block(&self) -> Arc<SubstrateBlock> {
191			unimplemented!()
192		}
193
194		async fn latest_block_number(&self) -> SubstrateBlockNumber {
195			2u32
196		}
197
198		async fn block_by_number(
199			&self,
200			_block_number: SubstrateBlockNumber,
201		) -> Result<Option<Arc<SubstrateBlock>>, ClientError> {
202			Ok(None)
203		}
204
205		async fn block_by_hash(
206			&self,
207			_hash: &H256,
208		) -> Result<Option<Arc<SubstrateBlock>>, ClientError> {
209			Ok(None)
210		}
211	}
212}