diff --git a/beacon_node/Cargo.toml b/beacon_node/Cargo.toml index e5893195e..4a930cfd2 100644 --- a/beacon_node/Cargo.toml +++ b/beacon_node/Cargo.toml @@ -14,6 +14,7 @@ clap = "2.32.0" db = { path = "db" } dirs = "1.0.3" futures = "0.1.23" +fork_choice = { path = "../eth2/fork_choice" } genesis = { path = "../eth2/genesis" } slog = "^2.2.3" slot_clock = { path = "../eth2/utils/slot_clock" } diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 3a44fbda5..f97b42b78 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -54,9 +54,9 @@ pub enum InvalidBlock { #[derive(Debug, PartialEq)] pub enum BlockProcessingOutcome { - /// The block was sucessfully validated. + /// The block was successfully validated. ValidBlock(ValidBlock), - /// The block was not sucessfully validated. + /// The block was not successfully validated. InvalidBlock(InvalidBlock), } @@ -70,7 +70,7 @@ pub struct BeaconChain { justified_head: RwLock, pub state: RwLock, pub spec: ChainSpec, - pub fork_choice: F, + pub fork_choice: RwLock, } impl BeaconChain @@ -129,7 +129,7 @@ where finalized_head, canonical_head, spec, - fork_choice, + fork_choice: RwLock::new(fork_choice), }) } @@ -331,7 +331,7 @@ where /// - Create a new `Attestation`. /// - Aggregate it to an existing `Attestation`. pub fn process_free_attestation( - &mut self, + &self, free_attestation: FreeAttestation, ) -> Result { let aggregation_outcome = self @@ -347,7 +347,7 @@ where } // valid attestation, proceed with fork-choice logic - self.fork_choice.add_attestation( + self.fork_choice.write().add_attestation( free_attestation.validator_index, &free_attestation.data.beacon_block_root, )?; @@ -408,7 +408,7 @@ where /// Accept some block and attempt to add it to block DAG. /// /// Will accept blocks from prior slots, however it will reject any block from a future slot. - pub fn process_block(&mut self, block: BeaconBlock) -> Result { + pub fn process_block(&self, block: BeaconBlock) -> Result { debug!("Processing block with slot {}...", block.slot()); let block_root = block.canonical_root(); @@ -479,7 +479,7 @@ where self.state_store.put(&state_root, &ssz_encode(&state)[..])?; // run the fork_choice add_block logic - self.fork_choice.add_block(&block, &block_root)?; + self.fork_choice.write().add_block(&block, &block_root)?; // If the parent block was the parent_block, automatically update the canonical head. // @@ -501,7 +501,7 @@ where /// Produce a new block at the present slot. /// - /// The produced block will not be inheriently valid, it must be signed by a block producer. + /// The produced block will not be inherently valid, it must be signed by a block producer. /// Block signing is out of the scope of this function and should be done by a separate program. pub fn produce_block(&self, randao_reveal: Signature) -> Option<(BeaconBlock, BeaconState)> { debug!("Producing block at slot {}...", self.state.read().slot); @@ -559,10 +559,10 @@ where } // TODO: Left this as is, modify later - pub fn fork_choice(&mut self) -> Result<(), Error> { + pub fn fork_choice(&self) -> Result<(), Error> { let present_head = self.finalized_head().beacon_block_root; - let new_head = self.fork_choice.find_head(&present_head)?; + let new_head = self.fork_choice.write().find_head(&present_head)?; if new_head != present_head { let block = self diff --git a/beacon_node/beacon_chain/test_harness/src/harness.rs b/beacon_node/beacon_chain/test_harness/src/harness.rs index 010ba8f85..533bfe4f6 100644 --- a/beacon_node/beacon_chain/test_harness/src/harness.rs +++ b/beacon_node/beacon_chain/test_harness/src/harness.rs @@ -5,7 +5,7 @@ use db::{ stores::{BeaconBlockStore, BeaconStateStore}, MemoryDB, }; -use fork_choice::*; // import all the algorithms +use fork_choice::{optimised_lmd_ghost::OptimisedLMDGhost, slow_lmd_ghost::SlowLMDGhost}; // import all the algorithms use log::debug; use rayon::prelude::*; use slot_clock::TestingSlotClock; @@ -40,8 +40,8 @@ impl BeaconChainHarness { let db = Arc::new(MemoryDB::open()); let block_store = Arc::new(BeaconBlockStore::new(db.clone())); let state_store = Arc::new(BeaconStateStore::new(db.clone())); - let slot_clock = TestingSlotClock::new(spec.genesis_slot); + let fork_choice = OptimisedLMDGhost::new(block_store.clone(), state_store.clone()); // Remove the validators present in the spec (if any). spec.initial_validators = Vec::with_capacity(validator_count); @@ -83,6 +83,7 @@ impl BeaconChainHarness { block_store.clone(), slot_clock, spec.clone(), + fork_choice, ) .unwrap(), ); @@ -200,7 +201,7 @@ impl BeaconChainHarness { // Produce a new block. let block = self.produce_block(); debug!("Submitting block for processing..."); - self.beacon_chain.process_block(block).unwrap(); + &mut (self.beacon_chain).process_block(block).unwrap(); debug!("...block processed by BeaconChain."); debug!("Producing free attestations..."); diff --git a/beacon_node/beacon_chain/test_harness/src/validator/direct_beacon_node.rs b/beacon_node/beacon_chain/test_harness/src/validator/direct_beacon_node.rs index ed71f28d3..d33f782d6 100644 --- a/beacon_node/beacon_chain/test_harness/src/validator/direct_beacon_node.rs +++ b/beacon_node/beacon_chain/test_harness/src/validator/direct_beacon_node.rs @@ -8,6 +8,7 @@ use block_producer::{ PublishOutcome as BlockPublishOutcome, }; use db::ClientDB; +use fork_choice::ForkChoice; use parking_lot::RwLock; use slot_clock::SlotClock; use std::sync::Arc; @@ -22,14 +23,14 @@ use types::{AttestationData, BeaconBlock, FreeAttestation, PublicKey, Signature} /// `BeaconBlock`s and `FreeAttestation`s are not actually published to the `BeaconChain`, instead /// they are stored inside this struct. This is to allow one to benchmark the submission of the /// block/attestation directly, or modify it before submission. -pub struct DirectBeaconNode { - beacon_chain: Arc>, +pub struct DirectBeaconNode { + beacon_chain: Arc>, published_blocks: RwLock>, published_attestations: RwLock>, } -impl DirectBeaconNode { - pub fn new(beacon_chain: Arc>) -> Self { +impl DirectBeaconNode { + pub fn new(beacon_chain: Arc>) -> Self { Self { beacon_chain, published_blocks: RwLock::new(vec![]), @@ -48,7 +49,7 @@ impl DirectBeaconNode { } } -impl AttesterBeaconNode for DirectBeaconNode { +impl AttesterBeaconNode for DirectBeaconNode { fn produce_attestation_data( &self, _slot: u64, @@ -69,7 +70,7 @@ impl AttesterBeaconNode for DirectBeaconNode { } } -impl BeaconBlockNode for DirectBeaconNode { +impl BeaconBlockNode for DirectBeaconNode { /// Requests the `proposer_nonce` from the `BeaconChain`. fn proposer_nonce(&self, pubkey: &PublicKey) -> Result { let validator_index = self diff --git a/beacon_node/beacon_chain/test_harness/src/validator/direct_duties.rs b/beacon_node/beacon_chain/test_harness/src/validator/direct_duties.rs index e724b3e55..c6d97ee37 100644 --- a/beacon_node/beacon_chain/test_harness/src/validator/direct_duties.rs +++ b/beacon_node/beacon_chain/test_harness/src/validator/direct_duties.rs @@ -6,19 +6,20 @@ use block_producer::{ DutiesReader as ProducerDutiesReader, DutiesReaderError as ProducerDutiesReaderError, }; use db::ClientDB; +use fork_choice::ForkChoice; use slot_clock::SlotClock; use std::sync::Arc; use types::PublicKey; /// Connects directly to a borrowed `BeaconChain` and reads attester/proposer duties directly from /// it. -pub struct DirectDuties { - beacon_chain: Arc>, +pub struct DirectDuties { + beacon_chain: Arc>, pubkey: PublicKey, } -impl DirectDuties { - pub fn new(pubkey: PublicKey, beacon_chain: Arc>) -> Self { +impl DirectDuties { + pub fn new(pubkey: PublicKey, beacon_chain: Arc>) -> Self { Self { beacon_chain, pubkey, @@ -26,7 +27,7 @@ impl DirectDuties { } } -impl ProducerDutiesReader for DirectDuties { +impl ProducerDutiesReader for DirectDuties { fn is_block_production_slot(&self, slot: u64) -> Result { let validator_index = self .beacon_chain @@ -41,7 +42,7 @@ impl ProducerDutiesReader for DirectDuties { } } -impl AttesterDutiesReader for DirectDuties { +impl AttesterDutiesReader for DirectDuties { fn validator_index(&self) -> Option { match self.beacon_chain.validator_index(&self.pubkey) { Some(index) => Some(index as u64), diff --git a/beacon_node/beacon_chain/test_harness/src/validator/validator.rs b/beacon_node/beacon_chain/test_harness/src/validator/validator.rs index d33a0412b..2e9b4e981 100644 --- a/beacon_node/beacon_chain/test_harness/src/validator/validator.rs +++ b/beacon_node/beacon_chain/test_harness/src/validator/validator.rs @@ -7,6 +7,7 @@ use beacon_chain::BeaconChain; use block_producer::PollOutcome as BlockPollOutcome; use block_producer::{BlockProducer, Error as BlockPollError}; use db::MemoryDB; +use fork_choice::{optimised_lmd_ghost::OptimisedLMDGhost, slow_lmd_ghost::SlowLMDGhost}; use slot_clock::TestingSlotClock; use std::sync::Arc; use types::{BeaconBlock, ChainSpec, FreeAttestation, Keypair}; @@ -31,20 +32,20 @@ pub enum AttestationProduceError { pub struct TestValidator { pub block_producer: BlockProducer< TestingSlotClock, - DirectBeaconNode, - DirectDuties, + DirectBeaconNode>, + DirectDuties>, TestSigner, >, pub attester: Attester< TestingSlotClock, - DirectBeaconNode, - DirectDuties, + DirectBeaconNode>, + DirectDuties>, TestSigner, >, pub spec: Arc, - pub epoch_map: Arc>, + pub epoch_map: Arc>>, pub keypair: Keypair, - pub beacon_node: Arc>, + pub beacon_node: Arc>>, pub slot_clock: Arc, pub signer: Arc, } @@ -56,7 +57,7 @@ impl TestValidator { /// A `BlockProducer` and `Attester` is created.. pub fn new( keypair: Keypair, - beacon_chain: Arc>, + beacon_chain: Arc>>, spec: Arc, ) -> Self { let slot_clock = Arc::new(TestingSlotClock::new(spec.genesis_slot)); diff --git a/beacon_node/src/main.rs b/beacon_node/src/main.rs index 25239a9f6..09471860b 100644 --- a/beacon_node/src/main.rs +++ b/beacon_node/src/main.rs @@ -13,6 +13,7 @@ use db::{ stores::{BeaconBlockStore, BeaconStateStore}, MemoryDB, }; +use fork_choice::optimised_lmd_ghost::OptimisedLMDGhost; use slog::{error, info, o, Drain}; use slot_clock::SystemTimeSlotClock; use std::sync::Arc; @@ -78,10 +79,17 @@ fn main() { let slot_clock = SystemTimeSlotClock::new(spec.genesis_time, spec.slot_duration) .expect("Unable to load SystemTimeSlotClock"); + // Choose the fork choice + let fork_choice = OptimisedLMDGhost::new(block_store.clone(), state_store.clone()); // Genesis chain // TODO: persist chain to storage. - let _chain_result = - BeaconChain::genesis(state_store.clone(), block_store.clone(), slot_clock, spec); + let _chain_result = BeaconChain::genesis( + state_store.clone(), + block_store.clone(), + slot_clock, + spec, + fork_choice, + ); let _server = start_server(log.clone()); diff --git a/eth2/fork_choice/src/lib.rs b/eth2/fork_choice/src/lib.rs index bc5ada720..19ddcb04c 100644 --- a/eth2/fork_choice/src/lib.rs +++ b/eth2/fork_choice/src/lib.rs @@ -30,7 +30,7 @@ use types::{BeaconBlock, Hash256}; /// Defines the interface for Fork Choices. Each Fork choice will define their own data structures /// which can be built in block processing through the `add_block` and `add_attestation` functions. /// The main fork choice algorithm is specified in `find_head -pub trait ForkChoice { +pub trait ForkChoice: Send + Sync { /// Called when a block has been added. Allows generic block-level data structures to be /// built for a given fork-choice. fn add_block( diff --git a/eth2/fork_choice/src/optimised_lmd_ghost.rs b/eth2/fork_choice/src/optimised_lmd_ghost.rs index d312b140a..67faaca1c 100644 --- a/eth2/fork_choice/src/optimised_lmd_ghost.rs +++ b/eth2/fork_choice/src/optimised_lmd_ghost.rs @@ -62,15 +62,18 @@ impl OptimisedLMDGhost where T: ClientDB + Sized, { - pub fn new(block_store: BeaconBlockStore, state_store: BeaconStateStore) -> Self { + pub fn new( + block_store: Arc>, + state_store: Arc>, + ) -> Self { OptimisedLMDGhost { cache: HashMap::new(), ancestors: vec![HashMap::new(); 16], latest_attestation_targets: HashMap::new(), children: HashMap::new(), max_known_height: 0, - block_store: Arc::new(block_store), - state_store: Arc::new(state_store), + block_store, + state_store, } }