1use alloy_eips::eip4895::Withdrawals;
2use alloy_primitives::TxNumber;
3use core::ops::Range;
45/// Total number of transactions.
6pub type NumTransactions = u64;
78/// The storage of the block body indices.
9///
10/// It has the pointer to the transaction Number of the first
11/// transaction in the block and the total number of transactions.
12#[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/// The number of the first transaction in this block
19 ///
20 /// Note: If the block is empty, this is the number of the first transaction
21 /// in the next non-empty block.
22pub first_tx_num: TxNumber,
23/// The total number of transactions in the block
24 ///
25 /// NOTE: Number of transitions is equal to number of transactions with
26 /// additional transition for block change if block has block reward or withdrawal.
27pub tx_count: NumTransactions,
28}
2930impl StoredBlockBodyIndices {
31/// Return the range of transaction ids for this block.
32pub const fn tx_num_range(&self) -> Range<TxNumber> {
33self.first_tx_num..self.first_tx_num + self.tx_count
34 }
3536/// Return the index of last transaction in this block unless the block
37 /// is empty in which case it refers to the last transaction in a previous
38 /// non-empty block
39pub const fn last_tx_num(&self) -> TxNumber {
40self.first_tx_num.saturating_add(self.tx_count).saturating_sub(1)
41 }
4243/// First transaction index.
44 ///
45 /// Caution: If the block is empty, this is the number of the first transaction
46 /// in the next non-empty block.
47pub const fn first_tx_num(&self) -> TxNumber {
48self.first_tx_num
49 }
5051/// Return the index of the next transaction after this block.
52pub const fn next_tx_num(&self) -> TxNumber {
53self.first_tx_num + self.tx_count
54 }
5556/// Return a flag whether the block is empty
57pub const fn is_empty(&self) -> bool {
58self.tx_count == 0
59}
6061/// Return number of transaction inside block
62 ///
63 /// NOTE: This is not the same as the number of transitions.
64pub const fn tx_count(&self) -> NumTransactions {
65self.tx_count
66 }
67}
6869/// The storage representation of block withdrawals.
70#[derive(Debug, Default, Eq, PartialEq, Clone)]
71#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
72#[cfg_attr(any(test, feature = "reth-codec"), derive(reth_codecs::Compact))]
73#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
74#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
75pub struct StoredBlockWithdrawals {
76/// The block withdrawals.
77pub withdrawals: Withdrawals,
78}
7980/// A storage representation of block withdrawals that is static file friendly. An inner `None`
81/// represents a pre-merge block.
82#[derive(Debug, Default, Eq, PartialEq, Clone)]
83#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
84#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
85#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
86pub struct StaticFileBlockWithdrawals {
87/// The block withdrawals. A `None` value represents a pre-merge block.
88pub withdrawals: Option<Withdrawals>,
89}
9091#[cfg(any(test, feature = "reth-codec"))]
92impl reth_codecs::Compact for StaticFileBlockWithdrawals {
93fn to_compact<B>(&self, buf: &mut B) -> usize94where
95B: bytes::BufMut + AsMut<[u8]>,
96 {
97buf.put_u8(self.withdrawals.is_some() as u8);
98if let Some(withdrawals) = &self.withdrawals {
99return 1 + withdrawals.to_compact(buf);
100 }
1011
102}
103fn from_compact(mut buf: &[u8], _: usize) -> (Self, &[u8]) {
104use bytes::Buf;
105if buf.get_u8() == 1 {
106let (w, buf) = Withdrawals::from_compact(buf, buf.len());
107 (Self { withdrawals: Some(w) }, buf)
108 } else {
109 (Self { withdrawals: None }, buf)
110 }
111 }
112}
113114#[cfg(test)]
115mod tests {
116use crate::StoredBlockBodyIndices;
117118#[test]
119fn block_indices() {
120let first_tx_num = 10;
121let tx_count = 6;
122let block_indices = StoredBlockBodyIndices { first_tx_num, tx_count };
123124assert_eq!(block_indices.first_tx_num(), first_tx_num);
125assert_eq!(block_indices.last_tx_num(), first_tx_num + tx_count - 1);
126assert_eq!(block_indices.next_tx_num(), first_tx_num + tx_count);
127assert_eq!(block_indices.tx_count(), tx_count);
128assert_eq!(block_indices.tx_num_range(), first_tx_num..first_tx_num + tx_count);
129 }
130}