diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 81e5bdd65a..7af64924e4 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -60,7 +60,15 @@ pub enum BlockProcessingOutcome { #[derive(Debug, PartialEq)] pub enum AttestationProcessingOutcome { Processed, - UnknownHeadBlock { beacon_block_root: Hash256 }, + UnknownHeadBlock { + beacon_block_root: Hash256, + }, + /// The attestation is attesting to a state that is later than itself. (Viz., attesting to the + /// future). + AttestsToFutureState { + state: Slot, + attestation: Slot, + }, Invalid(AttestationValidationError), } @@ -582,11 +590,24 @@ impl BeaconChain { per_slot_processing(&mut state, &self.spec)?; } - self.process_attestation_for_state_and_block( - attestation, - &state, - &attestation_head_block, - ) + let attestation_slot = state.get_attestation_data_slot(&attestation.data)?; + + // Reject any attestation where the `state` loaded from `data.beacon_block_root` + // has a higher slot than the attestation. + // + // Permitting this would allow for attesters to vote on _future_ slots. + if attestation_slot > state.slot { + Ok(AttestationProcessingOutcome::AttestsToFutureState { + state: state.slot, + attestation: attestation_slot, + }) + } else { + self.process_attestation_for_state_and_block( + attestation, + &state, + &attestation_head_block, + ) + } } } else { // Reject any block where we have not processed `attestation.data.beacon_block_root`. diff --git a/eth2/state_processing/src/per_block_processing/errors.rs b/eth2/state_processing/src/per_block_processing/errors.rs index 436ec96cee..65179167c1 100644 --- a/eth2/state_processing/src/per_block_processing/errors.rs +++ b/eth2/state_processing/src/per_block_processing/errors.rs @@ -136,9 +136,6 @@ pub enum AttestationInvalid { delay: u64, attestation: Slot, }, - /// The attestation is attesting to a state that is later than itself. (Viz., attesting to the - /// future). - AttestsToFutureState { state: Slot, attestation: Slot }, /// Attestation slot is too far in the past to be included in a block. IncludedTooLate { state: Slot, attestation: Slot }, /// Attestation target epoch does not match the current or previous epoch. diff --git a/eth2/state_processing/src/per_block_processing/verify_attestation.rs b/eth2/state_processing/src/per_block_processing/verify_attestation.rs index 127d251dea..74dbefa232 100644 --- a/eth2/state_processing/src/per_block_processing/verify_attestation.rs +++ b/eth2/state_processing/src/per_block_processing/verify_attestation.rs @@ -62,17 +62,6 @@ pub fn verify_attestation_for_state( Invalid::BadShard ); - let attestation_slot = state.get_attestation_data_slot(&data)?; - - // An attestation cannot attest to a state that is later than itself. - verify!( - attestation_slot <= state.slot, - Invalid::AttestsToFutureState { - state: state.slot, - attestation: attestation_slot - } - ); - // Verify the Casper FFG vote and crosslink data. let parent_crosslink = verify_casper_ffg_vote(attestation, state)?;