Merge branch 'master' into paul-sync

This commit is contained in:
Paul Hauner
2019-03-22 07:11:04 +11:00
62 changed files with 1506 additions and 1386 deletions

View File

@@ -71,7 +71,7 @@ impl BeaconBlock {
/// Note: performs a full tree-hash of `self.body`.
///
/// Spec v0.5.0
pub fn into_header(&self) -> BeaconBlockHeader {
pub fn block_header(&self) -> BeaconBlockHeader {
BeaconBlockHeader {
slot: self.slot,
previous_block_root: self.previous_block_root,
@@ -84,11 +84,11 @@ impl BeaconBlock {
/// Returns a "temporary" header, where the `state_root` is `spec.zero_hash`.
///
/// Spec v0.5.0
pub fn into_temporary_header(&self, spec: &ChainSpec) -> BeaconBlockHeader {
pub fn temporary_block_header(&self, spec: &ChainSpec) -> BeaconBlockHeader {
BeaconBlockHeader {
state_root: spec.zero_hash,
signature: spec.empty_signature.clone(),
..self.into_header()
..self.block_header()
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -107,6 +107,7 @@ impl EpochCache {
})
}
/// Return a vec of `CrosslinkCommittee` for a given slot.
pub fn get_crosslink_committees_at_slot(
&self,
slot: Slot,
@@ -116,6 +117,8 @@ impl EpochCache {
.get_crosslink_committees_at_slot(slot, spec)
}
/// Return `Some(CrosslinkCommittee)` if the given shard has a committee during the given
/// `epoch`.
pub fn get_crosslink_committee_for_shard(
&self,
shard: Shard,
@@ -131,6 +134,10 @@ impl EpochCache {
}
}
/// Returns a list of all `validator_registry` indices where the validator is active at the given
/// `epoch`.
///
/// Spec v0.5.0
pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec<usize> {
let mut active = Vec::with_capacity(validators.len());
@@ -145,13 +152,17 @@ pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> V
active
}
/// Contains all `CrosslinkCommittees` for an epoch.
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
pub struct EpochCrosslinkCommittees {
/// The epoch the committees are present in.
epoch: Epoch,
/// Each commitee for each slot of the epoch.
pub crosslink_committees: Vec<Vec<CrosslinkCommittee>>,
}
impl EpochCrosslinkCommittees {
/// Return a new instances where all slots have zero committees.
fn new(epoch: Epoch, spec: &ChainSpec) -> Self {
Self {
epoch,
@@ -159,6 +170,7 @@ impl EpochCrosslinkCommittees {
}
}
/// Return a vec of `CrosslinkCommittee` for a given slot.
fn get_crosslink_committees_at_slot(
&self,
slot: Slot,
@@ -176,6 +188,7 @@ impl EpochCrosslinkCommittees {
}
}
/// Builds an `EpochCrosslinkCommittees` object.
pub struct EpochCrosslinkCommitteesBuilder {
epoch: Epoch,
shuffling_start_shard: Shard,
@@ -185,6 +198,7 @@ pub struct EpochCrosslinkCommitteesBuilder {
}
impl EpochCrosslinkCommitteesBuilder {
/// Instantiates a builder that will build for the `state`'s previous epoch.
pub fn for_previous_epoch(
state: &BeaconState,
active_validator_indices: Vec<usize>,
@@ -199,6 +213,7 @@ impl EpochCrosslinkCommitteesBuilder {
}
}
/// Instantiates a builder that will build for the `state`'s next epoch.
pub fn for_current_epoch(
state: &BeaconState,
active_validator_indices: Vec<usize>,
@@ -213,6 +228,10 @@ impl EpochCrosslinkCommitteesBuilder {
}
}
/// Instantiates a builder that will build for the `state`'s next epoch.
///
/// Note: there are two possible epoch builds for the next epoch, one where there is a registry
/// change and one where there is not.
pub fn for_next_epoch(
state: &BeaconState,
active_validator_indices: Vec<usize>,
@@ -257,6 +276,7 @@ impl EpochCrosslinkCommitteesBuilder {
})
}
/// Consumes the builder, returning a fully-build `EpochCrosslinkCommittee`.
pub fn build(self, spec: &ChainSpec) -> Result<EpochCrosslinkCommittees, Error> {
// The shuffler fails on a empty list, so if there are no active validator indices, simply
// return an empty list.
@@ -284,7 +304,6 @@ impl EpochCrosslinkCommitteesBuilder {
for (i, slot) in self.epoch.slot_iter(spec.slots_per_epoch).enumerate() {
for j in (0..committees.len())
.into_iter()
.skip(i * committees_per_slot)
.take(committees_per_slot)
{

View File

@@ -7,15 +7,19 @@ use swap_or_not_shuffle::shuffle_list;
fn do_sane_cache_test(
state: BeaconState,
epoch: Epoch,
relative_epoch: RelativeEpoch,
validator_count: usize,
expected_seed: Hash256,
expected_shuffling_start: u64,
spec: &ChainSpec,
) {
let active_indices: Vec<usize> = (0..validator_count).collect();
assert_eq!(
&active_indices[..],
state.get_active_validator_indices(epoch, &spec).unwrap(),
state
.get_cached_active_validator_indices(relative_epoch, &spec)
.unwrap(),
"Validator indices mismatch"
);
@@ -101,6 +105,7 @@ fn builds_sane_current_epoch_cache() {
do_sane_cache_test(
state.clone(),
state.current_epoch(&spec),
RelativeEpoch::Current,
validator_count as usize,
state.current_shuffling_seed,
state.current_shuffling_start_shard,
@@ -117,6 +122,7 @@ fn builds_sane_previous_epoch_cache() {
do_sane_cache_test(
state.clone(),
state.previous_epoch(&spec),
RelativeEpoch::Previous,
validator_count as usize,
state.previous_shuffling_seed,
state.previous_shuffling_start_shard,
@@ -134,6 +140,7 @@ fn builds_sane_next_without_update_epoch_cache() {
do_sane_cache_test(
state.clone(),
state.next_epoch(&spec),
RelativeEpoch::NextWithoutRegistryChange,
validator_count as usize,
state.current_shuffling_seed,
state.current_shuffling_start_shard,

View File

@@ -1,20 +0,0 @@
use crate::*;
/// Verify ``bitfield`` against the ``committee_size``.
///
/// Is title `verify_bitfield` in spec.
///
/// Spec v0.4.0
pub fn verify_bitfield_length(bitfield: &Bitfield, committee_size: usize) -> bool {
if bitfield.num_bytes() != ((committee_size + 7) / 8) {
return false;
}
for i in committee_size..(bitfield.num_bytes() * 8) {
if bitfield.get(i).unwrap_or(false) {
return false;
}
}
true
}

View File

@@ -6,13 +6,17 @@ type ValidatorIndex = usize;
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
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>,
}
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 {
self.map.len()
self.len
}
/// 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
/// that an index is never skipped.
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.len += 1;
true
} else {
false

View File

@@ -124,7 +124,7 @@ pub struct ChainSpec {
impl ChainSpec {
/// 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 {
std::cmp::max(
1,

View File

@@ -34,7 +34,6 @@ pub mod relative_epoch;
pub mod slot_epoch;
pub mod slot_height;
pub mod validator;
pub mod validator_registry;
use ethereum_types::{H160, H256, U256};
use std::collections::HashMap;

View File

@@ -33,7 +33,7 @@ impl RelativeEpoch {
/// Returns the `epoch` that `self` refers to, with respect to the `base` epoch.
///
/// Spec v0.5.0
pub fn into_epoch(&self, base: Epoch) -> Epoch {
pub fn into_epoch(self, base: Epoch) -> Epoch {
match self {
RelativeEpoch::Previous => base - 1,
RelativeEpoch::Current => base,

View File

@@ -215,7 +215,7 @@ impl TestingBeaconStateBuilder {
- spec.min_attestation_inclusion_delay;
let last_slot = std::cmp::min(state.slot.as_u64(), last_slot);
for slot in first_slot..last_slot + 1 {
for slot in first_slot..=last_slot {
let slot = Slot::from(slot);
let committees = state

View File

@@ -47,7 +47,7 @@ impl TestingDepositBuilder {
self.deposit
.deposit_data
.deposit_input
.withdrawal_credentials = withdrawal_credentials.clone();
.withdrawal_credentials = withdrawal_credentials;
self.deposit.deposit_data.deposit_input.proof_of_possession = self
.deposit

View File

@@ -9,7 +9,7 @@ use test_random_derive::TestRandom;
/// The data submitted to the deposit contract.
///
/// Spec v0.4.0
/// Spec v0.5.0
#[derive(
Debug,
PartialEq,

View File

@@ -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]);
}
}