reth_provider/providers/static_file/
jar.rs1use 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, BlockHashOrNumber};
11use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256};
12use reth_chainspec::ChainInfo;
13use reth_db::static_file::{
14 BlockHashMask, HeaderMask, HeaderWithHashMask, ReceiptMask, StaticFileCursor, TransactionMask,
15 TransactionSenderMask,
16};
17use reth_db_api::table::{Decompress, Value};
18use reth_node_types::NodePrimitives;
19use reth_primitives_traits::{SealedHeader, SignedTransaction};
20use reth_static_file_types::ChangesetOffset;
21use reth_storage_api::range_size_hint;
22use reth_storage_errors::provider::{ProviderError, ProviderResult};
23use std::{
24 fmt::Debug,
25 ops::{Deref, RangeBounds, RangeInclusive},
26 sync::Arc,
27};
28#[derive(Debug)]
30pub struct StaticFileJarProvider<'a, N> {
31 jar: LoadedJarRef<'a>,
33 auxiliary_jar: Option<Box<Self>>,
35 metrics: Option<Arc<StaticFileProviderMetrics>>,
37 _pd: std::marker::PhantomData<N>,
39}
40
41impl<'a, N: NodePrimitives> Deref for StaticFileJarProvider<'a, N> {
42 type Target = LoadedJarRef<'a>;
43 fn deref(&self) -> &Self::Target {
44 &self.jar
45 }
46}
47
48impl<'a, N: NodePrimitives> From<LoadedJarRef<'a>> for StaticFileJarProvider<'a, N> {
49 fn from(value: LoadedJarRef<'a>) -> Self {
50 StaticFileJarProvider {
51 jar: value,
52 auxiliary_jar: None,
53 metrics: None,
54 _pd: Default::default(),
55 }
56 }
57}
58
59impl<'a, N: NodePrimitives> StaticFileJarProvider<'a, N> {
60 pub fn cursor<'b>(&'b self) -> ProviderResult<StaticFileCursor<'a>>
62 where
63 'b: 'a,
64 {
65 let result = StaticFileCursor::new(self.value(), self.mmap_handle())?;
66
67 if let Some(metrics) = &self.metrics {
68 metrics.record_segment_operation(
69 self.segment(),
70 StaticFileProviderOperation::InitCursor,
71 None,
72 );
73 }
74
75 Ok(result)
76 }
77
78 pub fn with_auxiliary(mut self, auxiliary_jar: Self) -> Self {
80 self.auxiliary_jar = Some(Box::new(auxiliary_jar));
81 self
82 }
83
84 pub fn with_metrics(mut self, metrics: Arc<StaticFileProviderMetrics>) -> Self {
86 self.metrics = Some(metrics);
87 self
88 }
89
90 pub fn size(&self) -> usize {
92 self.jar.value().size()
93 }
94
95 pub fn read_changeset_offset(
102 &self,
103 block_number: BlockNumber,
104 ) -> ProviderResult<Option<ChangesetOffset>> {
105 let header = self.user_header();
106 if !header.segment().is_change_based() {
107 return Ok(None);
108 }
109
110 let Some(index) = header.changeset_offset_index(block_number) else {
111 return Ok(None);
112 };
113
114 if let Some(reader) = self.jar.value().csoff_reader() {
115 reader.get(index).map_err(ProviderError::other)
116 } else {
117 Ok(None)
118 }
119 }
120
121 pub fn read_changeset_offsets(&self) -> ProviderResult<Option<Vec<ChangesetOffset>>> {
127 let header = self.user_header();
128 if !header.segment().is_change_based() {
129 return Ok(None);
130 }
131
132 let len = header.changeset_offsets_len();
133 if len == 0 {
134 return Ok(Some(Vec::new()));
135 }
136
137 if let Some(reader) = self.jar.value().csoff_reader() {
138 let offsets = reader.get_range(0, len).map_err(ProviderError::other)?;
139 Ok(Some(offsets))
140 } else {
141 Ok(None)
142 }
143 }
144}
145
146impl<N: NodePrimitives<BlockHeader: Value>> HeaderProvider for StaticFileJarProvider<'_, N> {
147 type Header = N::BlockHeader;
148
149 fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
150 Ok(self
151 .cursor()?
152 .get_two::<HeaderWithHashMask<Self::Header>>((&block_hash).into())?
153 .filter(|(_, hash)| hash == &block_hash)
154 .map(|(header, _)| header))
155 }
156
157 fn header_by_number(&self, num: BlockNumber) -> ProviderResult<Option<Self::Header>> {
158 self.cursor()?.get_one::<HeaderMask<Self::Header>>(num.into())
159 }
160
161 fn headers_range(
162 &self,
163 range: impl RangeBounds<BlockNumber>,
164 ) -> ProviderResult<Vec<Self::Header>> {
165 let mut cursor = self.cursor()?;
166 let mut headers = Vec::with_capacity(range_size_hint(&range).unwrap_or(1024));
167
168 for num in to_range(range) {
169 if let Some(header) = cursor.get_one::<HeaderMask<Self::Header>>(num.into())? {
170 headers.push(header);
171 }
172 }
173
174 Ok(headers)
175 }
176
177 fn sealed_header(
178 &self,
179 number: BlockNumber,
180 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
181 Ok(self
182 .cursor()?
183 .get_two::<HeaderWithHashMask<Self::Header>>(number.into())?
184 .map(|(header, hash)| SealedHeader::new(header, hash)))
185 }
186
187 fn sealed_headers_while(
188 &self,
189 range: impl RangeBounds<BlockNumber>,
190 mut predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
191 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
192 let mut cursor = self.cursor()?;
193 let mut headers = Vec::with_capacity(range_size_hint(&range).unwrap_or(1024));
194
195 for number in to_range(range) {
196 if let Some((header, hash)) =
197 cursor.get_two::<HeaderWithHashMask<Self::Header>>(number.into())?
198 {
199 let sealed = SealedHeader::new(header, hash);
200 if !predicate(&sealed) {
201 break
202 }
203 headers.push(sealed);
204 }
205 }
206 Ok(headers)
207 }
208}
209
210impl<N: NodePrimitives> BlockHashReader for StaticFileJarProvider<'_, N> {
211 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
212 self.cursor()?.get_one::<BlockHashMask>(number.into())
213 }
214
215 fn canonical_hashes_range(
216 &self,
217 start: BlockNumber,
218 end: BlockNumber,
219 ) -> ProviderResult<Vec<B256>> {
220 let mut cursor = self.cursor()?;
221 let mut hashes = Vec::with_capacity((end - start) as usize);
222
223 for number in start..end {
224 if let Some(hash) = cursor.get_one::<BlockHashMask>(number.into())? {
225 hashes.push(hash)
226 }
227 }
228 Ok(hashes)
229 }
230}
231
232impl<N: NodePrimitives> BlockNumReader for StaticFileJarProvider<'_, N> {
233 fn chain_info(&self) -> ProviderResult<ChainInfo> {
234 Err(ProviderError::UnsupportedProvider)
236 }
237
238 fn best_block_number(&self) -> ProviderResult<BlockNumber> {
239 Err(ProviderError::UnsupportedProvider)
241 }
242
243 fn last_block_number(&self) -> ProviderResult<BlockNumber> {
244 Err(ProviderError::UnsupportedProvider)
246 }
247
248 fn block_number(&self, hash: B256) -> ProviderResult<Option<BlockNumber>> {
249 let mut cursor = self.cursor()?;
250
251 Ok(cursor
252 .get_one::<BlockHashMask>((&hash).into())?
253 .and_then(|res| (res == hash).then(|| cursor.number()).flatten()))
254 }
255}
256
257impl<N: NodePrimitives<SignedTx: Decompress + SignedTransaction>> TransactionsProvider
258 for StaticFileJarProvider<'_, N>
259{
260 type Transaction = N::SignedTx;
261
262 fn transaction_id(&self, hash: TxHash) -> ProviderResult<Option<TxNumber>> {
263 let mut cursor = self.cursor()?;
264
265 Ok(cursor
266 .get_one::<TransactionMask<Self::Transaction>>((&hash).into())?
267 .and_then(|res| (res.trie_hash() == hash).then(|| cursor.number()).flatten()))
268 }
269
270 fn transaction_by_id(&self, num: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
271 self.cursor()?.get_one::<TransactionMask<Self::Transaction>>(num.into())
272 }
273
274 fn transaction_by_id_unhashed(
275 &self,
276 num: TxNumber,
277 ) -> ProviderResult<Option<Self::Transaction>> {
278 self.cursor()?.get_one::<TransactionMask<Self::Transaction>>(num.into())
279 }
280
281 fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
282 self.cursor()?.get_one::<TransactionMask<Self::Transaction>>((&hash).into())
283 }
284
285 fn transaction_by_hash_with_meta(
286 &self,
287 _hash: TxHash,
288 ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
289 Err(ProviderError::UnsupportedProvider)
291 }
292
293 fn transactions_by_block(
294 &self,
295 _block_id: BlockHashOrNumber,
296 ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
297 Err(ProviderError::UnsupportedProvider)
300 }
301
302 fn transactions_by_block_range(
303 &self,
304 _range: impl RangeBounds<BlockNumber>,
305 ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
306 Err(ProviderError::UnsupportedProvider)
309 }
310
311 fn transactions_by_tx_range(
312 &self,
313 range: impl RangeBounds<TxNumber>,
314 ) -> ProviderResult<Vec<Self::Transaction>> {
315 let mut cursor = self.cursor()?;
316 let mut txs = Vec::with_capacity(range_size_hint(&range).unwrap_or(1024));
317
318 for num in to_range(range) {
319 if let Some(tx) = cursor.get_one::<TransactionMask<Self::Transaction>>(num.into())? {
320 txs.push(tx)
321 }
322 }
323 Ok(txs)
324 }
325
326 fn senders_by_tx_range(
327 &self,
328 range: impl RangeBounds<TxNumber>,
329 ) -> ProviderResult<Vec<Address>> {
330 let mut cursor = self.cursor()?;
331 let mut senders = Vec::with_capacity(range_size_hint(&range).unwrap_or(1024));
332
333 for num in to_range(range) {
334 if let Some(tx) = cursor.get_one::<TransactionSenderMask>(num.into())? {
335 senders.push(tx)
336 }
337 }
338 Ok(senders)
339 }
340
341 fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
342 self.cursor()?.get_one::<TransactionSenderMask>(id.into())
343 }
344}
345
346impl<N: NodePrimitives<SignedTx: Decompress + SignedTransaction, Receipt: Decompress>>
347 ReceiptProvider for StaticFileJarProvider<'_, N>
348{
349 type Receipt = N::Receipt;
350
351 fn receipt(&self, num: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
352 self.cursor()?.get_one::<ReceiptMask<Self::Receipt>>(num.into())
353 }
354
355 fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
356 if let Some(tx_static_file) = &self.auxiliary_jar &&
357 let Some(num) = tx_static_file.transaction_id(hash)?
358 {
359 return self.receipt(num)
360 }
361 Ok(None)
362 }
363
364 fn receipts_by_block(
365 &self,
366 _block: BlockHashOrNumber,
367 ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
368 Err(ProviderError::UnsupportedProvider)
371 }
372
373 fn receipts_by_tx_range(
374 &self,
375 range: impl RangeBounds<TxNumber>,
376 ) -> ProviderResult<Vec<Self::Receipt>> {
377 let mut cursor = self.cursor()?;
378 let mut receipts = Vec::with_capacity(range_size_hint(&range).unwrap_or(1024));
379
380 for num in to_range(range) {
381 if let Some(tx) = cursor.get_one::<ReceiptMask<Self::Receipt>>(num.into())? {
382 receipts.push(tx)
383 }
384 }
385 Ok(receipts)
386 }
387
388 fn receipts_by_block_range(
389 &self,
390 _block_range: RangeInclusive<BlockNumber>,
391 ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
392 Err(ProviderError::UnsupportedProvider)
395 }
396}