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::{
27 OnlineClient, config::RpcConfigFor, error::OnlineClientAtBlockError,
28 rpcs::methods::LegacyRpcMethods,
29};
30use tokio::sync::RwLock;
31
32#[async_trait]
34pub trait BlockInfoProvider: Send + Sync {
35 async fn update_latest(&self, block: Arc<SubstrateBlock>, subscription_type: SubscriptionType);
37
38 async fn latest_finalized_block(&self) -> Arc<SubstrateBlock>;
40
41 async fn latest_block(&self) -> Arc<SubstrateBlock>;
43
44 async fn latest_block_number(&self) -> SubstrateBlockNumber {
46 return self.latest_block().await.block_number();
47 }
48
49 async fn block_by_number(
51 &self,
52 block_number: SubstrateBlockNumber,
53 ) -> Result<Option<Arc<SubstrateBlock>>, ClientError>;
54
55 async fn block_by_hash(&self, hash: &H256) -> Result<Option<Arc<SubstrateBlock>>, ClientError>;
57}
58
59#[derive(Clone)]
61pub struct SubxtBlockInfoProvider {
62 latest_block: Arc<RwLock<Arc<SubstrateBlock>>>,
64
65 latest_finalized_block: Arc<RwLock<Arc<SubstrateBlock>>>,
67
68 rpc: LegacyRpcMethods<RpcConfigFor<SrcChainConfig>>,
70
71 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 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}