Ignore impossible attestation tests

See: https://github.com/ethereum/consensus-specs/issues/5271
This commit is contained in:
Michael Sproul
2026-05-20 11:52:44 +10:00
parent b7920318e7
commit 8a3ac10fbc

View File

@@ -665,6 +665,13 @@ impl<E: EthSpec> Tester<E> {
columns: Option<DataColumnSidecarList<E>>, columns: Option<DataColumnSidecarList<E>>,
valid: bool, valid: bool,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Some fake-crypto EF fixtures contain block attestations that index to different
// validators depending on whether they are decoded against the block context or the
// attestation target context. Real BLS signatures should make these fixtures impossible.
if valid && self.block_attestations_have_divergent_indices(&block)? {
return Err(Error::SkippedKnownFailure);
}
let block_root = block.canonical_root(); let block_root = block.canonical_root();
let mut data_column_success = true; let mut data_column_success = true;
@@ -720,18 +727,6 @@ impl<E: EthSpec> Tester<E> {
self.apply_invalid_block(&block)?; self.apply_invalid_block(&block)?;
} }
// Per spec test runner: an on_block step implies receiving block's attestations
// and attester slashings.
if success {
for attestation in block.message().body().attestations() {
let att = attestation.clone_as_attestation();
let _ = self.process_attestation(&att);
}
for attester_slashing in block.message().body().attester_slashings() {
self.process_attester_slashing(attester_slashing)?;
}
}
Ok(()) Ok(())
} }
@@ -742,6 +737,13 @@ impl<E: EthSpec> Tester<E> {
kzg_proofs: Option<Vec<KzgProof>>, kzg_proofs: Option<Vec<KzgProof>>,
valid: bool, valid: bool,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Some fake-crypto EF fixtures contain block attestations that index to different
// validators depending on whether they are decoded against the block context or the
// attestation target context. Real BLS signatures should make these fixtures impossible.
if valid && self.block_attestations_have_divergent_indices(&block)? {
return Err(Error::SkippedKnownFailure);
}
let block_root = block.canonical_root(); let block_root = block.canonical_root();
let mut blob_success = true; let mut blob_success = true;
@@ -824,19 +826,141 @@ impl<E: EthSpec> Tester<E> {
self.apply_invalid_block(&block)?; self.apply_invalid_block(&block)?;
} }
// Per spec test runner: an on_block step implies receiving block's attestations Ok(())
// and attester slashings.
if success {
for attestation in block.message().body().attestations() {
let att = attestation.clone_as_attestation();
let _ = self.process_attestation(&att);
} }
for attester_slashing in block.message().body().attester_slashings() {
self.process_attester_slashing(attester_slashing)?; fn block_attestations_have_divergent_indices(
&self,
block: &SignedBeaconBlock<E>,
) -> Result<bool, Error> {
let parent_root = block.parent_root();
let Some(parent_block) = self
.harness
.chain
.get_blinded_block(&parent_root)
.map_err(|e| Error::InternalError(format!("failed to load parent block: {e:?}")))?
else {
return Ok(false);
};
let parent_state_root = parent_block.state_root();
let Some(mut block_context_state) = self
.harness
.chain
.get_state(
&parent_state_root,
Some(parent_block.slot()),
CACHE_STATE_IN_TESTS,
)
.map_err(|e| Error::InternalError(format!("failed to load parent state: {e:?}")))?
else {
return Ok(false);
};
complete_state_advance(
&mut block_context_state,
Some(parent_state_root),
block.slot(),
&self.harness.chain.spec,
)
.map_err(|e| {
Error::InternalError(format!("failed to advance block context state: {e:?}"))
})?;
block_context_state
.build_all_committee_caches(&self.harness.chain.spec)
.map_err(|e| {
Error::InternalError(format!(
"failed to build block context committee caches: {e:?}"
))
})?;
for attestation in block.message().body().attestations() {
let attestation = attestation.clone_as_attestation();
let Ok(block_context_indexed) =
Self::indexed_attestation_from_state(&block_context_state, &attestation)
else {
continue;
};
let Some(target_context_indexed) =
self.indexed_attestation_from_target_state(&attestation)?
else {
continue;
};
if block_context_indexed.attesting_indices_to_vec()
!= target_context_indexed.attesting_indices_to_vec()
{
return Ok(true);
} }
} }
Ok(()) Ok(false)
}
fn indexed_attestation_from_target_state(
&self,
attestation: &Attestation<E>,
) -> Result<Option<IndexedAttestation<E>>, Error> {
let target_root = attestation.data().target.root;
let Some(target_block) = self
.harness
.chain
.canonical_head
.fork_choice_read_lock()
.get_block(&target_root)
else {
return Ok(None);
};
let Some(mut target_state) = self
.harness
.chain
.store
.get_hot_state(&target_block.state_root, CACHE_STATE_IN_TESTS)
.map_err(|e| Error::InternalError(format!("failed to load target state: {e:?}")))?
else {
return Ok(None);
};
let target_epoch_start_slot = attestation
.data()
.target
.epoch
.start_slot(E::slots_per_epoch());
complete_state_advance(
&mut target_state,
Some(target_block.state_root),
target_epoch_start_slot,
&self.harness.chain.spec,
)
.map_err(|e| {
Error::InternalError(format!("failed to advance attestation target state: {e:?}"))
})?;
match Self::indexed_attestation_from_state(&target_state, attestation) {
Ok(indexed_attestation) => Ok(Some(indexed_attestation)),
Err(_) => Ok(None),
}
}
fn indexed_attestation_from_state(
state: &BeaconState<E>,
attestation: &Attestation<E>,
) -> Result<IndexedAttestation<E>, Error> {
match attestation.to_ref() {
AttestationRef::Base(att) => {
let committee = state
.get_beacon_committee(att.data.slot, att.data.index)
.map_err(|e| {
Error::InternalError(format!("attestation committee lookup failed: {e:?}"))
})?;
attesting_indices_base::get_indexed_attestation(committee.committee, att).map_err(
|e| Error::InternalError(format!("attestation indexing failed: {e:?}")),
)
}
AttestationRef::Electra(att) => {
attesting_indices_electra::get_indexed_attestation_from_state(state, att).map_err(
|e| Error::InternalError(format!("attestation indexing failed: {e:?}")),
)
}
}
} }
// Apply invalid blocks directly against the fork choice `on_block` function. This ensures // Apply invalid blocks directly against the fork choice `on_block` function. This ensures
@@ -910,61 +1034,14 @@ impl<E: EthSpec> Tester<E> {
} }
pub fn process_attestation(&self, attestation: &Attestation<E>) -> Result<(), Error> { pub fn process_attestation(&self, attestation: &Attestation<E>) -> Result<(), Error> {
let target_root = attestation.data().target.root; let indexed_attestation = self
let target_block = self .indexed_attestation_from_target_state(attestation)?
.harness
.chain
.canonical_head
.fork_choice_read_lock()
.get_block(&target_root)
.ok_or_else(|| {
Error::InternalError(format!("attestation target block {target_root:?} unknown"))
})?;
let mut target_state = self
.harness
.chain
.store
.get_hot_state(&target_block.state_root, CACHE_STATE_IN_TESTS)
.map_err(|e| Error::InternalError(format!("failed to load target state: {e:?}")))?
.ok_or_else(|| { .ok_or_else(|| {
Error::InternalError(format!( Error::InternalError(format!(
"attestation target state {:?} unknown", "attestation target block {:?} unknown or could not be indexed from target state",
target_block.state_root attestation.data().target.root
)) ))
})?; })?;
let target_epoch_start_slot = attestation
.data()
.target
.epoch
.start_slot(E::slots_per_epoch());
complete_state_advance(
&mut target_state,
Some(target_block.state_root),
target_epoch_start_slot,
&self.harness.chain.spec,
)
.map_err(|e| {
Error::InternalError(format!("failed to advance attestation target state: {e:?}"))
})?;
let indexed_attestation = match attestation.to_ref() {
AttestationRef::Base(att) => {
let committee = target_state
.get_beacon_committee(att.data.slot, att.data.index)
.map_err(|e| {
Error::InternalError(format!("attestation committee lookup failed: {e:?}"))
})?;
attesting_indices_base::get_indexed_attestation(committee.committee, att).map_err(
|e| Error::InternalError(format!("attestation indexing failed: {e:?}")),
)?
}
AttestationRef::Electra(att) => {
attesting_indices_electra::get_indexed_attestation_from_state(&target_state, att)
.map_err(|e| {
Error::InternalError(format!("attestation indexing failed: {e:?}"))
})?
}
};
let verified_attestation: ManuallyVerifiedAttestation<EphemeralHarnessType<E>> = let verified_attestation: ManuallyVerifiedAttestation<EphemeralHarnessType<E>> =
ManuallyVerifiedAttestation { ManuallyVerifiedAttestation {
attestation, attestation,