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#[derive(Debug, Default, Eq, PartialEq, Clone)]
76#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
77#[cfg_attr(any(test, feature = "reth-codec"), derive(reth_codecs::Compact))]
78#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
79#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
80pub struct StoredBlockWithdrawals {
81 pub withdrawals: Withdrawals,
83}
84
85#[derive(Debug, Default, Eq, PartialEq, Clone)]
88#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
89#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
90#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
91pub struct StaticFileBlockWithdrawals {
92 pub withdrawals: Option<Withdrawals>,
94}
95
96#[cfg(any(test, feature = "reth-codec"))]
97impl reth_codecs::Compact for StaticFileBlockWithdrawals {
98 fn to_compact<B>(&self, buf: &mut B) -> usize
99 where
100 B: bytes::BufMut + AsMut<[u8]>,
101 {
102 buf.put_u8(self.withdrawals.is_some() as u8);
103 if let Some(withdrawals) = &self.withdrawals {
104 return 1 + withdrawals.to_compact(buf);
105 }
106 1
107 }
108 fn from_compact(mut buf: &[u8], _: usize) -> (Self, &[u8]) {
109 use bytes::Buf;
110 if buf.get_u8() == 1 {
111 let (w, buf) = Withdrawals::from_compact(buf, buf.len());
112 (Self { withdrawals: Some(w) }, buf)
113 } else {
114 (Self { withdrawals: None }, buf)
115 }
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use crate::StoredBlockBodyIndices;
122
123 #[test]
124 fn block_indices() {
125 let first_tx_num = 10;
126 let tx_count = 6;
127 let block_indices = StoredBlockBodyIndices { first_tx_num, tx_count };
128
129 assert_eq!(block_indices.first_tx_num(), first_tx_num);
130 assert_eq!(block_indices.last_tx_num(), first_tx_num + tx_count - 1);
131 assert_eq!(block_indices.next_tx_num(), first_tx_num + tx_count);
132 assert_eq!(block_indices.tx_count(), tx_count);
133 assert_eq!(block_indices.tx_num_range(), first_tx_num..first_tx_num + tx_count);
134 }
135}