reth_evm_ethereum/
build.rs

1use alloc::{sync::Arc, vec::Vec};
2use alloy_consensus::{
3    proofs::{self, calculate_receipt_root},
4    Block, BlockBody, BlockHeader, Header, TxReceipt, EMPTY_OMMER_ROOT_HASH,
5};
6use alloy_eips::merge::BEACON_NONCE;
7use alloy_evm::{block::BlockExecutorFactory, eth::EthBlockExecutionCtx};
8use reth_chainspec::{EthChainSpec, EthereumHardforks};
9use reth_evm::execute::{BlockAssembler, BlockAssemblerInput, BlockExecutionError};
10use reth_execution_types::BlockExecutionResult;
11use reth_primitives_traits::{logs_bloom, Receipt, SignedTransaction};
12use revm::context::Block as _;
13
14/// Block builder for Ethereum.
15#[derive(Debug, Clone)]
16pub struct EthBlockAssembler<ChainSpec = reth_chainspec::ChainSpec> {
17    /// The chainspec.
18    pub chain_spec: Arc<ChainSpec>,
19}
20
21impl<ChainSpec> EthBlockAssembler<ChainSpec> {
22    /// Creates a new [`EthBlockAssembler`].
23    pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
24        Self { chain_spec }
25    }
26}
27
28impl<F, ChainSpec> BlockAssembler<F> for EthBlockAssembler<ChainSpec>
29where
30    F: for<'a> BlockExecutorFactory<
31        ExecutionCtx<'a> = EthBlockExecutionCtx<'a>,
32        Transaction: SignedTransaction,
33        Receipt: Receipt,
34    >,
35    ChainSpec: EthChainSpec + EthereumHardforks,
36{
37    type Block = Block<F::Transaction>;
38
39    fn assemble_block(
40        &self,
41        input: BlockAssemblerInput<'_, '_, F>,
42    ) -> Result<Self::Block, BlockExecutionError> {
43        let BlockAssemblerInput {
44            evm_env,
45            execution_ctx: ctx,
46            parent,
47            transactions,
48            output: BlockExecutionResult { receipts, requests, gas_used, blob_gas_used },
49            state_root,
50            ..
51        } = input;
52
53        let timestamp = evm_env.block_env.timestamp().saturating_to();
54
55        let transactions_root = proofs::calculate_transaction_root(&transactions);
56        let receipts_root = calculate_receipt_root(
57            &receipts.iter().map(|r| r.with_bloom_ref()).collect::<Vec<_>>(),
58        );
59        let logs_bloom = logs_bloom(receipts.iter().flat_map(|r| r.logs()));
60
61        let withdrawals = self
62            .chain_spec
63            .is_shanghai_active_at_timestamp(timestamp)
64            .then(|| ctx.withdrawals.map(|w| w.into_owned()).unwrap_or_default());
65
66        let withdrawals_root =
67            withdrawals.as_deref().map(|w| proofs::calculate_withdrawals_root(w));
68        let requests_hash = self
69            .chain_spec
70            .is_prague_active_at_timestamp(timestamp)
71            .then(|| requests.requests_hash());
72
73        let mut excess_blob_gas = None;
74        let mut block_blob_gas_used = None;
75
76        // only determine cancun fields when active
77        if self.chain_spec.is_cancun_active_at_timestamp(timestamp) {
78            block_blob_gas_used = Some(*blob_gas_used);
79            excess_blob_gas = if self.chain_spec.is_cancun_active_at_timestamp(parent.timestamp) {
80                parent.maybe_next_block_excess_blob_gas(
81                    self.chain_spec.blob_params_at_timestamp(timestamp),
82                )
83            } else {
84                // for the first post-fork block, both parent.blob_gas_used and
85                // parent.excess_blob_gas are evaluated as 0
86                Some(
87                    alloy_eips::eip7840::BlobParams::cancun()
88                        .next_block_excess_blob_gas_osaka(0, 0, 0),
89                )
90            };
91        }
92
93        let header = Header {
94            parent_hash: ctx.parent_hash,
95            ommers_hash: EMPTY_OMMER_ROOT_HASH,
96            beneficiary: evm_env.block_env.beneficiary(),
97            state_root,
98            transactions_root,
99            receipts_root,
100            withdrawals_root,
101            logs_bloom,
102            timestamp,
103            mix_hash: evm_env.block_env.prevrandao().unwrap_or_default(),
104            nonce: BEACON_NONCE.into(),
105            base_fee_per_gas: Some(evm_env.block_env.basefee()),
106            number: evm_env.block_env.number().saturating_to(),
107            gas_limit: evm_env.block_env.gas_limit(),
108            difficulty: evm_env.block_env.difficulty(),
109            gas_used: *gas_used,
110            extra_data: ctx.extra_data,
111            parent_beacon_block_root: ctx.parent_beacon_block_root,
112            blob_gas_used: block_blob_gas_used,
113            excess_blob_gas,
114            requests_hash,
115        };
116
117        Ok(Block {
118            header,
119            body: BlockBody { transactions, ommers: Default::default(), withdrawals },
120        })
121    }
122}