Skip to content

Commit 434a1c7

Browse files
committed
test(consensus): pin the fork digest to other clients' output
A fork digest that differs by one byte is invisible locally but fatal on the wire: peers reject our Status and we subscribe to the wrong gossip topics. Cover the EIP-7892 masking against Lighthouse's own vector, plus the two boundary behaviours that are easy to regress — the digest only changing on a BPO entry, and no masking at all before Fulu.
1 parent f3e483a commit 434a1c7

1 file changed

Lines changed: 67 additions & 0 deletions

File tree

crates/common/consensus/misc/src/fork_data.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,70 @@ pub fn compute_fork_digest(
5252

5353
B32::from_slice(&result)
5454
}
55+
56+
#[cfg(test)]
57+
mod tests {
58+
use alloy_primitives::fixed_bytes;
59+
60+
use super::*;
61+
62+
fn schedule() -> Vec<BlobParameters> {
63+
vec![
64+
BlobParameters {
65+
epoch: 9,
66+
max_blobs_per_block: 9,
67+
},
68+
BlobParameters {
69+
epoch: 100,
70+
max_blobs_per_block: 100,
71+
},
72+
BlobParameters {
73+
epoch: 150,
74+
max_blobs_per_block: 175,
75+
},
76+
]
77+
}
78+
79+
fn fork_data() -> ForkData {
80+
ForkData {
81+
current_version: fixed_bytes!("0x06000000"),
82+
genesis_validators_root: B256::ZERO,
83+
}
84+
}
85+
86+
/// Cross-check against the vector in Lighthouse's `blob_schedule_fork_digest`
87+
/// (`consensus/types/src/core/chain_spec.rs`). A mismatch means peers reject our
88+
/// `Status` and we subscribe to the wrong gossip topics, so this must stay
89+
/// byte-identical to other clients.
90+
#[test]
91+
fn test_compute_fork_digest_matches_other_clients() {
92+
assert_eq!(
93+
compute_fork_digest(fork_data(), &schedule(), 100, 100),
94+
fixed_bytes!("0xdf67557b"),
95+
);
96+
}
97+
98+
/// The digest only changes on a BPO boundary, so every epoch between two entries
99+
/// resolves to the earlier one.
100+
#[test]
101+
fn test_compute_fork_digest_is_stable_between_bpo_entries() {
102+
assert_eq!(
103+
compute_fork_digest(fork_data(), &schedule(), 100, 149),
104+
compute_fork_digest(fork_data(), &schedule(), 100, 100),
105+
);
106+
assert_ne!(
107+
compute_fork_digest(fork_data(), &schedule(), 100, 150),
108+
compute_fork_digest(fork_data(), &schedule(), 100, 149),
109+
);
110+
}
111+
112+
/// Before Fulu there is no BPO masking, so the digest is the first four bytes of the
113+
/// fork data root.
114+
#[test]
115+
fn test_compute_fork_digest_is_unmasked_before_fulu() {
116+
assert_eq!(
117+
compute_fork_digest(fork_data(), &schedule(), 100, 99),
118+
B32::from_slice(&fork_data().compute_fork_data_root()[..4]),
119+
);
120+
}
121+
}

0 commit comments

Comments
 (0)