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::{
27	OnlineClient, config::RpcConfigFor, error::OnlineClientAtBlockError,
28	rpcs::methods::LegacyRpcMethods,
29};
30use tokio::sync::RwLock;
31
32/// BlockInfoProvider cache and retrieves information about blocks.
33#[async_trait]
34pub trait BlockInfoProvider: Send + Sync {
35	/// Update the latest block
36	async fn update_latest(&self, block: Arc<SubstrateBlock>, subscription_type: SubscriptionType);
37
38	/// Return the latest finalized block.
39	async fn latest_finalized_block(&self) -> Arc<SubstrateBlock>;
40
41	/// Return the latest block.
42	async fn latest_block(&self) -> Arc<SubstrateBlock>;
43
44	/// Return the latest block number
45	async fn latest_block_number(&self) -> SubstrateBlockNumber {
46		return self.latest_block().await.block_number();
47	}
48
49	/// Get block by block_number.
50	async fn block_by_number(
51		&self,
52		block_number: SubstrateBlockNumber,
53	) -> Result<Option<Arc<SubstrateBlock>>, ClientError>;
54
55	/// Get block by block hash.
56	async fn block_by_hash(&self, hash: &H256) -> Result<Option<Arc<SubstrateBlock>>, ClientError>;
57}
58
59/// Provides information about blocks.
60#[derive(Clone)]
61pub struct SubxtBlockInfoProvider {
62	/// The latest block.
63	latest_block: Arc<RwLock<Arc<SubstrateBlock>>>,
64
65	/// The latest finalized block.
66	latest_finalized_block: Arc<RwLock<Arc<SubstrateBlock>>>,
67
68	/// The rpc client, used to fetch blocks not in the cache.
69	rpc: LegacyRpcMethods<RpcConfigFor<SrcChainConfig>>,
70
71	/// The api client, used to fetch blocks not in the cache.
72	api: OnlineClient<SrcChainConfig>,
73}
74
75impl SubxtBlockInfoProvider {
76	pub async fn new(
77		api: OnlineClient<SrcChainConfig>,
78		rpc: LegacyRpcMethods<RpcConfigFor<SrcChainConfig>>,
79	) -> Result<Self, ClientError> {
80		let latest = Arc::new(api.at_current_block().await?);
81		Ok(Self {
82			api,
83			rpc,
84			latest_block: Arc::new(RwLock::new(latest.clone())),
85			latest_finalized_block: Arc::new(RwLock::new(latest)),
86		})
87	}
88}
89
90#[async_trait]
91impl BlockInfoProvider for SubxtBlockInfoProvider {
92	async fn update_latest(&self, block: Arc<SubstrateBlock>, subscription_type: SubscriptionType) {
93		let mut latest = match subscription_type {
94			SubscriptionType::FinalizedBlocks => self.latest_finalized_block.write().await,
95			SubscriptionType::BestBlocks => self.latest_block.write().await,
96		};
97		*latest = block;
98	}
99
100	async fn latest_block(&self) -> Arc<SubstrateBlock> {
101		self.latest_block.read().await.clone()
102	}
103
104	async fn latest_finalized_block(&self) -> Arc<SubstrateBlock> {
105		self.latest_finalized_block.read().await.clone()
106	}
107
108	async fn block_by_number(
109		&self,
110		block_number: SubstrateBlockNumber,
111	) -> Result<Option<Arc<SubstrateBlock>>, ClientError> {
112		let latest = self.latest_block().await;
113		if block_number == latest.block_number() {
114			return Ok(Some(latest));
115		}
116
117		let latest_finalized = self.latest_finalized_block().await;
118		if block_number == latest_finalized.block_number() {
119			return Ok(Some(latest_finalized));
120		}
121
122		let Some(hash) = self.rpc.chain_get_block_hash(Some(block_number.into())).await? else {
123			return Ok(None);
124		};
125
126		match self.api.at_block(hash).await {
127			Ok(block) => Ok(Some(Arc::new(block))),
128			Err(
129				OnlineClientAtBlockError::BlockHeaderNotFound { .. } |
130				OnlineClientAtBlockError::BlockNotFound { .. },
131			) => Ok(None),
132			Err(err) => Err(err.into()),
133		}
134	}
135
136	async fn block_by_hash(&self, hash: &H256) -> Result<Option<Arc<SubstrateBlock>>, ClientError> {
137		let latest = self.latest_block().await;
138		if hash == &latest.block_hash() {
139			return Ok(Some(latest));
140		}
141
142		let latest_finalized = self.latest_finalized_block().await;
143		if hash == &latest_finalized.block_hash() {
144			return Ok(Some(latest_finalized));
145		}
146
147		match self.api.at_block(*hash).await {
148			Ok(block) => Ok(Some(Arc::new(block))),
149			Err(
150				OnlineClientAtBlockError::BlockHeaderNotFound { .. } |
151				OnlineClientAtBlockError::BlockNotFound { .. },
152			) => {
153				log::trace!(target: LOG_TARGET, "block_by_hash: block {hash:?} not found");
154				Ok(None)
155			},
156			Err(err) => {
157				log::trace!(target: LOG_TARGET, "block_by_hash: failed to fetch block {hash:?}: {err:?}");
158				Err(err.into())
159			},
160		}
161	}
162}
163
164#[cfg(test)]
165pub mod test {
166	use super::*;
167	use crate::BlockInfo;
168
169	/// A Noop BlockInfoProvider used to test [`db::ReceiptProvider`].
170	pub struct MockBlockInfoProvider;
171
172	pub struct MockBlockInfo {
173		pub number: SubstrateBlockNumber,
174		pub hash: H256,
175	}
176
177	impl BlockInfo for MockBlockInfo {
178		fn hash(&self) -> H256 {
179			self.hash
180		}
181		fn number(&self) -> SubstrateBlockNumber {
182			self.number
183		}
184	}
185
186	#[async_trait]
187	impl BlockInfoProvider for MockBlockInfoProvider {
188		async fn update_latest(
189			&self,
190			_block: Arc<SubstrateBlock>,
191			_subscription_type: SubscriptionType,
192		) {
193		}
194
195		async fn latest_finalized_block(&self) -> Arc<SubstrateBlock> {
196			unimplemented!()
197		}
198
199		async fn latest_block(&self) -> Arc<SubstrateBlock> {
200			unimplemented!()
201		}
202
203		async fn latest_block_number(&self) -> SubstrateBlockNumber {
204			2u64
205		}
206
207		async fn block_by_number(
208			&self,
209			_block_number: SubstrateBlockNumber,
210		) -> Result<Option<Arc<SubstrateBlock>>, ClientError> {
211			Ok(None)
212		}
213
214		async fn block_by_hash(
215			&self,
216			_hash: &H256,
217		) -> Result<Option<Arc<SubstrateBlock>>, ClientError> {
218			Ok(None)
219		}
220	}
221}