From 7756a658a752e2d8e8b83e646075abf441d3306e Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 15 Jun 2019 15:05:34 -0400 Subject: [PATCH] Update fork choice find head fn --- beacon_node/beacon_chain/src/beacon_chain.rs | 6 +- beacon_node/beacon_chain/src/fork_choice.rs | 83 ++++++++++++++------ eth2/lmd_ghost/src/lib.rs | 4 +- eth2/lmd_ghost/src/reduced_tree.rs | 5 +- 4 files changed, 71 insertions(+), 27 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index b0fe9278c..31b1759e7 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -74,7 +74,7 @@ pub struct BeaconChain { genesis_block_root: Hash256, /// A state-machine that is updated with information from the network and chooses a canonical /// head block. - pub fork_choice: ForkChoice, + pub fork_choice: ForkChoice, /// Stores metrics about this `BeaconChain`. pub metrics: Metrics, } @@ -87,7 +87,7 @@ impl BeaconChain { mut genesis_state: BeaconState, genesis_block: BeaconBlock, spec: ChainSpec, - fork_choice: ForkChoice, + fork_choice: ForkChoice, ) -> Result { let state_root = genesis_state.canonical_root(); store.put(&state_root, &genesis_state)?; @@ -714,7 +714,7 @@ impl BeaconChain { let timer = self.metrics.fork_choice_times.start_timer(); // Determine the root of the block that is the head of the chain. - let beacon_block_root = self.fork_choice.find_head()?; + let beacon_block_root = self.fork_choice.find_head(&self)?; // End fork choice metrics timer. timer.observe_duration(); diff --git a/beacon_node/beacon_chain/src/fork_choice.rs b/beacon_node/beacon_chain/src/fork_choice.rs index b2a45baa2..da20e934f 100644 --- a/beacon_node/beacon_chain/src/fork_choice.rs +++ b/beacon_node/beacon_chain/src/fork_choice.rs @@ -1,46 +1,75 @@ -use crate::BeaconChain; +use crate::{BeaconChain, BeaconChainTypes}; use lmd_ghost::LmdGhost; use state_processing::common::get_attesting_indices_unsorted; -use std::marker::PhantomData; use std::sync::Arc; -use store::Store; +use store::{Error as StoreError, Store}; use types::{Attestation, BeaconBlock, BeaconState, BeaconStateError, EthSpec, Hash256}; type Result = std::result::Result; #[derive(Debug, PartialEq)] pub enum Error { + MissingBlock(Hash256), + MissingState(Hash256), BackendError(String), BeaconStateError(BeaconStateError), + StoreError(StoreError), } -pub struct ForkChoice { - backend: L, - _phantom_a: PhantomData, - _phantom_b: PhantomData, +pub struct ForkChoice { + backend: T::LmdGhost, } -impl ForkChoice -where - L: LmdGhost, - S: Store, - E: EthSpec, -{ - pub fn new(store: Arc) -> Self { +impl ForkChoice { + pub fn new(store: Arc) -> Self { Self { - backend: L::new(store), - _phantom_a: PhantomData, - _phantom_b: PhantomData, + backend: T::LmdGhost::new(store), } } - pub fn find_head(&self) -> Result { - self.backend.find_head().map_err(Into::into) + pub fn find_head(&self, chain: &BeaconChain) -> Result { + // From the specification: + // + // Let justified_head be the descendant of finalized_head with the highest epoch that has + // been justified for at least 1 epoch ... If no such descendant exists, + // set justified_head to finalized_head. + let (start_state, start_block_root) = { + let state = chain.current_state(); + + let block_root = if state.current_epoch() + 1 > state.current_justified_epoch { + state.current_justified_root + } else { + state.finalized_root + }; + let block = chain + .store + .get::(&block_root)? + .ok_or_else(|| Error::MissingBlock(block_root))?; + + let state = chain + .store + .get::>(&block.state_root)? + .ok_or_else(|| Error::MissingState(block.state_root))?; + + (state, block_root) + }; + + // A function that returns the weight for some validator index. + let weight = |validator_index: usize| -> Option { + start_state + .validator_registry + .get(validator_index) + .and_then(|v| Some(v.effective_balance)) + }; + + self.backend + .find_head(start_block_root, weight) + .map_err(Into::into) } pub fn process_attestation( &self, - state: &BeaconState, + state: &BeaconState, attestation: &Attestation, ) -> Result<()> { // Note: `get_attesting_indices_unsorted` requires that the beacon state caches be built. @@ -56,7 +85,7 @@ where let block_slot = attestation .data .target_epoch - .start_slot(E::slots_per_epoch()); + .start_slot(T::EthSpec::slots_per_epoch()); for validator_index in validator_indices { self.backend @@ -70,7 +99,11 @@ where /// /// 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, block: &BeaconBlock) -> Result<()> { + pub fn process_block( + &self, + state: &BeaconState, + 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 @@ -91,6 +124,12 @@ impl From for Error { } } +impl From for Error { + fn from(e: StoreError) -> Error { + Error::StoreError(e) + } +} + impl From for Error { fn from(e: String) -> Error { Error::BackendError(e) diff --git a/eth2/lmd_ghost/src/lib.rs b/eth2/lmd_ghost/src/lib.rs index 5cd1b1892..a50532758 100644 --- a/eth2/lmd_ghost/src/lib.rs +++ b/eth2/lmd_ghost/src/lib.rs @@ -18,5 +18,7 @@ pub trait LmdGhost: Send + Sync { block_slot: Slot, ) -> Result<()>; - fn find_head(&self) -> Result; + fn find_head(&self, start_block_root: Hash256, weight: F) -> Result + where + F: Fn(usize) -> Option; } diff --git a/eth2/lmd_ghost/src/reduced_tree.rs b/eth2/lmd_ghost/src/reduced_tree.rs index 6f2b31c99..44b34b070 100644 --- a/eth2/lmd_ghost/src/reduced_tree.rs +++ b/eth2/lmd_ghost/src/reduced_tree.rs @@ -86,7 +86,10 @@ where .map_err(Into::into) } - fn find_head(&self) -> SuperResult { + fn find_head(&self, _start_block_root: Hash256, _weight: F) -> SuperResult + where + F: Fn(usize) -> Option, + { unimplemented!(); } }