Integrate ForkChoice into beacon_node.
This commit is contained in:
parent
c4c1e5647e
commit
4370035448
@ -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" }
|
||||
|
@ -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
|
||||
|
@ -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...");
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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));
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user