reth_optimism_evm/
build.rs
1use alloc::sync::Arc;
2use alloy_consensus::{
3 constants::EMPTY_WITHDRAWALS, proofs, Block, BlockBody, Header, TxReceipt,
4 EMPTY_OMMER_ROOT_HASH,
5};
6use alloy_eips::merge::BEACON_NONCE;
7use alloy_evm::block::BlockExecutorFactory;
8use alloy_op_evm::OpBlockExecutionCtx;
9use alloy_primitives::logs_bloom;
10use reth_evm::execute::{BlockAssembler, BlockAssemblerInput};
11use reth_execution_errors::BlockExecutionError;
12use reth_execution_types::BlockExecutionResult;
13use reth_optimism_consensus::{calculate_receipt_root_no_memo_optimism, isthmus};
14use reth_optimism_forks::OpHardforks;
15use reth_optimism_primitives::DepositReceipt;
16use reth_primitives_traits::{Receipt, SignedTransaction};
17
18#[derive(Debug)]
20pub struct OpBlockAssembler<ChainSpec> {
21 chain_spec: Arc<ChainSpec>,
22}
23
24impl<ChainSpec> OpBlockAssembler<ChainSpec> {
25 pub fn new(chain_spec: Arc<ChainSpec>) -> Self {
27 Self { chain_spec }
28 }
29}
30
31impl<ChainSpec> Clone for OpBlockAssembler<ChainSpec> {
32 fn clone(&self) -> Self {
33 Self { chain_spec: self.chain_spec.clone() }
34 }
35}
36
37impl<F, ChainSpec> BlockAssembler<F> for OpBlockAssembler<ChainSpec>
38where
39 ChainSpec: OpHardforks,
40 F: for<'a> BlockExecutorFactory<
41 ExecutionCtx<'a> = OpBlockExecutionCtx,
42 Transaction: SignedTransaction,
43 Receipt: Receipt + DepositReceipt,
44 >,
45{
46 type Block = alloy_consensus::Block<F::Transaction>;
47
48 fn assemble_block(
49 &self,
50 input: BlockAssemblerInput<'_, '_, F>,
51 ) -> Result<Self::Block, BlockExecutionError> {
52 let BlockAssemblerInput {
53 evm_env,
54 execution_ctx: ctx,
55 transactions,
56 output: BlockExecutionResult { receipts, gas_used, .. },
57 bundle_state,
58 state_root,
59 state_provider,
60 ..
61 } = input;
62
63 let timestamp = evm_env.block_env.timestamp;
64
65 let transactions_root = proofs::calculate_transaction_root(&transactions);
66 let receipts_root =
67 calculate_receipt_root_no_memo_optimism(receipts, &self.chain_spec, timestamp);
68 let logs_bloom = logs_bloom(receipts.iter().flat_map(|r| r.logs()));
69
70 let withdrawals_root = if self.chain_spec.is_isthmus_active_at_timestamp(timestamp) {
71 Some(
74 isthmus::withdrawals_root(bundle_state, state_provider)
75 .map_err(BlockExecutionError::other)?,
76 )
77 } else if self.chain_spec.is_canyon_active_at_timestamp(timestamp) {
78 Some(EMPTY_WITHDRAWALS)
79 } else {
80 None
81 };
82
83 let (excess_blob_gas, blob_gas_used) =
84 if self.chain_spec.is_ecotone_active_at_timestamp(timestamp) {
85 (Some(0), Some(0))
86 } else {
87 (None, None)
88 };
89
90 let header = Header {
91 parent_hash: ctx.parent_hash,
92 ommers_hash: EMPTY_OMMER_ROOT_HASH,
93 beneficiary: evm_env.block_env.beneficiary,
94 state_root,
95 transactions_root,
96 receipts_root,
97 withdrawals_root,
98 logs_bloom,
99 timestamp,
100 mix_hash: evm_env.block_env.prevrandao.unwrap_or_default(),
101 nonce: BEACON_NONCE.into(),
102 base_fee_per_gas: Some(evm_env.block_env.basefee),
103 number: evm_env.block_env.number,
104 gas_limit: evm_env.block_env.gas_limit,
105 difficulty: evm_env.block_env.difficulty,
106 gas_used: *gas_used,
107 extra_data: ctx.extra_data,
108 parent_beacon_block_root: ctx.parent_beacon_block_root,
109 blob_gas_used,
110 excess_blob_gas,
111 requests_hash: None,
112 };
113
114 Ok(Block::new(
115 header,
116 BlockBody {
117 transactions,
118 ommers: Default::default(),
119 withdrawals: self
120 .chain_spec
121 .is_canyon_active_at_timestamp(timestamp)
122 .then(Default::default),
123 },
124 ))
125 }
126}