reth_provider/providers/static_file/
jar.rs
1use super::{
2 metrics::{StaticFileProviderMetrics, StaticFileProviderOperation},
3 LoadedJarRef,
4};
5use crate::{
6 to_range, BlockHashReader, BlockNumReader, HeaderProvider, ReceiptProvider,
7 TransactionsProvider,
8};
9use alloy_consensus::transaction::TransactionMeta;
10use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawals, BlockHashOrNumber};
11use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256};
12use reth_chainspec::ChainInfo;
13use reth_db::static_file::{
14 BlockHashMask, BodyIndicesMask, HeaderMask, HeaderWithHashMask, OmmersMask, ReceiptMask,
15 StaticFileCursor, TDWithHashMask, TotalDifficultyMask, TransactionMask, WithdrawalsMask,
16};
17use reth_db_api::{
18 models::StoredBlockBodyIndices,
19 table::{Decompress, Value},
20};
21use reth_node_types::{FullNodePrimitives, NodePrimitives};
22use reth_primitives_traits::{SealedHeader, SignedTransaction};
23use reth_storage_api::{BlockBodyIndicesProvider, OmmersProvider, WithdrawalsProvider};
24use reth_storage_errors::provider::{ProviderError, ProviderResult};
25use std::{
26 fmt::Debug,
27 ops::{Deref, RangeBounds, RangeInclusive},
28 sync::Arc,
29};
30#[derive(Debug)]
32pub struct StaticFileJarProvider<'a, N> {
33 jar: LoadedJarRef<'a>,
35 auxiliary_jar: Option<Box<Self>>,
37 metrics: Option<Arc<StaticFileProviderMetrics>>,
39 _pd: std::marker::PhantomData<N>,
41}
42
43impl<'a, N: NodePrimitives> Deref for StaticFileJarProvider<'a, N> {
44 type Target = LoadedJarRef<'a>;
45 fn deref(&self) -> &Self::Target {
46 &self.jar
47 }
48}
49
50impl<'a, N: NodePrimitives> From<LoadedJarRef<'a>> for StaticFileJarProvider<'a, N> {
51 fn from(value: LoadedJarRef<'a>) -> Self {
52 StaticFileJarProvider {
53 jar: value,
54 auxiliary_jar: None,
55 metrics: None,
56 _pd: Default::default(),
57 }
58 }
59}
60
61impl<'a, N: NodePrimitives> StaticFileJarProvider<'a, N> {
62 pub fn cursor<'b>(&'b self) -> ProviderResult<StaticFileCursor<'a>>
64 where
65 'b: 'a,
66 {
67 let result = StaticFileCursor::new(self.value(), self.mmap_handle())?;
68
69 if let Some(metrics) = &self.metrics {
70 metrics.record_segment_operation(
71 self.segment(),
72 StaticFileProviderOperation::InitCursor,
73 None,
74 );
75 }
76
77 Ok(result)
78 }
79
80 pub fn with_auxiliary(mut self, auxiliary_jar: Self) -> Self {
82 self.auxiliary_jar = Some(Box::new(auxiliary_jar));
83 self
84 }
85
86 pub fn with_metrics(mut self, metrics: Arc<StaticFileProviderMetrics>) -> Self {
88 self.metrics = Some(metrics);
89 self
90 }
91}
92
93impl<N: NodePrimitives<BlockHeader: Value>> HeaderProvider for StaticFileJarProvider<'_, N> {
94 type Header = N::BlockHeader;
95
96 fn header(&self, block_hash: &BlockHash) -> ProviderResult<Option<Self::Header>> {
97 Ok(self
98 .cursor()?
99 .get_two::<HeaderWithHashMask<Self::Header>>(block_hash.into())?
100 .filter(|(_, hash)| hash == block_hash)
101 .map(|(header, _)| header))
102 }
103
104 fn header_by_number(&self, num: BlockNumber) -> ProviderResult<Option<Self::Header>> {
105 self.cursor()?.get_one::<HeaderMask<Self::Header>>(num.into())
106 }
107
108 fn header_td(&self, block_hash: &BlockHash) -> ProviderResult<Option<U256>> {
109 Ok(self
110 .cursor()?
111 .get_two::<TDWithHashMask>(block_hash.into())?
112 .filter(|(_, hash)| hash == block_hash)
113 .map(|(td, _)| td.into()))
114 }
115
116 fn header_td_by_number(&self, num: BlockNumber) -> ProviderResult<Option<U256>> {
117 Ok(self.cursor()?.get_one::<TotalDifficultyMask>(num.into())?.map(Into::into))
118 }
119
120 fn headers_range(
121 &self,
122 range: impl RangeBounds<BlockNumber>,
123 ) -> ProviderResult<Vec<Self::Header>> {
124 let range = to_range(range);
125
126 let mut cursor = self.cursor()?;
127 let mut headers = Vec::with_capacity((range.end - range.start) as usize);
128
129 for num in range {
130 if let Some(header) = cursor.get_one::<HeaderMask<Self::Header>>(num.into())? {
131 headers.push(header);
132 }
133 }
134
135 Ok(headers)
136 }
137
138 fn sealed_header(
139 &self,
140 number: BlockNumber,
141 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
142 Ok(self
143 .cursor()?
144 .get_two::<HeaderWithHashMask<Self::Header>>(number.into())?
145 .map(|(header, hash)| SealedHeader::new(header, hash)))
146 }
147
148 fn sealed_headers_while(
149 &self,
150 range: impl RangeBounds<BlockNumber>,
151 mut predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
152 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
153 let range = to_range(range);
154
155 let mut cursor = self.cursor()?;
156 let mut headers = Vec::with_capacity((range.end - range.start) as usize);
157
158 for number in range {
159 if let Some((header, hash)) =
160 cursor.get_two::<HeaderWithHashMask<Self::Header>>(number.into())?
161 {
162 let sealed = SealedHeader::new(header, hash);
163 if !predicate(&sealed) {
164 break
165 }
166 headers.push(sealed);
167 }
168 }
169 Ok(headers)
170 }
171}
172
173impl<N: NodePrimitives> BlockHashReader for StaticFileJarProvider<'_, N> {
174 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
175 self.cursor()?.get_one::<BlockHashMask>(number.into())
176 }
177
178 fn canonical_hashes_range(
179 &self,
180 start: BlockNumber,
181 end: BlockNumber,
182 ) -> ProviderResult<Vec<B256>> {
183 let mut cursor = self.cursor()?;
184 let mut hashes = Vec::with_capacity((end - start) as usize);
185
186 for number in start..end {
187 if let Some(hash) = cursor.get_one::<BlockHashMask>(number.into())? {
188 hashes.push(hash)
189 }
190 }
191 Ok(hashes)
192 }
193}
194
195impl<N: NodePrimitives> BlockNumReader for StaticFileJarProvider<'_, N> {
196 fn chain_info(&self) -> ProviderResult<ChainInfo> {
197 Err(ProviderError::UnsupportedProvider)
199 }
200
201 fn best_block_number(&self) -> ProviderResult<BlockNumber> {
202 Err(ProviderError::UnsupportedProvider)
204 }
205
206 fn last_block_number(&self) -> ProviderResult<BlockNumber> {
207 Err(ProviderError::UnsupportedProvider)
209 }
210
211 fn block_number(&self, hash: B256) -> ProviderResult<Option<BlockNumber>> {
212 let mut cursor = self.cursor()?;
213
214 Ok(cursor
215 .get_one::<BlockHashMask>((&hash).into())?
216 .and_then(|res| (res == hash).then(|| cursor.number()).flatten()))
217 }
218}
219
220impl<N: NodePrimitives<SignedTx: Decompress + SignedTransaction>> TransactionsProvider
221 for StaticFileJarProvider<'_, N>
222{
223 type Transaction = N::SignedTx;
224
225 fn transaction_id(&self, hash: TxHash) -> ProviderResult<Option<TxNumber>> {
226 let mut cursor = self.cursor()?;
227
228 Ok(cursor
229 .get_one::<TransactionMask<Self::Transaction>>((&hash).into())?
230 .and_then(|res| (res.trie_hash() == hash).then(|| cursor.number()).flatten()))
231 }
232
233 fn transaction_by_id(&self, num: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
234 self.cursor()?.get_one::<TransactionMask<Self::Transaction>>(num.into())
235 }
236
237 fn transaction_by_id_unhashed(
238 &self,
239 num: TxNumber,
240 ) -> ProviderResult<Option<Self::Transaction>> {
241 self.cursor()?.get_one::<TransactionMask<Self::Transaction>>(num.into())
242 }
243
244 fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
245 self.cursor()?.get_one::<TransactionMask<Self::Transaction>>((&hash).into())
246 }
247
248 fn transaction_by_hash_with_meta(
249 &self,
250 _hash: TxHash,
251 ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
252 Err(ProviderError::UnsupportedProvider)
254 }
255
256 fn transaction_block(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
257 Err(ProviderError::UnsupportedProvider)
259 }
260
261 fn transactions_by_block(
262 &self,
263 _block_id: BlockHashOrNumber,
264 ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
265 Err(ProviderError::UnsupportedProvider)
268 }
269
270 fn transactions_by_block_range(
271 &self,
272 _range: impl RangeBounds<BlockNumber>,
273 ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
274 Err(ProviderError::UnsupportedProvider)
277 }
278
279 fn transactions_by_tx_range(
280 &self,
281 range: impl RangeBounds<TxNumber>,
282 ) -> ProviderResult<Vec<Self::Transaction>> {
283 let range = to_range(range);
284 let mut cursor = self.cursor()?;
285 let mut txes = Vec::with_capacity((range.end - range.start) as usize);
286
287 for num in range {
288 if let Some(tx) = cursor.get_one::<TransactionMask<Self::Transaction>>(num.into())? {
289 txes.push(tx)
290 }
291 }
292 Ok(txes)
293 }
294
295 fn senders_by_tx_range(
296 &self,
297 range: impl RangeBounds<TxNumber>,
298 ) -> ProviderResult<Vec<Address>> {
299 let txs = self.transactions_by_tx_range(range)?;
300 Ok(reth_primitives_traits::transaction::recover::recover_signers(&txs)?)
301 }
302
303 fn transaction_sender(&self, num: TxNumber) -> ProviderResult<Option<Address>> {
304 Ok(self
305 .cursor()?
306 .get_one::<TransactionMask<Self::Transaction>>(num.into())?
307 .and_then(|tx| tx.recover_signer().ok()))
308 }
309}
310
311impl<N: NodePrimitives<SignedTx: Decompress + SignedTransaction, Receipt: Decompress>>
312 ReceiptProvider for StaticFileJarProvider<'_, N>
313{
314 type Receipt = N::Receipt;
315
316 fn receipt(&self, num: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
317 self.cursor()?.get_one::<ReceiptMask<Self::Receipt>>(num.into())
318 }
319
320 fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
321 if let Some(tx_static_file) = &self.auxiliary_jar {
322 if let Some(num) = tx_static_file.transaction_id(hash)? {
323 return self.receipt(num)
324 }
325 }
326 Ok(None)
327 }
328
329 fn receipts_by_block(
330 &self,
331 _block: BlockHashOrNumber,
332 ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
333 Err(ProviderError::UnsupportedProvider)
336 }
337
338 fn receipts_by_tx_range(
339 &self,
340 range: impl RangeBounds<TxNumber>,
341 ) -> ProviderResult<Vec<Self::Receipt>> {
342 let range = to_range(range);
343 let mut cursor = self.cursor()?;
344 let mut receipts = Vec::with_capacity((range.end - range.start) as usize);
345
346 for num in range {
347 if let Some(tx) = cursor.get_one::<ReceiptMask<Self::Receipt>>(num.into())? {
348 receipts.push(tx)
349 }
350 }
351 Ok(receipts)
352 }
353}
354
355impl<N: NodePrimitives> WithdrawalsProvider for StaticFileJarProvider<'_, N> {
356 fn withdrawals_by_block(
357 &self,
358 id: BlockHashOrNumber,
359 _: u64,
360 ) -> ProviderResult<Option<Withdrawals>> {
361 if let Some(num) = id.as_number() {
362 return Ok(self
363 .cursor()?
364 .get_one::<WithdrawalsMask>(num.into())?
365 .and_then(|s| s.withdrawals))
366 }
367 Err(ProviderError::UnsupportedProvider)
369 }
370}
371
372impl<N: FullNodePrimitives<BlockHeader: Value>> OmmersProvider for StaticFileJarProvider<'_, N> {
373 fn ommers(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Vec<Self::Header>>> {
374 if let Some(num) = id.as_number() {
375 return Ok(self
376 .cursor()?
377 .get_one::<OmmersMask<Self::Header>>(num.into())?
378 .map(|s| s.ommers))
379 }
380 Err(ProviderError::UnsupportedProvider)
382 }
383}
384
385impl<N: NodePrimitives> BlockBodyIndicesProvider for StaticFileJarProvider<'_, N> {
386 fn block_body_indices(&self, num: u64) -> ProviderResult<Option<StoredBlockBodyIndices>> {
387 self.cursor()?.get_one::<BodyIndicesMask>(num.into())
388 }
389
390 fn block_body_indices_range(
391 &self,
392 range: RangeInclusive<BlockNumber>,
393 ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
394 let mut cursor = self.cursor()?;
395 let mut indices = Vec::with_capacity((range.end() - range.start() + 1) as usize);
396
397 for num in range {
398 if let Some(block) = cursor.get_one::<BodyIndicesMask>(num.into())? {
399 indices.push(block)
400 }
401 }
402 Ok(indices)
403 }
404}