1use alloy_eips::eip4895::Withdrawals;
2use alloy_primitives::TxNumber;
3use core::ops::Range;
4
5pub type NumTransactions = u64;
7
8#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
13#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
14#[cfg_attr(any(test, feature = "reth-codec"), derive(reth_codecs::Compact))]
15#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct StoredBlockBodyIndices {
18 pub first_tx_num: TxNumber,
23 pub tx_count: NumTransactions,
28}
29
30impl StoredBlockBodyIndices {
31 pub const fn tx_num_range(&self) -> Range<TxNumber> {
33 self.first_tx_num..self.first_tx_num + self.tx_count
34 }
35
36 pub const fn last_tx_num(&self) -> TxNumber {
40 self.first_tx_num.saturating_add(self.tx_count).saturating_sub(1)
41 }
42
43 pub const fn first_tx_num(&self) -> TxNumber {
48 self.first_tx_num
49 }
50
51 pub const fn next_tx_num(&self) -> TxNumber {
53 self.first_tx_num + self.tx_count
54 }
55
56 pub const fn is_empty(&self) -> bool {
58 self.tx_count == 0
59 }
60
61 pub const fn tx_count(&self) -> NumTransactions {
65 self.tx_count
66 }
67
68 pub const fn contains_tx(&self, tx_num: TxNumber) -> bool {
70 tx_num >= self.first_tx_num && tx_num < self.next_tx_num()
71 }
72}
73
74#[cfg(any(test, feature = "reth-codec"))]
75reth_codecs::impl_compression_for_compact!(StoredBlockBodyIndices);
76
77#[derive(Debug, Default, Eq, PartialEq, Clone)]
79#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
80#[cfg_attr(any(test, feature = "reth-codec"), derive(reth_codecs::Compact))]
81#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
82#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
83pub struct StoredBlockWithdrawals {
84 pub withdrawals: Withdrawals,
86}
87
88#[cfg(any(test, feature = "reth-codec"))]
89reth_codecs::impl_compression_for_compact!(StoredBlockWithdrawals);
90
91#[derive(Debug, Default, Eq, PartialEq, Clone)]
94#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
95#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
96#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
97pub struct StaticFileBlockWithdrawals {
98 pub withdrawals: Option<Withdrawals>,
100}
101
102#[cfg(any(test, feature = "reth-codec"))]
103impl reth_codecs::Compact for StaticFileBlockWithdrawals {
104 fn to_compact<B>(&self, buf: &mut B) -> usize
105 where
106 B: bytes::BufMut + AsMut<[u8]>,
107 {
108 buf.put_u8(self.withdrawals.is_some() as u8);
109 if let Some(withdrawals) = &self.withdrawals {
110 return 1 + withdrawals.to_compact(buf);
111 }
112 1
113 }
114 fn from_compact(mut buf: &[u8], _: usize) -> (Self, &[u8]) {
115 use bytes::Buf;
116 if buf.get_u8() == 1 {
117 let (w, buf) = Withdrawals::from_compact(buf, buf.len());
118 (Self { withdrawals: Some(w) }, buf)
119 } else {
120 (Self { withdrawals: None }, buf)
121 }
122 }
123}
124
125#[cfg(any(test, feature = "reth-codec"))]
126reth_codecs::impl_compression_for_compact!(StaticFileBlockWithdrawals);
127
128#[cfg(test)]
129mod tests {
130 use crate::StoredBlockBodyIndices;
131
132 #[test]
133 fn block_indices() {
134 let first_tx_num = 10;
135 let tx_count = 6;
136 let block_indices = StoredBlockBodyIndices { first_tx_num, tx_count };
137
138 assert_eq!(block_indices.first_tx_num(), first_tx_num);
139 assert_eq!(block_indices.last_tx_num(), first_tx_num + tx_count - 1);
140 assert_eq!(block_indices.next_tx_num(), first_tx_num + tx_count);
141 assert_eq!(block_indices.tx_count(), tx_count);
142 assert_eq!(block_indices.tx_num_range(), first_tx_num..first_tx_num + tx_count);
143 }
144}