diff --git a/eth2/fork_choice_2/Cargo.toml b/eth2/fork_choice_2/Cargo.toml index f71523f0a..61b3f7dcf 100644 --- a/eth2/fork_choice_2/Cargo.toml +++ b/eth2/fork_choice_2/Cargo.toml @@ -13,6 +13,7 @@ bit-vec = "0.5.0" [dev-dependencies] criterion = "0.2" +parking_lot = "0.7" hex = "0.3.2" yaml-rust = "0.4.2" bls = { path = "../utils/bls" } diff --git a/eth2/fork_choice_2/src/lib.rs b/eth2/fork_choice_2/src/lib.rs index 0731f301b..1c2451666 100644 --- a/eth2/fork_choice_2/src/lib.rs +++ b/eth2/fork_choice_2/src/lib.rs @@ -1,9 +1,7 @@ pub mod reduced_tree; use std::sync::Arc; -use store::Error as DBError; -use store::Store; -use types::{BeaconBlock, ChainSpec, Hash256, Slot}; +use types::{Hash256, Slot}; type Result = std::result::Result; @@ -12,17 +10,17 @@ pub enum Error { BackendError(String), } -pub trait LmdGhostBackend { +pub trait LmdGhostBackend: Send + Sync { fn new(store: Arc) -> Self; fn process_message( - &mut self, + &self, validator_index: usize, block_hash: Hash256, block_slot: Slot, ) -> Result<()>; - fn find_head(&mut self) -> Result; + fn find_head(&self) -> Result; } pub struct ForkChoice { @@ -30,7 +28,7 @@ pub struct ForkChoice { } impl> ForkChoice { - fn new(store: Arc) -> Self { + pub fn new(store: Arc) -> Self { Self { algorithm: T::new(store), } diff --git a/eth2/fork_choice_2/src/reduced_tree.rs b/eth2/fork_choice_2/src/reduced_tree.rs index a7316c997..ca32c17f6 100644 --- a/eth2/fork_choice_2/src/reduced_tree.rs +++ b/eth2/fork_choice_2/src/reduced_tree.rs @@ -1,4 +1,5 @@ use super::{Error as SuperError, LmdGhostBackend}; +use parking_lot::RwLock; use std::collections::HashMap; use std::marker::PhantomData; use std::sync::Arc; @@ -68,34 +69,30 @@ pub struct Vote { slot: Slot, } -pub struct ReducedTree { - store: Arc, - nodes: HashMap, - /// Maps validator indices to their latest votes. - latest_votes: ElasticList>, - _phantom: PhantomData, -} - -impl LmdGhostBackend for ReducedTree +impl LmdGhostBackend for ThreadSafeReducedTree where T: Store, E: EthSpec, { fn new(store: Arc) -> Self { - Self::new(store) + ThreadSafeReducedTree { + core: RwLock::new(ReducedTree::new(store)), + } } fn process_message( - &mut self, + &self, validator_index: usize, block_hash: Hash256, block_slot: Slot, ) -> std::result::Result<(), SuperError> { - self.process_message(validator_index, block_hash, block_slot) + self.core + .write() + .process_message(validator_index, block_hash, block_slot) .map_err(Into::into) } - fn find_head(&mut self) -> std::result::Result { + fn find_head(&self) -> std::result::Result { unimplemented!(); } } @@ -106,6 +103,19 @@ impl From for SuperError { } } +pub struct ThreadSafeReducedTree { + pub core: RwLock>, +} + +pub struct ReducedTree { + store: Arc, + /// Stores all nodes of the tree, keyed by the block hash contained in the node. + nodes: HashMap, + /// Maps validator indices to their latest votes. + latest_votes: ElasticList>, + _phantom: PhantomData, +} + impl ReducedTree where T: Store, @@ -144,12 +154,12 @@ where } } - // TODO: add new vote. + self.add_latest_message(validator_index, block_hash)?; Ok(()) } - pub fn remove_latest_message(&mut self, validator_index: usize) -> Result<()> { + fn remove_latest_message(&mut self, validator_index: usize) -> Result<()> { if self.latest_votes.get(validator_index).is_some() { // Unwrap is safe as prior `if` statements ensures the result is `Some`. let vote = self.latest_votes.get(validator_index).unwrap(); @@ -234,7 +244,7 @@ where Ok(()) } - pub fn add_latest_message(&mut self, validator_index: usize, hash: Hash256) -> Result<()> { + fn add_latest_message(&mut self, validator_index: usize, hash: Hash256) -> Result<()> { if let Ok(node) = self.get_mut_node(hash) { node.add_voter(validator_index); } else { @@ -244,7 +254,7 @@ where Ok(()) } - pub fn add_node(&mut self, hash: Hash256, voters: Vec) -> Result<()> { + fn add_node(&mut self, hash: Hash256, voters: Vec) -> Result<()> { // Find the highest (by slot) ancestor of the given hash/block that is in the reduced tree. let mut prev_in_tree = { let hash = self