From eba5d84f6d182987679b4ff9e9b29c7908d0ba88 Mon Sep 17 00:00:00 2001 From: eltitanb Date: Wed, 19 Mar 2025 19:48:53 +0000 Subject: [PATCH 1/2] add Hoodi known chain --- crates/common/src/signature.rs | 4 + crates/common/src/types.rs | 48 +++++++++- tests/data/hoodi_spec.json | 155 +++++++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 tests/data/hoodi_spec.json diff --git a/crates/common/src/signature.rs b/crates/common/src/signature.rs index 1c2dd1eb..e51e2291 100644 --- a/crates/common/src/signature.rs +++ b/crates/common/src/signature.rs @@ -112,5 +112,9 @@ mod tests { compute_domain(Chain::Helder, APPLICATION_BUILDER_DOMAIN), Chain::Helder.builder_domain() ); + assert_eq!( + compute_domain(Chain::Hoodi, APPLICATION_BUILDER_DOMAIN), + Chain::Hoodi.builder_domain() + ); } } diff --git a/crates/common/src/types.rs b/crates/common/src/types.rs index 71656178..b7d3e01a 100644 --- a/crates/common/src/types.rs +++ b/crates/common/src/types.rs @@ -23,6 +23,7 @@ pub enum Chain { Holesky, Sepolia, Helder, + Hoodi, Custom { genesis_time_secs: u64, slot_time_secs: u64, genesis_fork_version: ForkVersion }, } @@ -31,7 +32,9 @@ pub type ForkVersion = [u8; 4]; impl std::fmt::Display for Chain { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Mainnet | Self::Holesky | Self::Sepolia | Self::Helder => write!(f, "{self:?}"), + Self::Mainnet | Self::Holesky | Self::Sepolia | Self::Helder | Self::Hoodi => { + write!(f, "{self:?}") + } Self::Custom { .. } => write!(f, "Custom"), } } @@ -44,6 +47,7 @@ impl std::fmt::Debug for Chain { Self::Holesky => write!(f, "Holesky"), Self::Sepolia => write!(f, "Sepolia"), Self::Helder => write!(f, "Helder"), + Self::Hoodi => write!(f, "Hoodi"), Self::Custom { genesis_time_secs, slot_time_secs, genesis_fork_version } => f .debug_struct("Custom") .field("genesis_time_secs", genesis_time_secs) @@ -61,6 +65,7 @@ impl Chain { Chain::Holesky => KnownChain::Holesky.id(), Chain::Sepolia => KnownChain::Sepolia.id(), Chain::Helder => KnownChain::Helder.id(), + Chain::Hoodi => KnownChain::Hoodi.id(), Chain::Custom { .. } => { unimplemented!("chain id is not supported on custom chains, please file an issue") } @@ -73,6 +78,7 @@ impl Chain { Chain::Holesky => KnownChain::Holesky.builder_domain(), Chain::Sepolia => KnownChain::Sepolia.builder_domain(), Chain::Helder => KnownChain::Helder.builder_domain(), + Chain::Hoodi => KnownChain::Hoodi.builder_domain(), Chain::Custom { .. } => compute_domain(*self, APPLICATION_BUILDER_DOMAIN), } } @@ -83,6 +89,7 @@ impl Chain { Chain::Holesky => KnownChain::Holesky.genesis_fork_version(), Chain::Sepolia => KnownChain::Sepolia.genesis_fork_version(), Chain::Helder => KnownChain::Helder.genesis_fork_version(), + Chain::Hoodi => KnownChain::Hoodi.genesis_fork_version(), Chain::Custom { genesis_fork_version, .. } => *genesis_fork_version, } } @@ -93,6 +100,7 @@ impl Chain { Chain::Holesky => KnownChain::Holesky.genesis_time_sec(), Chain::Sepolia => KnownChain::Sepolia.genesis_time_sec(), Chain::Helder => KnownChain::Helder.genesis_time_sec(), + Chain::Hoodi => KnownChain::Hoodi.genesis_time_sec(), Chain::Custom { genesis_time_secs, .. } => *genesis_time_secs, } } @@ -103,6 +111,7 @@ impl Chain { Chain::Holesky => KnownChain::Holesky.slot_time_sec(), Chain::Sepolia => KnownChain::Sepolia.slot_time_sec(), Chain::Helder => KnownChain::Helder.slot_time_sec(), + Chain::Hoodi => KnownChain::Hoodi.slot_time_sec(), Chain::Custom { slot_time_secs, .. } => *slot_time_secs, } } @@ -118,6 +127,8 @@ pub enum KnownChain { Sepolia, #[serde(alias = "helder")] Helder, + #[serde(alias = "hoodi")] + Hoodi, } // Constants @@ -128,6 +139,7 @@ impl KnownChain { KnownChain::Holesky => 17000, KnownChain::Sepolia => 11155111, KnownChain::Helder => 167000, + KnownChain::Hoodi => 560048, } } @@ -149,6 +161,10 @@ impl KnownChain { 0, 0, 0, 1, 148, 196, 26, 244, 132, 255, 247, 150, 73, 105, 224, 189, 217, 34, 248, 45, 255, 15, 75, 232, 122, 96, 208, 102, 76, 201, 209, 255, ], + KnownChain::Hoodi => [ + 0, 0, 0, 1, 113, 145, 3, 81, 30, 250, 79, 19, 98, 255, 42, 80, 153, 108, 204, 243, + 41, 204, 132, 203, 65, 12, 94, 92, 125, 53, 29, 3, + ], } } @@ -158,6 +174,7 @@ impl KnownChain { KnownChain::Holesky => hex!("01017000"), KnownChain::Sepolia => hex!("90000069"), KnownChain::Helder => hex!("10000000"), + KnownChain::Hoodi => hex!("10000910"), } } @@ -167,6 +184,7 @@ impl KnownChain { KnownChain::Holesky => 1695902400, KnownChain::Sepolia => 1655733600, KnownChain::Helder => 1718967660, + KnownChain::Hoodi => 1742213400, } } @@ -175,7 +193,8 @@ impl KnownChain { KnownChain::Mainnet | KnownChain::Holesky | KnownChain::Sepolia | - KnownChain::Helder => 12, + KnownChain::Helder | + KnownChain::Hoodi => 12, } } } @@ -187,6 +206,7 @@ impl From for Chain { KnownChain::Holesky => Chain::Holesky, KnownChain::Sepolia => Chain::Sepolia, KnownChain::Helder => Chain::Helder, + KnownChain::Hoodi => Chain::Hoodi, } } } @@ -220,6 +240,7 @@ impl Serialize for Chain { Chain::Holesky => ChainLoader::Known(KnownChain::Holesky), Chain::Sepolia => ChainLoader::Known(KnownChain::Sepolia), Chain::Helder => ChainLoader::Known(KnownChain::Helder), + Chain::Hoodi => ChainLoader::Known(KnownChain::Hoodi), Chain::Custom { genesis_time_secs, slot_time_secs, genesis_fork_version } => { ChainLoader::Custom { genesis_time_secs: *genesis_time_secs, @@ -372,6 +393,7 @@ mod tests { let s = format!("chain = {{ genesis_time_secs = 1, path = {path:?}}}"); let decoded: MockConfig = toml::from_str(&s).unwrap(); + assert_eq!(decoded.chain.slot_time_sec(), KnownChain::Holesky.slot_time_sec()); assert_eq!(decoded.chain, Chain::Custom { genesis_time_secs: 1, slot_time_secs: KnownChain::Holesky.slot_time_sec(), @@ -391,6 +413,7 @@ mod tests { let s = format!("chain = {{ genesis_time_secs = 1, path = {path:?}}}"); let decoded: MockConfig = toml::from_str(&s).unwrap(); + assert_eq!(decoded.chain.slot_time_sec(), KnownChain::Helder.slot_time_sec()); assert_eq!(decoded.chain, Chain::Custom { genesis_time_secs: 1, slot_time_secs: KnownChain::Sepolia.slot_time_sec(), @@ -398,6 +421,26 @@ mod tests { }) } + #[test] + fn test_spec_hoodi_data_json() { + let a = env!("CARGO_MANIFEST_DIR"); + let mut path = PathBuf::from(a); + + path.pop(); + path.pop(); + path.push("tests/data/hoodi_spec.json"); + + let s = format!("chain = {{ genesis_time_secs = 1, path = {path:?}}}"); + + let decoded: MockConfig = toml::from_str(&s).unwrap(); + assert_eq!(decoded.chain.slot_time_sec(), KnownChain::Hoodi.slot_time_sec()); + assert_eq!(decoded.chain, Chain::Custom { + genesis_time_secs: 1, + slot_time_secs: KnownChain::Hoodi.slot_time_sec(), + genesis_fork_version: KnownChain::Hoodi.genesis_fork_version() + }) + } + #[test] fn test_spec_helder_yml() { let a = env!("CARGO_MANIFEST_DIR"); @@ -410,6 +453,7 @@ mod tests { let s = format!("chain = {{ genesis_time_secs = 1, path = {path:?}}}"); let decoded: MockConfig = toml::from_str(&s).unwrap(); + assert_eq!(decoded.chain.slot_time_sec(), KnownChain::Helder.slot_time_sec()); assert_eq!(decoded.chain, Chain::Custom { genesis_time_secs: 1, slot_time_secs: KnownChain::Helder.slot_time_sec(), diff --git a/tests/data/hoodi_spec.json b/tests/data/hoodi_spec.json new file mode 100644 index 00000000..df9801f1 --- /dev/null +++ b/tests/data/hoodi_spec.json @@ -0,0 +1,155 @@ +{ + "data": { + "CONFIG_NAME": "hoodi", + "PRESET_BASE": "mainnet", + "TERMINAL_TOTAL_DIFFICULTY": "0", + "TERMINAL_BLOCK_HASH": "0x0000000000000000000000000000000000000000000000000000000000000000", + "TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH": "18446744073709551615", + "MIN_GENESIS_ACTIVE_VALIDATOR_COUNT": "16384", + "MIN_GENESIS_TIME": "1742212800", + "GENESIS_FORK_VERSION": "0x10000910", + "GENESIS_DELAY": "600", + "ALTAIR_FORK_VERSION": "0x20000910", + "ALTAIR_FORK_EPOCH": "0", + "BELLATRIX_FORK_VERSION": "0x30000910", + "BELLATRIX_FORK_EPOCH": "0", + "CAPELLA_FORK_VERSION": "0x40000910", + "CAPELLA_FORK_EPOCH": "0", + "DENEB_FORK_VERSION": "0x50000910", + "DENEB_FORK_EPOCH": "0", + "ELECTRA_FORK_VERSION": "0x60000910", + "ELECTRA_FORK_EPOCH": "2048", + "FULU_FORK_VERSION": "0x70000910", + "FULU_FORK_EPOCH": "18446744073709551615", + "SECONDS_PER_SLOT": "12", + "SECONDS_PER_ETH1_BLOCK": "12", + "MIN_VALIDATOR_WITHDRAWABILITY_DELAY": "256", + "SHARD_COMMITTEE_PERIOD": "256", + "ETH1_FOLLOW_DISTANCE": "2048", + "SUBNETS_PER_NODE": "2", + "INACTIVITY_SCORE_BIAS": "4", + "INACTIVITY_SCORE_RECOVERY_RATE": "16", + "EJECTION_BALANCE": "16000000000", + "MIN_PER_EPOCH_CHURN_LIMIT": "4", + "MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT": "8", + "CHURN_LIMIT_QUOTIENT": "65536", + "PROPOSER_SCORE_BOOST": "40", + "DEPOSIT_CHAIN_ID": "560048", + "DEPOSIT_NETWORK_ID": "560048", + "DEPOSIT_CONTRACT_ADDRESS": "0x00000000219ab540356cbb839cbe05303d7705fa", + "GAS_LIMIT_ADJUSTMENT_FACTOR": "1024", + "GOSSIP_MAX_SIZE": "10485760", + "MAX_REQUEST_BLOCKS": "1024", + "MIN_EPOCHS_FOR_BLOCK_REQUESTS": "33024", + "MAX_CHUNK_SIZE": "10485760", + "TTFB_TIMEOUT": "5", + "RESP_TIMEOUT": "10", + "ATTESTATION_PROPAGATION_SLOT_RANGE": "32", + "MAXIMUM_GOSSIP_CLOCK_DISPARITY_MILLIS": "500", + "MESSAGE_DOMAIN_INVALID_SNAPPY": "0x00000000", + "MESSAGE_DOMAIN_VALID_SNAPPY": "0x01000000", + "ATTESTATION_SUBNET_PREFIX_BITS": "6", + "MAX_REQUEST_BLOCKS_DENEB": "128", + "MAX_REQUEST_BLOB_SIDECARS": "768", + "MAX_REQUEST_DATA_COLUMN_SIDECARS": "16384", + "MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS": "4096", + "BLOB_SIDECAR_SUBNET_COUNT": "6", + "MAX_BLOBS_PER_BLOCK": "6", + "MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA": "128000000000", + "MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT": "256000000000", + "MAX_BLOBS_PER_BLOCK_ELECTRA": "9", + "BLOB_SIDECAR_SUBNET_COUNT_ELECTRA": "9", + "MAX_REQUEST_BLOB_SIDECARS_ELECTRA": "1152", + "NUMBER_OF_COLUMNS": "128", + "NUMBER_OF_CUSTODY_GROUPS": "128", + "DATA_COLUMN_SIDECAR_SUBNET_COUNT": "128", + "SAMPLES_PER_SLOT": "8", + "CUSTODY_REQUIREMENT": "4", + "MAX_COMMITTEES_PER_SLOT": "64", + "TARGET_COMMITTEE_SIZE": "128", + "MAX_VALIDATORS_PER_COMMITTEE": "2048", + "SHUFFLE_ROUND_COUNT": "90", + "HYSTERESIS_QUOTIENT": "4", + "HYSTERESIS_DOWNWARD_MULTIPLIER": "1", + "HYSTERESIS_UPWARD_MULTIPLIER": "5", + "MIN_DEPOSIT_AMOUNT": "1000000000", + "MAX_EFFECTIVE_BALANCE": "32000000000", + "EFFECTIVE_BALANCE_INCREMENT": "1000000000", + "MIN_ATTESTATION_INCLUSION_DELAY": "1", + "SLOTS_PER_EPOCH": "32", + "MIN_SEED_LOOKAHEAD": "1", + "MAX_SEED_LOOKAHEAD": "4", + "EPOCHS_PER_ETH1_VOTING_PERIOD": "64", + "SLOTS_PER_HISTORICAL_ROOT": "8192", + "MIN_EPOCHS_TO_INACTIVITY_PENALTY": "4", + "EPOCHS_PER_HISTORICAL_VECTOR": "65536", + "EPOCHS_PER_SLASHINGS_VECTOR": "8192", + "HISTORICAL_ROOTS_LIMIT": "16777216", + "VALIDATOR_REGISTRY_LIMIT": "1099511627776", + "BASE_REWARD_FACTOR": "64", + "WHISTLEBLOWER_REWARD_QUOTIENT": "512", + "PROPOSER_REWARD_QUOTIENT": "8", + "INACTIVITY_PENALTY_QUOTIENT": "67108864", + "MIN_SLASHING_PENALTY_QUOTIENT": "128", + "PROPORTIONAL_SLASHING_MULTIPLIER": "1", + "MAX_PROPOSER_SLASHINGS": "16", + "MAX_ATTESTER_SLASHINGS": "2", + "MAX_ATTESTATIONS": "128", + "MAX_DEPOSITS": "16", + "MAX_VOLUNTARY_EXITS": "16", + "INACTIVITY_PENALTY_QUOTIENT_ALTAIR": "50331648", + "MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR": "64", + "PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR": "2", + "SYNC_COMMITTEE_SIZE": "512", + "EPOCHS_PER_SYNC_COMMITTEE_PERIOD": "256", + "MIN_SYNC_COMMITTEE_PARTICIPANTS": "1", + "INACTIVITY_PENALTY_QUOTIENT_BELLATRIX": "16777216", + "MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX": "32", + "PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX": "3", + "MAX_BYTES_PER_TRANSACTION": "1073741824", + "MAX_TRANSACTIONS_PER_PAYLOAD": "1048576", + "BYTES_PER_LOGS_BLOOM": "256", + "MAX_EXTRA_DATA_BYTES": "32", + "MAX_BLS_TO_EXECUTION_CHANGES": "16", + "MAX_WITHDRAWALS_PER_PAYLOAD": "16", + "MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP": "16384", + "MAX_BLOB_COMMITMENTS_PER_BLOCK": "4096", + "FIELD_ELEMENTS_PER_BLOB": "4096", + "MIN_ACTIVATION_BALANCE": "32000000000", + "MAX_EFFECTIVE_BALANCE_ELECTRA": "2048000000000", + "MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA": "4096", + "WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA": "4096", + "MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP": "8", + "PENDING_DEPOSITS_LIMIT": "134217728", + "PENDING_PARTIAL_WITHDRAWALS_LIMIT": "134217728", + "PENDING_CONSOLIDATIONS_LIMIT": "262144", + "MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD": "2", + "MAX_DEPOSIT_REQUESTS_PER_PAYLOAD": "8192", + "MAX_ATTESTER_SLASHINGS_ELECTRA": "1", + "MAX_ATTESTATIONS_ELECTRA": "8", + "MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD": "16", + "FIELD_ELEMENTS_PER_CELL": "64", + "FIELD_ELEMENTS_PER_EXT_BLOB": "8192", + "KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH": "4", + "VERSIONED_HASH_VERSION_KZG": "1", + "DOMAIN_SYNC_COMMITTEE": "0x07000000", + "DOMAIN_VOLUNTARY_EXIT": "0x04000000", + "TARGET_AGGREGATORS_PER_COMMITTEE": "16", + "SYNC_COMMITTEE_SUBNET_COUNT": "4", + "DOMAIN_BEACON_ATTESTER": "0x01000000", + "FULL_EXIT_REQUEST_AMOUNT": "0", + "BLS_WITHDRAWAL_PREFIX": "0x00", + "DOMAIN_SELECTION_PROOF": "0x05000000", + "DOMAIN_AGGREGATE_AND_PROOF": "0x06000000", + "DOMAIN_DEPOSIT": "0x03000000", + "DOMAIN_CONTRIBUTION_AND_PROOF": "0x09000000", + "DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF": "0x08000000", + "COMPOUNDING_WITHDRAWAL_PREFIX": "0x02", + "DOMAIN_APPLICATION_MASK": "0x00000001", + "DOMAIN_RANDAO": "0x02000000", + "UNSET_DEPOSIT_REQUESTS_START_INDEX": "18446744073709551615", + "TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE": "16", + "DOMAIN_BEACON_PROPOSER": "0x00000000", + "ETH1_ADDRESS_WITHDRAWAL_PREFIX": "0x01" + } +} \ No newline at end of file From 4c260cfa7261b13dac40fb280a9f35e9f88ff787 Mon Sep 17 00:00:00 2001 From: eltitanb Date: Wed, 19 Mar 2025 19:49:51 +0000 Subject: [PATCH 2/2] update config --- config.example.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.example.toml b/config.example.toml index 5821391c..23e7cbb4 100644 --- a/config.example.toml +++ b/config.example.toml @@ -2,7 +2,7 @@ # Some fields are optional and can be omitted, in which case the default value, if present, will be used. # Chain spec ID. Supported values: -# A network ID. Supported values: Mainnet, Holesky, Sepolia, Helder. +# A network ID. Supported values: Mainnet, Holesky, Sepolia, Helder, Hoodi. # A custom object, e.g., chain = { genesis_time_secs = 1695902400, path = "/path/to/spec.json" }, with a path to a chain spec file, either in .json format (e.g., as returned by the beacon endpoint /eth/v1/config/spec), or in .yml format (see examples in tests/data). # A custom object, e.g., chain = { genesis_time_secs = 1695902400, slot_time_secs = 12, genesis_fork_version = "0x01017000" }. chain = "Holesky"