Gloas alpha spec 9 (#9393)

Changes implemented

Ensure bids are for a higher slot than their parent (https://github.com/ethereum/consensus-specs/pull/5302)
Ignore PTC attestations for empty assigned slots (https://github.com/ethereum/consensus-specs/pull/5281)
Limit should_build_on_full checks to the previous slot (https://github.com/ethereum/consensus-specs/pull/5309)
Apply proposer boost if dependent roots match (https://github.com/ethereum/consensus-specs/pull/5306)
Exclude slashed validators from proposing (EIP-8045) (https://github.com/ethereum/consensus-specs/pull/5115)
Force the proposer to reorg late payloads (https://github.com/ethereum/consensus-specs/pull/5210)
Remove support for old deposit mechanism in Fulu (https://github.com/ethereum/consensus-specs/pull/4704)


  


Co-Authored-By: Eitan Seri-Levi <eserilev@ucsc.edu>

Co-Authored-By: dapplion <35266934+dapplion@users.noreply.github.com>

Co-Authored-By: Eitan Seri-Levi <eserilev@gmail.com>

Co-Authored-By: Michael Sproul <michael@sigmaprime.io>

Co-Authored-By: Michael Sproul <michaelsproul@users.noreply.github.com>
This commit is contained in:
Eitan Seri-Levi
2026-06-15 16:56:09 -07:00
committed by GitHub
parent d8e406b6ac
commit 58e35bc96f
33 changed files with 785 additions and 247 deletions

View File

@@ -546,9 +546,15 @@ impl<E: EthSpec> OperationPool<E> {
}
});
let max_attester_slashings = if state.fork_name_unchecked().electra_enabled() {
E::max_attester_slashings_electra()
} else {
E::MaxAttesterSlashings::to_usize()
};
maximum_cover(
relevant_attester_slashings,
E::MaxAttesterSlashings::to_usize(),
max_attester_slashings,
"attester_slashings",
)
.into_iter()
@@ -927,6 +933,29 @@ mod release_tests {
harness
}
/// The maximum number of attester slashings allowed in a block for the state's fork.
fn max_attester_slashings<E: EthSpec>(state: &BeaconState<E>) -> usize {
if state.fork_name_unchecked().electra_enabled() {
E::max_attester_slashings_electra()
} else {
E::MaxAttesterSlashings::to_usize()
}
}
/// Given the candidate slashings ordered most-profitable first, return the prefix that a
/// block on the state's fork would actually include (i.e. the N most profitable, where N
/// is the per-block attester slashing limit). This keeps the max-cover assertions generic
/// across forks.
fn most_profitable_slashings<E: EthSpec, T>(
state: &BeaconState<E>,
ordered_by_profitability: Vec<T>,
) -> Vec<T> {
ordered_by_profitability
.into_iter()
.take(max_attester_slashings(state))
.collect()
}
/// Test state for attestation-related tests.
fn attestation_test_state<E: EthSpec>(
num_committees: usize,
@@ -1594,7 +1623,10 @@ mod release_tests {
op_pool.insert_attester_slashing(slashing_4.clone().validate(&state, spec).unwrap());
let best_slashings = op_pool.get_slashings_and_exits(&state, &harness.spec);
assert_eq!(best_slashings.1, vec![slashing_4, slashing_3]);
assert_eq!(
best_slashings.1,
most_profitable_slashings(&state, vec![slashing_4, slashing_3])
);
}
// Check that we get maximum coverage for attester slashings with overlapping indices
@@ -1616,7 +1648,10 @@ mod release_tests {
op_pool.insert_attester_slashing(slashing_4.clone().validate(&state, spec).unwrap());
let best_slashings = op_pool.get_slashings_and_exits(&state, &harness.spec);
assert_eq!(best_slashings.1, vec![slashing_1, slashing_3]);
assert_eq!(
best_slashings.1,
most_profitable_slashings(&state, vec![slashing_1, slashing_3])
);
}
// Max coverage of attester slashings taking into account proposer slashings
@@ -1638,7 +1673,10 @@ mod release_tests {
op_pool.insert_attester_slashing(a_slashing_3.clone().validate(&state, spec).unwrap());
let best_slashings = op_pool.get_slashings_and_exits(&state, &harness.spec);
assert_eq!(best_slashings.1, vec![a_slashing_1, a_slashing_3]);
assert_eq!(
best_slashings.1,
most_profitable_slashings(&state, vec![a_slashing_1, a_slashing_3])
);
}
//Max coverage checking that non overlapping indices are still recognized for their value
@@ -1661,7 +1699,10 @@ mod release_tests {
op_pool.insert_attester_slashing(slashing_3.clone().validate(&state, spec).unwrap());
let best_slashings = op_pool.get_slashings_and_exits(&state, &harness.spec);
assert_eq!(best_slashings.1, vec![slashing_1, slashing_3]);
assert_eq!(
best_slashings.1,
most_profitable_slashings(&state, vec![slashing_1, slashing_3])
);
}
// Max coverage should be affected by the overall effective balances
@@ -1684,7 +1725,10 @@ mod release_tests {
op_pool.insert_attester_slashing(slashing_3.clone().validate(&state, spec).unwrap());
let best_slashings = op_pool.get_slashings_and_exits(&state, &harness.spec);
assert_eq!(best_slashings.1, vec![slashing_2, slashing_3]);
assert_eq!(
best_slashings.1,
most_profitable_slashings(&state, vec![slashing_2, slashing_3])
);
}
/// End-to-end test of basic sync contribution handling.
@@ -2177,6 +2221,53 @@ mod release_tests {
assert_eq!(op_pool.attester_slashings.read().len(), 1);
}
/// Regression test to ensure that we are using the correct spec value for max attester slashings post-Electra.
#[tokio::test]
async fn attester_slashings_capped_at_electra_limit() {
let (harness, spec) = cross_fork_harness::<MainnetEthSpec>();
let slots_per_epoch = MainnetEthSpec::slots_per_epoch();
let electra_fork_epoch = spec.electra_fork_epoch.unwrap();
let deneb_fork_epoch = spec.deneb_fork_epoch.unwrap();
let op_pool = OperationPool::<MainnetEthSpec>::new();
harness
.extend_to_slot(electra_fork_epoch.start_slot(slots_per_epoch))
.await;
let electra_head = harness.chain.canonical_head.cached_head().snapshot;
assert!(
electra_head
.beacon_state
.fork_name_unchecked()
.electra_enabled()
);
// Create two slashings
for validators in [vec![0], vec![1]] {
let slashing = harness.make_attester_slashing_with_epochs(
validators,
Some(Epoch::new(0)),
Some(deneb_fork_epoch - 1),
Some(Epoch::new(0)),
Some(deneb_fork_epoch - 1),
);
let verified = slashing
.validate(&electra_head.beacon_state, &harness.chain.spec)
.unwrap();
op_pool.insert_attester_slashing(verified);
}
assert_eq!(op_pool.attester_slashings.read().len(), 2);
// Despite two valid slashings being pending, only one may be extracted post-Electra.
let mut to_be_slashed = HashSet::new();
let attester_slashings =
op_pool.get_attester_slashings(&electra_head.beacon_state, &mut to_be_slashed);
assert_eq!(
attester_slashings.len(),
MainnetEthSpec::max_attester_slashings_electra()
);
}
fn make_payload_attestation_message(
slot: Slot,
validator_index: u64,