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}
40
41impl HighestStaticFiles {
42 pub const fn highest(&self, segment: StaticFileSegment) -> Option<BlockNumber> {
44 match segment {
45 StaticFileSegment::Headers => self.headers,
46 StaticFileSegment::Transactions => self.transactions,
47 StaticFileSegment::Receipts => self.receipts,
48 }
49 }
50
51 pub const fn as_mut(&mut self, segment: StaticFileSegment) -> &mut Option<BlockNumber> {
53 match segment {
54 StaticFileSegment::Headers => &mut self.headers,
55 StaticFileSegment::Transactions => &mut self.transactions,
56 StaticFileSegment::Receipts => &mut self.receipts,
57 }
58 }
59
60 fn iter(&self) -> impl Iterator<Item = Option<BlockNumber>> {
62 [self.headers, self.transactions, self.receipts].into_iter()
63 }
64
65 pub fn min_block_num(&self) -> Option<u64> {
67 self.iter().flatten().min()
68 }
69
70 pub fn max_block_num(&self) -> Option<u64> {
72 self.iter().flatten().max()
73 }
74}
75
76#[derive(Debug, Clone, Eq, PartialEq)]
78pub struct StaticFileTargets {
79 pub headers: Option<RangeInclusive<BlockNumber>>,
81 pub receipts: Option<RangeInclusive<BlockNumber>>,
83 pub transactions: Option<RangeInclusive<BlockNumber>>,
85}
86
87impl StaticFileTargets {
88 pub const fn any(&self) -> bool {
90 self.headers.is_some() || self.receipts.is_some() || self.transactions.is_some()
91 }
92
93 pub fn is_contiguous_to_highest_static_files(&self, static_files: HighestStaticFiles) -> bool {
96 [
97 (self.headers.as_ref(), static_files.headers),
98 (self.receipts.as_ref(), static_files.receipts),
99 (self.transactions.as_ref(), static_files.transactions),
100 ]
101 .iter()
102 .all(|(target_block_range, highest_static_file_block)| {
103 target_block_range.is_none_or(|target_block_range| {
104 *target_block_range.start() ==
105 highest_static_file_block
106 .map_or(0, |highest_static_file_block| highest_static_file_block + 1)
107 })
108 })
109 }
110}
111
112pub const fn find_fixed_range(
115 block: BlockNumber,
116 blocks_per_static_file: u64,
117) -> SegmentRangeInclusive {
118 let start = (block / blocks_per_static_file) * blocks_per_static_file;
119 SegmentRangeInclusive::new(start, start + blocks_per_static_file - 1)
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test_highest_static_files_highest() {
128 let files =
129 HighestStaticFiles { headers: Some(100), receipts: Some(200), transactions: None };
130
131 assert_eq!(files.highest(StaticFileSegment::Headers), Some(100));
133
134 assert_eq!(files.highest(StaticFileSegment::Receipts), Some(200));
136
137 assert_eq!(files.highest(StaticFileSegment::Transactions), None);
139 }
140
141 #[test]
142 fn test_highest_static_files_as_mut() {
143 let mut files = HighestStaticFiles::default();
144
145 *files.as_mut(StaticFileSegment::Headers) = Some(150);
147 assert_eq!(files.headers, Some(150));
148
149 *files.as_mut(StaticFileSegment::Receipts) = Some(250);
151 assert_eq!(files.receipts, Some(250));
152
153 *files.as_mut(StaticFileSegment::Transactions) = Some(350);
155 assert_eq!(files.transactions, Some(350));
156 }
157
158 #[test]
159 fn test_highest_static_files_min() {
160 let files =
161 HighestStaticFiles { headers: Some(300), receipts: Some(100), transactions: None };
162
163 assert_eq!(files.min_block_num(), Some(100));
165
166 let empty_files = HighestStaticFiles::default();
167 assert_eq!(empty_files.min_block_num(), None);
169 }
170
171 #[test]
172 fn test_highest_static_files_max() {
173 let files =
174 HighestStaticFiles { headers: Some(300), receipts: Some(100), transactions: Some(500) };
175
176 assert_eq!(files.max_block_num(), Some(500));
178
179 let empty_files = HighestStaticFiles::default();
180 assert_eq!(empty_files.max_block_num(), None);
182 }
183
184 #[test]
185 fn test_find_fixed_range() {
186 let block: BlockNumber = 600_000;
188 let range = find_fixed_range(block, DEFAULT_BLOCKS_PER_STATIC_FILE);
189 assert_eq!(range.start(), 500_000);
190 assert_eq!(range.end(), 999_999);
191
192 let block: BlockNumber = 1_200_000;
194 let range = find_fixed_range(block, 1_000_000);
195 assert_eq!(range.start(), 1_000_000);
196 assert_eq!(range.end(), 1_999_999);
197 }
198}