diff --git a/eth2/types/Cargo.toml b/eth2/types/Cargo.toml index fefd431a3..4c5be65b5 100644 --- a/eth2/types/Cargo.toml +++ b/eth2/types/Cargo.toml @@ -18,7 +18,7 @@ serde_derive = "1.0" serde_json = "1.0" slog = "^2.2.3" ssz = { path = "../utils/ssz" } -fisher_yates_shuffle = { path = "../utils/fisher_yates_shuffle" } +swap_or_not_shuffle = { path = "../utils/swap_or_not_shuffle" } [dev-dependencies] env_logger = "0.6.0" diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index d826344de..af815cbe2 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -5,15 +5,16 @@ use crate::{ PendingAttestation, PublicKey, Signature, Slot, Validator, }; use bls::verify_proof_of_possession; -use fisher_yates_shuffle::shuffle; use honey_badger_split::SplitExt; use rand::RngCore; use serde_derive::Serialize; use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use swap_or_not_shuffle::get_permutated_index; #[derive(Debug, PartialEq)] pub enum BeaconStateError { EpochOutOfBounds, + UnableToShuffle, InsufficientRandaoMixes, InsufficientValidators, InsufficientBlockRoots, @@ -249,23 +250,36 @@ impl BeaconState { /// committee is itself a list of validator indices. /// /// Spec v0.1 - pub fn get_shuffling(&self, seed: Hash256, epoch: Epoch, spec: &ChainSpec) -> Vec> { + pub fn get_shuffling( + &self, + seed: Hash256, + epoch: Epoch, + spec: &ChainSpec, + ) -> Option>> { let active_validator_indices = get_active_validator_indices(&self.validator_registry, epoch); let committees_per_epoch = self.get_epoch_committee_count(active_validator_indices.len(), spec); - // TODO: check that Hash256::from(u64) matches 'int_to_bytes32'. - let seed = seed ^ Hash256::from(epoch.as_u64()); - // TODO: fix `expect` assert. - let shuffled_active_validator_indices = - shuffle(&seed, active_validator_indices).expect("Max validator count exceed!"); + let mut shuffled_active_validator_indices = + Vec::with_capacity(active_validator_indices.len()); + for &i in &active_validator_indices { + let shuffled_i = get_permutated_index( + i, + active_validator_indices.len(), + &seed[..], + spec.shuffle_round_count, + )?; + shuffled_active_validator_indices[i] = active_validator_indices[shuffled_i] + } - shuffled_active_validator_indices - .honey_badger_split(committees_per_epoch as usize) - .map(|slice: &[usize]| slice.to_vec()) - .collect() + Some( + shuffled_active_validator_indices + .honey_badger_split(committees_per_epoch as usize) + .map(|slice: &[usize]| slice.to_vec()) + .collect(), + ) } /// Return the number of committees in the previous epoch. @@ -401,7 +415,9 @@ impl BeaconState { return Err(BeaconStateError::EpochOutOfBounds); }; - let shuffling = self.get_shuffling(seed, shuffling_epoch, spec); + let shuffling = self + .get_shuffling(seed, shuffling_epoch, spec) + .ok_or_else(|| BeaconStateError::UnableToShuffle)?; let offset = slot.as_u64() % spec.epoch_length; let committees_per_slot = committees_per_epoch / spec.epoch_length; let slot_start_shard = diff --git a/eth2/types/src/spec/mod.rs b/eth2/types/src/spec/mod.rs index 53c78a2c2..3632108ca 100644 --- a/eth2/types/src/spec/mod.rs +++ b/eth2/types/src/spec/mod.rs @@ -17,7 +17,7 @@ pub struct ChainSpec { pub beacon_chain_shard_number: u64, pub max_indices_per_slashable_vote: u64, pub max_withdrawals_per_epoch: u64, - pub shuffle_round_count: u64, + pub shuffle_round_count: u8, /* * Deposit contract