test fixes

This commit is contained in:
hopinheimer
2026-03-02 15:33:53 -05:00
parent 6f6da5b393
commit 275ac11200
3 changed files with 29 additions and 33 deletions

View File

@@ -178,6 +178,11 @@ pub enum InvalidAttestation {
/// A same-slot attestation has a non-zero index, indicating a payload attestation during the
/// same slot as the block. Payload attestations must only arrive in subsequent slots.
PayloadAttestationDuringSameSlot { slot: Slot },
/// A gossip payload attestation must be for the current slot.
PayloadAttestationNotCurrentSlot {
attestation_slot: Slot,
current_slot: Slot,
},
}
impl<T> From<String> for Error<T> {
@@ -1139,7 +1144,7 @@ where
fn validate_on_payload_attestation(
&self,
indexed_payload_attestation: &IndexedPayloadAttestation<E>,
_is_from_block: bool,
is_from_block: bool,
) -> Result<(), InvalidAttestation> {
if indexed_payload_attestation.attesting_indices.is_empty() {
return Err(InvalidAttestation::EmptyAggregationBitfield);
@@ -1159,6 +1164,17 @@ where
});
}
// Gossip payload attestations must be for the current slot.
// https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/fork-choice.md
if !is_from_block
&& indexed_payload_attestation.data.slot != self.fc_store.get_current_slot()
{
return Err(InvalidAttestation::PayloadAttestationNotCurrentSlot {
attestation_slot: indexed_payload_attestation.data.slot,
current_slot: self.fc_store.get_current_slot(),
});
}
if self.fc_store.get_current_slot() == block.slot
&& indexed_payload_attestation.data.payload_present
{

View File

@@ -1047,10 +1047,10 @@ async fn payload_attestation_for_previous_slot_is_accepted_at_next_slot() {
assert!(latest_message.payload_present);
}
/// Non-block payload attestations at slot S+1 for data.slot S are delayed; they are not applied
/// until a later slot.
/// Gossip payload attestations must be for the current slot. A payload attestation for slot S
/// received at slot S+1 should be rejected per the spec.
#[tokio::test]
async fn non_block_payload_attestation_at_next_slot_is_delayed() {
async fn non_block_payload_attestation_for_previous_slot_is_rejected() {
let test = ForkChoiceTest::new()
.apply_blocks_without_new_attestations(1)
.await;
@@ -1062,7 +1062,6 @@ async fn non_block_payload_attestation_at_next_slot_is_delayed() {
.expect("block A should exist");
let block_a_root = block_a.canonical_root();
let s_plus_1 = block_a.slot().saturating_add(1_u64);
let s_plus_2 = block_a.slot().saturating_add(2_u64);
let payload_attestation = IndexedPayloadAttestation::<E> {
attesting_indices: vec![0_u64].try_into().expect("valid attesting indices"),
@@ -1080,34 +1079,15 @@ async fn non_block_payload_attestation_at_next_slot_is_delayed() {
.fork_choice_write_lock()
.on_payload_attestation(s_plus_1, &payload_attestation, false);
assert!(
result.is_ok(),
"payload attestation should be accepted for queueing"
matches!(
result,
Err(ForkChoiceError::InvalidAttestation(
InvalidAttestation::PayloadAttestationNotCurrentSlot { .. }
))
),
"gossip payload attestation for previous slot should be rejected, got: {:?}",
result
);
// Vote should not be applied yet; message remains unset.
let latest_before = chain
.canonical_head
.fork_choice_read_lock()
.latest_message(0);
assert!(
latest_before.is_none(),
"non-block payload attestation at S+1 should not apply immediately"
);
// Advance fork choice time to S+2, queue should now be processed.
chain
.canonical_head
.fork_choice_write_lock()
.update_time(s_plus_2)
.expect("update_time should succeed");
let latest_after = chain
.canonical_head
.fork_choice_read_lock()
.latest_message(0)
.expect("latest message should exist after delay");
assert_eq!(latest_after.slot, s_plus_2);
assert!(latest_after.payload_present);
}
/// Specification v0.12.1:

View File

@@ -659,7 +659,7 @@ impl ProtoArrayForkChoice {
)?;
// Only re-org a single slot. This prevents cascading failures during asynchrony.
let head_slot_ok = info.head_node.slot() + 1 == current_slot;
let head_slot_ok = info.head_node.slot().saturating_add(1_u64) == current_slot;
if !head_slot_ok {
return Err(DoNotReOrg::HeadDistance.into());
}