Add new fork choice struct to beacon chain

This commit is contained in:
Paul Hauner 2019-06-15 14:03:29 -04:00
parent c43bbfe183
commit 2ee71aa808
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
7 changed files with 127 additions and 129 deletions

View File

@ -11,7 +11,6 @@ store = { path = "../store" }
failure = "0.1"
failure_derive = "0.1"
hashing = { path = "../../eth2/utils/hashing" }
fork_choice = { path = "../../eth2/fork_choice" }
parking_lot = "0.7"
prometheus = "^0.6"
log = "0.4"
@ -26,3 +25,4 @@ ssz_derive = { path = "../../eth2/utils/ssz_derive" }
state_processing = { path = "../../eth2/state_processing" }
tree_hash = { path = "../../eth2/utils/tree_hash" }
types = { path = "../../eth2/types" }
lmd_ghost = { path = "../../eth2/lmd_ghost" }

View File

@ -1,9 +1,10 @@
use crate::checkpoint::CheckPoint;
use crate::errors::{BeaconChainError as Error, BlockProductionError};
use crate::fork_choice::{Error as ForkChoiceError, ForkChoice};
use crate::iter::{BlockIterator, BlockRootsIterator};
use crate::metrics::Metrics;
use crate::persisted_beacon_chain::{PersistedBeaconChain, BEACON_CHAIN_DB_KEY};
use fork_choice::{ForkChoice, ForkChoiceError};
use lmd_ghost::LmdGhost;
use log::{debug, trace};
use operation_pool::DepositInsertStatus;
use operation_pool::OperationPool;
@ -48,7 +49,7 @@ pub enum BlockProcessingOutcome {
pub trait BeaconChainTypes {
type Store: store::Store;
type SlotClock: slot_clock::SlotClock;
type ForkChoice: fork_choice::ForkChoice<Self::Store>;
type LmdGhost: LmdGhost<Self::Store, Self::EthSpec>;
type EthSpec: types::EthSpec;
}
@ -73,7 +74,7 @@ pub struct BeaconChain<T: BeaconChainTypes> {
genesis_block_root: Hash256,
/// A state-machine that is updated with information from the network and chooses a canonical
/// head block.
pub fork_choice: RwLock<T::ForkChoice>,
pub fork_choice: ForkChoice<T::LmdGhost, T::Store, T::EthSpec>,
/// Stores metrics about this `BeaconChain`.
pub metrics: Metrics,
}
@ -86,7 +87,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
mut genesis_state: BeaconState<T::EthSpec>,
genesis_block: BeaconBlock,
spec: ChainSpec,
fork_choice: T::ForkChoice,
fork_choice: ForkChoice<T::LmdGhost, T::Store, T::EthSpec>,
) -> Result<Self, Error> {
let state_root = genesis_state.canonical_root();
store.put(&state_root, &genesis_state)?;
@ -115,7 +116,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
state: RwLock::new(genesis_state),
canonical_head,
genesis_block_root,
fork_choice: RwLock::new(fork_choice),
fork_choice,
metrics: Metrics::new()?,
})
}
@ -138,18 +139,19 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
spec.seconds_per_slot,
);
let fork_choice = T::ForkChoice::new(store.clone());
// let fork_choice = T::ForkChoice::new(store.clone());
// let fork_choice: ForkChoice<T::LmdGhost, T::EthSpec> = ForkChoice::new(store.clone());
Ok(Some(BeaconChain {
spec,
store,
slot_clock,
op_pool: OperationPool::default(),
canonical_head: RwLock::new(p.canonical_head),
state: RwLock::new(p.state),
fork_choice: RwLock::new(fork_choice),
fork_choice: ForkChoice::new(store.clone()),
genesis_block_root: p.genesis_block_root,
metrics: Metrics::new()?,
store,
}))
}
@ -613,9 +615,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
self.store.put(&state_root, &state)?;
// Register the new block with the fork choice service.
self.fork_choice
.write()
.add_block(&block, &block_root, &self.spec)?;
self.fork_choice.process_block(&state, &block)?;
// Execute the fork choice algorithm, enthroning a new head if discovered.
//
@ -713,20 +713,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// Start fork choice metrics timer.
let timer = self.metrics.fork_choice_times.start_timer();
let justified_root = {
let root = self.head().beacon_state.current_justified_root;
if root == self.spec.zero_hash {
self.genesis_block_root
} else {
root
}
};
// Determine the root of the block that is the head of the chain.
let beacon_block_root = self
.fork_choice
.write()
.find_head(&justified_root, &self.spec)?;
let beacon_block_root = self.fork_choice.find_head()?;
// End fork choice metrics timer.
timer.observe_duration();

View File

@ -1,5 +1,5 @@
use crate::fork_choice::Error as ForkChoiceError;
use crate::metrics::Error as MetricsError;
use fork_choice::ForkChoiceError;
use state_processing::BlockProcessingError;
use state_processing::SlotProcessingError;
use types::*;

View File

@ -0,0 +1,98 @@
use crate::BeaconChain;
use lmd_ghost::LmdGhost;
use state_processing::common::get_attesting_indices_unsorted;
use std::marker::PhantomData;
use std::sync::Arc;
use store::Store;
use types::{Attestation, BeaconBlock, BeaconState, BeaconStateError, EthSpec, Hash256};
type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, PartialEq)]
pub enum Error {
BackendError(String),
BeaconStateError(BeaconStateError),
}
pub struct ForkChoice<L, S, E> {
backend: L,
_phantom_a: PhantomData<S>,
_phantom_b: PhantomData<E>,
}
impl<L, S, E> ForkChoice<L, S, E>
where
L: LmdGhost<S, E>,
S: Store,
E: EthSpec,
{
pub fn new(store: Arc<S>) -> Self {
Self {
backend: L::new(store),
_phantom_a: PhantomData,
_phantom_b: PhantomData,
}
}
pub fn find_head(&self) -> Result<Hash256> {
self.backend.find_head().map_err(Into::into)
}
pub fn process_attestation(
&self,
state: &BeaconState<E>,
attestation: &Attestation,
) -> Result<()> {
// Note: `get_attesting_indices_unsorted` requires that the beacon state caches be built.
let validator_indices = get_attesting_indices_unsorted(
state,
&attestation.data,
&attestation.aggregation_bitfield,
)?;
let block_hash = attestation.data.target_root;
// TODO: what happens when the target root is not the same slot as the block?
let block_slot = attestation
.data
.target_epoch
.start_slot(E::slots_per_epoch());
for validator_index in validator_indices {
self.backend
.process_message(validator_index, block_hash, block_slot)?;
}
Ok(())
}
/// A helper function which runs `self.process_attestation` on all `Attestation` in the given `BeaconBlock`.
///
/// Assumes the block (and therefore it's attestations) are valid. It is a logic error to
/// provide an invalid block.
pub fn process_block(&self, state: &BeaconState<E>, block: &BeaconBlock) -> Result<()> {
// Note: we never count the block as a latest message, only attestations.
//
// I (Paul H) do not have an explicit reference to this, however I derive it from this
// document:
//
// https://github.com/ethereum/eth2.0-specs/blob/v0.7.0/specs/core/0_fork-choice.md
for attestation in &block.body.attestations {
self.process_attestation(state, attestation)?;
}
Ok(())
}
}
impl From<BeaconStateError> for Error {
fn from(e: BeaconStateError) -> Error {
Error::BeaconStateError(e)
}
}
impl From<String> for Error {
fn from(e: String) -> Error {
Error::BackendError(e)
}
}

View File

@ -1,6 +1,7 @@
mod beacon_chain;
mod checkpoint;
mod errors;
mod fork_choice;
pub mod iter;
mod metrics;
mod persisted_beacon_chain;
@ -8,7 +9,6 @@ mod persisted_beacon_chain;
pub use self::beacon_chain::{BeaconChain, BeaconChainTypes, BlockProcessingOutcome};
pub use self::checkpoint::CheckPoint;
pub use self::errors::{BeaconChainError, BlockProductionError};
pub use fork_choice;
pub use parking_lot;
pub use slot_clock;
pub use state_processing::per_block_processing::errors::{

View File

@ -1,20 +1,15 @@
pub mod reduced_tree;
mod reduced_tree;
use state_processing::common::get_attesting_indices_unsorted;
use std::marker::PhantomData;
use std::sync::Arc;
use types::{Attestation, BeaconBlock, BeaconState, BeaconStateError, EthSpec, Hash256, Slot};
use store::Store;
use types::{EthSpec, Hash256, Slot};
type Result<T> = std::result::Result<T, Error>;
pub use reduced_tree::ThreadSafeReducedTree;
#[derive(Debug, PartialEq)]
pub enum Error {
BackendError(String),
BeaconStateError(BeaconStateError),
}
pub type Result<T> = std::result::Result<T, String>;
pub trait LmdGhostBackend<T, E: EthSpec>: Send + Sync {
fn new(store: Arc<T>) -> Self;
pub trait LmdGhost<S: Store, E: EthSpec>: Send + Sync {
fn new(store: Arc<S>) -> Self;
fn process_message(
&self,
@ -25,75 +20,3 @@ pub trait LmdGhostBackend<T, E: EthSpec>: Send + Sync {
fn find_head(&self) -> Result<Hash256>;
}
pub struct ForkChoice<T, E> {
backend: T,
_phantom: PhantomData<E>,
}
impl<T, E> ForkChoice<T, E>
where
T: LmdGhostBackend<T, E>,
E: EthSpec,
{
pub fn new(store: Arc<T>) -> Self {
Self {
backend: T::new(store),
_phantom: PhantomData,
}
}
pub fn find_head(&self) -> Result<Hash256> {
self.backend.find_head()
}
pub fn process_attestation(
&self,
state: &BeaconState<E>,
attestation: &Attestation,
) -> Result<()> {
let validator_indices = get_attesting_indices_unsorted(
state,
&attestation.data,
&attestation.aggregation_bitfield,
)?;
let block_hash = attestation.data.target_root;
// TODO: what happens when the target root is not the same slot as the block?
let block_slot = attestation
.data
.target_epoch
.start_slot(E::slots_per_epoch());
for validator_index in validator_indices {
self.backend
.process_message(validator_index, block_hash, block_slot)?;
}
Ok(())
}
pub fn process_block(
&self,
state: &BeaconState<E>,
block: &BeaconBlock,
block_hash: Hash256,
block_proposer: usize,
) -> Result<()> {
self.backend
.process_message(block_proposer, block_hash, block.slot)?;
for attestation in &block.body.attestations {
self.process_attestation(state, attestation)?;
}
Ok(())
}
}
impl From<BeaconStateError> for Error {
fn from(e: BeaconStateError) -> Error {
Error::BeaconStateError(e)
}
}

View File

@ -1,4 +1,4 @@
use super::{Error as SuperError, LmdGhostBackend};
use super::{LmdGhost, Result as SuperResult};
use parking_lot::RwLock;
use std::collections::HashMap;
use std::marker::PhantomData;
@ -8,8 +8,6 @@ use types::{BeaconBlock, BeaconState, EthSpec, Hash256, Slot};
type Result<T> = std::result::Result<T, Error>;
pub const SKIP_LIST_LEN: usize = 16;
#[derive(Debug, PartialEq)]
pub enum Error {
MissingNode(Hash256),
@ -51,10 +49,6 @@ impl Node {
pub fn has_votes(&self) -> bool {
!self.voters.is_empty()
}
pub fn is_genesis(&self) -> bool {
self.parent_hash.is_some()
}
}
impl Node {
@ -69,7 +63,7 @@ pub struct Vote {
slot: Slot,
}
impl<T, E> LmdGhostBackend<T, E> for ThreadSafeReducedTree<T, E>
impl<T, E> LmdGhost<T, E> for ThreadSafeReducedTree<T, E>
where
T: Store,
E: EthSpec,
@ -85,21 +79,21 @@ where
validator_index: usize,
block_hash: Hash256,
block_slot: Slot,
) -> std::result::Result<(), SuperError> {
) -> SuperResult<()> {
self.core
.write()
.process_message(validator_index, block_hash, block_slot)
.map_err(Into::into)
}
fn find_head(&self) -> std::result::Result<Hash256, SuperError> {
fn find_head(&self) -> SuperResult<Hash256> {
unimplemented!();
}
}
impl From<Error> for SuperError {
fn from(e: Error) -> SuperError {
SuperError::BackendError(format!("{:?}", e))
impl From<Error> for String {
fn from(e: Error) -> String {
format!("{:?}", e)
}
}
@ -415,11 +409,6 @@ where
&self.0[i]
}
pub fn get_mut(&mut self, i: usize) -> &mut T {
self.ensure(i);
&mut self.0[i]
}
pub fn insert(&mut self, i: usize, element: T) {
self.ensure(i);
self.0[i] = element;