From db8a6f81ea25ceaca1842e030f9dd1331a5ac28b Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 17 May 2022 01:51:25 +0000 Subject: [PATCH] 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 --- .../beacon_chain/src/early_attester_cache.rs | 4 ++ .../tests/attestation_production.rs | 55 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/beacon_node/beacon_chain/src/early_attester_cache.rs b/beacon_node/beacon_chain/src/early_attester_cache.rs index 56dced94e..f589585f8 100644 --- a/beacon_node/beacon_chain/src/early_attester_cache.rs +++ b/beacon_node/beacon_chain/src/early_attester_cache.rs @@ -104,6 +104,10 @@ impl EarlyAttesterCache { return Ok(None); } + if request_slot < item.block.slot() { + return Ok(None); + } + let committee_count = item .committee_lengths .get_committee_count_per_slot::(spec)?; diff --git a/beacon_node/beacon_chain/tests/attestation_production.rs b/beacon_node/beacon_chain/tests/attestation_production.rs index 0ea5debc3..b1d1f71d6 100644 --- a/beacon_node/beacon_chain/tests/attestation_production.rs +++ b/beacon_node/beacon_chain/tests/attestation_production.rs @@ -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); +}