Prevent attestation to future blocks from early attester cache (#3183)

## Issue Addressed

N/A

## Proposed Changes

Prevents the early attester cache from producing attestations to future blocks. This bug could result in a missed head vote if the BN was requested to produce an attestation for an earlier slot than the head block during the (usually) short window of time between verifying a block and setting it as the head.

This bug was noticed in an [Antithesis](https://andreagrieser.com/) test and diagnosed by @realbigsean. 

## Additional Info

NA
This commit is contained in:
Paul Hauner 2022-05-17 01:51:25 +00:00
parent 38050fa460
commit db8a6f81ea
2 changed files with 59 additions and 0 deletions

View File

@ -104,6 +104,10 @@ impl<E: EthSpec> EarlyAttesterCache<E> {
return Ok(None);
}
if request_slot < item.block.slot() {
return Ok(None);
}
let committee_count = item
.committee_lengths
.get_committee_count_per_slot::<E>(spec)?;

View File

@ -148,3 +148,58 @@ fn produces_attestations() {
}
}
}
/// Ensures that the early attester cache wont create an attestation to a block in a later slot than
/// the one requested.
#[test]
fn early_attester_cache_old_request() {
let harness = BeaconChainHarness::builder(MainnetEthSpec)
.default_spec()
.keypairs(KEYPAIRS[..].to_vec())
.fresh_ephemeral_store()
.mock_execution_layer()
.build();
harness.advance_slot();
harness.extend_chain(
2,
BlockStrategy::OnCanonicalHead,
AttestationStrategy::AllValidators,
);
let head = harness.chain.head().unwrap();
assert_eq!(head.beacon_block.slot(), 2);
let head_proto_block = harness
.chain
.fork_choice
.read()
.get_block(&head.beacon_block_root)
.unwrap();
harness
.chain
.early_attester_cache
.add_head_block(
head.beacon_block_root,
head.beacon_block.clone(),
head_proto_block,
&head.beacon_state,
&harness.chain.spec,
)
.unwrap();
let attest_slot = head.beacon_block.slot() - 1;
let attestation = harness
.chain
.produce_unaggregated_attestation(attest_slot, 0)
.unwrap();
assert_eq!(attestation.data.slot, attest_slot);
let attested_block = harness
.chain
.get_blinded_block(&attestation.data.beacon_block_root)
.unwrap()
.unwrap();
assert_eq!(attested_block.slot(), attest_slot);
}