mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(op): opchainspec builder (#11630)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@ -755,13 +755,19 @@ impl ChainSpecBuilder {
|
||||
}
|
||||
|
||||
/// Add the given fork with the given activation condition to the spec.
|
||||
pub fn with_fork(mut self, fork: EthereumHardfork, condition: ForkCondition) -> Self {
|
||||
pub fn with_fork<H: Hardfork>(mut self, fork: H, condition: ForkCondition) -> Self {
|
||||
self.hardforks.insert(fork, condition);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add the given chain hardforks to the spec.
|
||||
pub fn with_forks(mut self, forks: ChainHardforks) -> Self {
|
||||
self.hardforks = forks;
|
||||
self
|
||||
}
|
||||
|
||||
/// Remove the given fork from the spec.
|
||||
pub fn without_fork(mut self, fork: EthereumHardfork) -> Self {
|
||||
pub fn without_fork<H: Hardfork>(mut self, fork: H) -> Self {
|
||||
self.hardforks.remove(fork);
|
||||
self
|
||||
}
|
||||
@ -876,63 +882,6 @@ impl ChainSpecBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Bedrock at genesis
|
||||
#[cfg(feature = "optimism")]
|
||||
pub fn bedrock_activated(mut self) -> Self {
|
||||
self = self.paris_activated();
|
||||
self.hardforks
|
||||
.insert(reth_optimism_forks::OptimismHardfork::Bedrock, ForkCondition::Block(0));
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Regolith at genesis
|
||||
#[cfg(feature = "optimism")]
|
||||
pub fn regolith_activated(mut self) -> Self {
|
||||
self = self.bedrock_activated();
|
||||
self.hardforks
|
||||
.insert(reth_optimism_forks::OptimismHardfork::Regolith, ForkCondition::Timestamp(0));
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Canyon at genesis
|
||||
#[cfg(feature = "optimism")]
|
||||
pub fn canyon_activated(mut self) -> Self {
|
||||
self = self.regolith_activated();
|
||||
// Canyon also activates changes from L1's Shanghai hardfork
|
||||
self.hardforks.insert(EthereumHardfork::Shanghai, ForkCondition::Timestamp(0));
|
||||
self.hardforks
|
||||
.insert(reth_optimism_forks::OptimismHardfork::Canyon, ForkCondition::Timestamp(0));
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Ecotone at genesis
|
||||
#[cfg(feature = "optimism")]
|
||||
pub fn ecotone_activated(mut self) -> Self {
|
||||
self = self.canyon_activated();
|
||||
self.hardforks.insert(EthereumHardfork::Cancun, ForkCondition::Timestamp(0));
|
||||
self.hardforks
|
||||
.insert(reth_optimism_forks::OptimismHardfork::Ecotone, ForkCondition::Timestamp(0));
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Fjord at genesis
|
||||
#[cfg(feature = "optimism")]
|
||||
pub fn fjord_activated(mut self) -> Self {
|
||||
self = self.ecotone_activated();
|
||||
self.hardforks
|
||||
.insert(reth_optimism_forks::OptimismHardfork::Fjord, ForkCondition::Timestamp(0));
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Granite at genesis
|
||||
#[cfg(feature = "optimism")]
|
||||
pub fn granite_activated(mut self) -> Self {
|
||||
self = self.fjord_activated();
|
||||
self.hardforks
|
||||
.insert(reth_optimism_forks::OptimismHardfork::Granite, ForkCondition::Timestamp(0));
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the resulting [`ChainSpec`].
|
||||
///
|
||||
/// # Panics
|
||||
|
||||
@ -16,25 +16,154 @@ mod dev;
|
||||
mod op;
|
||||
mod op_sepolia;
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use alloy_chains::Chain;
|
||||
use alloy_genesis::Genesis;
|
||||
use alloy_primitives::{Parity, Signature, B256, U256};
|
||||
pub use base::BASE_MAINNET;
|
||||
pub use base_sepolia::BASE_SEPOLIA;
|
||||
use derive_more::{Constructor, Deref, From, Into};
|
||||
pub use dev::OP_DEV;
|
||||
use once_cell::sync::OnceCell;
|
||||
pub use op::OP_MAINNET;
|
||||
pub use op_sepolia::OP_SEPOLIA;
|
||||
|
||||
use derive_more::{Constructor, Deref, Into};
|
||||
use once_cell::sync::OnceCell;
|
||||
use reth_chainspec::{
|
||||
BaseFeeParams, BaseFeeParamsKind, ChainSpec, DepositContract, EthChainSpec, EthereumHardforks,
|
||||
ForkFilter, ForkId, Hardforks, Head,
|
||||
BaseFeeParams, BaseFeeParamsKind, ChainSpec, ChainSpecBuilder, DepositContract, EthChainSpec,
|
||||
EthereumHardforks, ForkFilter, ForkId, Hardforks, Head,
|
||||
};
|
||||
use reth_ethereum_forks::{ChainHardforks, EthereumHardfork, ForkCondition};
|
||||
use reth_ethereum_forks::{ChainHardforks, EthereumHardfork, ForkCondition, Hardfork};
|
||||
use reth_network_peers::NodeRecord;
|
||||
use reth_primitives_traits::Header;
|
||||
use std::fmt::Display;
|
||||
|
||||
/// Chain spec builder for a OP stack chain.
|
||||
#[derive(Debug, Default, From)]
|
||||
pub struct OpChainSpecBuilder {
|
||||
/// [`ChainSpecBuilder`]
|
||||
inner: ChainSpecBuilder,
|
||||
}
|
||||
|
||||
impl OpChainSpecBuilder {
|
||||
/// Construct a new builder from the base mainnet chain spec.
|
||||
pub fn base_mainnet() -> Self {
|
||||
let mut inner = ChainSpecBuilder::default()
|
||||
.chain(BASE_MAINNET.chain)
|
||||
.genesis(BASE_MAINNET.genesis.clone());
|
||||
let forks = BASE_MAINNET.hardforks.clone();
|
||||
inner = inner.with_forks(forks);
|
||||
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
/// Construct a new builder from the optimism mainnet chain spec.
|
||||
pub fn optimism_mainnet() -> Self {
|
||||
let mut inner =
|
||||
ChainSpecBuilder::default().chain(OP_MAINNET.chain).genesis(OP_MAINNET.genesis.clone());
|
||||
let forks = OP_MAINNET.hardforks.clone();
|
||||
inner = inner.with_forks(forks);
|
||||
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl OpChainSpecBuilder {
|
||||
/// Set the chain ID
|
||||
pub fn chain(mut self, chain: Chain) -> Self {
|
||||
self.inner = self.inner.chain(chain);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the genesis block.
|
||||
pub fn genesis(mut self, genesis: Genesis) -> Self {
|
||||
self.inner = self.inner.genesis(genesis);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add the given fork with the given activation condition to the spec.
|
||||
pub fn with_fork<H: Hardfork>(mut self, fork: H, condition: ForkCondition) -> Self {
|
||||
self.inner = self.inner.with_fork(fork, condition);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add the given forks with the given activation condition to the spec.
|
||||
pub fn with_forks(mut self, forks: ChainHardforks) -> Self {
|
||||
self.inner = self.inner.with_forks(forks);
|
||||
self
|
||||
}
|
||||
|
||||
/// Remove the given fork from the spec.
|
||||
pub fn without_fork(mut self, fork: reth_optimism_forks::OptimismHardfork) -> Self {
|
||||
self.inner = self.inner.without_fork(fork);
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Bedrock at genesis
|
||||
pub fn bedrock_activated(mut self) -> Self {
|
||||
self.inner = self.inner.paris_activated();
|
||||
self.inner = self
|
||||
.inner
|
||||
.with_fork(reth_optimism_forks::OptimismHardfork::Bedrock, ForkCondition::Block(0));
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Regolith at genesis
|
||||
pub fn regolith_activated(mut self) -> Self {
|
||||
self = self.bedrock_activated();
|
||||
self.inner = self.inner.with_fork(
|
||||
reth_optimism_forks::OptimismHardfork::Regolith,
|
||||
ForkCondition::Timestamp(0),
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Canyon at genesis
|
||||
pub fn canyon_activated(mut self) -> Self {
|
||||
self = self.regolith_activated();
|
||||
// Canyon also activates changes from L1's Shanghai hardfork
|
||||
self.inner = self.inner.with_fork(EthereumHardfork::Shanghai, ForkCondition::Timestamp(0));
|
||||
self.inner = self
|
||||
.inner
|
||||
.with_fork(reth_optimism_forks::OptimismHardfork::Canyon, ForkCondition::Timestamp(0));
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Ecotone at genesis
|
||||
pub fn ecotone_activated(mut self) -> Self {
|
||||
self = self.canyon_activated();
|
||||
self.inner = self.inner.with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(0));
|
||||
self.inner = self
|
||||
.inner
|
||||
.with_fork(reth_optimism_forks::OptimismHardfork::Ecotone, ForkCondition::Timestamp(0));
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Fjord at genesis
|
||||
pub fn fjord_activated(mut self) -> Self {
|
||||
self = self.ecotone_activated();
|
||||
self.inner = self
|
||||
.inner
|
||||
.with_fork(reth_optimism_forks::OptimismHardfork::Fjord, ForkCondition::Timestamp(0));
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable Granite at genesis
|
||||
pub fn granite_activated(mut self) -> Self {
|
||||
self = self.fjord_activated();
|
||||
self.inner = self
|
||||
.inner
|
||||
.with_fork(reth_optimism_forks::OptimismHardfork::Granite, ForkCondition::Timestamp(0));
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the resulting [`OpChainSpec`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if the chain ID and genesis is not set ([`Self::chain`] and
|
||||
/// [`Self::genesis`])
|
||||
pub fn build(self) -> OpChainSpec {
|
||||
OpChainSpec { inner: self.inner.build() }
|
||||
}
|
||||
}
|
||||
|
||||
/// OP stack chain spec type.
|
||||
#[derive(Debug, Clone, Deref, Into, Constructor, PartialEq, Eq)]
|
||||
@ -286,6 +415,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn base_mainnet_forkids() {
|
||||
let base_mainnet = OpChainSpecBuilder::base_mainnet().build();
|
||||
let _ = base_mainnet.genesis_hash.set(BASE_MAINNET.genesis_hash.get().copied().unwrap());
|
||||
test_fork_ids(
|
||||
&BASE_MAINNET,
|
||||
&[
|
||||
@ -372,8 +503,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn op_mainnet_forkids() {
|
||||
let op_mainnet = OpChainSpecBuilder::optimism_mainnet().build();
|
||||
// for OP mainnet we have to do this because the genesis header can't be properly computed
|
||||
// from the genesis.json file
|
||||
let _ = op_mainnet.genesis_hash.set(OP_MAINNET.genesis_hash());
|
||||
test_fork_ids(
|
||||
&OP_MAINNET,
|
||||
&op_mainnet,
|
||||
&[
|
||||
(
|
||||
Head { number: 0, ..Default::default() },
|
||||
@ -483,9 +618,19 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn latest_base_mainnet_fork_id_with_builder() {
|
||||
let base_mainnet = OpChainSpecBuilder::base_mainnet().build();
|
||||
assert_eq!(
|
||||
ForkId { hash: ForkHash([0xbc, 0x38, 0xf9, 0xca]), next: 0 },
|
||||
base_mainnet.latest_fork_id()
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_bedrock_active() {
|
||||
assert!(!OP_MAINNET.is_bedrock_active_at_block(1))
|
||||
let op_mainnet = OpChainSpecBuilder::optimism_mainnet().build();
|
||||
assert!(!op_mainnet.is_bedrock_active_at_block(1))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_ethereum_forks::{EthereumHardfork, Head};
|
||||
use reth_optimism_chainspec::OpChainSpec;
|
||||
use reth_optimism_forks::OptimismHardfork;
|
||||
|
||||
/// Returns the revm [`SpecId`](revm_primitives::SpecId) at the given timestamp.
|
||||
@ -9,7 +9,7 @@ use reth_optimism_forks::OptimismHardfork;
|
||||
/// 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: &ChainSpec,
|
||||
chain_spec: &OpChainSpec,
|
||||
timestamp: u64,
|
||||
) -> revm_primitives::SpecId {
|
||||
if chain_spec.fork(OptimismHardfork::Granite).active_at_timestamp(timestamp) {
|
||||
@ -28,7 +28,7 @@ pub fn revm_spec_by_timestamp_after_bedrock(
|
||||
}
|
||||
|
||||
/// Map the latest active hardfork at the given block to a revm [`SpecId`](revm_primitives::SpecId).
|
||||
pub fn revm_spec(chain_spec: &ChainSpec, block: &Head) -> revm_primitives::SpecId {
|
||||
pub fn revm_spec(chain_spec: &OpChainSpec, block: &Head) -> revm_primitives::SpecId {
|
||||
if chain_spec.fork(OptimismHardfork::Granite).active_at_head(block) {
|
||||
revm_primitives::GRANITE
|
||||
} else if chain_spec.fork(OptimismHardfork::Fjord).active_at_head(block) {
|
||||
@ -79,12 +79,13 @@ pub fn revm_spec(chain_spec: &ChainSpec, block: &Head) -> revm_primitives::SpecI
|
||||
mod tests {
|
||||
use super::*;
|
||||
use reth_chainspec::ChainSpecBuilder;
|
||||
use reth_optimism_chainspec::{OpChainSpec, OpChainSpecBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_revm_spec_by_timestamp_after_merge() {
|
||||
#[inline(always)]
|
||||
fn op_cs(f: impl FnOnce(ChainSpecBuilder) -> ChainSpecBuilder) -> ChainSpec {
|
||||
let cs = ChainSpecBuilder::mainnet().chain(reth_chainspec::Chain::from_id(10));
|
||||
fn op_cs(f: impl FnOnce(OpChainSpecBuilder) -> OpChainSpecBuilder) -> OpChainSpec {
|
||||
let cs = ChainSpecBuilder::mainnet().chain(reth_chainspec::Chain::from_id(10)).into();
|
||||
f(cs).build()
|
||||
}
|
||||
assert_eq!(
|
||||
@ -116,8 +117,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_to_revm_spec() {
|
||||
#[inline(always)]
|
||||
fn op_cs(f: impl FnOnce(ChainSpecBuilder) -> ChainSpecBuilder) -> ChainSpec {
|
||||
let cs = ChainSpecBuilder::mainnet().chain(reth_chainspec::Chain::from_id(10));
|
||||
fn op_cs(f: impl FnOnce(OpChainSpecBuilder) -> OpChainSpecBuilder) -> OpChainSpec {
|
||||
let cs = ChainSpecBuilder::mainnet().chain(reth_chainspec::Chain::from_id(10)).into();
|
||||
f(cs).build()
|
||||
}
|
||||
assert_eq!(
|
||||
|
||||
@ -513,8 +513,8 @@ mod tests {
|
||||
use crate::OpChainSpec;
|
||||
use alloy_consensus::TxEip1559;
|
||||
use alloy_primitives::{b256, Address, StorageKey, StorageValue};
|
||||
use reth_chainspec::{ChainSpecBuilder, MIN_TRANSACTION_GAS};
|
||||
use reth_optimism_chainspec::{optimism_deposit_tx_signature, BASE_MAINNET};
|
||||
use reth_chainspec::MIN_TRANSACTION_GAS;
|
||||
use reth_optimism_chainspec::{optimism_deposit_tx_signature, OpChainSpecBuilder};
|
||||
use reth_primitives::{Account, Block, BlockBody, Signature, Transaction, TransactionSigned};
|
||||
use reth_revm::{
|
||||
database::StateProviderDatabase, test_utils::StateProviderTest, L1_BLOCK_CONTRACT,
|
||||
@ -548,8 +548,7 @@ mod tests {
|
||||
db
|
||||
}
|
||||
|
||||
fn executor_provider(chain_spec: Arc<ChainSpec>) -> OpExecutorProvider<OptimismEvmConfig> {
|
||||
let chain_spec = Arc::new(OpChainSpec::new(Arc::unwrap_or_clone(chain_spec)));
|
||||
fn executor_provider(chain_spec: Arc<OpChainSpec>) -> OpExecutorProvider<OptimismEvmConfig> {
|
||||
OpExecutorProvider { evm_config: OptimismEvmConfig::new(chain_spec.clone()), chain_spec }
|
||||
}
|
||||
|
||||
@ -572,11 +571,7 @@ mod tests {
|
||||
let account = Account { balance: U256::MAX, ..Account::default() };
|
||||
db.insert_account(addr, account, None, HashMap::default());
|
||||
|
||||
let chain_spec = Arc::new(
|
||||
ChainSpecBuilder::from(&Arc::new(BASE_MAINNET.inner.clone()))
|
||||
.regolith_activated()
|
||||
.build(),
|
||||
);
|
||||
let chain_spec = Arc::new(OpChainSpecBuilder::base_mainnet().regolith_activated().build());
|
||||
|
||||
let tx = TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Eip1559(TxEip1559 {
|
||||
@ -656,11 +651,7 @@ mod tests {
|
||||
|
||||
db.insert_account(addr, account, None, HashMap::default());
|
||||
|
||||
let chain_spec = Arc::new(
|
||||
ChainSpecBuilder::from(&Arc::new(BASE_MAINNET.inner.clone()))
|
||||
.canyon_activated()
|
||||
.build(),
|
||||
);
|
||||
let chain_spec = Arc::new(OpChainSpecBuilder::base_mainnet().canyon_activated().build());
|
||||
|
||||
let tx = TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Eip1559(TxEip1559 {
|
||||
|
||||
@ -1,15 +1,13 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use alloy_genesis::Genesis;
|
||||
use alloy_primitives::{Address, B256};
|
||||
use reth::{rpc::types::engine::PayloadAttributes, tasks::TaskManager};
|
||||
use reth_chainspec::ChainSpecBuilder;
|
||||
use reth_e2e_test_utils::{transaction::TransactionTestContext, wallet::Wallet, NodeHelperType};
|
||||
use reth_optimism_chainspec::{OpChainSpec, BASE_MAINNET};
|
||||
use reth_optimism_chainspec::OpChainSpecBuilder;
|
||||
use reth_optimism_node::{
|
||||
node::OptimismAddOns, OptimismBuiltPayload, OptimismNode, OptimismPayloadBuilderAttributes,
|
||||
};
|
||||
use reth_payload_builder::EthPayloadBuilderAttributes;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
/// Optimism Node Helper type
|
||||
@ -19,13 +17,7 @@ pub(crate) async fn setup(num_nodes: usize) -> eyre::Result<(Vec<OpNode>, TaskMa
|
||||
let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap();
|
||||
reth_e2e_test_utils::setup(
|
||||
num_nodes,
|
||||
Arc::new(OpChainSpec::new(
|
||||
ChainSpecBuilder::default()
|
||||
.chain(BASE_MAINNET.chain)
|
||||
.genesis(genesis)
|
||||
.ecotone_activated()
|
||||
.build(),
|
||||
)),
|
||||
Arc::new(OpChainSpecBuilder::base_mainnet().genesis(genesis).ecotone_activated().build()),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user