mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 12:47:05 +00:00
Ignore impossible attestation tests
See: https://github.com/ethereum/consensus-specs/issues/5271
This commit is contained in:
@@ -665,6 +665,13 @@ impl<E: EthSpec> Tester<E> {
|
||||
columns: Option<DataColumnSidecarList<E>>,
|
||||
valid: bool,
|
||||
) -> 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 mut data_column_success = true;
|
||||
@@ -720,18 +727,6 @@ impl<E: EthSpec> Tester<E> {
|
||||
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(())
|
||||
}
|
||||
|
||||
@@ -742,6 +737,13 @@ impl<E: EthSpec> Tester<E> {
|
||||
kzg_proofs: Option<Vec<KzgProof>>,
|
||||
valid: bool,
|
||||
) -> 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 mut blob_success = true;
|
||||
@@ -824,19 +826,141 @@ impl<E: EthSpec> Tester<E> {
|
||||
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);
|
||||
Ok(())
|
||||
}
|
||||
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
|
||||
@@ -910,61 +1034,14 @@ impl<E: EthSpec> Tester<E> {
|
||||
}
|
||||
|
||||
pub fn process_attestation(&self, attestation: &Attestation<E>) -> Result<(), Error> {
|
||||
let target_root = attestation.data().target.root;
|
||||
let target_block = self
|
||||
.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:?}")))?
|
||||
let indexed_attestation = self
|
||||
.indexed_attestation_from_target_state(attestation)?
|
||||
.ok_or_else(|| {
|
||||
Error::InternalError(format!(
|
||||
"attestation target state {:?} unknown",
|
||||
target_block.state_root
|
||||
"attestation target block {:?} unknown or could not be indexed from target state",
|
||||
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>> =
|
||||
ManuallyVerifiedAttestation {
|
||||
attestation,
|
||||
|
||||
Reference in New Issue
Block a user