diff --git a/beacon_node/beacon_chain/test_harness/Cargo.toml b/beacon_node/beacon_chain/test_harness/Cargo.toml index 77b52ccf67..657cc79552 100644 --- a/beacon_node/beacon_chain/test_harness/Cargo.toml +++ b/beacon_node/beacon_chain/test_harness/Cargo.toml @@ -10,6 +10,7 @@ harness = false [dev-dependencies] criterion = "0.2" +state_processing = { path = "../../../eth2/state_processing" } [dependencies] attester = { path = "../../../eth2/attester" } diff --git a/beacon_node/beacon_chain/test_harness/benches/state_transition.rs b/beacon_node/beacon_chain/test_harness/benches/state_transition.rs index 013ecfd1e1..aa2a858fab 100644 --- a/beacon_node/beacon_chain/test_harness/benches/state_transition.rs +++ b/beacon_node/beacon_chain/test_harness/benches/state_transition.rs @@ -1,6 +1,7 @@ use criterion::Criterion; use criterion::{black_box, criterion_group, criterion_main, Benchmark}; // use env_logger::{Builder, Env}; +use state_processing::SlotProcessable; use test_harness::BeaconChainHarness; use types::{ChainSpec, Hash256}; diff --git a/eth2/state_processing/benches/benches.rs b/eth2/state_processing/benches/benches.rs index 68a9735e12..244e3c8a5a 100644 --- a/eth2/state_processing/benches/benches.rs +++ b/eth2/state_processing/benches/benches.rs @@ -2,24 +2,30 @@ use criterion::Criterion; use criterion::{black_box, criterion_group, criterion_main}; // use env_logger::{Builder, Env}; use state_processing::SlotProcessable; -use types::*; use types::beacon_state::BeaconStateBuilder; +use types::*; fn epoch_processing(c: &mut Criterion) { // Builder::from_env(Env::default().default_filter_or("debug")).init(); - let mut builder = BeaconStateBuilder::with_random_validators(8); + let mut builder = BeaconStateBuilder::new(8); builder.spec = ChainSpec::few_validators(); - builder.genesis().unwrap(); + builder.build().unwrap(); builder.teleport_to_end_of_epoch(builder.spec.genesis_epoch + 4); - let mut state = builder.build().unwrap(); + let mut state = builder.cloned_state(); // Build all the caches so the following state does _not_ include the cache-building time. - state.build_epoch_cache(RelativeEpoch::Previous, &builder.spec).unwrap(); - state.build_epoch_cache(RelativeEpoch::Current, &builder.spec).unwrap(); - state.build_epoch_cache(RelativeEpoch::Next, &builder.spec).unwrap(); + state + .build_epoch_cache(RelativeEpoch::Previous, &builder.spec) + .unwrap(); + state + .build_epoch_cache(RelativeEpoch::Current, &builder.spec) + .unwrap(); + state + .build_epoch_cache(RelativeEpoch::Next, &builder.spec) + .unwrap(); let cached_state = state.clone(); diff --git a/eth2/state_processing/src/epoch_processable/tests.rs b/eth2/state_processing/src/epoch_processable/tests.rs index 353672fd1d..d683d39715 100644 --- a/eth2/state_processing/src/epoch_processable/tests.rs +++ b/eth2/state_processing/src/epoch_processable/tests.rs @@ -8,13 +8,13 @@ use types::*; fn runs_without_error() { Builder::from_env(Env::default().default_filter_or("error")).init(); - let mut builder = BeaconStateBuilder::with_random_validators(8); + let mut builder = BeaconStateBuilder::new(8); builder.spec = ChainSpec::few_validators(); - builder.genesis().unwrap(); + builder.build().unwrap(); builder.teleport_to_end_of_epoch(builder.spec.genesis_epoch + 4); - let mut state = builder.build().unwrap(); + let mut state = builder.cloned_state(); let spec = &builder.spec; state.per_epoch_processing(spec).unwrap(); diff --git a/eth2/types/src/beacon_state/builder.rs b/eth2/types/src/beacon_state/builder.rs index 7273f3658d..80e4d501f4 100644 --- a/eth2/types/src/beacon_state/builder.rs +++ b/eth2/types/src/beacon_state/builder.rs @@ -6,20 +6,19 @@ use bls::create_proof_of_possession; /// Building the `BeaconState` is a three step processes: /// /// 1. Create a new `BeaconStateBuilder`. -/// 2. Run the `genesis` function to generate a new BeaconState. +/// 2. Call `Self::build()` or `Self::build_fast()` generate a `BeaconState`. /// 3. (Optional) Use builder functions to modify the `BeaconState`. -/// 4. Call `build()` to obtain a cloned `BeaconState`. +/// 4. Call `Self::cloned_state()` to obtain a `BeaconState` cloned from this struct. /// -/// Step (2) is necessary because step (3) requires an existing `BeaconState` object. (2) is not -/// included in (1) to allow for modifying params before generating the `BeaconState` (e.g., the -/// spec). +/// Step (2) happens prior to step (3) because some functionality requires an existing +/// `BeaconState`. /// /// Step (4) produces a clone of the BeaconState and doesn't consume the `BeaconStateBuilder` to -/// allow access to the `keypairs` and `spec`. +/// allow access to `self.keypairs` and `self.spec`. pub struct BeaconStateBuilder { + pub validator_count: usize, pub state: Option, pub genesis_time: u64, - pub initial_validator_deposits: Vec, pub latest_eth1_data: Eth1Data, pub spec: ChainSpec, pub keypairs: Vec, @@ -27,21 +26,41 @@ pub struct BeaconStateBuilder { impl BeaconStateBuilder { /// Create a new builder with the given number of validators. - pub fn with_random_validators(validator_count: usize) -> Self { + pub fn new(validator_count: usize) -> Self { let genesis_time = 10_000_000; - let keypairs: Vec = (0..validator_count) + + let latest_eth1_data = Eth1Data { + deposit_root: Hash256::zero(), + block_hash: Hash256::zero(), + }; + + let spec = ChainSpec::foundation(); + + Self { + validator_count, + state: None, + genesis_time, + latest_eth1_data, + spec, + keypairs: vec![], + } + } + + pub fn build(&mut self) -> Result<(), BeaconStateError> { + self.keypairs = (0..self.validator_count) .collect::>() .iter() .map(|_| Keypair::random()) .collect(); - let initial_validator_deposits = keypairs + + let initial_validator_deposits = self.keypairs .iter() .map(|keypair| Deposit { branch: vec![], // branch verification is not specified. index: 0, // index verification is not specified. deposit_data: DepositData { amount: 32_000_000_000, // 32 ETH (in Gwei) - timestamp: genesis_time - 1, + timestamp: self.genesis_time - 1, deposit_input: DepositInput { pubkey: keypair.pk.clone(), withdrawal_credentials: Hash256::zero(), // Withdrawal not possible. @@ -50,27 +69,10 @@ impl BeaconStateBuilder { }, }) .collect(); - let latest_eth1_data = Eth1Data { - deposit_root: Hash256::zero(), - block_hash: Hash256::zero(), - }; - let spec = ChainSpec::foundation(); - Self { - state: None, - genesis_time, - initial_validator_deposits, - latest_eth1_data, - spec, - keypairs, - } - } - - /// Runs the `BeaconState::genesis` function and produces a `BeaconState`. - pub fn genesis(&mut self) -> Result<(), BeaconStateError> { let state = BeaconState::genesis( self.genesis_time, - self.initial_validator_deposits.clone(), + initial_validator_deposits, self.latest_eth1_data.clone(), &self.spec, )?; @@ -80,6 +82,40 @@ impl BeaconStateBuilder { Ok(()) } + pub fn build_fast(&mut self) -> Result<(), BeaconStateError> { + let common_keypair = Keypair::random(); + + let mut validator_registry = Vec::with_capacity(self.validator_count); + let mut validator_balances = Vec::with_capacity(self.validator_count); + self.keypairs = Vec::with_capacity(self.validator_count); + + for _ in 0..self.validator_count { + self.keypairs.push(common_keypair.clone()); + validator_balances.push(32_000_000_000); + validator_registry.push(Validator { + pubkey: common_keypair.pk.clone(), + withdrawal_credentials: Hash256::zero(), + activation_epoch: self.spec.genesis_epoch, + ..Validator::default() + }) + } + + let state = BeaconState { + validator_registry, + validator_balances, + ..BeaconState::genesis( + self.genesis_time, + vec![], + self.latest_eth1_data.clone(), + &self.spec, + )? + }; + + self.state = Some(state); + + Ok(()) + } + /// Sets the `BeaconState` to be in the last slot of the given epoch. /// /// Sets all justification/finalization parameters to be be as "perfect" as possible (i.e., @@ -145,11 +181,8 @@ impl BeaconStateBuilder { } /// Returns a cloned `BeaconState`. - pub fn build(&self) -> Result { - match &self.state { - Some(state) => Ok(state.clone()), - None => panic!("Genesis required"), - } + pub fn cloned_state(&self) -> BeaconState { + self.state.as_ref().expect("Genesis required").clone() } } diff --git a/eth2/types/src/beacon_state/tests.rs b/eth2/types/src/beacon_state/tests.rs index 01b4be8037..bb85615111 100644 --- a/eth2/types/src/beacon_state/tests.rs +++ b/eth2/types/src/beacon_state/tests.rs @@ -7,9 +7,7 @@ use ssz::{ssz_encode, Decodable}; #[test] pub fn can_produce_genesis_block() { - let mut builder = BeaconStateBuilder::with_random_validators(2); - builder.genesis().unwrap(); - + let mut builder = BeaconStateBuilder::new(2); builder.build().unwrap(); } @@ -19,12 +17,12 @@ pub fn can_produce_genesis_block() { pub fn get_attestation_participants_consistency() { let mut rng = XorShiftRng::from_seed([42; 16]); - let mut builder = BeaconStateBuilder::with_random_validators(8); + let mut builder = BeaconStateBuilder::new(8); builder.spec = ChainSpec::few_validators(); - builder.genesis().unwrap(); + builder.build().unwrap(); - let mut state = builder.build().unwrap(); + let mut state = builder.cloned_state(); let spec = builder.spec.clone(); state