diff --git a/crates/chainspec/src/genesis/dev.json b/crates/chainspec/src/genesis/dev.json index 3fc03d3d5c..99c1112c19 100644 --- a/crates/chainspec/src/genesis/dev.json +++ b/crates/chainspec/src/genesis/dev.json @@ -27,7 +27,7 @@ "t1cTime": 0, "t2Time": 0, "t3Time": 0, - "t4Time": 9223372036854775807, + "t4Time": 0, "depositContractAddress": "0x0000000000000000000000000000000000000000" }, "nonce": "0x42", diff --git a/crates/node/tests/assets/test-genesis.json b/crates/node/tests/assets/test-genesis.json index 0eda7691e8..0a003e6384 100644 --- a/crates/node/tests/assets/test-genesis.json +++ b/crates/node/tests/assets/test-genesis.json @@ -27,7 +27,7 @@ "t1cTime": 0, "t2Time": 0, "t3Time": 0, - "t4Time": 9223372036854775807, + "t4Time": 0, "depositContractAddress": "0x0000000000000000000000000000000000000000" }, "nonce": "0x42", diff --git a/crates/node/tests/it/key_authorization.rs b/crates/node/tests/it/key_authorization.rs index ff1ec66d10..4c6b184be7 100644 --- a/crates/node/tests/it/key_authorization.rs +++ b/crates/node/tests/it/key_authorization.rs @@ -1,4 +1,4 @@ -use crate::utils::{TEST_MNEMONIC, TestNodeBuilder}; +use crate::utils::{TEST_MNEMONIC, TestNodeBuilder, make_genesis_at}; use alloy::{ primitives::{Address, Bytes, U256}, providers::{Provider, ProviderBuilder}, @@ -102,14 +102,8 @@ fn build_2d_nonce_transfer_tx( Ok(envelope.encoded_2718()) } -fn make_pre_t1b_genesis() -> eyre::Result { - let genesis_str = include_str!("../assets/test-genesis.json"); - let mut genesis: serde_json::Value = serde_json::from_str(genesis_str)?; - genesis["config"].as_object_mut().unwrap().remove("t1bTime"); - genesis["config"].as_object_mut().unwrap().remove("t1cTime"); - genesis["config"].as_object_mut().unwrap().remove("t2Time"); - genesis["config"].as_object_mut().unwrap().remove("t3Time"); - Ok(serde_json::to_string(&genesis)?) +fn make_pre_t1b_genesis() -> String { + make_genesis_at(tempo_chainspec::hardfork::TempoHardfork::T1A) } /// Pre-T1B fee-drain replay: the poisoned KeyAuth CREATE tx is followed by a @@ -130,7 +124,7 @@ async fn test_pre_t1b_keyauth_oog_replay() -> eyre::Result<()> { reth_tracing::init_test_tracing(); let mut setup = TestNodeBuilder::new() - .with_genesis(make_pre_t1b_genesis()?) + .with_genesis(make_pre_t1b_genesis()) .build_with_node_access() .await?; @@ -231,7 +225,7 @@ async fn test_pre_t1b_keyauth_oog_single_tx_nonce_not_bumped() -> eyre::Result<( reth_tracing::init_test_tracing(); let mut setup = TestNodeBuilder::new() - .with_genesis(make_pre_t1b_genesis()?) + .with_genesis(make_pre_t1b_genesis()) .build_with_node_access() .await?; diff --git a/crates/node/tests/it/max_gas_limit.rs b/crates/node/tests/it/max_gas_limit.rs index 9502c4bc15..5a2cab051e 100644 --- a/crates/node/tests/it/max_gas_limit.rs +++ b/crates/node/tests/it/max_gas_limit.rs @@ -19,7 +19,7 @@ use reth_node_api::BuiltPayload; use reth_primitives_traits::transaction::TxHashRef; use tempo_chainspec::spec::{TEMPO_T1_BASE_FEE, TEMPO_T1_TX_GAS_LIMIT_CAP}; -use crate::utils::{TEST_MNEMONIC, TestNodeBuilder}; +use crate::utils::{TEST_MNEMONIC, TestNodeBuilder, make_genesis_at}; /// Helper to build and encode a signed EIP-1559 transaction with a specific gas limit. fn build_tx( @@ -160,15 +160,7 @@ async fn test_post_t1a_tx_exceeding_tempo_cap() -> eyre::Result<()> { async fn test_pre_t1a_tx_at_osaka_limit() -> eyre::Result<()> { reth_tracing::init_test_tracing(); - let genesis_str = include_str!("../assets/test-genesis.json"); - let mut genesis: serde_json::Value = serde_json::from_str(genesis_str)?; - genesis["config"].as_object_mut().unwrap().remove("t1Time"); - genesis["config"].as_object_mut().unwrap().remove("t1aTime"); - genesis["config"].as_object_mut().unwrap().remove("t1bTime"); - genesis["config"].as_object_mut().unwrap().remove("t1cTime"); - genesis["config"].as_object_mut().unwrap().remove("t2Time"); - genesis["config"].as_object_mut().unwrap().remove("t3Time"); - let pre_t1a_genesis = serde_json::to_string(&genesis)?; + let pre_t1a_genesis = make_genesis_at(tempo_chainspec::hardfork::TempoHardfork::T0); let mut setup = TestNodeBuilder::new() .with_genesis(pre_t1a_genesis) @@ -201,15 +193,7 @@ async fn test_pre_t1a_tx_at_osaka_limit() -> eyre::Result<()> { async fn test_pre_t1a_tx_above_osaka_limit() -> eyre::Result<()> { reth_tracing::init_test_tracing(); - let genesis_str = include_str!("../assets/test-genesis.json"); - let mut genesis: serde_json::Value = serde_json::from_str(genesis_str)?; - genesis["config"].as_object_mut().unwrap().remove("t1Time"); - genesis["config"].as_object_mut().unwrap().remove("t1aTime"); - genesis["config"].as_object_mut().unwrap().remove("t1bTime"); - genesis["config"].as_object_mut().unwrap().remove("t1cTime"); - genesis["config"].as_object_mut().unwrap().remove("t2Time"); - genesis["config"].as_object_mut().unwrap().remove("t3Time"); - let pre_t1a_genesis = serde_json::to_string(&genesis)?; + let pre_t1a_genesis = make_genesis_at(tempo_chainspec::hardfork::TempoHardfork::T0); let setup = TestNodeBuilder::new() .with_genesis(pre_t1a_genesis) diff --git a/crates/node/tests/it/tempo_transaction/local.rs b/crates/node/tests/it/tempo_transaction/local.rs index 5b8d6d2770..8ba0f64122 100644 --- a/crates/node/tests/it/tempo_transaction/local.rs +++ b/crates/node/tests/it/tempo_transaction/local.rs @@ -4,7 +4,9 @@ //! which spins up an in-process node with direct pool/block access, plus tests //! that require pool introspection or controlled block mining. -use crate::utils::{ForkSchedule, SingleNodeSetup, TEST_MNEMONIC, TestNodeBuilder}; +use crate::utils::{ + ForkSchedule, SingleNodeSetup, TEST_MNEMONIC, TestNodeBuilder, make_genesis_at, +}; use alloy::{ consensus::{BlockHeader, Transaction}, network::{EthereumWallet, ReceiptResponse}, @@ -2062,17 +2064,8 @@ async fn test_v1_keychain_cross_account_replay_pre_t1c() -> eyre::Result<()> { reth_tracing::init_test_tracing(); // Pre-T1C genesis so V1 keychain sigs are accepted. - // Set t1cTime and t2Time far in the future instead of removing them, - // because the genesis deserializer requires all hardfork fields. - let genesis_json = include_str!("../../assets/test-genesis.json").to_string(); - let mut genesis: serde_json::Value = serde_json::from_str(&genesis_json)?; - let config = genesis["config"].as_object_mut().unwrap(); - let far_future = serde_json::Value::Number(serde_json::Number::from(u64::MAX)); - config.insert("t1cTime".to_string(), far_future.clone()); - config.insert("t2Time".to_string(), far_future.clone()); - config.insert("t3Time".to_string(), far_future); let mut setup = TestNodeBuilder::new() - .with_genesis(serde_json::to_string(&genesis)?) + .with_genesis(make_genesis_at(TempoHardfork::T1B)) .build_with_node_access() .await?; diff --git a/crates/node/tests/it/tip_fee_manager.rs b/crates/node/tests/it/tip_fee_manager.rs index e752cd8764..29f560ac67 100644 --- a/crates/node/tests/it/tip_fee_manager.rs +++ b/crates/node/tests/it/tip_fee_manager.rs @@ -1,4 +1,4 @@ -use crate::utils::{TestNodeBuilder, setup_test_token}; +use crate::utils::{TestNodeBuilder, make_genesis_at, setup_test_token}; use alloy::{ consensus::Transaction, network::ReceiptResponse, @@ -409,14 +409,10 @@ async fn test_fee_payer_tx() -> eyre::Result<()> { async fn test_fee_payer_transfer_whitelist_pre_t1c() -> eyre::Result<()> { reth_tracing::init_test_tracing(); - let genesis_str = include_str!("../assets/test-genesis.json"); - let mut genesis: serde_json::Value = serde_json::from_str(genesis_str)?; - genesis["config"].as_object_mut().unwrap().remove("t1cTime"); - genesis["config"].as_object_mut().unwrap().remove("t2Time"); - genesis["config"].as_object_mut().unwrap().remove("t3Time"); + let pre_t1c_genesis = make_genesis_at(tempo_chainspec::hardfork::TempoHardfork::T1B); let setup = TestNodeBuilder::new() - .with_genesis(serde_json::to_string(&genesis)?) + .with_genesis(pre_t1c_genesis) .build_http_only() .await?; diff --git a/crates/node/tests/it/utils.rs b/crates/node/tests/it/utils.rs index cec4ada2c2..56bee100fd 100644 --- a/crates/node/tests/it/utils.rs +++ b/crates/node/tests/it/utils.rs @@ -97,6 +97,36 @@ impl ForkSchedule { } } +/// Build a genesis JSON string from `test-genesis.json` with only forks up to +/// (and including) `last_active` enabled. All subsequent forks are removed so +/// the node starts in a "pre-" configuration. +/// +/// This scales automatically when new hardforks are appended to +/// `TempoHardfork` — no manual maintenance required. +pub(crate) fn make_genesis_at(last_active: TempoHardfork) -> String { + let mut genesis: serde_json::Value = + serde_json::from_str(include_str!("../assets/test-genesis.json")) + .expect("test-genesis.json must parse"); + let config = genesis["config"] + .as_object_mut() + .expect("genesis must have config"); + + let mut past_cutoff = false; + for &fork in TempoHardfork::VARIANTS { + if fork == TempoHardfork::Genesis { + continue; + } + if past_cutoff { + let key = format!("{}Time", fork.name().to_lowercase()); + config.remove(&key); + } + if fork == last_active { + past_cutoff = true; + } + } + serde_json::to_string(&genesis).expect("genesis must serialize") +} + /// Standard test mnemonic phrase used across integration tests pub(crate) const TEST_MNEMONIC: &str = "test test test test test test test test test test test junk"; diff --git a/tempo.nu b/tempo.nu index 99d0dbc430..a0e37823e3 100755 --- a/tempo.nu +++ b/tempo.nu @@ -280,7 +280,7 @@ def read-bench-marker [datadir: string] { # ============================================================================ # Ordered list of all Tempo hardforks (must match TempoHardfork enum in crates/chainspec) -const TEMPO_HARDFORKS = ["T0" "T1" "T1A" "T1B" "T1C" "T2"] +const TEMPO_HARDFORKS = ["T0" "T1" "T1A" "T1B" "T1C" "T2" "T3" "T4"] # Map a hardfork name to generate-genesis CLI args. # Forks up to and including the given fork are active at genesis (time=0). diff --git a/xtask/src/genesis_args.rs b/xtask/src/genesis_args.rs index 87ddf34168..4630a3dfbb 100644 --- a/xtask/src/genesis_args.rs +++ b/xtask/src/genesis_args.rs @@ -176,7 +176,7 @@ pub(crate) struct GenesisArgs { t3_time: u64, /// T4 hardfork activation time. - #[arg(long, default_value = "9223372036854775807")] + #[arg(long, default_value = "0")] t4_time: u64, /// Whether to skip initializing validator config v1