Update chainspec p2p and etc (#8601)

[Missing values in /eth/v1/config/spec #8571
](https://github.com/sigp/lighthouse/issues/8571) - there will be follow up PR for the re org props


  1. As per above issue from EF dev ops, I added
```
"EPOCHS_PER_SUBNET_SUBSCRIPTION": "256",
"ATTESTATION_SUBNET_COUNT": "64",
"ATTESTATION_SUBNET_EXTRA_BITS": "0",
"UPDATE_TIMEOUT": "8192",
"DOMAIN_BLS_TO_EXECUTION_CHANGE": "0x0a000000"
```
to `/eth/v1/config/spec`
2. Had to change the minimal config for UPDATE_TIMEOUT to get currents tests to pass. This is ok given UPDATE_TIMEOUT is not used in lighthouse as this config for light client spec from altair
3. ATTESTATION_SUBNET_PREFIX_BITS is now dynamically calculated and shimmed into the /eth/v1/config/spec output as advised by @michaelsproul


Co-Authored-By: Joseph Patchen <josephmipatchen@gmail.com>
This commit is contained in:
Mr Ree
2026-01-14 22:35:57 -06:00
committed by GitHub
parent 1abc41e337
commit acc746d947
10 changed files with 138 additions and 10 deletions

View File

@@ -125,6 +125,7 @@ SUBNETS_PER_NODE: 2
ATTESTATION_SUBNET_COUNT: 64
ATTESTATION_SUBNET_EXTRA_BITS: 0
# ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS
# computed at runtime
ATTESTATION_SUBNET_PREFIX_BITS: 6
# Deneb

View File

@@ -108,6 +108,8 @@ MESSAGE_DOMAIN_INVALID_SNAPPY: 0x00000000
MESSAGE_DOMAIN_VALID_SNAPPY: 0x01000000
ATTESTATION_SUBNET_COUNT: 64
ATTESTATION_SUBNET_EXTRA_BITS: 0
# ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS
# computed at runtime
ATTESTATION_SUBNET_PREFIX_BITS: 6
ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS: 3

View File

@@ -127,6 +127,7 @@ SUBNETS_PER_NODE: 2
ATTESTATION_SUBNET_COUNT: 64
ATTESTATION_SUBNET_EXTRA_BITS: 0
# ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS
# computed at runtime
ATTESTATION_SUBNET_PREFIX_BITS: 6
ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS: 3

View File

@@ -133,6 +133,7 @@ SUBNETS_PER_NODE: 2
ATTESTATION_SUBNET_COUNT: 64
ATTESTATION_SUBNET_EXTRA_BITS: 0
# ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS
# computed at runtime
ATTESTATION_SUBNET_PREFIX_BITS: 6
# Deneb

View File

@@ -154,6 +154,7 @@ ATTESTATION_SUBNET_COUNT: 64
# 0 bits
ATTESTATION_SUBNET_EXTRA_BITS: 0
# ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS (= 6 + 0) bits
# computed at runtime
ATTESTATION_SUBNET_PREFIX_BITS: 6
ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS: 3

View File

@@ -133,6 +133,7 @@ SUBNETS_PER_NODE: 2
ATTESTATION_SUBNET_COUNT: 64
ATTESTATION_SUBNET_EXTRA_BITS: 0
# ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS
# computed at runtime
ATTESTATION_SUBNET_PREFIX_BITS: 6
ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS: 3

View File

@@ -163,6 +163,7 @@ pub struct ChainSpec {
pub inactivity_score_bias: u64,
pub inactivity_score_recovery_rate: u64,
pub min_sync_committee_participants: u64,
pub update_timeout: u64,
pub(crate) domain_sync_committee: u32,
pub(crate) domain_sync_committee_selection_proof: u32,
pub(crate) domain_contribution_and_proof: u32,
@@ -251,7 +252,9 @@ pub struct ChainSpec {
pub message_domain_invalid_snappy: [u8; 4],
pub message_domain_valid_snappy: [u8; 4],
pub subnets_per_node: u8,
pub epochs_per_subnet_subscription: u64,
pub attestation_subnet_count: u64,
pub attestation_subnet_extra_bits: u8,
pub attestation_subnet_prefix_bits: u8,
/*
@@ -1014,6 +1017,7 @@ impl ChainSpec {
inactivity_score_bias: 4,
inactivity_score_recovery_rate: 16,
min_sync_committee_participants: 1,
update_timeout: 8192,
epochs_per_sync_committee_period: Epoch::new(256),
domain_sync_committee: 7,
domain_sync_committee_selection_proof: 8,
@@ -1106,7 +1110,9 @@ impl ChainSpec {
boot_nodes: vec![],
network_id: 1, // mainnet network id
attestation_propagation_slot_range: default_attestation_propagation_slot_range(),
epochs_per_subnet_subscription: 256,
attestation_subnet_count: 64,
attestation_subnet_extra_bits: 0,
subnets_per_node: 2,
maximum_gossip_clock_disparity: default_maximum_gossip_clock_disparity(),
target_aggregators_per_committee: 16,
@@ -1116,7 +1122,10 @@ impl ChainSpec {
resp_timeout: default_resp_timeout(),
message_domain_invalid_snappy: default_message_domain_invalid_snappy(),
message_domain_valid_snappy: default_message_domain_valid_snappy(),
attestation_subnet_prefix_bits: default_attestation_subnet_prefix_bits(),
attestation_subnet_prefix_bits: compute_attestation_subnet_prefix_bits(
default_attestation_subnet_count(),
default_attestation_subnet_extra_bits(),
),
max_request_blocks: default_max_request_blocks(),
/*
@@ -1197,6 +1206,7 @@ impl ChainSpec {
proportional_slashing_multiplier: 2,
// Altair
epochs_per_sync_committee_period: Epoch::new(8),
update_timeout: 64,
altair_fork_version: [0x01, 0x00, 0x00, 0x01],
altair_fork_epoch: None,
// Bellatrix
@@ -1380,6 +1390,7 @@ impl ChainSpec {
inactivity_score_bias: 4,
inactivity_score_recovery_rate: 16,
min_sync_committee_participants: 1,
update_timeout: 8192,
epochs_per_sync_committee_period: Epoch::new(512),
domain_sync_committee: 7,
domain_sync_committee_selection_proof: 8,
@@ -1471,7 +1482,9 @@ impl ChainSpec {
boot_nodes: vec![],
network_id: 100, // Gnosis Chain network id
attestation_propagation_slot_range: default_attestation_propagation_slot_range(),
epochs_per_subnet_subscription: 256,
attestation_subnet_count: 64,
attestation_subnet_extra_bits: 0,
subnets_per_node: 4, // Make this larger than usual to avoid network damage
maximum_gossip_clock_disparity: default_maximum_gossip_clock_disparity(),
target_aggregators_per_committee: 16,
@@ -1482,7 +1495,10 @@ impl ChainSpec {
message_domain_invalid_snappy: default_message_domain_invalid_snappy(),
message_domain_valid_snappy: default_message_domain_valid_snappy(),
max_request_blocks: default_max_request_blocks(),
attestation_subnet_prefix_bits: default_attestation_subnet_prefix_bits(),
attestation_subnet_prefix_bits: compute_attestation_subnet_prefix_bits(
default_attestation_subnet_count(),
default_attestation_subnet_extra_bits(),
),
/*
* Networking Deneb Specific
@@ -1803,9 +1819,15 @@ pub struct Config {
#[serde(default = "default_message_domain_valid_snappy")]
#[serde(with = "serde_utils::bytes_4_hex")]
message_domain_valid_snappy: [u8; 4],
#[serde(default = "default_attestation_subnet_prefix_bits")]
#[serde(default = "default_epochs_per_subnet_subscription")]
#[serde(with = "serde_utils::quoted_u64")]
epochs_per_subnet_subscription: u64,
#[serde(default = "default_attestation_subnet_count")]
#[serde(with = "serde_utils::quoted_u64")]
attestation_subnet_count: u64,
#[serde(default = "default_attestation_subnet_extra_bits")]
#[serde(with = "serde_utils::quoted_u8")]
attestation_subnet_prefix_bits: u8,
attestation_subnet_extra_bits: u8,
#[serde(default = "default_max_request_blocks_deneb")]
#[serde(with = "serde_utils::quoted_u64")]
max_request_blocks_deneb: u64,
@@ -1920,8 +1942,36 @@ fn default_subnets_per_node() -> u8 {
2u8
}
fn default_attestation_subnet_prefix_bits() -> u8 {
6
const fn default_epochs_per_subnet_subscription() -> u64 {
256
}
const fn default_attestation_subnet_count() -> u64 {
64
}
const fn default_attestation_subnet_extra_bits() -> u8 {
0
}
/// Compute attestation_subnet_prefix_bits dynamically as:
/// ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS
fn compute_attestation_subnet_prefix_bits(
attestation_subnet_count: u64,
attestation_subnet_extra_bits: u8,
) -> u8 {
let default_attestation_subnet_prefix_bits = 6u8;
// ceillog2() = next_power_of_two().ilog2()
// casting to u8 is fine given ilog2(u64::MAX) = 63
let min_bits_needed = attestation_subnet_count
.checked_next_power_of_two()
.and_then(|x| x.checked_ilog2())
.unwrap_or(default_attestation_subnet_prefix_bits as u32) as u8;
min_bits_needed
.safe_add(attestation_subnet_extra_bits)
.unwrap_or(default_attestation_subnet_prefix_bits)
}
const fn default_max_per_epoch_activation_churn_limit() -> u64 {
@@ -2206,7 +2256,9 @@ impl Config {
shard_committee_period: spec.shard_committee_period,
eth1_follow_distance: spec.eth1_follow_distance,
subnets_per_node: spec.subnets_per_node,
attestation_subnet_prefix_bits: spec.attestation_subnet_prefix_bits,
epochs_per_subnet_subscription: spec.epochs_per_subnet_subscription,
attestation_subnet_count: spec.attestation_subnet_count,
attestation_subnet_extra_bits: spec.attestation_subnet_extra_bits,
inactivity_score_bias: spec.inactivity_score_bias,
inactivity_score_recovery_rate: spec.inactivity_score_recovery_rate,
@@ -2297,7 +2349,9 @@ impl Config {
shard_committee_period,
eth1_follow_distance,
subnets_per_node,
attestation_subnet_prefix_bits,
epochs_per_subnet_subscription,
attestation_subnet_count,
attestation_subnet_extra_bits,
inactivity_score_bias,
inactivity_score_recovery_rate,
ejection_balance,
@@ -2370,6 +2424,9 @@ impl Config {
shard_committee_period,
eth1_follow_distance,
subnets_per_node,
epochs_per_subnet_subscription,
attestation_subnet_count,
attestation_subnet_extra_bits,
inactivity_score_bias,
inactivity_score_recovery_rate,
ejection_balance,
@@ -2390,7 +2447,11 @@ impl Config {
resp_timeout,
message_domain_invalid_snappy,
message_domain_valid_snappy,
attestation_subnet_prefix_bits,
// Compute attestation_subnet_prefix_bits dynamically
attestation_subnet_prefix_bits: compute_attestation_subnet_prefix_bits(
attestation_subnet_count,
attestation_subnet_extra_bits,
),
max_request_blocks,
attestation_propagation_slot_range,
maximum_gossip_clock_disparity,
@@ -2559,6 +2620,13 @@ mod tests {
}
}
}
#[test]
fn test_compute_min_bits_for_n_values_edge_cases() {
assert_eq!(compute_attestation_subnet_prefix_bits(64, 0), 6);
assert_eq!(compute_attestation_subnet_prefix_bits(65, 0), 7);
assert_eq!(compute_attestation_subnet_prefix_bits(0, 1), 1);
}
}
#[cfg(test)]
@@ -2638,6 +2706,9 @@ mod yaml_tests {
REORG_HEAD_WEIGHT_THRESHOLD: 20
REORG_PARENT_WEIGHT_THRESHOLD: 160
REORG_MAX_EPOCHS_SINCE_FINALIZATION: 2
EPOCHS_PER_SUBNET_SUBSCRIPTION: 256
ATTESTATION_SUBNET_COUNT: 64
ATTESTATION_SUBNET_EXTRA_BITS: 0
DEPOSIT_CHAIN_ID: 7042643276
DEPOSIT_NETWORK_ID: 7042643276
DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa
@@ -2787,6 +2858,9 @@ mod yaml_tests {
REORG_HEAD_WEIGHT_THRESHOLD: 20
REORG_PARENT_WEIGHT_THRESHOLD: 160
REORG_MAX_EPOCHS_SINCE_FINALIZATION: 2
EPOCHS_PER_SUBNET_SUBSCRIPTION: 256
ATTESTATION_SUBNET_COUNT: 64
ATTESTATION_SUBNET_EXTRA_BITS: 0
DEPOSIT_CHAIN_ID: 7042643276
DEPOSIT_NETWORK_ID: 7042643276
DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa
@@ -2896,6 +2970,9 @@ mod yaml_tests {
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8
CHURN_LIMIT_QUOTIENT: 65536
PROPOSER_SCORE_BOOST: 40
EPOCHS_PER_SUBNET_SUBSCRIPTION: 256
ATTESTATION_SUBNET_COUNT: 64
ATTESTATION_SUBNET_EXTRA_BITS: 0
DEPOSIT_CHAIN_ID: 1
DEPOSIT_NETWORK_ID: 1
DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa
@@ -2928,7 +3005,6 @@ mod yaml_tests {
check_default!(resp_timeout);
check_default!(message_domain_invalid_snappy);
check_default!(message_domain_valid_snappy);
check_default!(attestation_subnet_prefix_bits);
assert_eq!(chain_spec.bellatrix_fork_epoch, None);
}

View File

@@ -114,6 +114,7 @@ pub fn get_extra_fields(spec: &ChainSpec) -> HashMap<String, Value> {
let u32_hex = |v: u32| hex_string(&v.to_le_bytes());
let u8_hex = |v: u8| hex_string(&v.to_le_bytes());
hashmap! {
"attestation_subnet_prefix_bits".to_uppercase() => spec.attestation_subnet_prefix_bits.to_string().into(),
"bls_withdrawal_prefix".to_uppercase() => u8_hex(spec.bls_withdrawal_prefix_byte),
"eth1_address_withdrawal_prefix".to_uppercase() => u8_hex(spec.eth1_address_withdrawal_prefix_byte),
"domain_beacon_proposer".to_uppercase() => u32_hex(spec.domain_beacon_proposer),
@@ -131,6 +132,7 @@ pub fn get_extra_fields(spec: &ChainSpec) -> HashMap<String, Value> {
"domain_sync_committee".to_uppercase() => u32_hex(spec.domain_sync_committee),
"domain_sync_committee_selection_proof".to_uppercase() =>
u32_hex(spec.domain_sync_committee_selection_proof),
"domain_bls_to_execution_change".to_uppercase() => u32_hex(spec.domain_bls_to_execution_change),
"sync_committee_subnet_count".to_uppercase() =>
consts::altair::SYNC_COMMITTEE_SUBNET_COUNT.to_string().into(),
"target_aggregators_per_sync_subcommittee".to_uppercase() =>
@@ -183,4 +185,38 @@ mod test {
serde_yaml::from_reader(reader).expect("error while deserializing");
assert_eq!(ConfigAndPreset::Gloas(from), yamlconfig);
}
#[test]
fn test_attestation_subnet_prefix_bits_in_extra_fields() {
let mainnet_spec = ChainSpec::mainnet();
let config = ConfigAndPreset::from_chain_spec::<MainnetEthSpec>(&mainnet_spec);
let extra_fields = config.extra_fields();
assert!(extra_fields.contains_key("ATTESTATION_SUBNET_PREFIX_BITS"));
// For mainnet: 64 subnets, 0 extra bits -> ceil(log2(64)) + 0 = 6
assert_eq!(
extra_fields.get("ATTESTATION_SUBNET_PREFIX_BITS"),
Some(&Value::String("6".to_string()))
);
}
// This is not exhaustive, but it can be extended as new fields are added to the spec.
#[test]
fn test_required_spec_fields_exist() {
let mainnet_spec = ChainSpec::mainnet();
let config = ConfigAndPreset::from_chain_spec::<MainnetEthSpec>(&mainnet_spec);
let json = serde_json::to_value(&config).expect("should serialize");
let obj = json.as_object().expect("should be an object");
let required_fields = [
"EPOCHS_PER_SUBNET_SUBSCRIPTION",
"ATTESTATION_SUBNET_COUNT",
"ATTESTATION_SUBNET_EXTRA_BITS",
"ATTESTATION_SUBNET_PREFIX_BITS",
"UPDATE_TIMEOUT",
"DOMAIN_BLS_TO_EXECUTION_CHANGE",
];
for field in required_fields {
assert!(obj.contains_key(field), "Missing required field: {}", field);
}
}
}

View File

@@ -134,6 +134,9 @@ pub struct AltairPreset {
pub epochs_per_sync_committee_period: Epoch,
#[serde(with = "serde_utils::quoted_u64")]
pub min_sync_committee_participants: u64,
#[serde(default = "default_update_timeout")]
#[serde(with = "serde_utils::quoted_u64")]
pub update_timeout: u64,
}
impl AltairPreset {
@@ -145,10 +148,15 @@ impl AltairPreset {
sync_committee_size: E::SyncCommitteeSize::to_u64(),
epochs_per_sync_committee_period: spec.epochs_per_sync_committee_period,
min_sync_committee_participants: spec.min_sync_committee_participants,
update_timeout: spec.update_timeout,
}
}
}
const fn default_update_timeout() -> u64 {
8192
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub struct BellatrixPreset {

View File

@@ -93,6 +93,7 @@ TTFB_TIMEOUT: 5
RESP_TIMEOUT: 10
MESSAGE_DOMAIN_INVALID_SNAPPY: 0x00000000
MESSAGE_DOMAIN_VALID_SNAPPY: 0x01000000
EPOCHS_PER_SUBNET_SUBSCRIPTION: 256
ATTESTATION_SUBNET_COUNT: 64
ATTESTATION_SUBNET_EXTRA_BITS: 0
ATTESTATION_SUBNET_PREFIX_BITS: 6