mirror of
https://github.com/sigp/lighthouse.git
synced 2026-06-10 09:37:38 +00:00
new test
This commit is contained in:
@@ -2058,6 +2058,85 @@ async fn gloas_get_head_can_return_justified_empty_payload_branch() {
|
||||
assert_eq!(payload_status, PayloadStatus::Empty);
|
||||
}
|
||||
|
||||
// Post-Gloas, `get_beacon_proposer_indices` excludes slashed validators. The lookup prefers the
|
||||
// slashings cache but falls back to reading validators directly when the cache is cold (e.g. block
|
||||
// replay / state reconstruction). This test asserts the cold-cache fallback produces exactly the
|
||||
// same proposers as the warm cache, and that neither path ever selects a slashed validator.
|
||||
#[tokio::test]
|
||||
async fn gloas_proposer_indices_exclude_slashed_with_cold_cache() {
|
||||
let spec = test_spec::<E>();
|
||||
if !spec.fork_name_at_epoch(Epoch::new(0)).gloas_enabled() {
|
||||
return;
|
||||
}
|
||||
|
||||
let harness = BeaconChainHarness::builder(MainnetEthSpec)
|
||||
.spec(spec.into())
|
||||
.chain_config(ChainConfig {
|
||||
archive: true,
|
||||
..ChainConfig::default()
|
||||
})
|
||||
.keypairs(KEYPAIRS[0..VALIDATOR_COUNT].to_vec())
|
||||
.node_custody_type(NodeCustodyType::Supernode)
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer()
|
||||
.build();
|
||||
|
||||
// Advance a couple of epochs so we have a fully-formed Gloas state.
|
||||
harness
|
||||
.extend_slots(E::slots_per_epoch() as usize * 2)
|
||||
.await;
|
||||
|
||||
let spec = harness.chain.spec.clone();
|
||||
let mut state = harness.get_current_state();
|
||||
let current_epoch = state.current_epoch();
|
||||
|
||||
// Slash every odd-indexed validator directly on the state. A large slashed fraction ensures
|
||||
// the filter materially changes the candidate set, so a regressed (non-filtering) fallback
|
||||
// would diverge from the cache rather than passing by luck.
|
||||
let mut slashed_count = 0;
|
||||
for index in (1..VALIDATOR_COUNT).step_by(2) {
|
||||
state.get_validator_mut(index).unwrap().slashed = true;
|
||||
slashed_count += 1;
|
||||
}
|
||||
assert!(
|
||||
slashed_count > 0,
|
||||
"test must actually slash some validators"
|
||||
);
|
||||
|
||||
// `current + 2` is beyond `next_epoch`, so it bypasses the cached proposer-lookahead
|
||||
// early-return and exercises the slashed-filter path in `get_beacon_proposer_indices`.
|
||||
let request_epoch = current_epoch + 2;
|
||||
|
||||
// Warm path: rebuild the slashings cache so it reflects the validators we just slashed.
|
||||
state.drop_all_caches().unwrap();
|
||||
state.build_slashings_cache().unwrap();
|
||||
assert!(state.slashings_cache_is_initialized());
|
||||
let warm = state
|
||||
.get_beacon_proposer_indices(request_epoch, &spec)
|
||||
.unwrap();
|
||||
|
||||
// Cold path: drop the slashings cache so the lookup falls back to reading validators directly.
|
||||
state.drop_all_caches().unwrap();
|
||||
assert!(!state.slashings_cache_is_initialized());
|
||||
let cold = state
|
||||
.get_beacon_proposer_indices(request_epoch, &spec)
|
||||
.unwrap();
|
||||
|
||||
// The fallback must produce exactly the same proposers as the warm cache.
|
||||
assert_eq!(
|
||||
warm, cold,
|
||||
"cold-cache fallback diverged from the slashings cache"
|
||||
);
|
||||
|
||||
// And in both cases, no slashed validator may be selected as a proposer.
|
||||
for proposer in &cold {
|
||||
assert!(
|
||||
!state.get_validator(*proposer).unwrap().slashed,
|
||||
"slashed validator {proposer} was selected as a proposer"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a regression test for this bug:
|
||||
// https://github.com/sigp/lighthouse/issues/4332#issuecomment-1565092279
|
||||
#[tokio::test]
|
||||
|
||||
Reference in New Issue
Block a user