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" }
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" }

View File

@ -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<T: ClientDB + Sized, U: SlotClock, F: ForkChoice> {
justified_head: RwLock<CheckPoint>,
pub state: RwLock<BeaconState>,
pub spec: ChainSpec,
pub fork_choice: F,
pub fork_choice: RwLock<F>,
}
impl<T, U, F> BeaconChain<T, U, F>
@ -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<AggregationOutcome, Error> {
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<BlockProcessingOutcome, Error> {
pub fn process_block(&self, block: BeaconBlock) -> Result<BlockProcessingOutcome, Error> {
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

View File

@ -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...");

View File

@ -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<T: ClientDB, U: SlotClock> {
beacon_chain: Arc<BeaconChain<T, U>>,
pub struct DirectBeaconNode<T: ClientDB, U: SlotClock, F: ForkChoice> {
beacon_chain: Arc<BeaconChain<T, U, F>>,
published_blocks: RwLock<Vec<BeaconBlock>>,
published_attestations: RwLock<Vec<FreeAttestation>>,
}
impl<T: ClientDB, U: SlotClock> DirectBeaconNode<T, U> {
pub fn new(beacon_chain: Arc<BeaconChain<T, U>>) -> Self {
impl<T: ClientDB, U: SlotClock, F: ForkChoice> DirectBeaconNode<T, U, F> {
pub fn new(beacon_chain: Arc<BeaconChain<T, U, F>>) -> Self {
Self {
beacon_chain,
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(
&self,
_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`.
fn proposer_nonce(&self, pubkey: &PublicKey) -> Result<u64, BeaconBlockNodeError> {
let validator_index = self

View File

@ -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<T: ClientDB, U: SlotClock> {
beacon_chain: Arc<BeaconChain<T, U>>,
pub struct DirectDuties<T: ClientDB, U: SlotClock, F: ForkChoice> {
beacon_chain: Arc<BeaconChain<T, U, F>>,
pubkey: PublicKey,
}
impl<T: ClientDB, U: SlotClock> DirectDuties<T, U> {
pub fn new(pubkey: PublicKey, beacon_chain: Arc<BeaconChain<T, U>>) -> Self {
impl<T: ClientDB, U: SlotClock, F: ForkChoice> DirectDuties<T, U, F> {
pub fn new(pubkey: PublicKey, beacon_chain: Arc<BeaconChain<T, U, F>>) -> Self {
Self {
beacon_chain,
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> {
let validator_index = self
.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> {
match self.beacon_chain.validator_index(&self.pubkey) {
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::{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<MemoryDB, TestingSlotClock>,
DirectDuties<MemoryDB, TestingSlotClock>,
DirectBeaconNode<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>,
DirectDuties<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>,
TestSigner,
>,
pub attester: Attester<
TestingSlotClock,
DirectBeaconNode<MemoryDB, TestingSlotClock>,
DirectDuties<MemoryDB, TestingSlotClock>,
DirectBeaconNode<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>,
DirectDuties<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>,
TestSigner,
>,
pub spec: Arc<ChainSpec>,
pub epoch_map: Arc<DirectDuties<MemoryDB, TestingSlotClock>>,
pub epoch_map: Arc<DirectDuties<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>>,
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 signer: Arc<TestSigner>,
}
@ -56,7 +57,7 @@ impl TestValidator {
/// A `BlockProducer` and `Attester` is created..
pub fn new(
keypair: Keypair,
beacon_chain: Arc<BeaconChain<MemoryDB, TestingSlotClock>>,
beacon_chain: Arc<BeaconChain<MemoryDB, TestingSlotClock, OptimisedLMDGhost<MemoryDB>>>,
spec: Arc<ChainSpec>,
) -> Self {
let slot_clock = Arc::new(TestingSlotClock::new(spec.genesis_slot));

View File

@ -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());

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
/// 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(

View File

@ -62,15 +62,18 @@ impl<T> OptimisedLMDGhost<T>
where
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 {
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,
}
}