Move BeaconChainHarness to interop spec

This commit is contained in:
Paul Hauner 2019-09-04 10:25:30 +10:00
parent 2706025a34
commit 7edc5f37b9
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
6 changed files with 91 additions and 82 deletions

View File

@ -13,8 +13,8 @@ use std::sync::Arc;
use std::time::SystemTime; use std::time::SystemTime;
use tree_hash::{SignedRoot, TreeHash}; use tree_hash::{SignedRoot, TreeHash};
use types::{ use types::{
test_utils::generate_deterministic_keypairs, BeaconBlock, BeaconState, ChainSpec, Deposit, BeaconBlock, BeaconState, ChainSpec, Deposit, DepositData, Domain, EthSpec, Fork, Hash256,
DepositData, Domain, EthSpec, Fork, Hash256, PublicKey, Signature, Keypair, PublicKey, Signature,
}; };
enum BuildStrategy<T: BeaconChainTypes> { enum BuildStrategy<T: BeaconChainTypes> {
@ -33,21 +33,21 @@ pub struct BeaconChainBuilder<T: BeaconChainTypes> {
impl<T: BeaconChainTypes> BeaconChainBuilder<T> { impl<T: BeaconChainTypes> BeaconChainBuilder<T> {
pub fn recent_genesis( pub fn recent_genesis(
validator_count: usize, keypairs: &[Keypair],
minutes: u64, minutes: u64,
spec: ChainSpec, spec: ChainSpec,
log: Logger, log: Logger,
) -> Result<Self, String> { ) -> Result<Self, String> {
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( pub fn quick_start(
genesis_time: u64, genesis_time: u64,
validator_count: usize, keypairs: &[Keypair],
spec: ChainSpec, spec: ChainSpec,
log: Logger, log: Logger,
) -> Result<Self, String> { ) -> Result<Self, String> {
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)) Ok(Self::from_genesis_state(genesis_state, spec, log))
} }
@ -167,11 +167,10 @@ fn genesis_block<T: EthSpec>(genesis_state: &BeaconState<T>, spec: &ChainSpec) -
/// Reference: /// Reference:
/// https://github.com/ethereum/eth2.0-pm/tree/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start /// https://github.com/ethereum/eth2.0-pm/tree/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start
fn interop_genesis_state<T: EthSpec>( fn interop_genesis_state<T: EthSpec>(
validator_count: usize, keypairs: &[Keypair],
genesis_time: u64, genesis_time: u64,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<BeaconState<T>, String> { ) -> Result<BeaconState<T>, String> {
let keypairs = generate_deterministic_keypairs(validator_count);
let eth1_block_hash = Hash256::from_slice(&[0x42; 32]); let eth1_block_hash = Hash256::from_slice(&[0x42; 32]);
let eth1_timestamp = 2_u64.pow(40); let eth1_timestamp = 2_u64.pow(40);
let amount = spec.max_effective_balance; let amount = spec.max_effective_balance;
@ -187,7 +186,7 @@ fn interop_genesis_state<T: EthSpec>(
.map(|keypair| { .map(|keypair| {
let mut data = DepositData { let mut data = DepositData {
withdrawal_credentials: withdrawal_credentials(&keypair.pk), withdrawal_credentials: withdrawal_credentials(&keypair.pk),
pubkey: keypair.pk.into(), pubkey: keypair.pk.clone().into(),
amount, amount,
signature: Signature::empty_signature().into(), signature: Signature::empty_signature().into(),
}; };
@ -269,7 +268,7 @@ fn recent_genesis_time(minutes: u64) -> u64 {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use types::{EthSpec, MinimalEthSpec}; use types::{test_utils::generate_deterministic_keypairs, EthSpec, MinimalEthSpec};
type TestEthSpec = MinimalEthSpec; type TestEthSpec = MinimalEthSpec;
@ -279,7 +278,9 @@ mod test {
let genesis_time = 42; let genesis_time = 42;
let spec = &TestEthSpec::default_spec(); let spec = &TestEthSpec::default_spec();
let state = interop_genesis_state::<TestEthSpec>(validator_count, genesis_time, spec) let keypairs = generate_deterministic_keypairs(validator_count);
let state = interop_genesis_state::<TestEthSpec>(&keypairs, genesis_time, spec)
.expect("should build state"); .expect("should build state");
assert_eq!( assert_eq!(

View File

@ -34,6 +34,7 @@ pub enum BeaconChainError {
MissingBeaconBlock(Hash256), MissingBeaconBlock(Hash256),
MissingBeaconState(Hash256), MissingBeaconState(Hash256),
SlotProcessingError(SlotProcessingError), SlotProcessingError(SlotProcessingError),
UnableToAdvanceState(String),
NoStateForAttestation { NoStateForAttestation {
beacon_block_root: Hash256, beacon_block_root: Hash256,
}, },

View File

@ -1,22 +1,28 @@
use crate::{BeaconChain, BeaconChainTypes, BlockProcessingOutcome, InteropEth1ChainBackend}; use crate::{
AttestationProcessingOutcome, BeaconChain, BeaconChainBuilder, BeaconChainTypes,
BlockProcessingOutcome, InteropEth1ChainBackend,
};
use lmd_ghost::LmdGhost; use lmd_ghost::LmdGhost;
use rayon::prelude::*; use rayon::prelude::*;
use sloggers::{null::NullLoggerBuilder, Build}; use sloggers::{terminal::TerminalLoggerBuilder, types::Severity, Build};
use slot_clock::TestingSlotClock; use slot_clock::TestingSlotClock;
use state_processing::per_slot_processing; use state_processing::per_slot_processing;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::Arc; use std::sync::Arc;
use store::MemoryStore; use store::MemoryStore;
use store::Store;
use tree_hash::{SignedRoot, TreeHash}; use tree_hash::{SignedRoot, TreeHash};
use types::{ use types::{
test_utils::TestingBeaconStateBuilder, AggregateSignature, Attestation, AggregateSignature, Attestation, AttestationDataAndCustodyBit, BeaconBlock, BeaconState,
AttestationDataAndCustodyBit, BeaconBlock, BeaconState, BitList, ChainSpec, Domain, EthSpec, BitList, ChainSpec, Domain, EthSpec, Hash256, Keypair, RelativeEpoch, SecretKey, Signature,
Hash256, Keypair, RelativeEpoch, SecretKey, Signature, Slot, Slot,
}; };
pub use types::test_utils::generate_deterministic_keypairs;
pub use crate::persisted_beacon_chain::{PersistedBeaconChain, BEACON_CHAIN_DB_KEY}; 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. /// Indicates how the `BeaconChainHarness` should produce blocks.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub enum BlockStrategy { pub enum BlockStrategy {
@ -84,46 +90,21 @@ where
E: EthSpec, E: EthSpec,
{ {
/// Instantiate a new harness with `validator_count` initial validators. /// Instantiate a new harness with `validator_count` initial validators.
pub fn new(validator_count: usize) -> Self { pub fn new(keypairs: Vec<Keypair>) -> 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<Keypair>) -> 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<E>, keypairs: Vec<Keypair>) -> Self {
let spec = E::default_spec(); let spec = E::default_spec();
let log = TerminalLoggerBuilder::new()
.level(Severity::Warning)
.build()
.expect("logger should build");
let store = Arc::new(MemoryStore::open()); let store = Arc::new(MemoryStore::open());
let mut genesis_block = BeaconBlock::empty(&spec); let chain =
genesis_block.state_root = Hash256::from_slice(&genesis_state.tree_hash_root()); BeaconChainBuilder::quick_start(HARNESS_GENESIS_TIME, &keypairs, spec.clone(), log)
.unwrap_or_else(|e| panic!("Failed to create beacon chain builder: {}", e))
let builder = NullLoggerBuilder; .build(store.clone(), InteropEth1ChainBackend::default())
let log = builder.build().expect("logger should build"); .unwrap_or_else(|e| panic!("Failed to build beacon chain: {}", e));
let chain = BeaconChain::from_genesis(
store,
InteropEth1ChainBackend::default(),
genesis_state,
genesis_block,
spec.clone(),
log,
)
.expect("Terminate if beacon chain generation fails");
Self { Self {
chain, chain,
@ -163,7 +144,10 @@ where
BlockStrategy::ForkCanonicalChainAt { previous_slot, .. } => previous_slot, 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. // Determine the first slot where a block should be built.
@ -201,21 +185,6 @@ where
head_block_root.expect("did not produce any blocks") head_block_root.expect("did not produce any blocks")
} }
fn get_state_at_slot(&self, state_slot: Slot) -> BeaconState<E> {
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. /// Returns a newly created block, signed by the proposer for the given slot.
fn build_block( fn build_block(
&self, &self,
@ -289,9 +258,14 @@ where
) )
.into_iter() .into_iter()
.for_each(|attestation| { .for_each(|attestation| {
self.chain match self
.chain
.process_attestation(attestation) .process_attestation(attestation)
.expect("should process attestation"); .expect("should not error during attestation processing")
{
AttestationProcessingOutcome::Processed => (),
other => panic!("did not successfully process attestation: {:?}", other),
}
}); });
} }

View File

@ -3,11 +3,14 @@
#[macro_use] #[macro_use]
extern crate lazy_static; 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::AttestationProcessingOutcome;
use beacon_chain::{
test_utils::{
AttestationStrategy, BeaconChainHarness, BlockStrategy, CommonTypes, PersistedBeaconChain,
BEACON_CHAIN_DB_KEY,
},
BlockProcessingOutcome,
};
use lmd_ghost::ThreadSafeReducedTree; use lmd_ghost::ThreadSafeReducedTree;
use rand::Rng; use rand::Rng;
use store::{MemoryStore, Store}; use store::{MemoryStore, Store};
@ -25,7 +28,7 @@ lazy_static! {
type TestForkChoice = ThreadSafeReducedTree<MemoryStore, MinimalEthSpec>; type TestForkChoice = ThreadSafeReducedTree<MemoryStore, MinimalEthSpec>;
fn get_harness(validator_count: usize) -> BeaconChainHarness<TestForkChoice, MinimalEthSpec> { fn get_harness(validator_count: usize) -> BeaconChainHarness<TestForkChoice, MinimalEthSpec> {
let harness = BeaconChainHarness::from_keypairs(KEYPAIRS[0..validator_count].to_vec()); let harness = BeaconChainHarness::new(KEYPAIRS[0..validator_count].to_vec());
harness.advance_slot(); 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
})
);
}

View File

@ -6,8 +6,8 @@ pub mod error;
pub mod notifier; pub mod notifier;
use beacon_chain::{ use beacon_chain::{
lmd_ghost::ThreadSafeReducedTree, slot_clock::SystemTimeSlotClock, store::Store, BeaconChain, lmd_ghost::ThreadSafeReducedTree, slot_clock::SystemTimeSlotClock, store::Store,
BeaconChainBuilder, test_utils::generate_deterministic_keypairs, BeaconChain, BeaconChainBuilder,
}; };
use exit_future::Signal; use exit_future::Signal;
use futures::{future::Future, Stream}; use futures::{future::Future, Stream};
@ -106,7 +106,7 @@ where
"method" => "recent" "method" => "recent"
); );
BeaconChainBuilder::recent_genesis( BeaconChainBuilder::recent_genesis(
*validator_count, &generate_deterministic_keypairs(*validator_count),
*minutes, *minutes,
spec.clone(), spec.clone(),
log.clone(), log.clone(),
@ -125,7 +125,7 @@ where
); );
BeaconChainBuilder::quick_start( BeaconChainBuilder::quick_start(
*genesis_time, *genesis_time,
*validator_count, &generate_deterministic_keypairs(*validator_count),
spec.clone(), spec.clone(),
log.clone(), log.clone(),
)? )?

View File

@ -4,7 +4,8 @@
extern crate lazy_static; extern crate lazy_static;
use beacon_chain::test_utils::{ 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 lmd_ghost::{LmdGhost, ThreadSafeReducedTree as BaseThreadSafeReducedTree};
use rand::{prelude::*, rngs::StdRng}; use rand::{prelude::*, rngs::StdRng};
@ -51,7 +52,7 @@ struct ForkedHarness {
impl ForkedHarness { impl ForkedHarness {
/// A new standard instance of with constant parameters. /// A new standard instance of with constant parameters.
pub fn new() -> Self { pub fn new() -> Self {
let harness = BeaconChainHarness::new(VALIDATOR_COUNT); let harness = BeaconChainHarness::new(generate_deterministic_keypairs(VALIDATOR_COUNT));
// Move past the zero slot. // Move past the zero slot.
harness.advance_slot(); harness.advance_slot();