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