reth_evm_ethereum/
build.rs

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