diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index c16337fd4..6c7a8c751 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -253,6 +253,7 @@ where /// 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 { + trace!("BeaconChain::block_proposer: slot: {}", slot); let index = self .state .read() @@ -274,6 +275,10 @@ where &self, validator_index: usize, ) -> Result, BeaconStateError> { + trace!( + "BeaconChain::validator_attestion_slot_and_shard: validator_index: {}", + validator_index + ); if let Some((slot, shard, _committee)) = self .state .read() @@ -287,6 +292,7 @@ where /// Produce an `AttestationData` that is valid for the present `slot` and given `shard`. pub fn produce_attestation_data(&self, shard: u64) -> Result { + trace!("BeaconChain::produce_attestation_data: shard: {}", shard); let justified_epoch = self.justified_epoch(); let justified_block_root = *self .state diff --git a/beacon_node/beacon_chain/src/cached_beacon_state.rs b/beacon_node/beacon_chain/src/cached_beacon_state.rs new file mode 100644 index 000000000..4717d1744 --- /dev/null +++ b/beacon_node/beacon_chain/src/cached_beacon_state.rs @@ -0,0 +1,49 @@ +use types::{beacon_state::BeaconStateError, BeaconState, ChainSpec, Epoch, Slot}; + +pub const CACHED_EPOCHS: usize = 3; // previous, current, next. + +pub type CrosslinkCommittees = Vec<(Vec, u64)>; + +pub struct CachedBeaconState<'a> { + state: BeaconState, + crosslinks: Vec>, + spec: &'a ChainSpec, +} + +impl<'a> CachedBeaconState<'a> { + pub fn from_beacon_state( + state: BeaconState, + spec: &'a ChainSpec, + ) -> Result { + let current_epoch = state.current_epoch(spec); + let previous_epoch = if current_epoch == spec.genesis_epoch { + current_epoch + } else { + current_epoch.saturating_sub(1_u64) + }; + let next_epoch = state.next_epoch(spec); + + let mut crosslinks: Vec> = Vec::with_capacity(3); + crosslinks.push(committees_for_all_slots(&state, previous_epoch, spec)?); + crosslinks.push(committees_for_all_slots(&state, current_epoch, spec)?); + crosslinks.push(committees_for_all_slots(&state, next_epoch, spec)?); + + Ok(Self { + state, + crosslinks, + spec, + }) + } +} + +fn committees_for_all_slots( + state: &BeaconState, + epoch: Epoch, + spec: &ChainSpec, +) -> Result, BeaconStateError> { + let mut crosslinks: Vec = Vec::with_capacity(spec.epoch_length as usize); + for slot in epoch.slot_iter(spec.epoch_length) { + crosslinks.push(state.get_crosslink_committees_at_slot(slot, false, spec)?) + } + Ok(crosslinks) +} diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 4dac0b672..bc9085fbe 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -1,5 +1,6 @@ mod attestation_aggregator; mod beacon_chain; +mod cached_beacon_state; mod checkpoint; pub use self::beacon_chain::{BeaconChain, Error}; diff --git a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs index acba2e015..5ea681ca3 100644 --- a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs +++ b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs @@ -209,6 +209,7 @@ impl BeaconChainHarness { self.increment_beacon_chain_slot(); // Produce a new block. + debug!("Producing block..."); let block = self.produce_block(); debug!("Submitting block for processing..."); self.beacon_chain.process_block(block).unwrap(); diff --git a/beacon_node/beacon_chain/test_harness/tests/chain.rs b/beacon_node/beacon_chain/test_harness/tests/chain.rs index 8be6f2a26..13e276abb 100644 --- a/beacon_node/beacon_chain/test_harness/tests/chain.rs +++ b/beacon_node/beacon_chain/test_harness/tests/chain.rs @@ -1,19 +1,14 @@ use env_logger::{Builder, Env}; use log::debug; use test_harness::BeaconChainHarness; -use types::{ChainSpec, Slot}; +use types::ChainSpec; #[test] -#[ignore] fn it_can_build_on_genesis_block() { - let mut spec = ChainSpec::foundation(); - spec.genesis_slot = Slot::new(spec.epoch_length * 8); + Builder::from_env(Env::default().default_filter_or("trace")).init(); + let spec = ChainSpec::few_validators(); - /* - spec.shard_count = spec.shard_count / 8; - spec.target_committee_size = spec.target_committee_size / 8; - */ - let validator_count = 1000; + let validator_count = 8; let mut harness = BeaconChainHarness::new(spec, validator_count as usize); @@ -23,7 +18,7 @@ fn it_can_build_on_genesis_block() { #[test] #[ignore] fn it_can_produce_past_first_epoch_boundary() { - Builder::from_env(Env::default().default_filter_or("debug")).init(); + Builder::from_env(Env::default().default_filter_or("trace")).init(); let validator_count = 100; @@ -33,7 +28,7 @@ fn it_can_produce_past_first_epoch_boundary() { debug!("Harness built, tests starting.."); - let blocks = harness.spec.epoch_length * 3 + 1; + let blocks = harness.spec.epoch_length * 2 + 1; for i in 0..blocks { harness.advance_chain_with_block(); diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index af815cbe2..aa6690705 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -6,6 +6,7 @@ use crate::{ }; use bls::verify_proof_of_possession; use honey_badger_split::SplitExt; +use log::trace; use rand::RngCore; use serde_derive::Serialize; use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; @@ -259,11 +260,24 @@ impl BeaconState { let active_validator_indices = get_active_validator_indices(&self.validator_registry, epoch); + if active_validator_indices.is_empty() { + return None; + } + + trace!( + "BeaconState::get_shuffling: active_validator_indices.len() == {}", + active_validator_indices.len() + ); + let committees_per_epoch = self.get_epoch_committee_count(active_validator_indices.len(), spec); - let mut shuffled_active_validator_indices = - Vec::with_capacity(active_validator_indices.len()); + trace!( + "BeaconState::get_shuffling: active_validator_indices.len() == {}, committees_per_epoch: {}", + active_validator_indices.len(), committees_per_epoch + ); + + let mut shuffled_active_validator_indices = vec![0; active_validator_indices.len()]; for &i in &active_validator_indices { let shuffled_i = get_permutated_index( i, @@ -317,9 +331,17 @@ impl BeaconState { + 1; let latest_index_root = current_epoch + spec.entry_exit_delay; + trace!( + "BeaconState::get_active_index_root: epoch: {}, earliest: {}, latest: {}", + epoch, + earliest_index_root, + latest_index_root + ); + if (epoch >= earliest_index_root) & (epoch <= latest_index_root) { Some(self.latest_index_roots[epoch.as_usize() % spec.latest_index_roots_length]) } else { + trace!("BeaconState::get_active_index_root: epoch out of range."); None } } @@ -371,8 +393,14 @@ impl BeaconState { }; let next_epoch = self.next_epoch(spec); + trace!( + "BeaconState::get_crosslink_committees_at_slot: epoch: {}", + epoch + ); + let (committees_per_epoch, seed, shuffling_epoch, shuffling_start_shard) = if epoch == previous_epoch { + trace!("BeaconState::get_crosslink_committees_at_slot: epoch == previous_epoch"); ( self.get_previous_epoch_committee_count(spec), self.previous_epoch_seed, @@ -380,6 +408,7 @@ impl BeaconState { self.previous_epoch_start_shard, ) } else if epoch == current_epoch { + trace!("BeaconState::get_crosslink_committees_at_slot: epoch == current_epoch"); ( self.get_current_epoch_committee_count(spec), self.current_epoch_seed, @@ -387,6 +416,7 @@ impl BeaconState { self.current_epoch_start_shard, ) } else if epoch == next_epoch { + trace!("BeaconState::get_crosslink_committees_at_slot: epoch == next_epoch"); let current_committees_per_epoch = self.get_current_epoch_committee_count(spec); let epochs_since_last_registry_update = current_epoch - self.validator_registry_update_epoch; @@ -423,6 +453,12 @@ impl BeaconState { let slot_start_shard = (shuffling_start_shard + committees_per_slot * offset) % spec.shard_count; + trace!( + "BeaconState::get_crosslink_committees_at_slot: committees_per_slot: {}, slot_start_shard: {}", + committees_per_slot, + slot_start_shard + ); + let mut crosslinks_at_slot = vec![]; for i in 0..committees_per_slot { let tuple = ( @@ -474,6 +510,11 @@ impl BeaconState { spec: &ChainSpec, ) -> Result { let committees = self.get_crosslink_committees_at_slot(slot, false, spec)?; + trace!( + "get_beacon_proposer_index: slot: {}, committees_count: {}", + slot, + committees.len() + ); committees .first() .ok_or(BeaconStateError::InsufficientValidators) diff --git a/eth2/types/src/spec/few_validators.rs b/eth2/types/src/spec/few_validators.rs new file mode 100644 index 000000000..05fe4c6cd --- /dev/null +++ b/eth2/types/src/spec/few_validators.rs @@ -0,0 +1,21 @@ +use crate::{ChainSpec, Slot}; + +impl ChainSpec { + /// Returns a `ChainSpec` compatible with the specification suitable for 8 validators. + /// + /// Spec v0.2.0 + pub fn few_validators() -> Self { + let genesis_slot = Slot::new(2_u64.pow(19)); + let epoch_length = 8; + let genesis_epoch = genesis_slot.epoch(epoch_length); + + Self { + shard_count: 1, + target_committee_size: 1, + genesis_slot, + genesis_epoch, + epoch_length, + ..ChainSpec::foundation() + } + } +} diff --git a/eth2/types/src/spec/mod.rs b/eth2/types/src/spec/mod.rs index 3632108ca..3e983a148 100644 --- a/eth2/types/src/spec/mod.rs +++ b/eth2/types/src/spec/mod.rs @@ -1,3 +1,4 @@ +mod few_validators; mod foundation; use crate::{Address, Epoch, Hash256, Slot};