reth_evm_ethereum/
build.rs

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