pallet_revive_eth_rpc/
block_info_provider.rs1use 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#[async_trait]
31pub trait BlockInfoProvider: Send + Sync {
32 async fn update_latest(&self, block: Arc<SubstrateBlock>, subscription_type: SubscriptionType);
34
35 async fn latest_finalized_block(&self) -> Arc<SubstrateBlock>;
37
38 async fn latest_block(&self) -> Arc<SubstrateBlock>;
40
41 async fn latest_block_number(&self) -> SubstrateBlockNumber {
43 return self.latest_block().await.number();
44 }
45
46 async fn block_by_number(
48 &self,
49 block_number: SubstrateBlockNumber,
50 ) -> Result<Option<Arc<SubstrateBlock>>, ClientError>;
51
52 async fn block_by_hash(&self, hash: &H256) -> Result<Option<Arc<SubstrateBlock>>, ClientError>;
54}
55
56#[derive(Clone)]
58pub struct SubxtBlockInfoProvider {
59 latest_block: Arc<RwLock<Arc<SubstrateBlock>>>,
61
62 latest_finalized_block: Arc<RwLock<Arc<SubstrateBlock>>>,
64
65 rpc: LegacyRpcMethods<SrcChainConfig>,
67
68 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 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}