reth_evm_ethereum/
build.rs1use 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#[derive(Debug, Clone)]
16pub struct EthBlockAssembler<ChainSpec = reth_chainspec::ChainSpec> {
17 pub chain_spec: Arc<ChainSpec>,
19 pub extra_data: Bytes,
21}
22
23impl<ChainSpec> EthBlockAssembler<ChainSpec> {
24 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.saturating_to();
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 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 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: self.extra_data.clone(),
112 parent_beacon_block_root: ctx.parent_beacon_block_root,
113 blob_gas_used,
114 excess_blob_gas,
115 requests_hash,
116 };
117
118 Ok(Block {
119 header,
120 body: BlockBody { transactions, ommers: Default::default(), withdrawals },
121 })
122 }
123}