Remove equivocating validators from fork choice (#3371)

## Issue Addressed

Closes https://github.com/sigp/lighthouse/issues/3241
Closes https://github.com/sigp/lighthouse/issues/3242

## Proposed Changes

* [x] Implement logic to remove equivocating validators from fork choice per https://github.com/ethereum/consensus-specs/pull/2845
* [x] Update tests to v1.2.0-rc.1. The new test which exercises `equivocating_indices` is passing.
* [x] Pull in some SSZ abstractions from the `tree-states` branch that make implementing Vec-compatible encoding for types like `BTreeSet` and `BTreeMap`.
* [x] Implement schema upgrades and downgrades for the database (new schema version is V11).
* [x] Apply attester slashings from blocks to fork choice

## Additional Info

* This PR doesn't need the `BTreeMap` impl, but `tree-states` does, and I don't think there's any harm in keeping it. But I could also be convinced to drop it.

Blocked on #3322.
This commit is contained in:
Michael Sproul
2022-07-28 09:43:41 +00:00
parent efb360cc6d
commit d04fde3ba9
25 changed files with 742 additions and 151 deletions

View File

@@ -1,19 +1,23 @@
use crate::{ForkChoiceStore, InvalidationOperation};
use proto_array::{Block as ProtoBlock, ExecutionStatus, ProtoArrayForkChoice};
use ssz_derive::{Decode, Encode};
use state_processing::per_epoch_processing;
use state_processing::{
per_block_processing::errors::AttesterSlashingValidationError, per_epoch_processing,
};
use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::marker::PhantomData;
use std::time::Duration;
use types::{
consts::merge::INTERVALS_PER_SLOT, AttestationShufflingId, BeaconBlockRef, BeaconState,
BeaconStateError, ChainSpec, Checkpoint, Epoch, EthSpec, ExecPayload, ExecutionBlockHash,
Hash256, IndexedAttestation, RelativeEpoch, SignedBeaconBlock, Slot,
consts::merge::INTERVALS_PER_SLOT, AttestationShufflingId, AttesterSlashing, BeaconBlockRef,
BeaconState, BeaconStateError, ChainSpec, Checkpoint, Epoch, EthSpec, ExecPayload,
ExecutionBlockHash, Hash256, IndexedAttestation, RelativeEpoch, SignedBeaconBlock, Slot,
};
#[derive(Debug)]
pub enum Error<T> {
InvalidAttestation(InvalidAttestation),
InvalidAttesterSlashing(AttesterSlashingValidationError),
InvalidBlock(InvalidBlock),
ProtoArrayError(String),
InvalidProtoArrayBytes(String),
@@ -63,6 +67,12 @@ impl<T> From<InvalidAttestation> for Error<T> {
}
}
impl<T> From<AttesterSlashingValidationError> for Error<T> {
fn from(e: AttesterSlashingValidationError) -> Self {
Error::InvalidAttesterSlashing(e)
}
}
impl<T> From<state_processing::EpochProcessingError> for Error<T> {
fn from(e: state_processing::EpochProcessingError) -> Self {
Error::UnrealizedVoteProcessing(e)
@@ -413,26 +423,6 @@ where
Ok(fork_choice)
}
/*
/// Instantiates `Self` from some existing components.
///
/// This is useful if the existing components have been loaded from disk after a process
/// restart.
pub fn from_components(
fc_store: T,
proto_array: ProtoArrayForkChoice,
queued_attestations: Vec<QueuedAttestation>,
) -> Self {
Self {
fc_store,
proto_array,
queued_attestations,
forkchoice_update_parameters: None,
_phantom: PhantomData,
}
}
*/
/// Returns cached information that can be used to issue a `forkchoiceUpdated` message to an
/// execution engine.
///
@@ -507,6 +497,7 @@ where
*store.finalized_checkpoint(),
store.justified_balances(),
store.proposer_boost_root(),
store.equivocating_indices(),
current_slot,
spec,
)?;
@@ -1109,6 +1100,22 @@ where
Ok(())
}
/// Apply an attester slashing to fork choice.
///
/// We assume that the attester slashing provided to this function has already been verified.
pub fn on_attester_slashing(&mut self, slashing: &AttesterSlashing<E>) {
let attesting_indices_set = |att: &IndexedAttestation<E>| {
att.attesting_indices
.iter()
.copied()
.collect::<BTreeSet<_>>()
};
let att1_indices = attesting_indices_set(&slashing.attestation_1);
let att2_indices = attesting_indices_set(&slashing.attestation_2);
self.fc_store
.extend_equivocating_indices(att1_indices.intersection(&att2_indices).copied());
}
/// Call `on_tick` for all slots between `fc_store.get_current_slot()` and the provided
/// `current_slot`. Returns the value of `self.fc_store.get_current_slot`.
pub fn update_time(
@@ -1325,8 +1332,6 @@ where
// If the parent block has execution enabled, always import the block.
//
// TODO(bellatrix): this condition has not yet been merged into the spec.
//
// See:
//
// https://github.com/ethereum/consensus-specs/pull/2844

View File

@@ -1,3 +1,4 @@
use std::collections::BTreeSet;
use types::{BeaconBlockRef, BeaconState, Checkpoint, EthSpec, ExecPayload, Hash256, Slot};
/// Approximates the `Store` in "Ethereum 2.0 Phase 0 -- Beacon Chain Fork Choice":
@@ -76,4 +77,10 @@ pub trait ForkChoiceStore<T: EthSpec>: Sized {
/// Sets the proposer boost root.
fn set_proposer_boost_root(&mut self, proposer_boost_root: Hash256);
/// Gets the equivocating indices.
fn equivocating_indices(&self) -> &BTreeSet<u64>;
/// Adds to the set of equivocating indices.
fn extend_equivocating_indices(&mut self, indices: impl IntoIterator<Item = u64>);
}