reth_primitives_traits/block/
body.rs

1//! Block body abstraction.
2
3use crate::{
4    transaction::signed::RecoveryError, BlockHeader, FullSignedTx, InMemorySize, MaybeSerde,
5    MaybeSerdeBincodeCompat, SignedTransaction,
6};
7use alloc::{fmt, vec::Vec};
8use alloy_consensus::{
9    transaction::{Recovered, TxHashRef},
10    Transaction, Typed2718,
11};
12use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawals};
13use alloy_primitives::{Address, Bytes, B256};
14
15/// Helper trait that unifies all behaviour required by transaction to support full node operations.
16pub trait FullBlockBody: BlockBody<Transaction: FullSignedTx> + MaybeSerdeBincodeCompat {}
17
18impl<T> FullBlockBody for T where T: BlockBody<Transaction: FullSignedTx> + MaybeSerdeBincodeCompat {}
19
20/// Abstraction for block's body.
21///
22/// This type is a container for everything that is included in a block except the header.
23/// For ethereum this includes transactions, ommers, and withdrawals.
24pub trait BlockBody:
25    Send
26    + Sync
27    + Unpin
28    + Clone
29    + Default
30    + fmt::Debug
31    + PartialEq
32    + Eq
33    + alloy_rlp::Encodable
34    + alloy_rlp::Decodable
35    + InMemorySize
36    + MaybeSerde
37    + 'static
38{
39    /// Ordered list of signed transactions as committed in the block.
40    type Transaction: SignedTransaction;
41
42    /// Ommer header type.
43    type OmmerHeader: BlockHeader;
44
45    /// Returns reference to transactions in the block.
46    fn transactions(&self) -> &[Self::Transaction];
47
48    /// A Convenience function to convert this type into the regular ethereum block body that
49    /// consists of:
50    ///
51    /// - Transactions
52    /// - Withdrawals
53    /// - Ommers
54    ///
55    /// Note: This conversion can be incomplete. It is not expected that this `Body` is the same as
56    /// [`alloy_consensus::BlockBody`] only that it can be converted into it which is useful for
57    /// the `eth_` RPC namespace (e.g. RPC block).
58    fn into_ethereum_body(self)
59        -> alloy_consensus::BlockBody<Self::Transaction, Self::OmmerHeader>;
60
61    /// Returns an iterator over the transactions in the block.
62    fn transactions_iter(&self) -> impl Iterator<Item = &Self::Transaction> + '_ {
63        self.transactions().iter()
64    }
65
66    /// Returns the transaction with the matching hash.
67    ///
68    /// This is a convenience function for `transactions_iter().find()`
69    fn transaction_by_hash(&self, hash: &B256) -> Option<&Self::Transaction> {
70        self.transactions_iter().find(|tx| tx.tx_hash() == hash)
71    }
72
73    /// Returns true if the block body contains a transaction with the given hash.
74    ///
75    /// This is a convenience function for `transaction_by_hash().is_some()`
76    fn contains_transaction(&self, hash: &B256) -> bool {
77        self.transaction_by_hash(hash).is_some()
78    }
79
80    /// Clones the transactions in the block.
81    ///
82    /// This is a convenience function for `transactions().to_vec()`
83    fn clone_transactions(&self) -> Vec<Self::Transaction> {
84        self.transactions().to_vec()
85    }
86
87    /// Returns an iterator over all transaction hashes in the block body.
88    fn transaction_hashes_iter(&self) -> impl Iterator<Item = &B256> + '_ {
89        self.transactions_iter().map(|tx| tx.tx_hash())
90    }
91
92    /// Returns the number of the transactions in the block.
93    fn transaction_count(&self) -> usize {
94        self.transactions().len()
95    }
96
97    /// Consume the block body and return a [`Vec`] of transactions.
98    fn into_transactions(self) -> Vec<Self::Transaction>;
99
100    /// Returns `true` if the block body contains a transaction of the given type.
101    fn contains_transaction_type(&self, tx_type: u8) -> bool {
102        self.transactions_iter().any(|tx| tx.is_type(tx_type))
103    }
104
105    /// Calculate the transaction root for the block body.
106    fn calculate_tx_root(&self) -> B256 {
107        alloy_consensus::proofs::calculate_transaction_root(self.transactions())
108    }
109
110    /// Returns block withdrawals if any.
111    fn withdrawals(&self) -> Option<&Withdrawals>;
112
113    /// Calculate the withdrawals root for the block body.
114    ///
115    /// Returns `Some(root)` if withdrawals are present, otherwise `None`.
116    fn calculate_withdrawals_root(&self) -> Option<B256> {
117        self.withdrawals().map(|withdrawals| {
118            alloy_consensus::proofs::calculate_withdrawals_root(withdrawals.as_slice())
119        })
120    }
121
122    /// Returns block ommers if any.
123    fn ommers(&self) -> Option<&[Self::OmmerHeader]>;
124
125    /// Calculate the ommers root for the block body.
126    ///
127    /// Returns `Some(root)` if ommers are present, otherwise `None`.
128    fn calculate_ommers_root(&self) -> Option<B256> {
129        self.ommers().map(alloy_consensus::proofs::calculate_ommers_root)
130    }
131
132    /// Calculates the total blob gas used by _all_ EIP-4844 transactions in the block.
133    fn blob_gas_used(&self) -> u64 {
134        self.transactions_iter().filter_map(|tx| tx.blob_gas_used()).sum()
135    }
136
137    /// Returns an iterator over all blob versioned hashes in the block body.
138    fn blob_versioned_hashes_iter(&self) -> impl Iterator<Item = &B256> + '_ {
139        self.transactions_iter().filter_map(|tx| tx.blob_versioned_hashes()).flatten()
140    }
141
142    /// Returns an iterator over the encoded 2718 transactions.
143    ///
144    /// This is also known as `raw transactions`.
145    ///
146    /// See also [`Encodable2718`].
147    #[doc(alias = "raw_transactions_iter")]
148    fn encoded_2718_transactions_iter(&self) -> impl Iterator<Item = Vec<u8>> + '_ {
149        self.transactions_iter().map(|tx| tx.encoded_2718())
150    }
151
152    /// Returns a vector of encoded 2718 transactions.
153    ///
154    /// This is also known as `raw transactions`.
155    ///
156    /// See also [`Encodable2718`].
157    #[doc(alias = "raw_transactions")]
158    fn encoded_2718_transactions(&self) -> Vec<Bytes> {
159        self.encoded_2718_transactions_iter().map(Into::into).collect()
160    }
161
162    /// Recover signer addresses for all transactions in the block body.
163    fn recover_signers(&self) -> Result<Vec<Address>, RecoveryError> {
164        crate::transaction::recover::recover_signers(self.transactions())
165    }
166
167    /// Recover signer addresses for all transactions in the block body.
168    ///
169    /// Returns an error if some transaction's signature is invalid.
170    fn try_recover_signers(&self) -> Result<Vec<Address>, RecoveryError> {
171        self.recover_signers()
172    }
173
174    /// Recover signer addresses for all transactions in the block body _without ensuring that the
175    /// signature has a low `s` value_.
176    ///
177    /// Returns `RecoveryError`, if some transaction's signature is invalid.
178    fn recover_signers_unchecked(&self) -> Result<Vec<Address>, RecoveryError> {
179        crate::transaction::recover::recover_signers_unchecked(self.transactions())
180    }
181
182    /// Recover signer addresses for all transactions in the block body _without ensuring that the
183    /// signature has a low `s` value_.
184    ///
185    /// Returns an error if some transaction's signature is invalid.
186    fn try_recover_signers_unchecked(&self) -> Result<Vec<Address>, RecoveryError> {
187        self.recover_signers_unchecked()
188    }
189
190    /// Recovers signers for all transactions in the block body and returns a vector of
191    /// [`Recovered`].
192    fn recover_transactions(&self) -> Result<Vec<Recovered<Self::Transaction>>, RecoveryError> {
193        self.recover_signers().map(|signers| {
194            self.transactions()
195                .iter()
196                .zip(signers)
197                .map(|(tx, signer)| tx.clone().with_signer(signer))
198                .collect()
199        })
200    }
201}
202
203impl<T, H> BlockBody for alloy_consensus::BlockBody<T, H>
204where
205    T: SignedTransaction,
206    H: BlockHeader,
207{
208    type Transaction = T;
209    type OmmerHeader = H;
210
211    fn transactions(&self) -> &[Self::Transaction] {
212        &self.transactions
213    }
214
215    fn into_ethereum_body(self) -> Self {
216        self
217    }
218
219    fn into_transactions(self) -> Vec<Self::Transaction> {
220        self.transactions
221    }
222
223    fn withdrawals(&self) -> Option<&Withdrawals> {
224        self.withdrawals.as_ref()
225    }
226
227    fn ommers(&self) -> Option<&[Self::OmmerHeader]> {
228        Some(&self.ommers)
229    }
230}
231
232/// This is a helper alias to make it easy to refer to the inner `Transaction` associated type of a
233/// given type that implements [`BlockBody`].
234pub type BodyTx<N> = <N as BlockBody>::Transaction;
235
236/// This is a helper alias to make it easy to refer to the inner `OmmerHeader` associated type of a
237/// given type that implements [`BlockBody`].
238pub type BodyOmmer<N> = <N as BlockBody>::OmmerHeader;