Skip to main content

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::{eip4895::Withdrawals, 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            block_access_list_hash,
51            ..
52        } = input;
53
54        let timestamp = evm_env.block_env.timestamp().saturating_to();
55
56        let transactions_root = proofs::calculate_transaction_root(&transactions);
57        let receipts_root = calculate_receipt_root(
58            &receipts.iter().map(|r| r.with_bloom_ref()).collect::<Vec<_>>(),
59        );
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(|| Withdrawals::new(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 block_blob_gas_used = None;
76
77        // only determine cancun fields when active
78        if self.chain_spec.is_cancun_active_at_timestamp(timestamp) {
79            block_blob_gas_used = Some(*blob_gas_used);
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(
88                    alloy_eips::eip7840::BlobParams::cancun()
89                        .next_block_excess_blob_gas_osaka(0, 0, 0),
90                )
91            };
92        }
93
94        let header = Header {
95            parent_hash: ctx.parent_hash,
96            ommers_hash: EMPTY_OMMER_ROOT_HASH,
97            beneficiary: evm_env.block_env.beneficiary(),
98            state_root,
99            transactions_root,
100            receipts_root,
101            withdrawals_root,
102            logs_bloom,
103            timestamp,
104            mix_hash: evm_env.block_env.prevrandao().unwrap_or_default(),
105            nonce: BEACON_NONCE.into(),
106            base_fee_per_gas: Some(evm_env.block_env.basefee()),
107            number: evm_env.block_env.number().saturating_to(),
108            gas_limit: evm_env.block_env.gas_limit(),
109            difficulty: evm_env.block_env.difficulty(),
110            gas_used: *gas_used,
111            extra_data: ctx.extra_data,
112            parent_beacon_block_root: ctx.parent_beacon_block_root,
113            blob_gas_used: block_blob_gas_used,
114            excess_blob_gas,
115            requests_hash,
116            block_access_list_hash,
117            slot_number: ctx.slot_number,
118        };
119
120        Ok(Block {
121            header,
122            body: BlockBody { transactions, ommers: Default::default(), withdrawals },
123        })
124    }
125}