From 7edc5f37b9759b328d31221d747eff42af2d1ddb Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 4 Sep 2019 10:25:30 +1000 Subject: [PATCH] Move BeaconChainHarness to interop spec --- .../beacon_chain/src/beacon_chain_builder.rs | 23 ++--- beacon_node/beacon_chain/src/errors.rs | 1 + beacon_node/beacon_chain/src/test_utils.rs | 94 +++++++------------ beacon_node/beacon_chain/tests/tests.rs | 42 ++++++++- beacon_node/client/src/lib.rs | 8 +- eth2/lmd_ghost/tests/test.rs | 5 +- 6 files changed, 91 insertions(+), 82 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain_builder.rs b/beacon_node/beacon_chain/src/beacon_chain_builder.rs index f03cbcc96..e59aae22b 100644 --- a/beacon_node/beacon_chain/src/beacon_chain_builder.rs +++ b/beacon_node/beacon_chain/src/beacon_chain_builder.rs @@ -13,8 +13,8 @@ use std::sync::Arc; use std::time::SystemTime; use tree_hash::{SignedRoot, TreeHash}; use types::{ - test_utils::generate_deterministic_keypairs, BeaconBlock, BeaconState, ChainSpec, Deposit, - DepositData, Domain, EthSpec, Fork, Hash256, PublicKey, Signature, + BeaconBlock, BeaconState, ChainSpec, Deposit, DepositData, Domain, EthSpec, Fork, Hash256, + Keypair, PublicKey, Signature, }; enum BuildStrategy { @@ -33,21 +33,21 @@ pub struct BeaconChainBuilder { impl BeaconChainBuilder { pub fn recent_genesis( - validator_count: usize, + keypairs: &[Keypair], minutes: u64, spec: ChainSpec, log: Logger, ) -> Result { - Self::quick_start(recent_genesis_time(minutes), validator_count, spec, log) + Self::quick_start(recent_genesis_time(minutes), keypairs, spec, log) } pub fn quick_start( genesis_time: u64, - validator_count: usize, + keypairs: &[Keypair], spec: ChainSpec, log: Logger, ) -> Result { - let genesis_state = interop_genesis_state(validator_count, genesis_time, &spec)?; + let genesis_state = interop_genesis_state(keypairs, genesis_time, &spec)?; Ok(Self::from_genesis_state(genesis_state, spec, log)) } @@ -167,11 +167,10 @@ fn genesis_block(genesis_state: &BeaconState, spec: &ChainSpec) - /// Reference: /// https://github.com/ethereum/eth2.0-pm/tree/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start fn interop_genesis_state( - validator_count: usize, + keypairs: &[Keypair], genesis_time: u64, spec: &ChainSpec, ) -> Result, String> { - let keypairs = generate_deterministic_keypairs(validator_count); let eth1_block_hash = Hash256::from_slice(&[0x42; 32]); let eth1_timestamp = 2_u64.pow(40); let amount = spec.max_effective_balance; @@ -187,7 +186,7 @@ fn interop_genesis_state( .map(|keypair| { let mut data = DepositData { withdrawal_credentials: withdrawal_credentials(&keypair.pk), - pubkey: keypair.pk.into(), + pubkey: keypair.pk.clone().into(), amount, signature: Signature::empty_signature().into(), }; @@ -269,7 +268,7 @@ fn recent_genesis_time(minutes: u64) -> u64 { #[cfg(test)] mod test { use super::*; - use types::{EthSpec, MinimalEthSpec}; + use types::{test_utils::generate_deterministic_keypairs, EthSpec, MinimalEthSpec}; type TestEthSpec = MinimalEthSpec; @@ -279,7 +278,9 @@ mod test { let genesis_time = 42; let spec = &TestEthSpec::default_spec(); - let state = interop_genesis_state::(validator_count, genesis_time, spec) + let keypairs = generate_deterministic_keypairs(validator_count); + + let state = interop_genesis_state::(&keypairs, genesis_time, spec) .expect("should build state"); assert_eq!( diff --git a/beacon_node/beacon_chain/src/errors.rs b/beacon_node/beacon_chain/src/errors.rs index 58cfed271..030689928 100644 --- a/beacon_node/beacon_chain/src/errors.rs +++ b/beacon_node/beacon_chain/src/errors.rs @@ -34,6 +34,7 @@ pub enum BeaconChainError { MissingBeaconBlock(Hash256), MissingBeaconState(Hash256), SlotProcessingError(SlotProcessingError), + UnableToAdvanceState(String), NoStateForAttestation { beacon_block_root: Hash256, }, diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index 07d181a53..7670ac74e 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -1,22 +1,28 @@ -use crate::{BeaconChain, BeaconChainTypes, BlockProcessingOutcome, InteropEth1ChainBackend}; +use crate::{ + AttestationProcessingOutcome, BeaconChain, BeaconChainBuilder, BeaconChainTypes, + BlockProcessingOutcome, InteropEth1ChainBackend, +}; use lmd_ghost::LmdGhost; use rayon::prelude::*; -use sloggers::{null::NullLoggerBuilder, Build}; +use sloggers::{terminal::TerminalLoggerBuilder, types::Severity, Build}; use slot_clock::TestingSlotClock; use state_processing::per_slot_processing; use std::marker::PhantomData; use std::sync::Arc; use store::MemoryStore; -use store::Store; use tree_hash::{SignedRoot, TreeHash}; use types::{ - test_utils::TestingBeaconStateBuilder, AggregateSignature, Attestation, - AttestationDataAndCustodyBit, BeaconBlock, BeaconState, BitList, ChainSpec, Domain, EthSpec, - Hash256, Keypair, RelativeEpoch, SecretKey, Signature, Slot, + AggregateSignature, Attestation, AttestationDataAndCustodyBit, BeaconBlock, BeaconState, + BitList, ChainSpec, Domain, EthSpec, Hash256, Keypair, RelativeEpoch, SecretKey, Signature, + Slot, }; +pub use types::test_utils::generate_deterministic_keypairs; + pub use crate::persisted_beacon_chain::{PersistedBeaconChain, BEACON_CHAIN_DB_KEY}; +pub const HARNESS_GENESIS_TIME: u64 = 1567552690; // 4th September 2019 + /// Indicates how the `BeaconChainHarness` should produce blocks. #[derive(Clone, Copy, Debug)] pub enum BlockStrategy { @@ -84,46 +90,21 @@ where E: EthSpec, { /// Instantiate a new harness with `validator_count` initial validators. - pub fn new(validator_count: usize) -> Self { - let state_builder = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists( - validator_count, - &E::default_spec(), - ); - let (genesis_state, keypairs) = state_builder.build(); - - Self::from_state_and_keypairs(genesis_state, keypairs) - } - - /// Instantiate a new harness with an initial validator for each key supplied. - pub fn from_keypairs(keypairs: Vec) -> Self { - let state_builder = TestingBeaconStateBuilder::from_keypairs(keypairs, &E::default_spec()); - let (genesis_state, keypairs) = state_builder.build(); - - Self::from_state_and_keypairs(genesis_state, keypairs) - } - - /// Instantiate a new harness with the given genesis state and a keypair for each of the - /// initial validators in the given state. - pub fn from_state_and_keypairs(genesis_state: BeaconState, keypairs: Vec) -> Self { + pub fn new(keypairs: Vec) -> Self { let spec = E::default_spec(); + let log = TerminalLoggerBuilder::new() + .level(Severity::Warning) + .build() + .expect("logger should build"); + let store = Arc::new(MemoryStore::open()); - let mut genesis_block = BeaconBlock::empty(&spec); - genesis_block.state_root = Hash256::from_slice(&genesis_state.tree_hash_root()); - - let builder = NullLoggerBuilder; - let log = builder.build().expect("logger should build"); - - let chain = BeaconChain::from_genesis( - store, - InteropEth1ChainBackend::default(), - genesis_state, - genesis_block, - spec.clone(), - log, - ) - .expect("Terminate if beacon chain generation fails"); + let chain = + BeaconChainBuilder::quick_start(HARNESS_GENESIS_TIME, &keypairs, spec.clone(), log) + .unwrap_or_else(|e| panic!("Failed to create beacon chain builder: {}", e)) + .build(store.clone(), InteropEth1ChainBackend::default()) + .unwrap_or_else(|e| panic!("Failed to build beacon chain: {}", e)); Self { chain, @@ -163,7 +144,10 @@ where BlockStrategy::ForkCanonicalChainAt { previous_slot, .. } => previous_slot, }; - self.get_state_at_slot(state_slot) + self.chain + .state_at_slot(state_slot) + .expect("should find state for slot") + .clone() }; // Determine the first slot where a block should be built. @@ -201,21 +185,6 @@ where head_block_root.expect("did not produce any blocks") } - fn get_state_at_slot(&self, state_slot: Slot) -> BeaconState { - let state_root = self - .chain - .rev_iter_state_roots() - .find(|(_hash, slot)| *slot == state_slot) - .map(|(hash, _slot)| hash) - .expect("could not find state root"); - - self.chain - .store - .get(&state_root) - .expect("should read db") - .expect("should find state root") - } - /// Returns a newly created block, signed by the proposer for the given slot. fn build_block( &self, @@ -289,9 +258,14 @@ where ) .into_iter() .for_each(|attestation| { - self.chain + match self + .chain .process_attestation(attestation) - .expect("should process attestation"); + .expect("should not error during attestation processing") + { + AttestationProcessingOutcome::Processed => (), + other => panic!("did not successfully process attestation: {:?}", other), + } }); } diff --git a/beacon_node/beacon_chain/tests/tests.rs b/beacon_node/beacon_chain/tests/tests.rs index ba7f7bf84..bf853f284 100644 --- a/beacon_node/beacon_chain/tests/tests.rs +++ b/beacon_node/beacon_chain/tests/tests.rs @@ -3,11 +3,14 @@ #[macro_use] extern crate lazy_static; -use beacon_chain::test_utils::{ - AttestationStrategy, BeaconChainHarness, BlockStrategy, CommonTypes, PersistedBeaconChain, - BEACON_CHAIN_DB_KEY, -}; use beacon_chain::AttestationProcessingOutcome; +use beacon_chain::{ + test_utils::{ + AttestationStrategy, BeaconChainHarness, BlockStrategy, CommonTypes, PersistedBeaconChain, + BEACON_CHAIN_DB_KEY, + }, + BlockProcessingOutcome, +}; use lmd_ghost::ThreadSafeReducedTree; use rand::Rng; use store::{MemoryStore, Store}; @@ -25,7 +28,7 @@ lazy_static! { type TestForkChoice = ThreadSafeReducedTree; fn get_harness(validator_count: usize) -> BeaconChainHarness { - let harness = BeaconChainHarness::from_keypairs(KEYPAIRS[0..validator_count].to_vec()); + let harness = BeaconChainHarness::new(KEYPAIRS[0..validator_count].to_vec()); harness.advance_slot(); @@ -461,3 +464,32 @@ fn free_attestations_added_to_fork_choice_all_updated() { } } } + +#[test] +fn produces_and_processes_with_genesis_skip_slots() { + let num_validators = 8; + let harness_a = get_harness(num_validators); + let harness_b = get_harness(num_validators); + let skip_slots = 9; + + for _ in 0..skip_slots { + harness_a.advance_slot(); + harness_b.advance_slot(); + } + + harness_a.extend_chain( + 1, + BlockStrategy::OnCanonicalHead, + // No attestation required for test. + AttestationStrategy::SomeValidators(vec![]), + ); + + assert_eq!( + harness_b + .chain + .process_block(harness_a.chain.head().beacon_block.clone()), + Ok(BlockProcessingOutcome::Processed { + block_root: harness_a.chain.head().beacon_block_root + }) + ); +} diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 33f27f253..1d3cb40ec 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -6,8 +6,8 @@ pub mod error; pub mod notifier; use beacon_chain::{ - lmd_ghost::ThreadSafeReducedTree, slot_clock::SystemTimeSlotClock, store::Store, BeaconChain, - BeaconChainBuilder, + lmd_ghost::ThreadSafeReducedTree, slot_clock::SystemTimeSlotClock, store::Store, + test_utils::generate_deterministic_keypairs, BeaconChain, BeaconChainBuilder, }; use exit_future::Signal; use futures::{future::Future, Stream}; @@ -106,7 +106,7 @@ where "method" => "recent" ); BeaconChainBuilder::recent_genesis( - *validator_count, + &generate_deterministic_keypairs(*validator_count), *minutes, spec.clone(), log.clone(), @@ -125,7 +125,7 @@ where ); BeaconChainBuilder::quick_start( *genesis_time, - *validator_count, + &generate_deterministic_keypairs(*validator_count), spec.clone(), log.clone(), )? diff --git a/eth2/lmd_ghost/tests/test.rs b/eth2/lmd_ghost/tests/test.rs index 4c79a704e..49e9ff738 100644 --- a/eth2/lmd_ghost/tests/test.rs +++ b/eth2/lmd_ghost/tests/test.rs @@ -4,7 +4,8 @@ extern crate lazy_static; use beacon_chain::test_utils::{ - AttestationStrategy, BeaconChainHarness as BaseBeaconChainHarness, BlockStrategy, + generate_deterministic_keypairs, AttestationStrategy, + BeaconChainHarness as BaseBeaconChainHarness, BlockStrategy, }; use lmd_ghost::{LmdGhost, ThreadSafeReducedTree as BaseThreadSafeReducedTree}; use rand::{prelude::*, rngs::StdRng}; @@ -51,7 +52,7 @@ struct ForkedHarness { impl ForkedHarness { /// A new standard instance of with constant parameters. pub fn new() -> Self { - let harness = BeaconChainHarness::new(VALIDATOR_COUNT); + let harness = BeaconChainHarness::new(generate_deterministic_keypairs(VALIDATOR_COUNT)); // Move past the zero slot. harness.advance_slot();