reth_seismic_evm/
build.rs

1//! The SeismicBlockAssembler. Nearly identical to the EthBlockAssembler, except with seismic types
2
3use alloc::sync::Arc;
4use alloy_consensus::{
5    proofs, Block, BlockBody, BlockHeader, Header, Transaction, TxReceipt, EMPTY_OMMER_ROOT_HASH,
6};
7use alloy_eips::merge::BEACON_NONCE;
8use alloy_evm::block::BlockExecutorFactory;
9use alloy_primitives::{logs_bloom, Bytes};
10use reth_chainspec::{EthChainSpec, EthereumHardforks};
11use reth_evm::{
12    eth::EthBlockExecutionCtx,
13    execute::{BlockAssembler, BlockAssemblerInput},
14};
15use reth_execution_errors::BlockExecutionError;
16use reth_execution_types::BlockExecutionResult;
17use reth_seismic_primitives::{SeismicReceipt, SeismicTransactionSigned};
18
19/// Block builder for Seismic.
20#[derive(Debug, Clone)]
21pub struct SeismicBlockAssembler<ChainSpec> {
22    /// The chainspec.
23    pub chain_spec: Arc<ChainSpec>,
24    /// Extra data to use for the blocks.
25    pub extra_data: Bytes,
26}
27
28impl<ChainSpec> SeismicBlockAssembler<ChainSpec> {
29    /// Creates a new [`SeismicBlockAssembler`].
30    pub fn new(chain_spec: Arc<ChainSpec>) -> Self {
31        Self { chain_spec, extra_data: Default::default() }
32    }
33}
34
35impl<F, ChainSpec> BlockAssembler<F> for SeismicBlockAssembler<ChainSpec>
36where
37    F: for<'a> BlockExecutorFactory<
38        ExecutionCtx<'a> = EthBlockExecutionCtx<'a>,
39        Transaction = SeismicTransactionSigned,
40        Receipt = SeismicReceipt,
41    >,
42    ChainSpec: EthChainSpec + EthereumHardforks,
43{
44    type Block = Block<SeismicTransactionSigned>;
45
46    fn assemble_block(
47        &self,
48        input: BlockAssemblerInput<'_, '_, F>,
49    ) -> Result<Block<SeismicTransactionSigned>, BlockExecutionError> {
50        let BlockAssemblerInput {
51            evm_env,
52            execution_ctx: ctx,
53            parent,
54            transactions,
55            output: BlockExecutionResult { receipts, requests, gas_used },
56            state_root,
57            ..
58        } = input;
59
60        let timestamp = evm_env.block_env.timestamp;
61
62        let transactions_root = proofs::calculate_transaction_root(&transactions);
63        let receipts_root = SeismicReceipt::calculate_receipt_root_no_memo(receipts);
64        let logs_bloom = logs_bloom(receipts.iter().flat_map(|r| r.logs()));
65
66        let withdrawals = self
67            .chain_spec
68            .is_shanghai_active_at_timestamp(timestamp)
69            .then(|| ctx.withdrawals.map(|w| w.into_owned()).unwrap_or_default());
70
71        let withdrawals_root =
72            withdrawals.as_deref().map(|w| proofs::calculate_withdrawals_root(w));
73        let requests_hash = self
74            .chain_spec
75            .is_prague_active_at_timestamp(timestamp)
76            .then(|| requests.requests_hash());
77
78        let mut excess_blob_gas = None;
79        let mut blob_gas_used = None;
80
81        // only determine cancun fields when active
82        if self.chain_spec.is_cancun_active_at_timestamp(timestamp) {
83            blob_gas_used =
84                Some(transactions.iter().map(|tx| tx.blob_gas_used().unwrap_or_default()).sum());
85            excess_blob_gas = if self.chain_spec.is_cancun_active_at_timestamp(parent.timestamp) {
86                parent.maybe_next_block_excess_blob_gas(
87                    self.chain_spec.blob_params_at_timestamp(timestamp),
88                )
89            } else {
90                // for the first post-fork block, both parent.blob_gas_used and
91                // parent.excess_blob_gas are evaluated as 0
92                Some(alloy_eips::eip7840::BlobParams::cancun().next_block_excess_blob_gas(0, 0))
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,
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,
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}