From ea96d24420ffbe3c38ac9c84785abc3d1a7c877b Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 19 May 2019 16:56:39 +1000 Subject: [PATCH] Make #stateprocessingcompileagain --- .../src/per_epoch_processing.rs | 11 ++- .../src/per_epoch_processing/tests.rs | 2 +- .../validator_statuses.rs | 3 +- .../src/per_epoch_processing/winning_root.rs | 2 +- eth2/types/src/beacon_state.rs | 78 +++++++++++++------ eth2/types/src/beacon_state/epoch_cache.rs | 28 ++++++- 6 files changed, 89 insertions(+), 35 deletions(-) diff --git a/eth2/state_processing/src/per_epoch_processing.rs b/eth2/state_processing/src/per_epoch_processing.rs index 7a4d0a4128..c4d1c69a23 100644 --- a/eth2/state_processing/src/per_epoch_processing.rs +++ b/eth2/state_processing/src/per_epoch_processing.rs @@ -159,9 +159,10 @@ pub fn process_crosslinks( state.previous_crosslinks = state.current_crosslinks.clone(); - for epoch in vec![state.previous_epoch(), state.current_epoch()] { - for offset in 0..state.get_epoch_committee_count(epoch, spec) { - let shard = (state.get_epoch_start_shard(epoch, spec) + offset) % spec.shard_count; + for relative_epoch in vec![RelativeEpoch::Previous, RelativeEpoch::Current] { + let epoch = relative_epoch.into_epoch(state.current_epoch()); + for offset in 0..state.get_epoch_committee_count(relative_epoch)? { + let shard = (state.get_epoch_start_shard(relative_epoch)? + offset) % spec.shard_count; let crosslink_committee = state.get_crosslink_committee(epoch, shard, spec)?; let winning_root = winning_root(state, shard, epoch, spec)?; @@ -211,9 +212,7 @@ pub fn process_final_updates( } // Update start shard. - state.latest_start_shard = (state.latest_start_shard - + state.get_shard_delta(current_epoch, spec)) - % T::ShardCount::to_u64(); + state.latest_start_shard = state.next_epoch_start_shard()?; // This is a hack to allow us to update index roots and slashed balances for the next epoch. // diff --git a/eth2/state_processing/src/per_epoch_processing/tests.rs b/eth2/state_processing/src/per_epoch_processing/tests.rs index b075c5cd41..9841a5551a 100644 --- a/eth2/state_processing/src/per_epoch_processing/tests.rs +++ b/eth2/state_processing/src/per_epoch_processing/tests.rs @@ -1,5 +1,5 @@ #![cfg(test)] -use crate::per_epoch_processing; +use crate::per_epoch_processing::per_epoch_processing; use env_logger::{Builder, Env}; use types::test_utils::TestingBeaconStateBuilder; use types::*; diff --git a/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs b/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs index 266b358448..95cea17f49 100644 --- a/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs +++ b/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs @@ -232,7 +232,8 @@ impl ValidatorStatuses { // The inclusion slot and distance are only required for previous epoch attesters. let attestation_slot = state.get_attestation_slot(&a.data)?; let inclusion_slot = attestation_slot + a.inclusion_delay; - let relative_epoch = RelativeEpoch::from_slot(state.slot, inclusion_slot, spec)?; + let relative_epoch = + RelativeEpoch::from_slot(state.slot, inclusion_slot, spec.slots_per_epoch)?; status.inclusion_info = Some(InclusionInfo { slot: inclusion_slot, distance: a.inclusion_delay, diff --git a/eth2/state_processing/src/per_epoch_processing/winning_root.rs b/eth2/state_processing/src/per_epoch_processing/winning_root.rs index 9199f28cfe..d64af31bbb 100644 --- a/eth2/state_processing/src/per_epoch_processing/winning_root.rs +++ b/eth2/state_processing/src/per_epoch_processing/winning_root.rs @@ -42,7 +42,7 @@ pub fn winning_root( spec: &ChainSpec, ) -> Result, BeaconStateError> { let shard_attestations: Vec<&PendingAttestation> = state - .get_matching_source_attestations(epoch, spec)? + .get_matching_source_attestations(epoch)? .iter() .filter(|a| a.data.shard == shard) .collect(); diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index 42d88242d0..f193b178fb 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -4,7 +4,7 @@ use crate::test_utils::TestRandom; use crate::*; use cached_tree_hash::{Error as TreeHashCacheError, TreeHashCache}; use hashing::hash; -use int_to_bytes::int_to_bytes32; +use int_to_bytes::{int_to_bytes32, int_to_bytes8}; use pubkey_cache::PubkeyCache; use fixed_len_vec::{typenum::Unsigned, FixedLenVec}; @@ -24,6 +24,7 @@ mod pubkey_cache; mod tests; pub const CACHED_EPOCHS: usize = 3; +const MAX_RANDOM_BYTE: u64 = (1 << 8) - 1; #[derive(Debug, PartialEq)] pub enum Error { @@ -279,6 +280,27 @@ impl BeaconState { self.current_epoch() + 1 } + pub fn get_epoch_committee_count(&self, relative_epoch: RelativeEpoch) -> Result { + let cache = self.cache(relative_epoch)?; + + Ok(cache.epoch_committee_count() as u64) + } + + pub fn get_epoch_start_shard(&self, relative_epoch: RelativeEpoch) -> Result { + let cache = self.cache(relative_epoch)?; + + Ok(cache.epoch_start_shard()) + } + + pub fn next_epoch_start_shard(&self) -> Result { + let cache = self.cache(RelativeEpoch::Current)?; + + Ok( + (cache.epoch_start_shard() + cache.epoch_committee_count() as u64) + & T::shard_count() as u64, + ) + } + /// Get the slot of an attestation. /// /// Note: Utilizes the cache and will fail if the appropriate cache is not initialized. @@ -360,33 +382,41 @@ impl BeaconState { unimplemented!() } - /// Returns the beacon proposer index for the `slot`. + /// Returns the beacon proposer index for the `slot` in the given `relative_epoch`. /// - /// If the state does not contain an index for a beacon proposer at the requested `slot`, then `None` is returned. - /// - /// Spec v0.5.1 - pub fn get_beacon_proposer_index(&self, _spec: &ChainSpec) -> Result { - unimplemented!("FIXME(sproul)") - /* - let cache = self.cache(relative_epoch, spec)?; + /// Spec v0.6.1 + // NOTE: be sure to test this bad boy. + pub fn get_beacon_proposer_index( + &self, + slot: Slot, + relative_epoch: RelativeEpoch, + spec: &ChainSpec, + ) -> Result { + let cache = self.cache(relative_epoch)?; + let epoch = relative_epoch.into_epoch(self.current_epoch()); - let committees = cache - .get_crosslink_committees_at_slot(slot, spec) + let first_committee = cache + .first_committee_at_slot(slot) .ok_or_else(|| Error::SlotOutOfBounds)?; + let seed = self.generate_seed(epoch, spec)?; - let epoch = slot.epoch(spec.slots_per_epoch); - - committees - .first() - .ok_or(Error::UnableToDetermineProducer) - .and_then(|first| { - let index = epoch - .as_usize() - .checked_rem(first.committee.len()) - .ok_or(Error::UnableToDetermineProducer)?; - Ok(first.committee[index]) - }) - */ + let mut i = 0; + Ok(loop { + let candidate_index = first_committee[(epoch.as_usize() + i) % first_committee.len()]; + let random_byte = { + let mut preimage = seed.as_bytes().to_vec(); + preimage.append(&mut int_to_bytes8((i / 32) as u64)); + let hash = hash(&preimage); + hash[i % 32] + }; + let effective_balance = self.validator_registry[candidate_index].effective_balance; + if (effective_balance * MAX_RANDOM_BYTE) + >= (spec.max_effective_balance * random_byte as u64) + { + break candidate_index; + } + i += 1; + }) } /// Safely obtains the index for latest block roots, given some `slot`. diff --git a/eth2/types/src/beacon_state/epoch_cache.rs b/eth2/types/src/beacon_state/epoch_cache.rs index 33ba56071d..5072703a69 100644 --- a/eth2/types/src/beacon_state/epoch_cache.rs +++ b/eth2/types/src/beacon_state/epoch_cache.rs @@ -128,7 +128,7 @@ impl EpochCache { let committee_index = (shard + self.shard_count - self.shuffling_start_shard) % self.shard_count; - let committee = self.compute_committee(committee_index as usize, self.committee_count)?; + let committee = self.compute_committee(committee_index as usize)?; let slot = self.crosslink_slot_for_shard(shard)?; Some(CrosslinkCommittee { @@ -142,12 +142,36 @@ impl EpochCache { self.shuffling.len() } - fn compute_committee(&self, index: usize, count: usize) -> Option<&[usize]> { + pub fn epoch_committee_count(&self) -> usize { + self.committee_count + } + + pub fn epoch_start_shard(&self) -> u64 { + self.shuffling_start_shard + } + + pub fn first_committee_at_slot(&self, slot: Slot) -> Option<&[usize]> { + let position = self + .initialized_epoch? + .position(slot, self.slots_per_epoch)?; + + if position > self.committee_count { + None + } else { + let committees_per_slot = self.committee_count / self.slots_per_epoch as usize; + let index = position * committees_per_slot; + + self.compute_committee(index) + } + } + + fn compute_committee(&self, index: usize) -> Option<&[usize]> { if self.initialized_epoch.is_none() { return None; } let num_validators = self.shuffling.len(); + let count = self.committee_count; // Note: `count != 0` is enforced in the constructor. let start = (num_validators * index) / count;