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 alloy_primitives::Bytes;
9use reth_chainspec::{EthChainSpec, EthereumHardforks};
10use reth_evm::execute::{BlockAssembler, BlockAssemblerInput, BlockExecutionError};
11use reth_execution_types::BlockExecutionResult;
12use reth_primitives_traits::{logs_bloom, Receipt, SignedTransaction};
13use revm::context::Block as _;
14
15#[derive(Debug, Clone)]
17pub struct EthBlockAssembler<ChainSpec = reth_chainspec::ChainSpec> {
18 pub chain_spec: Arc<ChainSpec>,
20 pub extra_data: Bytes,
22}
23
24impl<ChainSpec> EthBlockAssembler<ChainSpec> {
25 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: SignedTransaction,
36 Receipt: Receipt,
37 >,
38 ChainSpec: EthChainSpec + EthereumHardforks,
39{
40 type Block = Block<F::Transaction>;
41
42 fn assemble_block(
43 &self,
44 input: BlockAssemblerInput<'_, '_, F>,
45 ) -> Result<Self::Block, BlockExecutionError> {
46 let BlockAssemblerInput {
47 evm_env,
48 execution_ctx: ctx,
49 parent,
50 transactions,
51 output: BlockExecutionResult { receipts, requests, gas_used, blob_gas_used },
52 state_root,
53 ..
54 } = input;
55
56 let timestamp = evm_env.block_env.timestamp().saturating_to();
57
58 let transactions_root = proofs::calculate_transaction_root(&transactions);
59 let receipts_root = calculate_receipt_root(
60 &receipts.iter().map(|r| r.with_bloom_ref()).collect::<Vec<_>>(),
61 );
62 let logs_bloom = logs_bloom(receipts.iter().flat_map(|r| r.logs()));
63
64 let withdrawals = self
65 .chain_spec
66 .is_shanghai_active_at_timestamp(timestamp)
67 .then(|| ctx.withdrawals.map(|w| w.into_owned()).unwrap_or_default());
68
69 let withdrawals_root =
70 withdrawals.as_deref().map(|w| proofs::calculate_withdrawals_root(w));
71 let requests_hash = self
72 .chain_spec
73 .is_prague_active_at_timestamp(timestamp)
74 .then(|| requests.requests_hash());
75
76 let mut excess_blob_gas = None;
77 let mut block_blob_gas_used = None;
78
79 if self.chain_spec.is_cancun_active_at_timestamp(timestamp) {
81 block_blob_gas_used = Some(*blob_gas_used);
82 excess_blob_gas = if self.chain_spec.is_cancun_active_at_timestamp(parent.timestamp) {
83 parent.maybe_next_block_excess_blob_gas(
84 self.chain_spec.blob_params_at_timestamp(timestamp),
85 )
86 } else {
87 Some(
90 alloy_eips::eip7840::BlobParams::cancun()
91 .next_block_excess_blob_gas_osaka(0, 0, 0),
92 )
93 };
94 }
95
96 let header = Header {
97 parent_hash: ctx.parent_hash,
98 ommers_hash: EMPTY_OMMER_ROOT_HASH,
99 beneficiary: evm_env.block_env.beneficiary(),
100 state_root,
101 transactions_root,
102 receipts_root,
103 withdrawals_root,
104 logs_bloom,
105 timestamp,
106 mix_hash: evm_env.block_env.prevrandao().unwrap_or_default(),
107 nonce: BEACON_NONCE.into(),
108 base_fee_per_gas: Some(evm_env.block_env.basefee()),
109 number: evm_env.block_env.number().saturating_to(),
110 gas_limit: evm_env.block_env.gas_limit(),
111 difficulty: evm_env.block_env.difficulty(),
112 gas_used: *gas_used,
113 extra_data: self.extra_data.clone(),
114 parent_beacon_block_root: ctx.parent_beacon_block_root,
115 blob_gas_used: block_blob_gas_used,
116 excess_blob_gas,
117 requests_hash,
118 };
119
120 Ok(Block {
121 header,
122 body: BlockBody { transactions, ommers: Default::default(), withdrawals },
123 })
124 }
125}