Integrate ForkChoice into beacon_node.

This commit is contained in:
Age Manning 2019-02-13 16:29:37 +11:00
parent c4c1e5647e
commit 4370035448
No known key found for this signature in database
GPG Key ID: 05EED64B79E06A93
9 changed files with 55 additions and 39 deletions

View File

@ -14,6 +14,7 @@ clap = "2.32.0"
db = { path = "db" } db = { path = "db" }
dirs = "1.0.3" dirs = "1.0.3"
futures = "0.1.23" futures = "0.1.23"
fork_choice = { path = "../eth2/fork_choice" }
genesis = { path = "../eth2/genesis" } genesis = { path = "../eth2/genesis" }
slog = "^2.2.3" slog = "^2.2.3"
slot_clock = { path = "../eth2/utils/slot_clock" } slot_clock = { path = "../eth2/utils/slot_clock" }

View File

@ -54,9 +54,9 @@ pub enum InvalidBlock {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum BlockProcessingOutcome { pub enum BlockProcessingOutcome {
/// The block was sucessfully validated. /// The block was successfully validated.
ValidBlock(ValidBlock), ValidBlock(ValidBlock),
/// The block was not sucessfully validated. /// The block was not successfully validated.
InvalidBlock(InvalidBlock), InvalidBlock(InvalidBlock),
} }
@ -70,7 +70,7 @@ pub struct BeaconChain<T: ClientDB + Sized, U: SlotClock, F: ForkChoice> {
justified_head: RwLock<CheckPoint>, justified_head: RwLock<CheckPoint>,
pub state: RwLock<BeaconState>, pub state: RwLock<BeaconState>,
pub spec: ChainSpec, pub spec: ChainSpec,
pub fork_choice: F, pub fork_choice: RwLock<F>,
} }
impl<T, U, F> BeaconChain<T, U, F> impl<T, U, F> BeaconChain<T, U, F>
@ -129,7 +129,7 @@ where
finalized_head, finalized_head,
canonical_head, canonical_head,
spec, spec,
fork_choice, fork_choice: RwLock::new(fork_choice),
}) })
} }
@ -331,7 +331,7 @@ where
/// - Create a new `Attestation`. /// - Create a new `Attestation`.
/// - Aggregate it to an existing `Attestation`. /// - Aggregate it to an existing `Attestation`.
pub fn process_free_attestation( pub fn process_free_attestation(
&mut self, &self,
free_attestation: FreeAttestation, free_attestation: FreeAttestation,
) -> Result<AggregationOutcome, Error> { ) -> Result<AggregationOutcome, Error> {
let aggregation_outcome = self let aggregation_outcome = self
@ -347,7 +347,7 @@ where
} }
// valid attestation, proceed with fork-choice logic // valid attestation, proceed with fork-choice logic
self.fork_choice.add_attestation( self.fork_choice.write().add_attestation(
free_attestation.validator_index, free_attestation.validator_index,
&free_attestation.data.beacon_block_root, &free_attestation.data.beacon_block_root,
)?; )?;
@ -408,7 +408,7 @@ where
/// Accept some block and attempt to add it to block DAG. /// 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. /// 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<BlockProcessingOutcome, Error> { pub fn process_block(&self, block: BeaconBlock) -> Result<BlockProcessingOutcome, Error> {
debug!("Processing block with slot {}...", block.slot()); debug!("Processing block with slot {}...", block.slot());
let block_root = block.canonical_root(); let block_root = block.canonical_root();
@ -479,7 +479,7 @@ where
self.state_store.put(&state_root, &ssz_encode(&state)[..])?; self.state_store.put(&state_root, &ssz_encode(&state)[..])?;
// run the fork_choice add_block logic // 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. // 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. /// 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. /// 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)> { pub fn produce_block(&self, randao_reveal: Signature) -> Option<(BeaconBlock, BeaconState)> {
debug!("Producing block at slot {}...", self.state.read().slot); debug!("Producing block at slot {}...", self.state.read().slot);
@ -559,10 +559,10 @@ where
} }
// TODO: Left this as is, modify later // 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 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 { if new_head != present_head {
let block = self let block = self

View File

@ -5,7 +5,7 @@ use db::{
stores::{BeaconBlockStore, BeaconStateStore}, stores::{BeaconBlockStore, BeaconStateStore},
MemoryDB, 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 log::debug;
use rayon::prelude::*; use rayon::prelude::*;
use slot_clock::TestingSlotClock; use slot_clock::TestingSlotClock;
@ -40,8 +40,8 @@ impl BeaconChainHarness {
let db = Arc::new(MemoryDB::open()); let db = Arc::new(MemoryDB::open());
let block_store = Arc::new(BeaconBlockStore::new(db.clone())); let block_store = Arc::new(BeaconBlockStore::new(db.clone()));
let state_store = Arc::new(BeaconStateStore::new(db.clone())); let state_store = Arc::new(BeaconStateStore::new(db.clone()));
let slot_clock = TestingSlotClock::new(spec.genesis_slot); 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). // Remove the validators present in the spec (if any).
spec.initial_validators = Vec::with_capacity(validator_count); spec.initial_validators = Vec::with_capacity(validator_count);
@ -83,6 +83,7 @@ impl BeaconChainHarness {
block_store.clone(), block_store.clone(),
slot_clock, slot_clock,
spec.clone(), spec.clone(),
fork_choice,
) )
.unwrap(), .unwrap(),
); );
@ -200,7 +201,7 @@ impl BeaconChainHarness {
// Produce a new block. // Produce a new block.
let block = self.produce_block(); let block = self.produce_block();
debug!("Submitting block for processing..."); 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!("...block processed by BeaconChain.");
debug!("Producing free attestations..."); debug!("Producing free attestations...");

View File

@ -8,6 +8,7 @@ use block_producer::{
PublishOutcome as BlockPublishOutcome, PublishOutcome as BlockPublishOutcome,
}; };
use db::ClientDB; use db::ClientDB;
use fork_choice::ForkChoice;
use parking_lot::RwLock; use parking_lot::RwLock;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use std::sync::Arc; 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 /// `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 /// 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. /// block/attestation directly, or modify it before submission.
pub struct DirectBeaconNode<T: ClientDB, U: SlotClock> { pub struct DirectBeaconNode<T: ClientDB, U: SlotClock, F: ForkChoice> {
beacon_chain: Arc<BeaconChain<T, U>>, beacon_chain: Arc<BeaconChain<T, U, F>>,
published_blocks: RwLock<Vec<BeaconBlock>>, published_blocks: RwLock<Vec<BeaconBlock>>,
published_attestations: RwLock<Vec<FreeAttestation>>, published_attestations: RwLock<Vec<FreeAttestation>>,
} }
impl<T: ClientDB, U: SlotClock> DirectBeaconNode<T, U> { impl<T: ClientDB, U: SlotClock, F: ForkChoice> DirectBeaconNode<T, U, F> {
pub fn new(beacon_chain: Arc<BeaconChain<T, U>>) -> Self { pub fn new(beacon_chain: Arc<BeaconChain<T, U, F>>) -> Self {
Self { Self {
beacon_chain, beacon_chain,
published_blocks: RwLock::new(vec![]), published_blocks: RwLock::new(vec![]),
@ -48,7 +49,7 @@ impl<T: ClientDB, U: SlotClock> DirectBeaconNode<T, U> {
} }
} }
impl<T: ClientDB, U: SlotClock> AttesterBeaconNode for DirectBeaconNode<T, U> { impl<T: ClientDB, U: SlotClock, F: ForkChoice> AttesterBeaconNode for DirectBeaconNode<T, U, F> {
fn produce_attestation_data( fn produce_attestation_data(
&self, &self,
_slot: u64, _slot: u64,
@ -69,7 +70,7 @@ impl<T: ClientDB, U: SlotClock> AttesterBeaconNode for DirectBeaconNode<T, U> {
} }
} }
impl<T: ClientDB, U: SlotClock> BeaconBlockNode for DirectBeaconNode<T, U> { impl<T: ClientDB, U: SlotClock, F: ForkChoice> BeaconBlockNode for DirectBeaconNode<T, U, F> {
/// Requests the `proposer_nonce` from the `BeaconChain`. /// Requests the `proposer_nonce` from the `BeaconChain`.
fn proposer_nonce(&self, pubkey: &PublicKey) -> Result<u64, BeaconBlockNodeError> { fn proposer_nonce(&self, pubkey: &PublicKey) -> Result<u64, BeaconBlockNodeError> {
let validator_index = self let validator_index = self

View File

@ -6,19 +6,20 @@ use block_producer::{
DutiesReader as ProducerDutiesReader, DutiesReaderError as ProducerDutiesReaderError, DutiesReader as ProducerDutiesReader, DutiesReaderError as ProducerDutiesReaderError,
}; };
use db::ClientDB; use db::ClientDB;
use fork_choice::ForkChoice;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use std::sync::Arc; use std::sync::Arc;
use types::PublicKey; use types::PublicKey;
/// Connects directly to a borrowed `BeaconChain` and reads attester/proposer duties directly from /// Connects directly to a borrowed `BeaconChain` and reads attester/proposer duties directly from
/// it. /// it.
pub struct DirectDuties<T: ClientDB, U: SlotClock> { pub struct DirectDuties<T: ClientDB, U: SlotClock, F: ForkChoice> {
beacon_chain: Arc<BeaconChain<T, U>>, beacon_chain: Arc<BeaconChain<T, U, F>>,
pubkey: PublicKey, pubkey: PublicKey,
} }
impl<T: ClientDB, U: SlotClock> DirectDuties<T, U> { impl<T: ClientDB, U: SlotClock, F: ForkChoice> DirectDuties<T, U, F> {
pub fn new(pubkey: PublicKey, beacon_chain: Arc<BeaconChain<T, U>>) -> Self { pub fn new(pubkey: PublicKey, beacon_chain: Arc<BeaconChain<T, U, F>>) -> Self {
Self { Self {
beacon_chain, beacon_chain,
pubkey, pubkey,
@ -26,7 +27,7 @@ impl<T: ClientDB, U: SlotClock> DirectDuties<T, U> {
} }
} }
impl<T: ClientDB, U: SlotClock> ProducerDutiesReader for DirectDuties<T, U> { impl<T: ClientDB, U: SlotClock, F: ForkChoice> ProducerDutiesReader for DirectDuties<T, U, F> {
fn is_block_production_slot(&self, slot: u64) -> Result<bool, ProducerDutiesReaderError> { fn is_block_production_slot(&self, slot: u64) -> Result<bool, ProducerDutiesReaderError> {
let validator_index = self let validator_index = self
.beacon_chain .beacon_chain
@ -41,7 +42,7 @@ impl<T: ClientDB, U: SlotClock> ProducerDutiesReader for DirectDuties<T, U> {
} }
} }
impl<T: ClientDB, U: SlotClock> AttesterDutiesReader for DirectDuties<T, U> { impl<T: ClientDB, U: SlotClock, F: ForkChoice> AttesterDutiesReader for DirectDuties<T, U, F> {
fn validator_index(&self) -> Option<u64> { fn validator_index(&self) -> Option<u64> {
match self.beacon_chain.validator_index(&self.pubkey) { match self.beacon_chain.validator_index(&self.pubkey) {
Some(index) => Some(index as u64), Some(index) => Some(index as u64),

View File

@ -7,6 +7,7 @@ use beacon_chain::BeaconChain;
use block_producer::PollOutcome as BlockPollOutcome; use block_producer::PollOutcome as BlockPollOutcome;
use block_producer::{BlockProducer, Error as BlockPollError}; use block_producer::{BlockProducer, Error as BlockPollError};
use db::MemoryDB; use db::MemoryDB;
use fork_choice::{optimised_lmd_ghost::OptimisedLMDGhost, slow_lmd_ghost::SlowLMDGhost};
use slot_clock::TestingSlotClock; use slot_clock::TestingSlotClock;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, FreeAttestation, Keypair}; use types::{BeaconBlock, ChainSpec, FreeAttestation, Keypair};
@ -31,20 +32,20 @@ pub enum AttestationProduceError {
pub struct TestValidator { pub struct TestValidator {
pub block_producer: BlockProducer< pub block_producer: BlockProducer<
TestingSlotClock, TestingSlotClock,
DirectBeaconNode<MemoryDB, TestingSlotClock>, DirectBeaconNode<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>,
DirectDuties<MemoryDB, TestingSlotClock>, DirectDuties<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>,
TestSigner, TestSigner,
>, >,
pub attester: Attester< pub attester: Attester<
TestingSlotClock, TestingSlotClock,
DirectBeaconNode<MemoryDB, TestingSlotClock>, DirectBeaconNode<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>,
DirectDuties<MemoryDB, TestingSlotClock>, DirectDuties<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>,
TestSigner, TestSigner,
>, >,
pub spec: Arc<ChainSpec>, pub spec: Arc<ChainSpec>,
pub epoch_map: Arc<DirectDuties<MemoryDB, TestingSlotClock>>, pub epoch_map: Arc<DirectDuties<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>>,
pub keypair: Keypair, pub keypair: Keypair,
pub beacon_node: Arc<DirectBeaconNode<MemoryDB, TestingSlotClock>>, pub beacon_node: Arc<DirectBeaconNode<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>>,
pub slot_clock: Arc<TestingSlotClock>, pub slot_clock: Arc<TestingSlotClock>,
pub signer: Arc<TestSigner>, pub signer: Arc<TestSigner>,
} }
@ -56,7 +57,7 @@ impl TestValidator {
/// A `BlockProducer` and `Attester` is created.. /// A `BlockProducer` and `Attester` is created..
pub fn new( pub fn new(
keypair: Keypair, keypair: Keypair,
beacon_chain: Arc<BeaconChain<MemoryDB, TestingSlotClock>>, beacon_chain: Arc<BeaconChain<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>>,
spec: Arc<ChainSpec>, spec: Arc<ChainSpec>,
) -> Self { ) -> Self {
let slot_clock = Arc::new(TestingSlotClock::new(spec.genesis_slot)); let slot_clock = Arc::new(TestingSlotClock::new(spec.genesis_slot));

View File

@ -13,6 +13,7 @@ use db::{
stores::{BeaconBlockStore, BeaconStateStore}, stores::{BeaconBlockStore, BeaconStateStore},
MemoryDB, MemoryDB,
}; };
use fork_choice::optimised_lmd_ghost::OptimisedLMDGhost;
use slog::{error, info, o, Drain}; use slog::{error, info, o, Drain};
use slot_clock::SystemTimeSlotClock; use slot_clock::SystemTimeSlotClock;
use std::sync::Arc; use std::sync::Arc;
@ -78,10 +79,17 @@ fn main() {
let slot_clock = SystemTimeSlotClock::new(spec.genesis_time, spec.slot_duration) let slot_clock = SystemTimeSlotClock::new(spec.genesis_time, spec.slot_duration)
.expect("Unable to load SystemTimeSlotClock"); .expect("Unable to load SystemTimeSlotClock");
// Choose the fork choice
let fork_choice = OptimisedLMDGhost::new(block_store.clone(), state_store.clone());
// Genesis chain // Genesis chain
// TODO: persist chain to storage. // TODO: persist chain to storage.
let _chain_result = let _chain_result = BeaconChain::genesis(
BeaconChain::genesis(state_store.clone(), block_store.clone(), slot_clock, spec); state_store.clone(),
block_store.clone(),
slot_clock,
spec,
fork_choice,
);
let _server = start_server(log.clone()); let _server = start_server(log.clone());

View File

@ -30,7 +30,7 @@ use types::{BeaconBlock, Hash256};
/// Defines the interface for Fork Choices. Each Fork choice will define their own data structures /// 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. /// 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 /// 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 /// Called when a block has been added. Allows generic block-level data structures to be
/// built for a given fork-choice. /// built for a given fork-choice.
fn add_block( fn add_block(

View File

@ -62,15 +62,18 @@ impl<T> OptimisedLMDGhost<T>
where where
T: ClientDB + Sized, T: ClientDB + Sized,
{ {
pub fn new(block_store: BeaconBlockStore<T>, state_store: BeaconStateStore<T>) -> Self { pub fn new(
block_store: Arc<BeaconBlockStore<T>>,
state_store: Arc<BeaconStateStore<T>>,
) -> Self {
OptimisedLMDGhost { OptimisedLMDGhost {
cache: HashMap::new(), cache: HashMap::new(),
ancestors: vec![HashMap::new(); 16], ancestors: vec![HashMap::new(); 16],
latest_attestation_targets: HashMap::new(), latest_attestation_targets: HashMap::new(),
children: HashMap::new(), children: HashMap::new(),
max_known_height: 0, max_known_height: 0,
block_store: Arc::new(block_store), block_store,
state_store: Arc::new(state_store), state_store,
} }
} }