From 85b23f9f1b7bcc035dd688b9769a835c99a466bd Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Thu, 20 Jun 2019 10:59:19 +1000 Subject: [PATCH] Add incomplete progress on fork choice --- beacon_node/beacon_chain/src/beacon_chain.rs | 45 +++---- beacon_node/beacon_chain/src/test_utils.rs | 119 +++++++++++++++---- eth2/types/src/beacon_state.rs | 3 + 3 files changed, 119 insertions(+), 48 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index c680498dca..86e0ded3ce 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -4,7 +4,7 @@ use crate::fork_choice::{Error as ForkChoiceError, ForkChoice}; use crate::metrics::Metrics; use crate::persisted_beacon_chain::{PersistedBeaconChain, BEACON_CHAIN_DB_KEY}; use lmd_ghost::LmdGhost; -use log::{debug, trace}; +use log::trace; use operation_pool::DepositInsertStatus; use operation_pool::OperationPool; use parking_lot::{RwLock, RwLockReadGuard}; @@ -300,18 +300,20 @@ impl BeaconChain { _ => return Err(Error::UnableToReadSlot), }; - let mut state = self.state.write(); + if self.state.read().slot < present_slot { + let mut state = self.state.write(); - // If required, transition the new state to the present slot. - for _ in state.slot.as_u64()..present_slot.as_u64() { - // Ensure the next epoch state caches are built in case of an epoch transition. - state.build_committee_cache(RelativeEpoch::Next, spec)?; + // If required, transition the new state to the present slot. + for _ in state.slot.as_u64()..present_slot.as_u64() { + // Ensure the next epoch state caches are built in case of an epoch transition. + state.build_committee_cache(RelativeEpoch::Next, spec)?; - per_slot_processing(&mut *state, spec)?; + per_slot_processing(&mut *state, spec)?; + } + + state.build_all_caches(spec)?; } - state.build_all_caches(spec)?; - Ok(()) } @@ -382,13 +384,14 @@ impl BeaconChain { /// Returns the block proposer for a given slot. /// - /// Information is read from the present `beacon_state` shuffling, so only information from the - /// present and prior epoch is available. - pub fn block_proposer(&self, slot: Slot) -> Result { - self.state - .write() - .build_committee_cache(RelativeEpoch::Current, &self.spec)?; + /// Information is read from the present `beacon_state` shuffling, only information from the + /// present epoch is available. + pub fn block_proposer(&self, slot: Slot) -> Result { + // Ensures that the present state has been advanced to the present slot, skipping slots if + // blocks are not present. + self.catchup_state()?; + // TODO: permit lookups of the proposer at any slot. let index = self.state.read().get_beacon_proposer_index( slot, RelativeEpoch::Current, @@ -559,6 +562,7 @@ impl BeaconChain { .read() .finalized_epoch .start_slot(T::EthSpec::slots_per_epoch()); + if block.slot <= finalized_slot { return Ok(BlockProcessingOutcome::FinalizedSlot); } @@ -573,7 +577,9 @@ impl BeaconChain { return Ok(BlockProcessingOutcome::GenesisBlock); } - let present_slot = self.present_slot(); + let present_slot = self + .read_slot_clock() + .ok_or_else(|| Error::UnableToReadSlot)?; if block.slot > present_slot { return Ok(BlockProcessingOutcome::FutureSlot { @@ -719,8 +725,8 @@ impl BeaconChain { signature: Signature::empty_signature(), // To be completed by a validator. body: BeaconBlockBody { randao_reveal, + // TODO: replace with real data. eth1_data: Eth1Data { - // TODO: replace with real data deposit_count: 0, deposit_root: Hash256::zero(), block_hash: Hash256::zero(), @@ -739,11 +745,6 @@ impl BeaconChain { }, }; - debug!( - "Produced block with {} attestations, updating state.", - block.body.attestations.len() - ); - per_block_processing_without_verifying_block_signature(&mut state, &block, &self.spec)?; let state_root = state.canonical_root(); diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index 097ad656cf..64e482a508 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -2,6 +2,7 @@ use crate::{BeaconChain, BeaconChainTypes, BlockProcessingOutcome}; use lmd_ghost::LmdGhost; use slot_clock::SlotClock; use slot_clock::TestingSlotClock; +use state_processing::per_slot_processing; use std::marker::PhantomData; use std::sync::Arc; use store::MemoryStore; @@ -13,7 +14,7 @@ use types::{ Hash256, Keypair, RelativeEpoch, SecretKey, Signature, Slot, }; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum BuildStrategy { OnCanonicalHead, ForkCanonicalChainAt(Slot), @@ -89,22 +90,14 @@ where } } - pub fn extend_chain(&self, build_strategy: BuildStrategy) { + pub fn advance_slot(&self) { self.chain.slot_clock.advance_slot(); self.chain.catchup_state().expect("should catchup state"); - - let block = self.build_block(build_strategy); - let outcome = self - .chain - .process_block(block) - .expect("should process block"); - assert_eq!(outcome, BlockProcessingOutcome::Processed); - - self.add_attestations_to_op_pool(); } - fn get_state(&self, build_strategy: BuildStrategy) -> BeaconState { - match build_strategy { + pub fn extend_chain(&self, build_strategy: BuildStrategy, blocks: usize) { + // Get an initial state to build the block upon, based on the build strategy. + let mut state = match build_strategy { BuildStrategy::OnCanonicalHead => self.chain.current_state().clone(), BuildStrategy::ForkCanonicalChainAt(fork_slot) => { let state_root = self @@ -120,18 +113,80 @@ where .expect("should read db") .expect("should find state root") } - } - } + }; - fn build_block(&self, build_strategy: BuildStrategy) -> BeaconBlock { - let mut state = self.get_state(build_strategy); - state.build_all_caches(&self.spec).unwrap(); - - let slot = match build_strategy { + // Get an initial slot to build upon, based on the build strategy. + let mut slot = match build_strategy { BuildStrategy::OnCanonicalHead => self.chain.read_slot_clock().unwrap(), BuildStrategy::ForkCanonicalChainAt(slot) => slot, }; + for _ in 0..blocks { + while self.chain.read_slot_clock().expect("should have a slot") < slot { + self.advance_slot(); + } + + let (block, new_state) = self.build_block(state.clone(), slot, build_strategy); + + let outcome = self + .chain + .process_block(block) + .expect("should process block"); + + assert_eq!(outcome, BlockProcessingOutcome::Processed); + + state = new_state; + slot += 1; + } + + self.add_attestations_to_op_pool(); + } + + fn build_block( + &self, + mut state: BeaconState, + slot: Slot, + build_strategy: BuildStrategy, + ) -> (BeaconBlock, BeaconState) { + if slot < state.slot { + panic!("produce slot cannot be prior to the state slot"); + } + + for _ in 0..slot.as_u64() - state.slot.as_u64() { + // Ensure the next epoch state caches are built in case of an epoch transition. + state + .build_committee_cache(RelativeEpoch::Next, &self.spec) + .expect("should be able to build caches"); + + per_slot_processing(&mut state, &self.spec) + .expect("should be able to advance state to slot"); + } + + state.drop_all_caches(); + state.build_all_caches(&self.spec).unwrap(); + + // dbg!(slot); + // dbg!(state.generate_seed(state.current_epoch(), &self.spec)); + dbg!(state.generate_seed(state.next_epoch(), &self.spec)); + /* + dbg!(self + .chain + .current_state() + .generate_seed(state.current_epoch(), &self.spec)); + // dbg!(state.generate_seed(state.next_epoch(), &self.spec)); + dbg!(state.canonical_root()); + dbg!(&state.committee_caches[0]); + dbg!(self.chain.current_state().canonical_root()); + dbg!(&self.chain.current_state().committee_caches[0]); + + dbg!(state.get_beacon_proposer_index(slot, RelativeEpoch::Current, &self.spec)); + dbg!(self.chain.current_state().get_beacon_proposer_index( + slot, + RelativeEpoch::Current, + &self.spec + )); + */ + let proposer_index = match build_strategy { BuildStrategy::OnCanonicalHead => self .chain @@ -152,7 +207,7 @@ where Signature::new(&message, domain, sk) }; - let (mut block, _state) = self + let (mut block, state) = self .chain .produce_block_on_state(state, slot, randao_reveal) .expect("should produce block"); @@ -164,7 +219,7 @@ where Signature::new(&message, domain, sk) }; - block + (block, state) } fn add_attestations_to_op_pool(&self) { @@ -239,18 +294,30 @@ mod test { pub const VALIDATOR_COUNT: usize = 16; + fn get_harness( + validator_count: usize, + ) -> BeaconChainHarness, MinimalEthSpec> + { + let harness = BeaconChainHarness::new(validator_count); + + // Move past the zero slot. + harness.advance_slot(); + + harness + } + #[test] fn can_finalize() { let num_blocks_produced = MinimalEthSpec::slots_per_epoch() * 5; - let harness: BeaconChainHarness< - ThreadSafeReducedTree, - MinimalEthSpec, - > = BeaconChainHarness::new(VALIDATOR_COUNT); + let harness = get_harness(VALIDATOR_COUNT); + harness.extend_chain(BuildStrategy::OnCanonicalHead, num_blocks_produced as usize); + /* for _ in 0..num_blocks_produced { harness.extend_chain(BuildStrategy::OnCanonicalHead); } + */ let state = &harness.chain.head().beacon_state; diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index 58237fe6f3..4790d95e7f 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -703,6 +703,9 @@ impl BeaconState { let active_index_root = self.get_active_index_root(epoch, spec)?; let epoch_bytes = int_to_bytes32(epoch.as_u64()); + dbg!(randao); + dbg!(active_index_root); + let mut preimage = [0; 32 * 3]; preimage[0..32].copy_from_slice(&randao[..]); preimage[32..64].copy_from_slice(&active_index_root[..]);