reth_evm_ethereum/
build.rs1use 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#[derive(Debug, Clone)]
16pub struct EthBlockAssembler<ChainSpec = reth_chainspec::ChainSpec> {
17 pub chain_spec: Arc<ChainSpec>,
19}
20
21impl<ChainSpec> EthBlockAssembler<ChainSpec> {
22 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 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 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}