reth_optimism_evm/
build.rs1use alloc::sync::Arc;
2use alloy_consensus::{
3 constants::EMPTY_WITHDRAWALS, proofs, Block, BlockBody, Header, TxReceipt,
4 EMPTY_OMMER_ROOT_HASH,
5};
6use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, 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 const fn new(chain_spec: Arc<ChainSpec>) -> Self {
27 Self { chain_spec }
28 }
29}
30
31impl<ChainSpec: OpHardforks> OpBlockAssembler<ChainSpec> {
32 pub fn assemble_block<
34 F: for<'a> BlockExecutorFactory<
35 ExecutionCtx<'a>: Into<OpBlockExecutionCtx>,
36 Transaction: SignedTransaction,
37 Receipt: Receipt + DepositReceipt,
38 >,
39 H,
40 >(
41 &self,
42 input: BlockAssemblerInput<'_, '_, F, H>,
43 ) -> Result<Block<F::Transaction>, BlockExecutionError> {
44 let BlockAssemblerInput {
45 evm_env,
46 execution_ctx: ctx,
47 transactions,
48 output: BlockExecutionResult { receipts, gas_used, .. },
49 bundle_state,
50 state_root,
51 state_provider,
52 ..
53 } = input;
54 let ctx = ctx.into();
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 =
60 calculate_receipt_root_no_memo_optimism(receipts, &self.chain_spec, timestamp);
61 let logs_bloom = logs_bloom(receipts.iter().flat_map(|r| r.logs()));
62
63 let mut requests_hash = None;
64
65 let withdrawals_root = if self.chain_spec.is_isthmus_active_at_timestamp(timestamp) {
66 requests_hash = Some(EMPTY_REQUESTS_HASH);
68
69 Some(
72 isthmus::withdrawals_root(bundle_state, state_provider)
73 .map_err(BlockExecutionError::other)?,
74 )
75 } else if self.chain_spec.is_canyon_active_at_timestamp(timestamp) {
76 Some(EMPTY_WITHDRAWALS)
77 } else {
78 None
79 };
80
81 let (excess_blob_gas, blob_gas_used) =
82 if self.chain_spec.is_ecotone_active_at_timestamp(timestamp) {
83 (Some(0), Some(0))
84 } else {
85 (None, None)
86 };
87
88 let header = Header {
89 parent_hash: ctx.parent_hash,
90 ommers_hash: EMPTY_OMMER_ROOT_HASH,
91 beneficiary: evm_env.block_env.beneficiary,
92 state_root,
93 transactions_root,
94 receipts_root,
95 withdrawals_root,
96 logs_bloom,
97 timestamp,
98 mix_hash: evm_env.block_env.prevrandao.unwrap_or_default(),
99 nonce: BEACON_NONCE.into(),
100 base_fee_per_gas: Some(evm_env.block_env.basefee),
101 number: evm_env.block_env.number.saturating_to(),
102 gas_limit: evm_env.block_env.gas_limit,
103 difficulty: evm_env.block_env.difficulty,
104 gas_used: *gas_used,
105 extra_data: ctx.extra_data,
106 parent_beacon_block_root: ctx.parent_beacon_block_root,
107 blob_gas_used,
108 excess_blob_gas,
109 requests_hash,
110 };
111
112 Ok(Block::new(
113 header,
114 BlockBody {
115 transactions,
116 ommers: Default::default(),
117 withdrawals: self
118 .chain_spec
119 .is_canyon_active_at_timestamp(timestamp)
120 .then(Default::default),
121 },
122 ))
123 }
124}
125
126impl<ChainSpec> Clone for OpBlockAssembler<ChainSpec> {
127 fn clone(&self) -> Self {
128 Self { chain_spec: self.chain_spec.clone() }
129 }
130}
131
132impl<F, ChainSpec> BlockAssembler<F> for OpBlockAssembler<ChainSpec>
133where
134 ChainSpec: OpHardforks,
135 F: for<'a> BlockExecutorFactory<
136 ExecutionCtx<'a> = OpBlockExecutionCtx,
137 Transaction: SignedTransaction,
138 Receipt: Receipt + DepositReceipt,
139 >,
140{
141 type Block = Block<F::Transaction>;
142
143 fn assemble_block(
144 &self,
145 input: BlockAssemblerInput<'_, '_, F>,
146 ) -> Result<Self::Block, BlockExecutionError> {
147 self.assemble_block(input)
148 }
149}