reth_static_file_types/
lib.rs1#![doc(
4 html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
5 html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
6 issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
7)]
8#![cfg_attr(not(test), warn(unused_crate_dependencies))]
9#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
10#![cfg_attr(not(feature = "std"), no_std)]
11
12extern crate alloc;
13
14mod compression;
15mod event;
16mod segment;
17
18use alloy_primitives::BlockNumber;
19pub use compression::Compression;
20use core::ops::RangeInclusive;
21pub use event::StaticFileProducerEvent;
22pub use segment::{SegmentConfig, SegmentHeader, SegmentRangeInclusive, StaticFileSegment};
23
24pub const DEFAULT_BLOCKS_PER_STATIC_FILE: u64 = 500_000;
26
27#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
29pub struct HighestStaticFiles {
30 pub headers: Option<BlockNumber>,
33 pub receipts: Option<BlockNumber>,
36 pub transactions: Option<BlockNumber>,
39 pub block_meta: Option<BlockNumber>,
42}
43
44impl HighestStaticFiles {
45 pub const fn highest(&self, segment: StaticFileSegment) -> Option<BlockNumber> {
47 match segment {
48 StaticFileSegment::Headers => self.headers,
49 StaticFileSegment::Transactions => self.transactions,
50 StaticFileSegment::Receipts => self.receipts,
51 StaticFileSegment::BlockMeta => self.block_meta,
52 }
53 }
54
55 pub fn as_mut(&mut self, segment: StaticFileSegment) -> &mut Option<BlockNumber> {
57 match segment {
58 StaticFileSegment::Headers => &mut self.headers,
59 StaticFileSegment::Transactions => &mut self.transactions,
60 StaticFileSegment::Receipts => &mut self.receipts,
61 StaticFileSegment::BlockMeta => &mut self.block_meta,
62 }
63 }
64
65 fn iter(&self) -> impl Iterator<Item = Option<BlockNumber>> {
67 [self.headers, self.transactions, self.receipts, self.block_meta].into_iter()
68 }
69
70 pub fn min_block_num(&self) -> Option<u64> {
72 self.iter().flatten().min()
73 }
74
75 pub fn max_block_num(&self) -> Option<u64> {
77 self.iter().flatten().max()
78 }
79}
80
81#[derive(Debug, Clone, Eq, PartialEq)]
83pub struct StaticFileTargets {
84 pub headers: Option<RangeInclusive<BlockNumber>>,
86 pub receipts: Option<RangeInclusive<BlockNumber>>,
88 pub transactions: Option<RangeInclusive<BlockNumber>>,
90 pub block_meta: Option<RangeInclusive<BlockNumber>>,
92}
93
94impl StaticFileTargets {
95 pub const fn any(&self) -> bool {
97 self.headers.is_some() ||
98 self.receipts.is_some() ||
99 self.transactions.is_some() ||
100 self.block_meta.is_some()
101 }
102
103 pub fn is_contiguous_to_highest_static_files(&self, static_files: HighestStaticFiles) -> bool {
106 [
107 (self.headers.as_ref(), static_files.headers),
108 (self.receipts.as_ref(), static_files.receipts),
109 (self.transactions.as_ref(), static_files.transactions),
110 (self.block_meta.as_ref(), static_files.block_meta),
111 ]
112 .iter()
113 .all(|(target_block_range, highest_static_fileted_block)| {
114 target_block_range.is_none_or(|target_block_range| {
115 *target_block_range.start() ==
116 highest_static_fileted_block.map_or(0, |highest_static_fileted_block| {
117 highest_static_fileted_block + 1
118 })
119 })
120 })
121 }
122}
123
124pub const fn find_fixed_range(
127 block: BlockNumber,
128 blocks_per_static_file: u64,
129) -> SegmentRangeInclusive {
130 let start = (block / blocks_per_static_file) * blocks_per_static_file;
131 SegmentRangeInclusive::new(start, start + blocks_per_static_file - 1)
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn test_highest_static_files_highest() {
140 let files = HighestStaticFiles {
141 headers: Some(100),
142 receipts: Some(200),
143 transactions: None,
144 block_meta: None,
145 };
146
147 assert_eq!(files.highest(StaticFileSegment::Headers), Some(100));
149
150 assert_eq!(files.highest(StaticFileSegment::Receipts), Some(200));
152
153 assert_eq!(files.highest(StaticFileSegment::Transactions), None);
155 }
156
157 #[test]
158 fn test_highest_static_files_as_mut() {
159 let mut files = HighestStaticFiles::default();
160
161 *files.as_mut(StaticFileSegment::Headers) = Some(150);
163 assert_eq!(files.headers, Some(150));
164
165 *files.as_mut(StaticFileSegment::Receipts) = Some(250);
167 assert_eq!(files.receipts, Some(250));
168
169 *files.as_mut(StaticFileSegment::Transactions) = Some(350);
171 assert_eq!(files.transactions, Some(350));
172
173 *files.as_mut(StaticFileSegment::BlockMeta) = Some(350);
175 assert_eq!(files.block_meta, Some(350));
176 }
177
178 #[test]
179 fn test_highest_static_files_min() {
180 let files = HighestStaticFiles {
181 headers: Some(300),
182 receipts: Some(100),
183 transactions: None,
184 block_meta: None,
185 };
186
187 assert_eq!(files.min_block_num(), Some(100));
189
190 let empty_files = HighestStaticFiles::default();
191 assert_eq!(empty_files.min_block_num(), None);
193 }
194
195 #[test]
196 fn test_highest_static_files_max() {
197 let files = HighestStaticFiles {
198 headers: Some(300),
199 receipts: Some(100),
200 transactions: Some(500),
201 block_meta: Some(500),
202 };
203
204 assert_eq!(files.max_block_num(), Some(500));
206
207 let empty_files = HighestStaticFiles::default();
208 assert_eq!(empty_files.max_block_num(), None);
210 }
211
212 #[test]
213 fn test_find_fixed_range() {
214 let block: BlockNumber = 600_000;
216 let range = find_fixed_range(block, DEFAULT_BLOCKS_PER_STATIC_FILE);
217 assert_eq!(range.start(), 500_000);
218 assert_eq!(range.end(), 999_999);
219
220 let block: BlockNumber = 1_200_000;
222 let range = find_fixed_range(block, 1_000_000);
223 assert_eq!(range.start(), 1_000_000);
224 assert_eq!(range.end(), 1_999_999);
225 }
226}