From 07090b315cc716b107f9f3471729d7dcea21a0b4 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 4 Feb 2025 16:55:51 +0400 Subject: [PATCH] feat: abstract `OpBeaconConsensus` over primitives and chainspec (#14171) --- crates/optimism/chainspec/src/lib.rs | 155 +------------------- crates/optimism/consensus/Cargo.toml | 2 +- crates/optimism/consensus/src/lib.rs | 42 +++--- crates/optimism/consensus/src/proof.rs | 9 +- crates/optimism/consensus/src/validation.rs | 154 ++++++++++++++++++- crates/optimism/evm/src/config.rs | 53 ++++--- crates/optimism/evm/src/execute.rs | 2 +- crates/optimism/evm/src/lib.rs | 30 ++-- crates/optimism/node/src/node.rs | 11 +- 9 files changed, 237 insertions(+), 221 deletions(-) diff --git a/crates/optimism/chainspec/src/lib.rs b/crates/optimism/chainspec/src/lib.rs index 2095bbd53..3387d06c2 100644 --- a/crates/optimism/chainspec/src/lib.rs +++ b/crates/optimism/chainspec/src/lib.rs @@ -19,7 +19,7 @@ mod op_sepolia; use alloc::{boxed::Box, vec, vec::Vec}; use alloy_chains::Chain; -use alloy_consensus::{BlockHeader, Header}; +use alloy_consensus::Header; use alloy_eips::eip7840::BlobParams; use alloy_genesis::Genesis; use alloy_primitives::{B256, U256}; @@ -28,7 +28,6 @@ pub use base_sepolia::BASE_SEPOLIA; use derive_more::{Constructor, Deref, Display, From, Into}; pub use dev::OP_DEV; pub use op::OP_MAINNET; -use op_alloy_consensus::{decode_holocene_extra_data, EIP1559ParamError}; pub use op_sepolia::OP_SEPOLIA; use reth_chainspec::{ BaseFeeParams, BaseFeeParamsKind, ChainSpec, ChainSpecBuilder, DepositContract, EthChainSpec, @@ -195,55 +194,6 @@ impl OpChainSpec { pub fn from_genesis(genesis: Genesis) -> Self { genesis.into() } - - /// Extracts the Holocene 1599 parameters from the encoded extra data from the parent header. - /// - /// Caution: Caller must ensure that holocene is active in the parent header. - /// - /// See also [Base fee computation](https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation) - pub fn decode_holocene_base_fee( - &self, - parent: &H, - timestamp: u64, - ) -> Result { - let (elasticity, denominator) = decode_holocene_extra_data(parent.extra_data())?; - let base_fee = if elasticity == 0 && denominator == 0 { - parent - .next_block_base_fee(self.base_fee_params_at_timestamp(timestamp)) - .unwrap_or_default() - } else { - let base_fee_params = BaseFeeParams::new(denominator as u128, elasticity as u128); - parent.next_block_base_fee(base_fee_params).unwrap_or_default() - }; - Ok(base_fee) - } - - /// Read from parent to determine the base fee for the next block - /// - /// See also [Base fee computation](https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation) - pub fn next_block_base_fee( - &self, - parent: &H, - timestamp: u64, - ) -> Result { - // > if Holocene is active in parent_header.timestamp, then the parameters from - // > parent_header.extraData are used. - let is_holocene_activated = - self.inner.is_fork_active_at_timestamp(OpHardfork::Holocene, parent.timestamp()); - - // If we are in the Holocene, we need to use the base fee params - // from the parent block's extra data. - // Else, use the base fee params (default values) from chainspec - if is_holocene_activated { - Ok(U256::from(self.decode_holocene_base_fee(parent, timestamp)?)) - } else { - Ok(U256::from( - parent - .next_block_base_fee(self.base_fee_params_at_timestamp(timestamp)) - .unwrap_or_default(), - )) - } - } } impl EthChainSpec for OpChainSpec { @@ -483,10 +433,8 @@ impl OpGenesisInfo { #[cfg(test)] mod tests { - use std::sync::Arc; - use alloy_genesis::{ChainConfig, Genesis}; - use alloy_primitives::{b256, hex, Bytes}; + use alloy_primitives::b256; use reth_chainspec::{test_fork_ids, BaseFeeParams, BaseFeeParamsKind}; use reth_ethereum_forks::{EthereumHardfork, ForkCondition, ForkHash, ForkId, Head}; use reth_optimism_forks::{OpHardfork, OpHardforks}; @@ -1026,105 +974,6 @@ mod tests { assert_eq!(expected_hardforks.len(), hardforks.len()); } - #[test] - fn test_get_base_fee_pre_holocene() { - let op_chain_spec = &BASE_SEPOLIA; - let parent = Header { - base_fee_per_gas: Some(1), - gas_used: 15763614, - gas_limit: 144000000, - ..Default::default() - }; - let base_fee = op_chain_spec.next_block_base_fee(&parent, 0); - assert_eq!( - base_fee.unwrap(), - U256::from( - parent - .next_block_base_fee(op_chain_spec.base_fee_params_at_timestamp(0)) - .unwrap_or_default() - ) - ); - } - - fn holocene_chainspec() -> Arc { - let mut hardforks = OpHardfork::base_sepolia(); - hardforks.insert(OpHardfork::Holocene.boxed(), ForkCondition::Timestamp(1800000000)); - Arc::new(OpChainSpec { - inner: ChainSpec { - chain: BASE_SEPOLIA.inner.chain, - genesis: BASE_SEPOLIA.inner.genesis.clone(), - genesis_hash: BASE_SEPOLIA.inner.genesis_hash.clone(), - paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks, - base_fee_params: BASE_SEPOLIA.inner.base_fee_params.clone(), - prune_delete_limit: 10000, - ..Default::default() - }, - }) - } - - #[test] - fn test_get_base_fee_holocene_extra_data_not_set() { - let op_chain_spec = holocene_chainspec(); - let parent = Header { - base_fee_per_gas: Some(1), - gas_used: 15763614, - gas_limit: 144000000, - timestamp: 1800000003, - extra_data: Bytes::from_static(&[0, 0, 0, 0, 0, 0, 0, 0, 0]), - ..Default::default() - }; - let base_fee = op_chain_spec.next_block_base_fee(&parent, 1800000005); - assert_eq!( - base_fee.unwrap(), - U256::from( - parent - .next_block_base_fee(op_chain_spec.base_fee_params_at_timestamp(0)) - .unwrap_or_default() - ) - ); - } - - #[test] - fn test_get_base_fee_holocene_extra_data_set() { - let op_chain_spec = holocene_chainspec(); - let parent = Header { - base_fee_per_gas: Some(1), - gas_used: 15763614, - gas_limit: 144000000, - extra_data: Bytes::from_static(&[0, 0, 0, 0, 8, 0, 0, 0, 8]), - timestamp: 1800000003, - ..Default::default() - }; - - let base_fee = op_chain_spec.next_block_base_fee(&parent, 1800000005); - assert_eq!( - base_fee.unwrap(), - U256::from( - parent - .next_block_base_fee(BaseFeeParams::new(0x00000008, 0x00000008)) - .unwrap_or_default() - ) - ); - } - - // - #[test] - fn test_get_base_fee_holocene_extra_data_set_base_sepolia() { - let op_chain_spec = BASE_SEPOLIA.clone(); - let parent = Header { - base_fee_per_gas: Some(507), - gas_used: 4847634, - gas_limit: 60000000, - extra_data: hex!("00000000fa0000000a").into(), - timestamp: 1735315544, - ..Default::default() - }; - - let base_fee = op_chain_spec.next_block_base_fee(&parent, 1735315546).unwrap(); - assert_eq!(base_fee, U256::from(507)); - } - #[test] fn json_genesis() { let geth_genesis = r#" diff --git a/crates/optimism/consensus/Cargo.toml b/crates/optimism/consensus/Cargo.toml index 7f2378a5b..2976ffd8e 100644 --- a/crates/optimism/consensus/Cargo.toml +++ b/crates/optimism/consensus/Cargo.toml @@ -30,12 +30,12 @@ alloy-eips.workspace = true alloy-primitives.workspace = true alloy-consensus.workspace = true alloy-trie.workspace = true +op-alloy-consensus.workspace = true tracing.workspace = true [dev-dependencies] alloy-primitives.workspace = true -op-alloy-consensus.workspace = true reth-optimism-chainspec.workspace = true [features] diff --git a/crates/optimism/consensus/src/lib.rs b/crates/optimism/consensus/src/lib.rs index 93d7576fe..17ab58416 100644 --- a/crates/optimism/consensus/src/lib.rs +++ b/crates/optimism/consensus/src/lib.rs @@ -12,6 +12,8 @@ extern crate alloc; +use core::fmt::Debug; + use alloc::sync::Arc; use alloy_consensus::{BlockHeader as _, EMPTY_OMMER_ROOT_HASH}; use alloy_primitives::{B64, U256}; @@ -25,45 +27,50 @@ use reth_consensus_common::validation::{ validate_body_against_header, validate_cancun_gas, validate_header_base_fee, validate_header_extra_data, validate_header_gas, validate_shanghai_withdrawals, }; -use reth_optimism_chainspec::OpChainSpec; use reth_optimism_forks::OpHardforks; -use reth_optimism_primitives::{OpBlock, OpPrimitives, OpReceipt}; -use reth_primitives::{GotExpected, RecoveredBlock, SealedHeader}; +use reth_optimism_primitives::DepositReceipt; +use reth_primitives::{GotExpected, NodePrimitives, RecoveredBlock, SealedHeader}; mod proof; pub use proof::calculate_receipt_root_no_memo_optimism; use reth_primitives_traits::{Block, BlockBody, BlockHeader, SealedBlock}; mod validation; -pub use validation::validate_block_post_execution; +pub use validation::{ + decode_holocene_base_fee, next_block_base_fee, validate_block_post_execution, +}; /// Optimism consensus implementation. /// /// Provides basic checks as outlined in the execution specs. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct OpBeaconConsensus { +pub struct OpBeaconConsensus { /// Configuration - chain_spec: Arc, + chain_spec: Arc, } -impl OpBeaconConsensus { +impl OpBeaconConsensus { /// Create a new instance of [`OpBeaconConsensus`] - pub const fn new(chain_spec: Arc) -> Self { + pub const fn new(chain_spec: Arc) -> Self { Self { chain_spec } } } -impl FullConsensus for OpBeaconConsensus { +impl> + FullConsensus for OpBeaconConsensus +{ fn validate_block_post_execution( &self, - block: &RecoveredBlock, - input: PostExecutionInput<'_, OpReceipt>, + block: &RecoveredBlock, + input: PostExecutionInput<'_, N::Receipt>, ) -> Result<(), ConsensusError> { validate_block_post_execution(block.header(), &self.chain_spec, input.receipts) } } -impl Consensus for OpBeaconConsensus { +impl Consensus + for OpBeaconConsensus +{ type Error = ConsensusError; fn validate_body_against_header( @@ -105,7 +112,9 @@ impl Consensus for OpBeaconConsensus { } } -impl HeaderValidator for OpBeaconConsensus { +impl HeaderValidator + for OpBeaconConsensus +{ fn validate_header(&self, header: &SealedHeader) -> Result<(), ConsensusError> { validate_header_gas(header.header())?; validate_header_base_fee(header.header(), &self.chain_spec) @@ -129,10 +138,9 @@ impl HeaderValidator for OpBeaconConsensus { if self.chain_spec.is_holocene_active_at_timestamp(parent.timestamp()) { let header_base_fee = header.base_fee_per_gas().ok_or(ConsensusError::BaseFeeMissing)?; - let expected_base_fee = self - .chain_spec - .decode_holocene_base_fee(parent.header(), header.timestamp()) - .map_err(|_| ConsensusError::BaseFeeMissing)?; + let expected_base_fee = + decode_holocene_base_fee(&self.chain_spec, parent.header(), header.timestamp()) + .map_err(|_| ConsensusError::BaseFeeMissing)?; if expected_base_fee != header_base_fee { return Err(ConsensusError::BaseFeeDiff(GotExpected { expected: expected_base_fee, diff --git a/crates/optimism/consensus/src/proof.rs b/crates/optimism/consensus/src/proof.rs index f1c7e41f9..d473539e1 100644 --- a/crates/optimism/consensus/src/proof.rs +++ b/crates/optimism/consensus/src/proof.rs @@ -4,15 +4,14 @@ use alloc::vec::Vec; use alloy_eips::eip2718::Encodable2718; use alloy_primitives::B256; use alloy_trie::root::ordered_trie_root_with_encoder; -use reth_chainspec::ChainSpec; -use reth_optimism_forks::{OpHardfork, OpHardforks}; +use reth_optimism_forks::OpHardforks; use reth_optimism_primitives::DepositReceipt; use reth_primitives::ReceiptWithBloom; /// Calculates the receipt root for a header. pub(crate) fn calculate_receipt_root_optimism( receipts: &[ReceiptWithBloom], - chain_spec: &ChainSpec, + chain_spec: impl OpHardforks, timestamp: u64, ) -> B256 { // There is a minor bug in op-geth and op-erigon where in the Regolith hardfork, @@ -20,8 +19,8 @@ pub(crate) fn calculate_receipt_root_optimism( // encoding. In the Regolith Hardfork, we must strip the deposit nonce from the // receipts before calculating the receipt root. This was corrected in the Canyon // hardfork. - if chain_spec.is_fork_active_at_timestamp(OpHardfork::Regolith, timestamp) && - !chain_spec.is_fork_active_at_timestamp(OpHardfork::Canyon, timestamp) + if chain_spec.is_regolith_active_at_timestamp(timestamp) && + !chain_spec.is_canyon_active_at_timestamp(timestamp) { let receipts = receipts .iter() diff --git a/crates/optimism/consensus/src/validation.rs b/crates/optimism/consensus/src/validation.rs index 51d0745dd..4343a1b51 100644 --- a/crates/optimism/consensus/src/validation.rs +++ b/crates/optimism/consensus/src/validation.rs @@ -2,8 +2,10 @@ use crate::proof::calculate_receipt_root_optimism; use alloc::vec::Vec; use alloy_consensus::{BlockHeader, TxReceipt}; use alloy_primitives::{Bloom, B256}; -use reth_chainspec::{ChainSpec, EthereumHardforks}; +use op_alloy_consensus::{decode_holocene_extra_data, EIP1559ParamError}; +use reth_chainspec::{BaseFeeParams, EthChainSpec}; use reth_consensus::ConsensusError; +use reth_optimism_forks::OpHardforks; use reth_optimism_primitives::DepositReceipt; use reth_primitives::{gas_spent_by_transactions, GotExpected}; @@ -13,7 +15,7 @@ use reth_primitives::{gas_spent_by_transactions, GotExpected}; /// - Compares the gas used in the block header to the actual gas usage after execution pub fn validate_block_post_execution( header: impl BlockHeader, - chain_spec: &ChainSpec, + chain_spec: impl OpHardforks, receipts: &[R], ) -> Result<(), ConsensusError> { // Before Byzantium, receipts contained state root that would mean that expensive @@ -21,7 +23,7 @@ pub fn validate_block_post_execution( // transaction This was replaced with is_success flag. // See more about EIP here: https://eips.ethereum.org/EIPS/eip-658 if chain_spec.is_byzantium_active_at_block(header.number()) { - if let Err(error) = verify_receipts( + if let Err(error) = verify_receipts_optimism( header.receipts_root(), header.logs_bloom(), receipts, @@ -47,11 +49,11 @@ pub fn validate_block_post_execution( } /// Verify the calculated receipts root against the expected receipts root. -fn verify_receipts( +fn verify_receipts_optimism( expected_receipts_root: B256, expected_logs_bloom: Bloom, receipts: &[R], - chain_spec: &ChainSpec, + chain_spec: impl OpHardforks, timestamp: u64, ) -> Result<(), ConsensusError> { // Calculate receipts root. @@ -94,3 +96,145 @@ fn compare_receipts_root_and_logs_bloom( Ok(()) } + +/// Extracts the Holocene 1599 parameters from the encoded extra data from the parent header. +/// +/// Caution: Caller must ensure that holocene is active in the parent header. +/// +/// See also [Base fee computation](https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation) +pub fn decode_holocene_base_fee( + chain_spec: impl EthChainSpec + OpHardforks, + parent: impl BlockHeader, + timestamp: u64, +) -> Result { + let (elasticity, denominator) = decode_holocene_extra_data(parent.extra_data())?; + let base_fee_params = if elasticity == 0 && denominator == 0 { + chain_spec.base_fee_params_at_timestamp(timestamp) + } else { + BaseFeeParams::new(denominator as u128, elasticity as u128) + }; + + Ok(parent.next_block_base_fee(base_fee_params).unwrap_or_default()) +} + +/// Read from parent to determine the base fee for the next block +/// +/// See also [Base fee computation](https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation) +pub fn next_block_base_fee( + chain_spec: impl EthChainSpec + OpHardforks, + parent: impl BlockHeader, + timestamp: u64, +) -> Result { + // If we are in the Holocene, we need to use the base fee params + // from the parent block's extra data. + // Else, use the base fee params (default values) from chainspec + if chain_spec.is_holocene_active_at_timestamp(parent.timestamp()) { + Ok(decode_holocene_base_fee(chain_spec, parent, timestamp)?) + } else { + Ok(parent + .next_block_base_fee(chain_spec.base_fee_params_at_timestamp(timestamp)) + .unwrap_or_default()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_consensus::Header; + use alloy_primitives::{hex, Bytes, U256}; + use reth_chainspec::{ChainSpec, ForkCondition, Hardfork}; + use reth_optimism_chainspec::{OpChainSpec, BASE_SEPOLIA}; + use reth_optimism_forks::OpHardfork; + use std::sync::Arc; + + fn holocene_chainspec() -> Arc { + let mut hardforks = OpHardfork::base_sepolia(); + hardforks.insert(OpHardfork::Holocene.boxed(), ForkCondition::Timestamp(1800000000)); + Arc::new(OpChainSpec { + inner: ChainSpec { + chain: BASE_SEPOLIA.inner.chain, + genesis: BASE_SEPOLIA.inner.genesis.clone(), + genesis_hash: BASE_SEPOLIA.inner.genesis_hash.clone(), + paris_block_and_final_difficulty: Some((0, U256::from(0))), + hardforks, + base_fee_params: BASE_SEPOLIA.inner.base_fee_params.clone(), + prune_delete_limit: 10000, + ..Default::default() + }, + }) + } + + #[test] + fn test_get_base_fee_pre_holocene() { + let op_chain_spec = BASE_SEPOLIA.clone(); + let parent = Header { + base_fee_per_gas: Some(1), + gas_used: 15763614, + gas_limit: 144000000, + ..Default::default() + }; + let base_fee = next_block_base_fee(&op_chain_spec, &parent, 0); + assert_eq!( + base_fee.unwrap(), + parent + .next_block_base_fee(op_chain_spec.base_fee_params_at_timestamp(0)) + .unwrap_or_default() + ); + } + + #[test] + fn test_get_base_fee_holocene_extra_data_not_set() { + let op_chain_spec = holocene_chainspec(); + let parent = Header { + base_fee_per_gas: Some(1), + gas_used: 15763614, + gas_limit: 144000000, + timestamp: 1800000003, + extra_data: Bytes::from_static(&[0, 0, 0, 0, 0, 0, 0, 0, 0]), + ..Default::default() + }; + let base_fee = next_block_base_fee(&op_chain_spec, &parent, 1800000005); + assert_eq!( + base_fee.unwrap(), + parent + .next_block_base_fee(op_chain_spec.base_fee_params_at_timestamp(0)) + .unwrap_or_default() + ); + } + + #[test] + fn test_get_base_fee_holocene_extra_data_set() { + let parent = Header { + base_fee_per_gas: Some(1), + gas_used: 15763614, + gas_limit: 144000000, + extra_data: Bytes::from_static(&[0, 0, 0, 0, 8, 0, 0, 0, 8]), + timestamp: 1800000003, + ..Default::default() + }; + + let base_fee = next_block_base_fee(holocene_chainspec(), &parent, 1800000005); + assert_eq!( + base_fee.unwrap(), + parent + .next_block_base_fee(BaseFeeParams::new(0x00000008, 0x00000008)) + .unwrap_or_default() + ); + } + + // + #[test] + fn test_get_base_fee_holocene_extra_data_set_base_sepolia() { + let parent = Header { + base_fee_per_gas: Some(507), + gas_used: 4847634, + gas_limit: 60000000, + extra_data: hex!("00000000fa0000000a").into(), + timestamp: 1735315544, + ..Default::default() + }; + + let base_fee = next_block_base_fee(&*BASE_SEPOLIA, &parent, 1735315546).unwrap(); + assert_eq!(base_fee, 507); + } +} diff --git a/crates/optimism/evm/src/config.rs b/crates/optimism/evm/src/config.rs index 4544aea89..770791dba 100644 --- a/crates/optimism/evm/src/config.rs +++ b/crates/optimism/evm/src/config.rs @@ -1,10 +1,9 @@ use alloy_consensus::Header; -use reth_optimism_chainspec::OpChainSpec; -use reth_optimism_forks::OpHardfork; +use reth_optimism_forks::OpHardforks; /// Map the latest active hardfork at the given header to a revm /// [`SpecId`](revm_primitives::SpecId). -pub fn revm_spec(chain_spec: &OpChainSpec, header: &Header) -> revm_primitives::SpecId { +pub fn revm_spec(chain_spec: impl OpHardforks, header: &Header) -> revm_primitives::SpecId { revm_spec_by_timestamp_after_bedrock(chain_spec, header.timestamp) } @@ -15,22 +14,22 @@ pub fn revm_spec(chain_spec: &OpChainSpec, header: &Header) -> revm_primitives:: /// This is only intended to be used after the Bedrock, when hardforks are activated by /// timestamp. pub fn revm_spec_by_timestamp_after_bedrock( - chain_spec: &OpChainSpec, + chain_spec: impl OpHardforks, timestamp: u64, ) -> revm_primitives::SpecId { - if chain_spec.fork(OpHardfork::Isthmus).active_at_timestamp(timestamp) { + if chain_spec.is_isthmus_active_at_timestamp(timestamp) { revm_primitives::ISTHMUS - } else if chain_spec.fork(OpHardfork::Holocene).active_at_timestamp(timestamp) { + } else if chain_spec.is_holocene_active_at_timestamp(timestamp) { revm_primitives::HOLOCENE - } else if chain_spec.fork(OpHardfork::Granite).active_at_timestamp(timestamp) { + } else if chain_spec.is_granite_active_at_timestamp(timestamp) { revm_primitives::GRANITE - } else if chain_spec.fork(OpHardfork::Fjord).active_at_timestamp(timestamp) { + } else if chain_spec.is_fjord_active_at_timestamp(timestamp) { revm_primitives::FJORD - } else if chain_spec.fork(OpHardfork::Ecotone).active_at_timestamp(timestamp) { + } else if chain_spec.is_ecotone_active_at_timestamp(timestamp) { revm_primitives::ECOTONE - } else if chain_spec.fork(OpHardfork::Canyon).active_at_timestamp(timestamp) { + } else if chain_spec.is_canyon_active_at_timestamp(timestamp) { revm_primitives::CANYON - } else if chain_spec.fork(OpHardfork::Regolith).active_at_timestamp(timestamp) { + } else if chain_spec.is_regolith_active_at_timestamp(timestamp) { revm_primitives::REGOLITH } else { revm_primitives::BEDROCK @@ -51,35 +50,35 @@ mod tests { f(cs).build() } assert_eq!( - revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.isthmus_activated()), 0), + revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.isthmus_activated()), 0), revm_primitives::ISTHMUS ); assert_eq!( - revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.holocene_activated()), 0), + revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.holocene_activated()), 0), revm_primitives::HOLOCENE ); assert_eq!( - revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.granite_activated()), 0), + revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.granite_activated()), 0), revm_primitives::GRANITE ); assert_eq!( - revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.fjord_activated()), 0), + revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.fjord_activated()), 0), revm_primitives::FJORD ); assert_eq!( - revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.ecotone_activated()), 0), + revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.ecotone_activated()), 0), revm_primitives::ECOTONE ); assert_eq!( - revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.canyon_activated()), 0), + revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.canyon_activated()), 0), revm_primitives::CANYON ); assert_eq!( - revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.bedrock_activated()), 0), + revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.bedrock_activated()), 0), revm_primitives::BEDROCK ); assert_eq!( - revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.regolith_activated()), 0), + revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.regolith_activated()), 0), revm_primitives::REGOLITH ); } @@ -92,35 +91,35 @@ mod tests { f(cs).build() } assert_eq!( - revm_spec(&op_cs(|cs| cs.isthmus_activated()), &Default::default()), + revm_spec(op_cs(|cs| cs.isthmus_activated()), &Default::default()), revm_primitives::ISTHMUS ); assert_eq!( - revm_spec(&op_cs(|cs| cs.holocene_activated()), &Default::default()), + revm_spec(op_cs(|cs| cs.holocene_activated()), &Default::default()), revm_primitives::HOLOCENE ); assert_eq!( - revm_spec(&op_cs(|cs| cs.granite_activated()), &Default::default()), + revm_spec(op_cs(|cs| cs.granite_activated()), &Default::default()), revm_primitives::GRANITE ); assert_eq!( - revm_spec(&op_cs(|cs| cs.fjord_activated()), &Default::default()), + revm_spec(op_cs(|cs| cs.fjord_activated()), &Default::default()), revm_primitives::FJORD ); assert_eq!( - revm_spec(&op_cs(|cs| cs.ecotone_activated()), &Default::default()), + revm_spec(op_cs(|cs| cs.ecotone_activated()), &Default::default()), revm_primitives::ECOTONE ); assert_eq!( - revm_spec(&op_cs(|cs| cs.canyon_activated()), &Default::default()), + revm_spec(op_cs(|cs| cs.canyon_activated()), &Default::default()), revm_primitives::CANYON ); assert_eq!( - revm_spec(&op_cs(|cs| cs.bedrock_activated()), &Default::default()), + revm_spec(op_cs(|cs| cs.bedrock_activated()), &Default::default()), revm_primitives::BEDROCK ); assert_eq!( - revm_spec(&op_cs(|cs| cs.regolith_activated()), &Default::default()), + revm_spec(op_cs(|cs| cs.regolith_activated()), &Default::default()), revm_primitives::REGOLITH ); } diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index c7841205c..2d11bd31c 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -304,7 +304,7 @@ where receipts: &[N::Receipt], _requests: &Requests, ) -> Result<(), ConsensusError> { - validate_block_post_execution(block.header(), &self.chain_spec.clone(), receipts) + validate_block_post_execution(block.header(), self.chain_spec.clone(), receipts) } } diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index 917f7c861..e9d6bd089 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -20,6 +20,8 @@ use op_alloy_consensus::EIP1559ParamError; use reth_chainspec::EthChainSpec; use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv, Database, Evm, NextBlockEnvAttributes}; use reth_optimism_chainspec::OpChainSpec; +use reth_optimism_consensus::next_block_base_fee; +use reth_optimism_forks::OpHardforks; use reth_optimism_primitives::OpTransactionSigned; use reth_primitives_traits::FillTxEnv; use reth_revm::{ @@ -126,24 +128,30 @@ impl Evm for OpEvm<'_, EXT, DB> { } /// Optimism-related EVM configuration. -#[derive(Debug, Clone)] -pub struct OpEvmConfig { - chain_spec: Arc, +#[derive(Debug)] +pub struct OpEvmConfig { + chain_spec: Arc, } -impl OpEvmConfig { +impl Clone for OpEvmConfig { + fn clone(&self) -> Self { + Self { chain_spec: self.chain_spec.clone() } + } +} + +impl OpEvmConfig { /// Creates a new [`OpEvmConfig`] with the given chain spec. - pub const fn new(chain_spec: Arc) -> Self { + pub const fn new(chain_spec: Arc) -> Self { Self { chain_spec } } /// Returns the chain spec associated with this configuration. - pub const fn chain_spec(&self) -> &Arc { + pub const fn chain_spec(&self) -> &Arc { &self.chain_spec } } -impl ConfigureEvmEnv for OpEvmConfig { +impl ConfigureEvmEnv for OpEvmConfig { type Header = Header; type Transaction = OpTransactionSigned; type Error = EIP1559ParamError; @@ -208,7 +216,11 @@ impl ConfigureEvmEnv for OpEvmConfig { prevrandao: Some(attributes.prev_randao), gas_limit: U256::from(attributes.gas_limit), // calculate basefee based on parent block's gas usage - basefee: self.chain_spec.next_block_base_fee(parent, attributes.timestamp)?, + basefee: U256::from(next_block_base_fee( + &self.chain_spec, + parent, + attributes.timestamp, + )?), // calculate excess gas based on parent block's blob gas usage blob_excess_gas_and_price, }; @@ -225,7 +237,7 @@ impl ConfigureEvmEnv for OpEvmConfig { } } -impl ConfigureEvm for OpEvmConfig { +impl ConfigureEvm for OpEvmConfig { type Evm<'a, DB: Database + 'a, I: 'a> = OpEvm<'a, I, DB>; type EvmError = EVMError; type HaltReason = HaltReason; diff --git a/crates/optimism/node/src/node.rs b/crates/optimism/node/src/node.rs index 55d0d41b2..83073673a 100644 --- a/crates/optimism/node/src/node.rs +++ b/crates/optimism/node/src/node.rs @@ -33,7 +33,7 @@ use reth_optimism_payload_builder::{ builder::OpPayloadTransactions, config::{OpBuilderConfig, OpDAConfig}, }; -use reth_optimism_primitives::{OpPrimitives, OpReceipt, OpTransactionSigned}; +use reth_optimism_primitives::{DepositReceipt, OpPrimitives, OpReceipt, OpTransactionSigned}; use reth_optimism_rpc::{ miner::{MinerApiExtServer, OpMinerExtApi}, witness::{DebugExecutionWitnessApiServer, OpDebugWitnessApi}, @@ -650,9 +650,14 @@ pub struct OpConsensusBuilder; impl ConsensusBuilder for OpConsensusBuilder where - Node: FullNodeTypes>, + Node: FullNodeTypes< + Types: NodeTypes< + ChainSpec: OpHardforks, + Primitives: NodePrimitives, + >, + >, { - type Consensus = Arc; + type Consensus = Arc::ChainSpec>>; async fn build_consensus(self, ctx: &BuilderContext) -> eyre::Result { Ok(Arc::new(OpBeaconConsensus::new(ctx.chain_spec())))