Skip to content

Commit fff4e8a

Browse files
authored
feat: add Hoodi known chain (#282)
1 parent db135c8 commit fff4e8a

File tree

4 files changed

+206
-3
lines changed

4 files changed

+206
-3
lines changed

config.example.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Some fields are optional and can be omitted, in which case the default value, if present, will be used.
33

44
# Chain spec ID. Supported values:
5-
# A network ID. Supported values: Mainnet, Holesky, Sepolia, Helder.
5+
# A network ID. Supported values: Mainnet, Holesky, Sepolia, Helder, Hoodi.
66
# 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).
77
# A custom object, e.g., chain = { genesis_time_secs = 1695902400, slot_time_secs = 12, genesis_fork_version = "0x01017000" }.
88
chain = "Holesky"

crates/common/src/signature.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,9 @@ mod tests {
112112
compute_domain(Chain::Helder, APPLICATION_BUILDER_DOMAIN),
113113
Chain::Helder.builder_domain()
114114
);
115+
assert_eq!(
116+
compute_domain(Chain::Hoodi, APPLICATION_BUILDER_DOMAIN),
117+
Chain::Hoodi.builder_domain()
118+
);
115119
}
116120
}

crates/common/src/types.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub enum Chain {
2323
Holesky,
2424
Sepolia,
2525
Helder,
26+
Hoodi,
2627
Custom { genesis_time_secs: u64, slot_time_secs: u64, genesis_fork_version: ForkVersion },
2728
}
2829

@@ -31,7 +32,9 @@ pub type ForkVersion = [u8; 4];
3132
impl std::fmt::Display for Chain {
3233
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3334
match self {
34-
Self::Mainnet | Self::Holesky | Self::Sepolia | Self::Helder => write!(f, "{self:?}"),
35+
Self::Mainnet | Self::Holesky | Self::Sepolia | Self::Helder | Self::Hoodi => {
36+
write!(f, "{self:?}")
37+
}
3538
Self::Custom { .. } => write!(f, "Custom"),
3639
}
3740
}
@@ -44,6 +47,7 @@ impl std::fmt::Debug for Chain {
4447
Self::Holesky => write!(f, "Holesky"),
4548
Self::Sepolia => write!(f, "Sepolia"),
4649
Self::Helder => write!(f, "Helder"),
50+
Self::Hoodi => write!(f, "Hoodi"),
4751
Self::Custom { genesis_time_secs, slot_time_secs, genesis_fork_version } => f
4852
.debug_struct("Custom")
4953
.field("genesis_time_secs", genesis_time_secs)
@@ -61,6 +65,7 @@ impl Chain {
6165
Chain::Holesky => KnownChain::Holesky.id(),
6266
Chain::Sepolia => KnownChain::Sepolia.id(),
6367
Chain::Helder => KnownChain::Helder.id(),
68+
Chain::Hoodi => KnownChain::Hoodi.id(),
6469
Chain::Custom { .. } => {
6570
unimplemented!("chain id is not supported on custom chains, please file an issue")
6671
}
@@ -73,6 +78,7 @@ impl Chain {
7378
Chain::Holesky => KnownChain::Holesky.builder_domain(),
7479
Chain::Sepolia => KnownChain::Sepolia.builder_domain(),
7580
Chain::Helder => KnownChain::Helder.builder_domain(),
81+
Chain::Hoodi => KnownChain::Hoodi.builder_domain(),
7682
Chain::Custom { .. } => compute_domain(*self, APPLICATION_BUILDER_DOMAIN),
7783
}
7884
}
@@ -83,6 +89,7 @@ impl Chain {
8389
Chain::Holesky => KnownChain::Holesky.genesis_fork_version(),
8490
Chain::Sepolia => KnownChain::Sepolia.genesis_fork_version(),
8591
Chain::Helder => KnownChain::Helder.genesis_fork_version(),
92+
Chain::Hoodi => KnownChain::Hoodi.genesis_fork_version(),
8693
Chain::Custom { genesis_fork_version, .. } => *genesis_fork_version,
8794
}
8895
}
@@ -93,6 +100,7 @@ impl Chain {
93100
Chain::Holesky => KnownChain::Holesky.genesis_time_sec(),
94101
Chain::Sepolia => KnownChain::Sepolia.genesis_time_sec(),
95102
Chain::Helder => KnownChain::Helder.genesis_time_sec(),
103+
Chain::Hoodi => KnownChain::Hoodi.genesis_time_sec(),
96104
Chain::Custom { genesis_time_secs, .. } => *genesis_time_secs,
97105
}
98106
}
@@ -103,6 +111,7 @@ impl Chain {
103111
Chain::Holesky => KnownChain::Holesky.slot_time_sec(),
104112
Chain::Sepolia => KnownChain::Sepolia.slot_time_sec(),
105113
Chain::Helder => KnownChain::Helder.slot_time_sec(),
114+
Chain::Hoodi => KnownChain::Hoodi.slot_time_sec(),
106115
Chain::Custom { slot_time_secs, .. } => *slot_time_secs,
107116
}
108117
}
@@ -118,6 +127,8 @@ pub enum KnownChain {
118127
Sepolia,
119128
#[serde(alias = "helder")]
120129
Helder,
130+
#[serde(alias = "hoodi")]
131+
Hoodi,
121132
}
122133

123134
// Constants
@@ -128,6 +139,7 @@ impl KnownChain {
128139
KnownChain::Holesky => 17000,
129140
KnownChain::Sepolia => 11155111,
130141
KnownChain::Helder => 167000,
142+
KnownChain::Hoodi => 560048,
131143
}
132144
}
133145

@@ -149,6 +161,10 @@ impl KnownChain {
149161
0, 0, 0, 1, 148, 196, 26, 244, 132, 255, 247, 150, 73, 105, 224, 189, 217, 34, 248,
150162
45, 255, 15, 75, 232, 122, 96, 208, 102, 76, 201, 209, 255,
151163
],
164+
KnownChain::Hoodi => [
165+
0, 0, 0, 1, 113, 145, 3, 81, 30, 250, 79, 19, 98, 255, 42, 80, 153, 108, 204, 243,
166+
41, 204, 132, 203, 65, 12, 94, 92, 125, 53, 29, 3,
167+
],
152168
}
153169
}
154170

@@ -158,6 +174,7 @@ impl KnownChain {
158174
KnownChain::Holesky => hex!("01017000"),
159175
KnownChain::Sepolia => hex!("90000069"),
160176
KnownChain::Helder => hex!("10000000"),
177+
KnownChain::Hoodi => hex!("10000910"),
161178
}
162179
}
163180

@@ -167,6 +184,7 @@ impl KnownChain {
167184
KnownChain::Holesky => 1695902400,
168185
KnownChain::Sepolia => 1655733600,
169186
KnownChain::Helder => 1718967660,
187+
KnownChain::Hoodi => 1742213400,
170188
}
171189
}
172190

@@ -175,7 +193,8 @@ impl KnownChain {
175193
KnownChain::Mainnet |
176194
KnownChain::Holesky |
177195
KnownChain::Sepolia |
178-
KnownChain::Helder => 12,
196+
KnownChain::Helder |
197+
KnownChain::Hoodi => 12,
179198
}
180199
}
181200
}
@@ -187,6 +206,7 @@ impl From<KnownChain> for Chain {
187206
KnownChain::Holesky => Chain::Holesky,
188207
KnownChain::Sepolia => Chain::Sepolia,
189208
KnownChain::Helder => Chain::Helder,
209+
KnownChain::Hoodi => Chain::Hoodi,
190210
}
191211
}
192212
}
@@ -220,6 +240,7 @@ impl Serialize for Chain {
220240
Chain::Holesky => ChainLoader::Known(KnownChain::Holesky),
221241
Chain::Sepolia => ChainLoader::Known(KnownChain::Sepolia),
222242
Chain::Helder => ChainLoader::Known(KnownChain::Helder),
243+
Chain::Hoodi => ChainLoader::Known(KnownChain::Hoodi),
223244
Chain::Custom { genesis_time_secs, slot_time_secs, genesis_fork_version } => {
224245
ChainLoader::Custom {
225246
genesis_time_secs: *genesis_time_secs,
@@ -372,6 +393,7 @@ mod tests {
372393
let s = format!("chain = {{ genesis_time_secs = 1, path = {path:?}}}");
373394

374395
let decoded: MockConfig = toml::from_str(&s).unwrap();
396+
assert_eq!(decoded.chain.slot_time_sec(), KnownChain::Holesky.slot_time_sec());
375397
assert_eq!(decoded.chain, Chain::Custom {
376398
genesis_time_secs: 1,
377399
slot_time_secs: KnownChain::Holesky.slot_time_sec(),
@@ -391,13 +413,34 @@ mod tests {
391413
let s = format!("chain = {{ genesis_time_secs = 1, path = {path:?}}}");
392414

393415
let decoded: MockConfig = toml::from_str(&s).unwrap();
416+
assert_eq!(decoded.chain.slot_time_sec(), KnownChain::Helder.slot_time_sec());
394417
assert_eq!(decoded.chain, Chain::Custom {
395418
genesis_time_secs: 1,
396419
slot_time_secs: KnownChain::Sepolia.slot_time_sec(),
397420
genesis_fork_version: KnownChain::Sepolia.genesis_fork_version()
398421
})
399422
}
400423

424+
#[test]
425+
fn test_spec_hoodi_data_json() {
426+
let a = env!("CARGO_MANIFEST_DIR");
427+
let mut path = PathBuf::from(a);
428+
429+
path.pop();
430+
path.pop();
431+
path.push("tests/data/hoodi_spec.json");
432+
433+
let s = format!("chain = {{ genesis_time_secs = 1, path = {path:?}}}");
434+
435+
let decoded: MockConfig = toml::from_str(&s).unwrap();
436+
assert_eq!(decoded.chain.slot_time_sec(), KnownChain::Hoodi.slot_time_sec());
437+
assert_eq!(decoded.chain, Chain::Custom {
438+
genesis_time_secs: 1,
439+
slot_time_secs: KnownChain::Hoodi.slot_time_sec(),
440+
genesis_fork_version: KnownChain::Hoodi.genesis_fork_version()
441+
})
442+
}
443+
401444
#[test]
402445
fn test_spec_helder_yml() {
403446
let a = env!("CARGO_MANIFEST_DIR");
@@ -410,6 +453,7 @@ mod tests {
410453
let s = format!("chain = {{ genesis_time_secs = 1, path = {path:?}}}");
411454

412455
let decoded: MockConfig = toml::from_str(&s).unwrap();
456+
assert_eq!(decoded.chain.slot_time_sec(), KnownChain::Helder.slot_time_sec());
413457
assert_eq!(decoded.chain, Chain::Custom {
414458
genesis_time_secs: 1,
415459
slot_time_secs: KnownChain::Helder.slot_time_sec(),

tests/data/hoodi_spec.json

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
{
2+
"data": {
3+
"CONFIG_NAME": "hoodi",
4+
"PRESET_BASE": "mainnet",
5+
"TERMINAL_TOTAL_DIFFICULTY": "0",
6+
"TERMINAL_BLOCK_HASH": "0x0000000000000000000000000000000000000000000000000000000000000000",
7+
"TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH": "18446744073709551615",
8+
"MIN_GENESIS_ACTIVE_VALIDATOR_COUNT": "16384",
9+
"MIN_GENESIS_TIME": "1742212800",
10+
"GENESIS_FORK_VERSION": "0x10000910",
11+
"GENESIS_DELAY": "600",
12+
"ALTAIR_FORK_VERSION": "0x20000910",
13+
"ALTAIR_FORK_EPOCH": "0",
14+
"BELLATRIX_FORK_VERSION": "0x30000910",
15+
"BELLATRIX_FORK_EPOCH": "0",
16+
"CAPELLA_FORK_VERSION": "0x40000910",
17+
"CAPELLA_FORK_EPOCH": "0",
18+
"DENEB_FORK_VERSION": "0x50000910",
19+
"DENEB_FORK_EPOCH": "0",
20+
"ELECTRA_FORK_VERSION": "0x60000910",
21+
"ELECTRA_FORK_EPOCH": "2048",
22+
"FULU_FORK_VERSION": "0x70000910",
23+
"FULU_FORK_EPOCH": "18446744073709551615",
24+
"SECONDS_PER_SLOT": "12",
25+
"SECONDS_PER_ETH1_BLOCK": "12",
26+
"MIN_VALIDATOR_WITHDRAWABILITY_DELAY": "256",
27+
"SHARD_COMMITTEE_PERIOD": "256",
28+
"ETH1_FOLLOW_DISTANCE": "2048",
29+
"SUBNETS_PER_NODE": "2",
30+
"INACTIVITY_SCORE_BIAS": "4",
31+
"INACTIVITY_SCORE_RECOVERY_RATE": "16",
32+
"EJECTION_BALANCE": "16000000000",
33+
"MIN_PER_EPOCH_CHURN_LIMIT": "4",
34+
"MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT": "8",
35+
"CHURN_LIMIT_QUOTIENT": "65536",
36+
"PROPOSER_SCORE_BOOST": "40",
37+
"DEPOSIT_CHAIN_ID": "560048",
38+
"DEPOSIT_NETWORK_ID": "560048",
39+
"DEPOSIT_CONTRACT_ADDRESS": "0x00000000219ab540356cbb839cbe05303d7705fa",
40+
"GAS_LIMIT_ADJUSTMENT_FACTOR": "1024",
41+
"GOSSIP_MAX_SIZE": "10485760",
42+
"MAX_REQUEST_BLOCKS": "1024",
43+
"MIN_EPOCHS_FOR_BLOCK_REQUESTS": "33024",
44+
"MAX_CHUNK_SIZE": "10485760",
45+
"TTFB_TIMEOUT": "5",
46+
"RESP_TIMEOUT": "10",
47+
"ATTESTATION_PROPAGATION_SLOT_RANGE": "32",
48+
"MAXIMUM_GOSSIP_CLOCK_DISPARITY_MILLIS": "500",
49+
"MESSAGE_DOMAIN_INVALID_SNAPPY": "0x00000000",
50+
"MESSAGE_DOMAIN_VALID_SNAPPY": "0x01000000",
51+
"ATTESTATION_SUBNET_PREFIX_BITS": "6",
52+
"MAX_REQUEST_BLOCKS_DENEB": "128",
53+
"MAX_REQUEST_BLOB_SIDECARS": "768",
54+
"MAX_REQUEST_DATA_COLUMN_SIDECARS": "16384",
55+
"MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS": "4096",
56+
"BLOB_SIDECAR_SUBNET_COUNT": "6",
57+
"MAX_BLOBS_PER_BLOCK": "6",
58+
"MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA": "128000000000",
59+
"MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT": "256000000000",
60+
"MAX_BLOBS_PER_BLOCK_ELECTRA": "9",
61+
"BLOB_SIDECAR_SUBNET_COUNT_ELECTRA": "9",
62+
"MAX_REQUEST_BLOB_SIDECARS_ELECTRA": "1152",
63+
"NUMBER_OF_COLUMNS": "128",
64+
"NUMBER_OF_CUSTODY_GROUPS": "128",
65+
"DATA_COLUMN_SIDECAR_SUBNET_COUNT": "128",
66+
"SAMPLES_PER_SLOT": "8",
67+
"CUSTODY_REQUIREMENT": "4",
68+
"MAX_COMMITTEES_PER_SLOT": "64",
69+
"TARGET_COMMITTEE_SIZE": "128",
70+
"MAX_VALIDATORS_PER_COMMITTEE": "2048",
71+
"SHUFFLE_ROUND_COUNT": "90",
72+
"HYSTERESIS_QUOTIENT": "4",
73+
"HYSTERESIS_DOWNWARD_MULTIPLIER": "1",
74+
"HYSTERESIS_UPWARD_MULTIPLIER": "5",
75+
"MIN_DEPOSIT_AMOUNT": "1000000000",
76+
"MAX_EFFECTIVE_BALANCE": "32000000000",
77+
"EFFECTIVE_BALANCE_INCREMENT": "1000000000",
78+
"MIN_ATTESTATION_INCLUSION_DELAY": "1",
79+
"SLOTS_PER_EPOCH": "32",
80+
"MIN_SEED_LOOKAHEAD": "1",
81+
"MAX_SEED_LOOKAHEAD": "4",
82+
"EPOCHS_PER_ETH1_VOTING_PERIOD": "64",
83+
"SLOTS_PER_HISTORICAL_ROOT": "8192",
84+
"MIN_EPOCHS_TO_INACTIVITY_PENALTY": "4",
85+
"EPOCHS_PER_HISTORICAL_VECTOR": "65536",
86+
"EPOCHS_PER_SLASHINGS_VECTOR": "8192",
87+
"HISTORICAL_ROOTS_LIMIT": "16777216",
88+
"VALIDATOR_REGISTRY_LIMIT": "1099511627776",
89+
"BASE_REWARD_FACTOR": "64",
90+
"WHISTLEBLOWER_REWARD_QUOTIENT": "512",
91+
"PROPOSER_REWARD_QUOTIENT": "8",
92+
"INACTIVITY_PENALTY_QUOTIENT": "67108864",
93+
"MIN_SLASHING_PENALTY_QUOTIENT": "128",
94+
"PROPORTIONAL_SLASHING_MULTIPLIER": "1",
95+
"MAX_PROPOSER_SLASHINGS": "16",
96+
"MAX_ATTESTER_SLASHINGS": "2",
97+
"MAX_ATTESTATIONS": "128",
98+
"MAX_DEPOSITS": "16",
99+
"MAX_VOLUNTARY_EXITS": "16",
100+
"INACTIVITY_PENALTY_QUOTIENT_ALTAIR": "50331648",
101+
"MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR": "64",
102+
"PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR": "2",
103+
"SYNC_COMMITTEE_SIZE": "512",
104+
"EPOCHS_PER_SYNC_COMMITTEE_PERIOD": "256",
105+
"MIN_SYNC_COMMITTEE_PARTICIPANTS": "1",
106+
"INACTIVITY_PENALTY_QUOTIENT_BELLATRIX": "16777216",
107+
"MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX": "32",
108+
"PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX": "3",
109+
"MAX_BYTES_PER_TRANSACTION": "1073741824",
110+
"MAX_TRANSACTIONS_PER_PAYLOAD": "1048576",
111+
"BYTES_PER_LOGS_BLOOM": "256",
112+
"MAX_EXTRA_DATA_BYTES": "32",
113+
"MAX_BLS_TO_EXECUTION_CHANGES": "16",
114+
"MAX_WITHDRAWALS_PER_PAYLOAD": "16",
115+
"MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP": "16384",
116+
"MAX_BLOB_COMMITMENTS_PER_BLOCK": "4096",
117+
"FIELD_ELEMENTS_PER_BLOB": "4096",
118+
"MIN_ACTIVATION_BALANCE": "32000000000",
119+
"MAX_EFFECTIVE_BALANCE_ELECTRA": "2048000000000",
120+
"MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA": "4096",
121+
"WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA": "4096",
122+
"MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP": "8",
123+
"PENDING_DEPOSITS_LIMIT": "134217728",
124+
"PENDING_PARTIAL_WITHDRAWALS_LIMIT": "134217728",
125+
"PENDING_CONSOLIDATIONS_LIMIT": "262144",
126+
"MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD": "2",
127+
"MAX_DEPOSIT_REQUESTS_PER_PAYLOAD": "8192",
128+
"MAX_ATTESTER_SLASHINGS_ELECTRA": "1",
129+
"MAX_ATTESTATIONS_ELECTRA": "8",
130+
"MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD": "16",
131+
"FIELD_ELEMENTS_PER_CELL": "64",
132+
"FIELD_ELEMENTS_PER_EXT_BLOB": "8192",
133+
"KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH": "4",
134+
"VERSIONED_HASH_VERSION_KZG": "1",
135+
"DOMAIN_SYNC_COMMITTEE": "0x07000000",
136+
"DOMAIN_VOLUNTARY_EXIT": "0x04000000",
137+
"TARGET_AGGREGATORS_PER_COMMITTEE": "16",
138+
"SYNC_COMMITTEE_SUBNET_COUNT": "4",
139+
"DOMAIN_BEACON_ATTESTER": "0x01000000",
140+
"FULL_EXIT_REQUEST_AMOUNT": "0",
141+
"BLS_WITHDRAWAL_PREFIX": "0x00",
142+
"DOMAIN_SELECTION_PROOF": "0x05000000",
143+
"DOMAIN_AGGREGATE_AND_PROOF": "0x06000000",
144+
"DOMAIN_DEPOSIT": "0x03000000",
145+
"DOMAIN_CONTRIBUTION_AND_PROOF": "0x09000000",
146+
"DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF": "0x08000000",
147+
"COMPOUNDING_WITHDRAWAL_PREFIX": "0x02",
148+
"DOMAIN_APPLICATION_MASK": "0x00000001",
149+
"DOMAIN_RANDAO": "0x02000000",
150+
"UNSET_DEPOSIT_REQUESTS_START_INDEX": "18446744073709551615",
151+
"TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE": "16",
152+
"DOMAIN_BEACON_PROPOSER": "0x00000000",
153+
"ETH1_ADDRESS_WITHDRAWAL_PREFIX": "0x01"
154+
}
155+
}

0 commit comments

Comments
 (0)