Move get_active_validator_indices
to state
This commit is contained in:
parent
4c4952e71b
commit
37b8e9f39a
@ -10,10 +10,7 @@ use db::{
|
|||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::{
|
use types::{BeaconBlock, ChainSpec, Hash256, Slot, SlotHeight};
|
||||||
validator_registry::get_active_validator_indices, BeaconBlock, ChainSpec, Hash256, Slot,
|
|
||||||
SlotHeight,
|
|
||||||
};
|
|
||||||
|
|
||||||
//TODO: Pruning - Children
|
//TODO: Pruning - Children
|
||||||
//TODO: Handle Syncing
|
//TODO: Handle Syncing
|
||||||
@ -93,10 +90,8 @@ where
|
|||||||
.get_deserialized(&state_root)?
|
.get_deserialized(&state_root)?
|
||||||
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
|
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
|
||||||
|
|
||||||
let active_validator_indices = get_active_validator_indices(
|
let active_validator_indices =
|
||||||
¤t_state.validator_registry[..],
|
current_state.get_active_validator_indices(block_slot.epoch(spec.slots_per_epoch));
|
||||||
block_slot.epoch(spec.slots_per_epoch),
|
|
||||||
);
|
|
||||||
|
|
||||||
for index in active_validator_indices {
|
for index in active_validator_indices {
|
||||||
let balance = std::cmp::min(
|
let balance = std::cmp::min(
|
||||||
|
@ -10,10 +10,7 @@ use log::{debug, trace};
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::{
|
use types::{BeaconBlock, ChainSpec, Hash256, Slot, SlotHeight};
|
||||||
validator_registry::get_active_validator_indices, BeaconBlock, ChainSpec, Hash256, Slot,
|
|
||||||
SlotHeight,
|
|
||||||
};
|
|
||||||
|
|
||||||
//TODO: Pruning - Children
|
//TODO: Pruning - Children
|
||||||
//TODO: Handle Syncing
|
//TODO: Handle Syncing
|
||||||
@ -93,10 +90,8 @@ where
|
|||||||
.get_deserialized(&state_root)?
|
.get_deserialized(&state_root)?
|
||||||
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
|
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
|
||||||
|
|
||||||
let active_validator_indices = get_active_validator_indices(
|
let active_validator_indices =
|
||||||
¤t_state.validator_registry[..],
|
current_state.get_active_validator_indices(block_slot.epoch(spec.slots_per_epoch));
|
||||||
block_slot.epoch(spec.slots_per_epoch),
|
|
||||||
);
|
|
||||||
|
|
||||||
for index in active_validator_indices {
|
for index in active_validator_indices {
|
||||||
let balance = std::cmp::min(
|
let balance = std::cmp::min(
|
||||||
|
@ -8,9 +8,7 @@ use db::{
|
|||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::{
|
use types::{BeaconBlock, ChainSpec, Hash256, Slot};
|
||||||
validator_registry::get_active_validator_indices, BeaconBlock, ChainSpec, Hash256, Slot,
|
|
||||||
};
|
|
||||||
|
|
||||||
//TODO: Pruning and syncing
|
//TODO: Pruning and syncing
|
||||||
|
|
||||||
@ -61,10 +59,8 @@ where
|
|||||||
.get_deserialized(&state_root)?
|
.get_deserialized(&state_root)?
|
||||||
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
|
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
|
||||||
|
|
||||||
let active_validator_indices = get_active_validator_indices(
|
let active_validator_indices =
|
||||||
¤t_state.validator_registry[..],
|
current_state.get_active_validator_indices(block_slot.epoch(spec.slots_per_epoch));
|
||||||
block_slot.epoch(spec.slots_per_epoch),
|
|
||||||
);
|
|
||||||
|
|
||||||
for index in active_validator_indices {
|
for index in active_validator_indices {
|
||||||
let balance = std::cmp::min(
|
let balance = std::cmp::min(
|
||||||
|
@ -242,8 +242,9 @@ fn setup_inital_state(
|
|||||||
|
|
||||||
let spec = ChainSpec::foundation();
|
let spec = ChainSpec::foundation();
|
||||||
|
|
||||||
let state_builder =
|
let mut state_builder =
|
||||||
TestingBeaconStateBuilder::from_single_keypair(num_validators, &Keypair::random(), &spec);
|
TestingBeaconStateBuilder::from_single_keypair(num_validators, &Keypair::random(), &spec);
|
||||||
|
state_builder.build_caches(&spec).unwrap();
|
||||||
let (state, _keypairs) = state_builder.build();
|
let (state, _keypairs) = state_builder.build();
|
||||||
|
|
||||||
let state_root = state.canonical_root();
|
let state_root = state.canonical_root();
|
||||||
|
@ -34,7 +34,7 @@ pub fn get_genesis_state(
|
|||||||
|
|
||||||
// Set all the active index roots to be the genesis active index root.
|
// Set all the active index roots to be the genesis active index root.
|
||||||
let active_validator_indices = state
|
let active_validator_indices = state
|
||||||
.get_active_validator_indices(spec.genesis_epoch, spec)?
|
.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?
|
||||||
.to_vec();
|
.to_vec();
|
||||||
let genesis_active_index_root = Hash256::from_slice(&active_validator_indices.hash_tree_root());
|
let genesis_active_index_root = Hash256::from_slice(&active_validator_indices.hash_tree_root());
|
||||||
state.fill_active_index_roots_with(genesis_active_index_root, spec);
|
state.fill_active_index_roots_with(genesis_active_index_root, spec);
|
||||||
|
@ -7,7 +7,7 @@ use process_validator_registry::process_validator_registry;
|
|||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use ssz::TreeHash;
|
use ssz::TreeHash;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use types::{validator_registry::get_active_validator_indices, *};
|
use types::*;
|
||||||
use validator_statuses::{TotalBalances, ValidatorStatuses};
|
use validator_statuses::{TotalBalances, ValidatorStatuses};
|
||||||
use winning_root::{winning_root, WinningRoot};
|
use winning_root::{winning_root, WinningRoot};
|
||||||
|
|
||||||
@ -70,16 +70,6 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of active validator indices for the state's current epoch.
|
|
||||||
///
|
|
||||||
/// Spec v0.5.0
|
|
||||||
pub fn calculate_active_validator_indices(state: &BeaconState, spec: &ChainSpec) -> Vec<usize> {
|
|
||||||
get_active_validator_indices(
|
|
||||||
&state.validator_registry,
|
|
||||||
state.slot.epoch(spec.slots_per_epoch),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculates various sets of attesters, including:
|
/// Calculates various sets of attesters, including:
|
||||||
///
|
///
|
||||||
/// - current epoch attesters
|
/// - current epoch attesters
|
||||||
@ -454,10 +444,9 @@ pub fn update_active_tree_index_roots(
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let next_epoch = state.next_epoch(spec);
|
let next_epoch = state.next_epoch(spec);
|
||||||
|
|
||||||
let active_tree_root = get_active_validator_indices(
|
let active_tree_root = state
|
||||||
&state.validator_registry,
|
.get_active_validator_indices(next_epoch + Epoch::from(spec.activation_exit_delay))
|
||||||
next_epoch + Epoch::from(spec.activation_exit_delay),
|
.to_vec()
|
||||||
)
|
|
||||||
.hash_tree_root();
|
.hash_tree_root();
|
||||||
|
|
||||||
state.set_active_index_root(next_epoch, Hash256::from_slice(&active_tree_root[..]), spec)?;
|
state.set_active_index_root(next_epoch, Hash256::from_slice(&active_tree_root[..]), spec)?;
|
||||||
|
@ -9,7 +9,7 @@ pub fn process_ejections(state: &mut BeaconState, spec: &ChainSpec) -> Result<()
|
|||||||
// There is an awkward double (triple?) loop here because we can't loop across the borrowed
|
// There is an awkward double (triple?) loop here because we can't loop across the borrowed
|
||||||
// active validator indices and mutate state in the one loop.
|
// active validator indices and mutate state in the one loop.
|
||||||
let exitable: Vec<usize> = state
|
let exitable: Vec<usize> = state
|
||||||
.get_active_validator_indices(state.current_epoch(spec), spec)?
|
.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|&i| {
|
.filter_map(|&i| {
|
||||||
if state.validator_balances[i as usize] < spec.ejection_balance {
|
if state.validator_balances[i as usize] < spec.ejection_balance {
|
||||||
|
@ -7,7 +7,8 @@ use types::{BeaconStateError as Error, *};
|
|||||||
/// Spec v0.4.0
|
/// Spec v0.4.0
|
||||||
pub fn process_slashings(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> {
|
pub fn process_slashings(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> {
|
||||||
let current_epoch = state.current_epoch(spec);
|
let current_epoch = state.current_epoch(spec);
|
||||||
let active_validator_indices = state.get_active_validator_indices(current_epoch, spec)?;
|
let active_validator_indices =
|
||||||
|
state.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?;
|
||||||
let total_balance = state.get_total_balance(&active_validator_indices[..], spec)?;
|
let total_balance = state.get_total_balance(&active_validator_indices[..], spec)?;
|
||||||
|
|
||||||
for (index, validator) in state.validator_registry.iter().enumerate() {
|
for (index, validator) in state.validator_registry.iter().enumerate() {
|
||||||
|
@ -21,7 +21,7 @@ pub fn process_validator_registry(state: &mut BeaconState, spec: &ChainSpec) ->
|
|||||||
state.current_shuffling_start_shard = (state.current_shuffling_start_shard
|
state.current_shuffling_start_shard = (state.current_shuffling_start_shard
|
||||||
+ spec.get_epoch_committee_count(
|
+ spec.get_epoch_committee_count(
|
||||||
state
|
state
|
||||||
.get_active_validator_indices(current_epoch, spec)?
|
.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?
|
||||||
.len(),
|
.len(),
|
||||||
) as u64)
|
) as u64)
|
||||||
% spec.shard_count;
|
% spec.shard_count;
|
||||||
@ -53,7 +53,7 @@ pub fn should_update_validator_registry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let num_active_validators = state
|
let num_active_validators = state
|
||||||
.get_active_validator_indices(state.current_epoch(spec), spec)?
|
.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?
|
||||||
.len();
|
.len();
|
||||||
let current_epoch_committee_count = spec.get_epoch_committee_count(num_active_validators);
|
let current_epoch_committee_count = spec.get_epoch_committee_count(num_active_validators);
|
||||||
|
|
||||||
|
@ -8,7 +8,8 @@ use types::{BeaconStateError as Error, *};
|
|||||||
/// Spec v0.4.0
|
/// Spec v0.4.0
|
||||||
pub fn update_validator_registry(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> {
|
pub fn update_validator_registry(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> {
|
||||||
let current_epoch = state.current_epoch(spec);
|
let current_epoch = state.current_epoch(spec);
|
||||||
let active_validator_indices = state.get_active_validator_indices(current_epoch, spec)?;
|
let active_validator_indices =
|
||||||
|
state.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?;
|
||||||
let total_balance = state.get_total_balance(&active_validator_indices[..], spec)?;
|
let total_balance = state.get_total_balance(&active_validator_indices[..], spec)?;
|
||||||
|
|
||||||
let max_balance_churn = std::cmp::max(
|
let max_balance_churn = std::cmp::max(
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use self::epoch_cache::{EpochCache, Error as EpochCacheError};
|
use self::epoch_cache::{get_active_validator_indices, EpochCache, Error as EpochCacheError};
|
||||||
use crate::test_utils::TestRandom;
|
use crate::test_utils::TestRandom;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use int_to_bytes::int_to_bytes32;
|
use int_to_bytes::int_to_bytes32;
|
||||||
@ -234,28 +234,31 @@ impl BeaconState {
|
|||||||
/// Returns the active validator indices for the given epoch, assuming there is no validator
|
/// Returns the active validator indices for the given epoch, assuming there is no validator
|
||||||
/// registry update in the next epoch.
|
/// registry update in the next epoch.
|
||||||
///
|
///
|
||||||
|
/// This uses the cache, so it saves an iteration over the validator registry, however it can
|
||||||
|
/// not return a result for any epoch before the previous epoch.
|
||||||
|
///
|
||||||
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
|
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
|
||||||
///
|
///
|
||||||
/// Spec v0.5.0
|
/// Spec v0.5.0
|
||||||
pub fn get_active_validator_indices(
|
pub fn get_cached_active_validator_indices(
|
||||||
&self,
|
&self,
|
||||||
epoch: Epoch,
|
relative_epoch: RelativeEpoch,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<&[usize], Error> {
|
) -> Result<&[usize], Error> {
|
||||||
// If the slot is in the next epoch, assume there was no validator registry update.
|
|
||||||
let relative_epoch =
|
|
||||||
match RelativeEpoch::from_epoch(self.slot.epoch(spec.slots_per_epoch), epoch) {
|
|
||||||
Err(RelativeEpochError::AmbiguiousNextEpoch) => {
|
|
||||||
Ok(RelativeEpoch::NextWithoutRegistryChange)
|
|
||||||
}
|
|
||||||
e => e,
|
|
||||||
}?;
|
|
||||||
|
|
||||||
let cache = self.cache(relative_epoch, spec)?;
|
let cache = self.cache(relative_epoch, spec)?;
|
||||||
|
|
||||||
Ok(&cache.active_validator_indices)
|
Ok(&cache.active_validator_indices)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the active validator indices for the given epoch.
|
||||||
|
///
|
||||||
|
/// Does not utilize the cache, performs a full iteration over the validator registry.
|
||||||
|
///
|
||||||
|
/// Spec v0.5.0
|
||||||
|
pub fn get_active_validator_indices(&self, epoch: Epoch) -> Vec<usize> {
|
||||||
|
get_active_validator_indices(&self.validator_registry, epoch)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the crosslink committees for some slot.
|
/// Returns the crosslink committees for some slot.
|
||||||
///
|
///
|
||||||
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
|
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
|
||||||
|
@ -7,15 +7,19 @@ use swap_or_not_shuffle::shuffle_list;
|
|||||||
fn do_sane_cache_test(
|
fn do_sane_cache_test(
|
||||||
state: BeaconState,
|
state: BeaconState,
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
|
relative_epoch: RelativeEpoch,
|
||||||
validator_count: usize,
|
validator_count: usize,
|
||||||
expected_seed: Hash256,
|
expected_seed: Hash256,
|
||||||
expected_shuffling_start: u64,
|
expected_shuffling_start: u64,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) {
|
) {
|
||||||
let active_indices: Vec<usize> = (0..validator_count).collect();
|
let active_indices: Vec<usize> = (0..validator_count).collect();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&active_indices[..],
|
&active_indices[..],
|
||||||
state.get_active_validator_indices(epoch, &spec).unwrap(),
|
state
|
||||||
|
.get_cached_active_validator_indices(relative_epoch, &spec)
|
||||||
|
.unwrap(),
|
||||||
"Validator indices mismatch"
|
"Validator indices mismatch"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -101,6 +105,7 @@ fn builds_sane_current_epoch_cache() {
|
|||||||
do_sane_cache_test(
|
do_sane_cache_test(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
state.current_epoch(&spec),
|
state.current_epoch(&spec),
|
||||||
|
RelativeEpoch::Current,
|
||||||
validator_count as usize,
|
validator_count as usize,
|
||||||
state.current_shuffling_seed,
|
state.current_shuffling_seed,
|
||||||
state.current_shuffling_start_shard,
|
state.current_shuffling_start_shard,
|
||||||
@ -117,6 +122,7 @@ fn builds_sane_previous_epoch_cache() {
|
|||||||
do_sane_cache_test(
|
do_sane_cache_test(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
state.previous_epoch(&spec),
|
state.previous_epoch(&spec),
|
||||||
|
RelativeEpoch::Previous,
|
||||||
validator_count as usize,
|
validator_count as usize,
|
||||||
state.previous_shuffling_seed,
|
state.previous_shuffling_seed,
|
||||||
state.previous_shuffling_start_shard,
|
state.previous_shuffling_start_shard,
|
||||||
@ -134,6 +140,7 @@ fn builds_sane_next_without_update_epoch_cache() {
|
|||||||
do_sane_cache_test(
|
do_sane_cache_test(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
state.next_epoch(&spec),
|
state.next_epoch(&spec),
|
||||||
|
RelativeEpoch::NextWithoutRegistryChange,
|
||||||
validator_count as usize,
|
validator_count as usize,
|
||||||
state.current_shuffling_seed,
|
state.current_shuffling_seed,
|
||||||
state.current_shuffling_start_shard,
|
state.current_shuffling_start_shard,
|
||||||
|
@ -6,13 +6,17 @@ type ValidatorIndex = usize;
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
|
||||||
pub struct PubkeyCache {
|
pub struct PubkeyCache {
|
||||||
|
/// Maintain the number of keys added to the map. It is not sufficient to just use the HashMap
|
||||||
|
/// len, as it does not increase when duplicate keys are added. Duplicate keys are used during
|
||||||
|
/// testing.
|
||||||
|
len: usize,
|
||||||
map: HashMap<PublicKey, ValidatorIndex>,
|
map: HashMap<PublicKey, ValidatorIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PubkeyCache {
|
impl PubkeyCache {
|
||||||
/// Returns the number of validator indices already in the map.
|
/// Returns the number of validator indices added to the map so far.
|
||||||
pub fn len(&self) -> ValidatorIndex {
|
pub fn len(&self) -> ValidatorIndex {
|
||||||
self.map.len()
|
self.len
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a validator index into the map.
|
/// Inserts a validator index into the map.
|
||||||
@ -20,8 +24,9 @@ impl PubkeyCache {
|
|||||||
/// The added index must equal the number of validators already added to the map. This ensures
|
/// The added index must equal the number of validators already added to the map. This ensures
|
||||||
/// that an index is never skipped.
|
/// that an index is never skipped.
|
||||||
pub fn insert(&mut self, pubkey: PublicKey, index: ValidatorIndex) -> bool {
|
pub fn insert(&mut self, pubkey: PublicKey, index: ValidatorIndex) -> bool {
|
||||||
if index == self.map.len() {
|
if index == self.len {
|
||||||
self.map.insert(pubkey, index);
|
self.map.insert(pubkey, index);
|
||||||
|
self.len += 1;
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -117,7 +117,7 @@ pub struct ChainSpec {
|
|||||||
impl ChainSpec {
|
impl ChainSpec {
|
||||||
/// Return the number of committees in one epoch.
|
/// Return the number of committees in one epoch.
|
||||||
///
|
///
|
||||||
/// Spec v0.4.0
|
/// Spec v0.5.0
|
||||||
pub fn get_epoch_committee_count(&self, active_validator_count: usize) -> u64 {
|
pub fn get_epoch_committee_count(&self, active_validator_count: usize) -> u64 {
|
||||||
std::cmp::max(
|
std::cmp::max(
|
||||||
1,
|
1,
|
||||||
|
@ -34,7 +34,6 @@ pub mod relative_epoch;
|
|||||||
pub mod slot_epoch;
|
pub mod slot_epoch;
|
||||||
pub mod slot_height;
|
pub mod slot_height;
|
||||||
pub mod validator;
|
pub mod validator;
|
||||||
pub mod validator_registry;
|
|
||||||
|
|
||||||
use ethereum_types::{H160, H256, U256};
|
use ethereum_types::{H160, H256, U256};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -9,7 +9,7 @@ use test_random_derive::TestRandom;
|
|||||||
|
|
||||||
/// The data submitted to the deposit contract.
|
/// The data submitted to the deposit contract.
|
||||||
///
|
///
|
||||||
/// Spec v0.4.0
|
/// Spec v0.5.0
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug,
|
Debug,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
|
@ -1,174 +0,0 @@
|
|||||||
/// Contains logic to manipulate a `&[Validator]`.
|
|
||||||
/// For now, we avoid defining a newtype and just have flat functions here.
|
|
||||||
use super::validator::*;
|
|
||||||
use crate::Epoch;
|
|
||||||
|
|
||||||
/// Given an indexed sequence of `validators`, return the indices corresponding to validators that are active at `epoch`.
|
|
||||||
///
|
|
||||||
/// Spec v0.4.0
|
|
||||||
pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec<usize> {
|
|
||||||
let mut active = Vec::with_capacity(validators.len());
|
|
||||||
|
|
||||||
for (index, validator) in validators.iter().enumerate() {
|
|
||||||
if validator.is_active_at(epoch) {
|
|
||||||
active.push(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
active.shrink_to_fit();
|
|
||||||
|
|
||||||
active
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_get_empty_active_validator_indices() {
|
|
||||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
|
||||||
|
|
||||||
let validators = vec![];
|
|
||||||
let some_epoch = Epoch::random_for_test(&mut rng);
|
|
||||||
let indices = get_active_validator_indices(&validators, some_epoch);
|
|
||||||
assert_eq!(indices, vec![]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_get_no_active_validator_indices() {
|
|
||||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
|
||||||
let mut validators = vec![];
|
|
||||||
let count_validators = 10;
|
|
||||||
for _ in 0..count_validators {
|
|
||||||
validators.push(Validator::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
let some_epoch = Epoch::random_for_test(&mut rng);
|
|
||||||
let indices = get_active_validator_indices(&validators, some_epoch);
|
|
||||||
assert_eq!(indices, vec![]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_get_all_active_validator_indices() {
|
|
||||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
|
||||||
let count_validators = 10;
|
|
||||||
let some_epoch = Epoch::random_for_test(&mut rng);
|
|
||||||
|
|
||||||
let mut validators = (0..count_validators)
|
|
||||||
.into_iter()
|
|
||||||
.map(|_| {
|
|
||||||
let mut validator = Validator::default();
|
|
||||||
|
|
||||||
let activation_offset = u64::random_for_test(&mut rng);
|
|
||||||
let exit_offset = u64::random_for_test(&mut rng);
|
|
||||||
|
|
||||||
validator.activation_epoch = some_epoch - activation_offset;
|
|
||||||
validator.exit_epoch = some_epoch + exit_offset;
|
|
||||||
|
|
||||||
validator
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// test boundary condition by ensuring that at least one validator in the list just activated
|
|
||||||
if let Some(validator) = validators.get_mut(0) {
|
|
||||||
validator.activation_epoch = some_epoch;
|
|
||||||
}
|
|
||||||
|
|
||||||
let indices = get_active_validator_indices(&validators, some_epoch);
|
|
||||||
assert_eq!(
|
|
||||||
indices,
|
|
||||||
(0..count_validators).into_iter().collect::<Vec<_>>()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_validators_to_default_entry_exit(validators: &mut [Validator]) {
|
|
||||||
for validator in validators.iter_mut() {
|
|
||||||
validator.activation_epoch = Epoch::max_value();
|
|
||||||
validator.exit_epoch = Epoch::max_value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets all `validators` to be active as of some epoch prior to `epoch`. returns the activation epoch.
|
|
||||||
fn set_validators_to_activated(validators: &mut [Validator], epoch: Epoch) -> Epoch {
|
|
||||||
let activation_epoch = epoch - 10;
|
|
||||||
for validator in validators.iter_mut() {
|
|
||||||
validator.activation_epoch = activation_epoch;
|
|
||||||
}
|
|
||||||
activation_epoch
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets all `validators` to be exited as of some epoch before `epoch`.
|
|
||||||
fn set_validators_to_exited(
|
|
||||||
validators: &mut [Validator],
|
|
||||||
epoch: Epoch,
|
|
||||||
activation_epoch: Epoch,
|
|
||||||
) {
|
|
||||||
assert!(activation_epoch < epoch);
|
|
||||||
let mut exit_epoch = activation_epoch + 10;
|
|
||||||
while exit_epoch >= epoch {
|
|
||||||
exit_epoch -= 1;
|
|
||||||
}
|
|
||||||
assert!(activation_epoch < exit_epoch && exit_epoch < epoch);
|
|
||||||
|
|
||||||
for validator in validators.iter_mut() {
|
|
||||||
validator.exit_epoch = exit_epoch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_get_some_active_validator_indices() {
|
|
||||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
|
||||||
const COUNT_PARTITIONS: usize = 3;
|
|
||||||
const COUNT_VALIDATORS: usize = 3 * COUNT_PARTITIONS;
|
|
||||||
let some_epoch: Epoch = Epoch::random_for_test(&mut rng);
|
|
||||||
|
|
||||||
let mut validators = (0..COUNT_VALIDATORS)
|
|
||||||
.into_iter()
|
|
||||||
.map(|_| {
|
|
||||||
let mut validator = Validator::default();
|
|
||||||
|
|
||||||
let activation_offset = Epoch::random_for_test(&mut rng);
|
|
||||||
let exit_offset = Epoch::random_for_test(&mut rng);
|
|
||||||
|
|
||||||
validator.activation_epoch = some_epoch - activation_offset;
|
|
||||||
validator.exit_epoch = some_epoch + exit_offset;
|
|
||||||
|
|
||||||
validator
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// we partition the set into partitions based on lifecycle:
|
|
||||||
for (i, chunk) in validators.chunks_exact_mut(COUNT_PARTITIONS).enumerate() {
|
|
||||||
match i {
|
|
||||||
0 => {
|
|
||||||
// 1. not activated (Default::default())
|
|
||||||
set_validators_to_default_entry_exit(chunk);
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
// 2. activated, but not exited
|
|
||||||
set_validators_to_activated(chunk, some_epoch);
|
|
||||||
// test boundary condition by ensuring that at least one validator in the list just activated
|
|
||||||
if let Some(validator) = chunk.get_mut(0) {
|
|
||||||
validator.activation_epoch = some_epoch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
// 3. exited
|
|
||||||
let activation_epoch = set_validators_to_activated(chunk, some_epoch);
|
|
||||||
set_validators_to_exited(chunk, some_epoch, activation_epoch);
|
|
||||||
// test boundary condition by ensuring that at least one validator in the list just exited
|
|
||||||
if let Some(validator) = chunk.get_mut(0) {
|
|
||||||
validator.exit_epoch = some_epoch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(
|
|
||||||
"constants local to this test not in sync with generation of test case"
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let indices = get_active_validator_indices(&validators, some_epoch);
|
|
||||||
assert_eq!(indices, vec![3, 4, 5]);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user