Merge branch 'docker-env' into v0.6.1

This commit is contained in:
Paul Hauner
2019-06-13 10:37:35 -04:00
142 changed files with 3186 additions and 2062 deletions

View File

@@ -1,4 +1,4 @@
use self::committee_cache::{get_active_validator_indices, CommitteeCache};
use self::committee_cache::get_active_validator_indices;
use self::exit_cache::ExitCache;
use crate::test_utils::TestRandom;
use crate::*;
@@ -15,6 +15,7 @@ use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
pub use self::committee_cache::CommitteeCache;
pub use beacon_state_types::*;
mod beacon_state_types;
@@ -111,7 +112,7 @@ where
pub previous_crosslinks: FixedLenVec<Crosslink, T::ShardCount>,
pub latest_block_roots: FixedLenVec<Hash256, T::SlotsPerHistoricalRoot>,
#[compare_fields(as_slice)]
latest_state_roots: FixedLenVec<Hash256, T::SlotsPerHistoricalRoot>,
pub latest_state_roots: FixedLenVec<Hash256, T::SlotsPerHistoricalRoot>,
#[compare_fields(as_slice)]
latest_active_index_roots: FixedLenVec<Hash256, T::LatestActiveIndexRootsLength>,
latest_slashed_balances: FixedLenVec<u64, T::LatestSlashedExitLength>,
@@ -163,7 +164,7 @@ impl<T: EthSpec> BeaconState<T> {
spec: &ChainSpec,
) -> BeaconState<T> {
let initial_crosslink = Crosslink {
epoch: spec.genesis_epoch,
epoch: T::genesis_epoch(),
previous_crosslink_root: spec.zero_hash,
crosslink_data_root: spec.zero_hash,
};
@@ -172,7 +173,7 @@ impl<T: EthSpec> BeaconState<T> {
// Misc
slot: spec.genesis_slot,
genesis_time,
fork: Fork::genesis(spec),
fork: Fork::genesis(T::genesis_epoch()),
// Validator registry
validator_registry: vec![], // Set later in the function.
@@ -188,12 +189,12 @@ impl<T: EthSpec> BeaconState<T> {
// Finality
previous_epoch_attestations: vec![],
current_epoch_attestations: vec![],
previous_justified_epoch: spec.genesis_epoch,
current_justified_epoch: spec.genesis_epoch,
previous_justified_epoch: T::genesis_epoch(),
current_justified_epoch: T::genesis_epoch(),
previous_justified_root: spec.zero_hash,
current_justified_root: spec.zero_hash,
justification_bitfield: 0,
finalized_epoch: spec.genesis_epoch,
finalized_epoch: T::genesis_epoch(),
finalized_root: spec.zero_hash,
// Recent state
@@ -300,10 +301,10 @@ impl<T: EthSpec> BeaconState<T> {
Ok(cache.epoch_start_shard())
}
pub fn next_epoch_start_shard(&self) -> Result<u64, Error> {
pub fn next_epoch_start_shard(&self, spec: &ChainSpec) -> Result<u64, Error> {
let cache = self.cache(RelativeEpoch::Current)?;
let active_validator_count = cache.active_validator_count();
let shard_delta = T::get_shard_delta(active_validator_count);
let shard_delta = T::get_shard_delta(active_validator_count, spec.target_committee_size);
Ok((self.latest_start_shard + shard_delta) % T::ShardCount::to_u64())
}
@@ -422,7 +423,7 @@ impl<T: EthSpec> BeaconState<T> {
};
let effective_balance = self.validator_registry[candidate_index].effective_balance;
if (effective_balance * MAX_RANDOM_BYTE)
>= (spec.max_effective_balance * random_byte as u64)
>= (spec.max_effective_balance * u64::from(random_byte))
{
break candidate_index;
}
@@ -453,12 +454,8 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Spec v0.6.0
// FIXME(sproul): name swap with get_block_root
pub fn get_block_root_at_epoch(
&self,
epoch: Epoch,
spec: &ChainSpec,
) -> Result<&Hash256, BeaconStateError> {
self.get_block_root(epoch.start_slot(spec.slots_per_epoch))
pub fn get_block_root_at_epoch(&self, epoch: Epoch) -> Result<&Hash256, BeaconStateError> {
self.get_block_root(epoch.start_slot(T::slots_per_epoch()))
}
/// Sets the block root for some given slot.

View File

@@ -1,5 +1,5 @@
use crate::*;
use fixed_len_vec::typenum::{Unsigned, U1024, U8, U8192};
use fixed_len_vec::typenum::{Unsigned, U0, U1024, U64, U8, U8192};
use serde_derive::{Deserialize, Serialize};
use std::fmt::Debug;
@@ -9,14 +9,24 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
type LatestRandaoMixesLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type LatestActiveIndexRootsLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type LatestSlashedExitLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;
/// Note: `SlotsPerEpoch` is not necessarily required to be a compile-time constant. We include
/// it here just for the convenience of not passing `slots_per_epoch` around all the time.
type SlotsPerEpoch: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type GenesisEpoch: Unsigned + Clone + Sync + Send + Debug + PartialEq;
fn spec() -> ChainSpec;
fn default_spec() -> ChainSpec;
fn genesis_epoch() -> Epoch {
Epoch::new(Self::GenesisEpoch::to_u64())
}
/// Return the number of committees in one epoch.
///
/// Spec v0.6.1
fn get_epoch_committee_count(active_validator_count: usize) -> usize {
let target_committee_size = Self::spec().target_committee_size;
fn get_epoch_committee_count(
active_validator_count: usize,
target_committee_size: usize,
) -> usize {
let shard_count = Self::shard_count();
let slots_per_epoch = Self::slots_per_epoch() as usize;
@@ -32,10 +42,10 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
/// Return the number of shards to increment `state.latest_start_shard` by in a given epoch.
///
/// Spec v0.6.3
fn get_shard_delta(active_validator_count: usize) -> u64 {
fn get_shard_delta(active_validator_count: usize, target_committee_size: usize) -> u64 {
std::cmp::min(
Self::get_epoch_committee_count(active_validator_count) as u64,
Self::ShardCount::to_u64() - Self::ShardCount::to_u64() / Self::spec().slots_per_epoch,
Self::get_epoch_committee_count(active_validator_count, target_committee_size) as u64,
Self::ShardCount::to_u64() - Self::ShardCount::to_u64() / Self::slots_per_epoch(),
)
}
@@ -45,21 +55,14 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
/// basic sense. This count is not required to provide any security guarantees regarding
/// decentralization, entropy, etc.
fn minimum_validator_count() -> usize {
Self::slots_per_epoch() as usize
Self::SlotsPerEpoch::to_usize()
}
/// Returns the `SLOTS_PER_EPOCH` constant for this specification.
///
/// Spec v0.6.1
fn slots_per_epoch() -> u64 {
Self::spec().slots_per_epoch
}
/// Returns the `SLOTS_PER_EPOCH` constant for this specification.
///
/// Spec v0.6.1
fn genesis_epoch() -> Epoch {
Self::spec().genesis_epoch
Self::SlotsPerEpoch::to_u64()
}
/// Returns the `SHARD_COUNT` constant for this specification.
@@ -102,54 +105,40 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
///
/// Spec v0.6.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct FoundationEthSpec;
pub struct MainnetEthSpec;
impl EthSpec for FoundationEthSpec {
impl EthSpec for MainnetEthSpec {
type ShardCount = U1024;
type SlotsPerHistoricalRoot = U8192;
type LatestRandaoMixesLength = U8192;
type LatestActiveIndexRootsLength = U8192;
type LatestSlashedExitLength = U8192;
type SlotsPerEpoch = U64;
type GenesisEpoch = U0;
fn spec() -> ChainSpec {
ChainSpec::foundation()
fn default_spec() -> ChainSpec {
ChainSpec::mainnet()
}
}
pub type FoundationBeaconState = BeaconState<FoundationEthSpec>;
pub type FoundationBeaconState = BeaconState<MainnetEthSpec>;
/// Ethereum Foundation specifications, modified to be suitable for < 1000 validators.
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct FewValidatorsEthSpec;
pub struct MinimalEthSpec;
impl EthSpec for FewValidatorsEthSpec {
impl EthSpec for MinimalEthSpec {
type ShardCount = U8;
type SlotsPerHistoricalRoot = U8192;
type LatestRandaoMixesLength = U8192;
type LatestActiveIndexRootsLength = U8192;
type LatestSlashedExitLength = U8192;
type SlotsPerEpoch = U8;
type GenesisEpoch = U0;
fn spec() -> ChainSpec {
ChainSpec::few_validators()
fn default_spec() -> ChainSpec {
ChainSpec::minimal()
}
}
pub type FewValidatorsBeaconState = BeaconState<FewValidatorsEthSpec>;
/// Specifications suitable for a small-scale (< 1000 validators) lighthouse testnet.
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct LighthouseTestnetEthSpec;
impl EthSpec for LighthouseTestnetEthSpec {
type ShardCount = U8;
type SlotsPerHistoricalRoot = U8192;
type LatestRandaoMixesLength = U8192;
type LatestActiveIndexRootsLength = U8192;
type LatestSlashedExitLength = U8192;
fn spec() -> ChainSpec {
ChainSpec::lighthouse_testnet()
}
}
pub type LighthouseTestnetBeaconState = BeaconState<LighthouseTestnetEthSpec>;
pub type MinimalBeaconState = BeaconState<MinimalEthSpec>;

View File

@@ -2,6 +2,7 @@ use super::BeaconState;
use crate::*;
use core::num::NonZeroUsize;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use std::ops::Range;
use swap_or_not_shuffle::shuffle_list;
@@ -9,7 +10,7 @@ mod tests;
/// Computes and stores the shuffling for an epoch. Provides various getters to allow callers to
/// read the committees for the given epoch.
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct CommitteeCache {
initialized_epoch: Option<Epoch>,
shuffling: Vec<usize>,
@@ -44,12 +45,16 @@ impl CommitteeCache {
return Err(Error::InsufficientValidators);
}
let committee_count = T::get_epoch_committee_count(active_validator_indices.len()) as usize;
let committee_count = T::get_epoch_committee_count(
active_validator_indices.len(),
spec.target_committee_size,
) as usize;
let shuffling_start_shard = match relative_epoch {
RelativeEpoch::Current => state.latest_start_shard,
RelativeEpoch::Previous => {
let shard_delta = T::get_shard_delta(active_validator_indices.len());
let shard_delta =
T::get_shard_delta(active_validator_indices.len(), spec.target_committee_size);
(state.latest_start_shard + T::ShardCount::to_u64() - shard_delta)
% T::ShardCount::to_u64()
@@ -57,7 +62,8 @@ impl CommitteeCache {
RelativeEpoch::Next => {
let current_active_validators =
get_active_validator_count(&state.validator_registry, state.current_epoch());
let shard_delta = T::get_shard_delta(current_active_validators);
let shard_delta =
T::get_shard_delta(current_active_validators, spec.target_committee_size);
(state.latest_start_shard + shard_delta) % T::ShardCount::to_u64()
}
@@ -152,7 +158,6 @@ impl CommitteeCache {
let i = self.shuffled_position(validator_index)?;
(0..self.committee_count)
.into_iter()
.map(|nth_committee| (nth_committee, self.compute_committee_range(nth_committee)))
.find(|(_, range)| {
if let Some(range) = range {

View File

@@ -20,12 +20,12 @@ fn default_values() {
}
fn new_state<T: EthSpec>(validator_count: usize, slot: Slot) -> BeaconState<T> {
let spec = &T::spec();
let spec = &T::default_spec();
let mut builder =
TestingBeaconStateBuilder::from_single_keypair(validator_count, &Keypair::random(), spec);
builder.teleport_to_slot(slot, spec);
builder.teleport_to_slot(slot);
let (state, _keypairs) = builder.build();
@@ -34,8 +34,8 @@ fn new_state<T: EthSpec>(validator_count: usize, slot: Slot) -> BeaconState<T> {
#[test]
fn fails_without_validators() {
let state = new_state::<FewValidatorsEthSpec>(0, Slot::new(0));
let spec = &FewValidatorsEthSpec::spec();
let state = new_state::<MinimalEthSpec>(0, Slot::new(0));
let spec = &MinimalEthSpec::default_spec();
assert_eq!(
CommitteeCache::initialized(&state, state.current_epoch(), &spec),
@@ -45,8 +45,8 @@ fn fails_without_validators() {
#[test]
fn initializes_with_the_right_epoch() {
let state = new_state::<FewValidatorsEthSpec>(16, Slot::new(0));
let spec = &FewValidatorsEthSpec::spec();
let state = new_state::<MinimalEthSpec>(16, Slot::new(0));
let spec = &MinimalEthSpec::default_spec();
let cache = CommitteeCache::default();
assert_eq!(cache.initialized_epoch, None);
@@ -63,14 +63,14 @@ fn initializes_with_the_right_epoch() {
#[test]
fn shuffles_for_the_right_epoch() {
let num_validators = FewValidatorsEthSpec::minimum_validator_count() * 2;
let num_validators = MinimalEthSpec::minimum_validator_count() * 2;
let epoch = Epoch::new(100_000_000);
let slot = epoch.start_slot(FewValidatorsEthSpec::slots_per_epoch());
let slot = epoch.start_slot(MinimalEthSpec::slots_per_epoch());
let mut state = new_state::<FewValidatorsEthSpec>(num_validators, slot);
let spec = &FewValidatorsEthSpec::spec();
let mut state = new_state::<MinimalEthSpec>(num_validators, slot);
let spec = &MinimalEthSpec::default_spec();
let distinct_hashes: Vec<Hash256> = (0..FewValidatorsEthSpec::latest_randao_mixes_length())
let distinct_hashes: Vec<Hash256> = (0..MinimalEthSpec::latest_randao_mixes_length())
.into_iter()
.map(|i| Hash256::from(i as u64))
.collect();
@@ -118,17 +118,19 @@ fn shuffles_for_the_right_epoch() {
#[test]
fn can_start_on_any_shard() {
let num_validators = FewValidatorsEthSpec::minimum_validator_count() * 2;
let num_validators = MinimalEthSpec::minimum_validator_count() * 2;
let epoch = Epoch::new(100_000_000);
let slot = epoch.start_slot(FewValidatorsEthSpec::slots_per_epoch());
let slot = epoch.start_slot(MinimalEthSpec::slots_per_epoch());
let mut state = new_state::<FewValidatorsEthSpec>(num_validators, slot);
let spec = &FewValidatorsEthSpec::spec();
let mut state = new_state::<MinimalEthSpec>(num_validators, slot);
let spec = &MinimalEthSpec::default_spec();
let shard_delta = FewValidatorsEthSpec::get_shard_delta(num_validators);
let shard_count = FewValidatorsEthSpec::shard_count() as u64;
let target_committee_size = MinimalEthSpec::default_spec().target_committee_size;
for i in 0..FewValidatorsEthSpec::shard_count() as u64 {
let shard_delta = MinimalEthSpec::get_shard_delta(num_validators, target_committee_size);
let shard_count = MinimalEthSpec::shard_count() as u64;
for i in 0..MinimalEthSpec::shard_count() as u64 {
state.latest_start_shard = i;
let cache = CommitteeCache::initialized(&state, state.current_epoch(), spec).unwrap();
@@ -156,15 +158,17 @@ impl EthSpec for ExcessShardsEthSpec {
type LatestRandaoMixesLength = U8192;
type LatestActiveIndexRootsLength = U8192;
type LatestSlashedExitLength = U8192;
type SlotsPerEpoch = U8;
type GenesisEpoch = U0;
fn spec() -> ChainSpec {
ChainSpec::few_validators()
fn default_spec() -> ChainSpec {
ChainSpec::minimal()
}
}
#[test]
fn starts_on_the_correct_shard() {
let spec = &ExcessShardsEthSpec::spec();
let spec = &ExcessShardsEthSpec::default_spec();
let num_validators = ExcessShardsEthSpec::shard_count();
@@ -206,14 +210,16 @@ fn starts_on_the_correct_shard() {
let previous_shards = ExcessShardsEthSpec::get_epoch_committee_count(
get_active_validator_count(&state.validator_registry, previous_epoch),
spec.target_committee_size,
);
let current_shards = ExcessShardsEthSpec::get_epoch_committee_count(
get_active_validator_count(&state.validator_registry, current_epoch),
spec.target_committee_size,
);
let next_shards = ExcessShardsEthSpec::get_epoch_committee_count(
get_active_validator_count(&state.validator_registry, next_epoch),
spec.target_committee_size,
);
let next_shards = ExcessShardsEthSpec::get_epoch_committee_count(get_active_validator_count(
&state.validator_registry,
next_epoch,
));
assert_eq!(
previous_shards as usize,

View File

@@ -7,7 +7,7 @@ ssz_tests!(FoundationBeaconState);
cached_tree_hash_tests!(FoundationBeaconState);
fn test_beacon_proposer_index<T: EthSpec>() {
let spec = T::spec();
let spec = T::default_spec();
let relative_epoch = RelativeEpoch::Current;
// Build a state for testing.
@@ -53,7 +53,7 @@ fn test_beacon_proposer_index<T: EthSpec>() {
#[test]
fn beacon_proposer_index() {
test_beacon_proposer_index::<FewValidatorsEthSpec>();
test_beacon_proposer_index::<MinimalEthSpec>();
}
/// Should produce (note the set notation brackets):
@@ -61,7 +61,7 @@ fn beacon_proposer_index() {
/// (current_epoch - LATEST_ACTIVE_INDEX_ROOTS_LENGTH + ACTIVATION_EXIT_DELAY, current_epoch +
/// ACTIVATION_EXIT_DELAY]
fn active_index_range<T: EthSpec>(current_epoch: Epoch) -> RangeInclusive<Epoch> {
let delay = T::spec().activation_exit_delay;
let delay = T::default_spec().activation_exit_delay;
let start: i32 =
current_epoch.as_u64() as i32 - T::latest_active_index_roots() as i32 + delay as i32;
@@ -79,7 +79,7 @@ fn active_index_range<T: EthSpec>(current_epoch: Epoch) -> RangeInclusive<Epoch>
/// Test getting an active index root at the start and end of the valid range, and one either side
/// of that range.
fn test_active_index<T: EthSpec>(state_slot: Slot) {
let spec = T::spec();
let spec = T::default_spec();
let builder: TestingBeaconStateBuilder<T> =
TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(16, &spec);
let (mut state, _keypairs) = builder.build();
@@ -115,11 +115,11 @@ fn test_active_index<T: EthSpec>(state_slot: Slot) {
#[test]
fn get_active_index_root_index() {
test_active_index::<FoundationEthSpec>(Slot::new(0));
test_active_index::<MainnetEthSpec>(Slot::new(0));
let epoch = Epoch::from(FoundationEthSpec::latest_active_index_roots() * 4);
let slot = epoch.start_slot(FoundationEthSpec::slots_per_epoch());
test_active_index::<FoundationEthSpec>(slot);
let epoch = Epoch::from(MainnetEthSpec::latest_active_index_roots() * 4);
let slot = epoch.start_slot(MainnetEthSpec::slots_per_epoch());
test_active_index::<MainnetEthSpec>(slot);
}
/// Test that
@@ -133,8 +133,8 @@ fn test_cache_initialization<'a, T: EthSpec>(
spec: &ChainSpec,
) {
let slot = relative_epoch
.into_epoch(state.slot.epoch(spec.slots_per_epoch))
.start_slot(spec.slots_per_epoch);
.into_epoch(state.slot.epoch(T::slots_per_epoch()))
.start_slot(T::slots_per_epoch());
// Assuming the cache isn't already built, assert that a call to a cache-using function fails.
assert_eq!(
@@ -166,13 +166,14 @@ fn test_cache_initialization<'a, T: EthSpec>(
#[test]
fn cache_initialization() {
let spec = FewValidatorsEthSpec::spec();
let spec = MinimalEthSpec::default_spec();
let builder: TestingBeaconStateBuilder<FewValidatorsEthSpec> =
let builder: TestingBeaconStateBuilder<MinimalEthSpec> =
TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(16, &spec);
let (mut state, _keypairs) = builder.build();
state.slot = (spec.genesis_epoch + 1).start_slot(spec.slots_per_epoch);
state.slot =
(MinimalEthSpec::genesis_epoch() + 1).start_slot(MinimalEthSpec::slots_per_epoch());
test_cache_initialization(&mut state, RelativeEpoch::Previous, &spec);
test_cache_initialization(&mut state, RelativeEpoch::Current, &spec);
@@ -202,7 +203,7 @@ fn tree_hash_cache() {
#[cfg(test)]
mod committees {
use super::*;
use crate::beacon_state::FewValidatorsEthSpec;
use crate::beacon_state::MinimalEthSpec;
use swap_or_not_shuffle::shuffle_list;
fn execute_committee_consistency_test<T: EthSpec>(
@@ -234,7 +235,7 @@ mod committees {
(start_shard..start_shard + T::shard_count() as u64).into_iter();
// Loop through all slots in the epoch being tested.
for slot in epoch.slot_iter(spec.slots_per_epoch) {
for slot in epoch.slot_iter(T::slots_per_epoch()) {
let crosslink_committees = state.get_crosslink_committees_at_slot(slot).unwrap();
// Assert that the number of committees in this slot is consistent with the reported number
@@ -290,7 +291,7 @@ mod committees {
state_epoch: Epoch,
cache_epoch: RelativeEpoch,
) {
let spec = &T::spec();
let spec = &T::default_spec();
let mut builder = TestingBeaconStateBuilder::from_single_keypair(
validator_count,
@@ -298,8 +299,8 @@ mod committees {
spec,
);
let slot = state_epoch.start_slot(spec.slots_per_epoch);
builder.teleport_to_slot(slot, spec);
let slot = state_epoch.start_slot(T::slots_per_epoch());
builder.teleport_to_slot(slot);
let (mut state, _keypairs): (BeaconState<T>, _) = builder.build();
@@ -325,7 +326,7 @@ mod committees {
}
fn committee_consistency_test_suite<T: EthSpec>(cached_epoch: RelativeEpoch) {
let spec = T::spec();
let spec = T::default_spec();
let validator_count = (T::shard_count() * spec.target_committee_size) + 1;
@@ -333,29 +334,29 @@ mod committees {
committee_consistency_test::<T>(
validator_count as usize,
spec.genesis_epoch + 4,
T::genesis_epoch() + 4,
cached_epoch,
);
committee_consistency_test::<T>(
validator_count as usize,
spec.genesis_epoch + T::slots_per_historical_root() as u64 * T::slots_per_epoch() * 4,
T::genesis_epoch() + T::slots_per_historical_root() as u64 * T::slots_per_epoch() * 4,
cached_epoch,
);
}
#[test]
fn current_epoch_committee_consistency() {
committee_consistency_test_suite::<FewValidatorsEthSpec>(RelativeEpoch::Current);
committee_consistency_test_suite::<MinimalEthSpec>(RelativeEpoch::Current);
}
#[test]
fn previous_epoch_committee_consistency() {
committee_consistency_test_suite::<FewValidatorsEthSpec>(RelativeEpoch::Previous);
committee_consistency_test_suite::<MinimalEthSpec>(RelativeEpoch::Previous);
}
#[test]
fn next_epoch_committee_consistency() {
committee_consistency_test_suite::<FewValidatorsEthSpec>(RelativeEpoch::Next);
committee_consistency_test_suite::<MinimalEthSpec>(RelativeEpoch::Next);
}
}

View File

@@ -1,7 +1,7 @@
use crate::*;
use int_to_bytes::int_to_bytes4;
use serde_derive::Deserialize;
use test_utils::u8_from_hex_str;
use serde_derive::{Deserialize, Serialize};
use test_utils::{u8_from_hex_str, u8_to_hex_str};
/// Each of the BLS signature domains.
///
@@ -18,7 +18,7 @@ pub enum Domain {
/// Holds all the "constants" for a BeaconChain.
///
/// Spec v0.6.1
#[derive(PartialEq, Debug, Clone, Deserialize)]
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct ChainSpec {
/*
@@ -48,18 +48,19 @@ pub struct ChainSpec {
* Initial Values
*/
pub genesis_slot: Slot,
pub genesis_epoch: Epoch,
// Skipped because serde TOML can't handle u64::max_value, the typical value for this field.
#[serde(skip_serializing)]
pub far_future_epoch: Epoch,
pub zero_hash: Hash256,
#[serde(deserialize_with = "u8_from_hex_str")]
#[serde(deserialize_with = "u8_from_hex_str", serialize_with = "u8_to_hex_str")]
pub bls_withdrawal_prefix_byte: u8,
/*
* Time parameters
*/
pub genesis_time: u64,
pub seconds_per_slot: u64,
pub min_attestation_inclusion_delay: u64,
pub slots_per_epoch: u64,
pub min_seed_lookahead: Epoch,
pub activation_exit_delay: u64,
pub slots_per_eth1_voting_period: u64,
@@ -137,7 +138,7 @@ impl ChainSpec {
/// Returns a `ChainSpec` compatible with the Ethereum Foundation specification.
///
/// Spec v0.6.1
pub(crate) fn foundation() -> Self {
pub fn mainnet() -> Self {
Self {
/*
* Misc
@@ -166,7 +167,6 @@ impl ChainSpec {
* Initial Values
*/
genesis_slot: Slot::new(0),
genesis_epoch: Epoch::new(0),
far_future_epoch: Epoch::new(u64::max_value()),
zero_hash: Hash256::zero(),
bls_withdrawal_prefix_byte: 0,
@@ -174,9 +174,9 @@ impl ChainSpec {
/*
* Time parameters
*/
genesis_time: u64::from(u32::max_value()),
seconds_per_slot: 6,
min_attestation_inclusion_delay: 4,
slots_per_epoch: 64,
min_seed_lookahead: Epoch::new(1),
activation_exit_delay: 4,
slots_per_eth1_voting_period: 1_024,
@@ -219,47 +219,35 @@ impl ChainSpec {
* Boot nodes
*/
boot_nodes: vec![],
chain_id: 1, // foundation chain id
chain_id: 1, // mainnet chain id
}
}
/// Returns a `ChainSpec` compatible with the Lighthouse testnet specification.
///
/// Spec v0.4.0
pub(crate) fn lighthouse_testnet() -> Self {
/*
* Lighthouse testnet bootnodes
*/
/// Returns a `ChainSpec` compatible with the specification suitable for 8 validators.
pub fn minimal() -> Self {
let genesis_slot = Slot::new(0);
// Note: these bootnodes are placeholders.
//
// Should be updated once static bootnodes exist.
let boot_nodes = vec!["/ip4/127.0.0.1/tcp/9000"
.parse()
.expect("correct multiaddr")];
Self {
boot_nodes,
chain_id: 2, // lighthouse testnet chain id
..ChainSpec::few_validators()
}
}
/// Returns a `ChainSpec` compatible with the specification suitable for 8 validators.
pub(crate) fn few_validators() -> Self {
let genesis_slot = Slot::new(0);
let slots_per_epoch = 8;
let genesis_epoch = genesis_slot.epoch(slots_per_epoch);
Self {
target_committee_size: 1,
chain_id: 2, // lighthouse testnet chain id
genesis_slot,
genesis_epoch,
slots_per_epoch,
..ChainSpec::foundation()
shuffle_round_count: 10,
..ChainSpec::mainnet()
}
}
}
impl Default for ChainSpec {
fn default() -> Self {
Self::foundation()
Self::mainnet()
}
}
@@ -269,12 +257,12 @@ mod tests {
use int_to_bytes::int_to_bytes8;
#[test]
fn test_foundation_spec_can_be_constructed() {
let _ = ChainSpec::foundation();
fn test_mainnet_spec_can_be_constructed() {
let _ = ChainSpec::mainnet();
}
fn test_domain(domain_type: Domain, raw_domain: u32, spec: &ChainSpec) {
let fork = Fork::genesis(&spec);
let fork = Fork::genesis(Epoch::new(0));
let epoch = Epoch::new(0);
let domain = spec.get_domain(epoch, domain_type, &fork);
@@ -287,7 +275,7 @@ mod tests {
#[test]
fn test_get_domain() {
let spec = ChainSpec::foundation();
let spec = ChainSpec::mainnet();
test_domain(Domain::BeaconProposer, spec.domain_beacon_proposer, &spec);
test_domain(Domain::Randao, spec.domain_randao, &spec);

View File

@@ -1,6 +1,6 @@
use crate::{
test_utils::{fork_from_hex_str, TestRandom},
ChainSpec, Epoch,
Epoch,
};
use serde_derive::{Deserialize, Serialize};
@@ -36,11 +36,11 @@ impl Fork {
/// Initialize the `Fork` from the genesis parameters in the `spec`.
///
/// Spec v0.6.1
pub fn genesis(spec: &ChainSpec) -> Self {
pub fn genesis(genesis_epoch: Epoch) -> Self {
Self {
previous_version: [0; 4],
current_version: [0; 4],
epoch: spec.genesis_epoch,
epoch: genesis_epoch,
}
}
@@ -63,13 +63,9 @@ mod tests {
cached_tree_hash_tests!(Fork);
fn test_genesis(epoch: Epoch) {
let mut spec = ChainSpec::foundation();
let fork = Fork::genesis(epoch);
spec.genesis_epoch = epoch;
let fork = Fork::genesis(&spec);
assert_eq!(fork.epoch, spec.genesis_epoch, "epoch incorrect");
assert_eq!(fork.epoch, epoch, "epoch incorrect");
assert_eq!(
fork.previous_version, fork.current_version,
"previous and current are not identical"

View File

@@ -31,7 +31,7 @@ pub struct HistoricalBatch<T: EthSpec> {
mod tests {
use super::*;
pub type FoundationHistoricalBatch = HistoricalBatch<FoundationEthSpec>;
pub type FoundationHistoricalBatch = HistoricalBatch<MainnetEthSpec>;
ssz_tests!(FoundationHistoricalBatch);
cached_tree_hash_tests!(FoundationHistoricalBatch);

View File

@@ -23,6 +23,7 @@ use std::iter::Iterator;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, Sub, SubAssign};
#[derive(Eq, Debug, Clone, Copy, Default, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Slot(u64);
#[derive(Eq, Debug, Clone, Copy, Default, Serialize, Deserialize)]
@@ -76,7 +77,7 @@ impl Epoch {
/// Position of some slot inside an epoch, if any.
///
/// E.g., the first `slot` in `epoch` is at position `0`.
pub fn position(&self, slot: Slot, slots_per_epoch: u64) -> Option<usize> {
pub fn position(self, slot: Slot, slots_per_epoch: u64) -> Option<usize> {
let start = self.start_slot(slots_per_epoch);
let end = self.end_slot(slots_per_epoch);

View File

@@ -184,7 +184,7 @@ macro_rules! impl_display {
key: slog::Key,
serializer: &mut slog::Serializer,
) -> slog::Result {
self.0.serialize(record, key, serializer)
slog::Value::serialize(&self.0, record, key, serializer)
}
}
};

View File

@@ -21,7 +21,7 @@ impl TestingAttestationDataBuilder {
let previous_epoch = state.previous_epoch();
let is_previous_epoch =
state.slot.epoch(spec.slots_per_epoch) != slot.epoch(spec.slots_per_epoch);
state.slot.epoch(T::slots_per_epoch()) != slot.epoch(T::slots_per_epoch());
let source_epoch = if is_previous_epoch {
state.previous_justified_epoch
@@ -37,11 +37,11 @@ impl TestingAttestationDataBuilder {
let target_root = if is_previous_epoch {
*state
.get_block_root(previous_epoch.start_slot(spec.slots_per_epoch))
.get_block_root(previous_epoch.start_slot(T::slots_per_epoch()))
.unwrap()
} else {
*state
.get_block_root(current_epoch.start_slot(spec.slots_per_epoch))
.get_block_root(current_epoch.start_slot(T::slots_per_epoch()))
.unwrap()
};
@@ -57,7 +57,7 @@ impl TestingAttestationDataBuilder {
};
let source_root = *state
.get_block_root(source_epoch.start_slot(spec.slots_per_epoch))
.get_block_root(source_epoch.start_slot(T::slots_per_epoch()))
.unwrap();
let data = AttestationData {

View File

@@ -36,9 +36,9 @@ impl TestingBeaconBlockBuilder {
/// Signs the block.
///
/// Modifying the block after signing may invalidate the signature.
pub fn sign(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) {
pub fn sign<T: EthSpec>(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) {
let message = self.block.signed_root();
let epoch = self.block.slot.epoch(spec.slots_per_epoch);
let epoch = self.block.slot.epoch(T::slots_per_epoch());
let domain = spec.get_domain(epoch, Domain::BeaconProposer, fork);
self.block.signature = Signature::new(&message, domain, sk);
}
@@ -46,8 +46,8 @@ impl TestingBeaconBlockBuilder {
/// Sets the randao to be a signature across the blocks epoch.
///
/// Modifying the block's slot after signing may invalidate the signature.
pub fn set_randao_reveal(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) {
let epoch = self.block.slot.epoch(spec.slots_per_epoch);
pub fn set_randao_reveal<T: EthSpec>(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) {
let epoch = self.block.slot.epoch(T::slots_per_epoch());
let message = epoch.tree_hash_root();
let domain = spec.get_domain(epoch, Domain::Randao, fork);
self.block.body.randao_reveal = Signature::new(&message, domain, sk);
@@ -59,14 +59,15 @@ impl TestingBeaconBlockBuilder {
}
/// Inserts a signed, valid `ProposerSlashing` for the validator.
pub fn insert_proposer_slashing(
pub fn insert_proposer_slashing<T: EthSpec>(
&mut self,
validator_index: u64,
secret_key: &SecretKey,
fork: &Fork,
spec: &ChainSpec,
) {
let proposer_slashing = build_proposer_slashing(validator_index, secret_key, fork, spec);
let proposer_slashing =
build_proposer_slashing::<T>(validator_index, secret_key, fork, spec);
self.block.body.proposer_slashings.push(proposer_slashing);
}
@@ -115,7 +116,7 @@ impl TestingBeaconBlockBuilder {
// - The slot is too old to be included in a block at this slot.
// - The `MAX_ATTESTATIONS`.
loop {
if state.slot >= slot + spec.slots_per_epoch {
if state.slot >= slot + T::slots_per_epoch() {
break;
}
@@ -194,7 +195,7 @@ impl TestingBeaconBlockBuilder {
builder.set_index(index);
builder.sign(
&keypair,
state.slot.epoch(spec.slots_per_epoch),
state.slot.epoch(T::slots_per_epoch()),
&state.fork,
spec,
);
@@ -211,7 +212,7 @@ impl TestingBeaconBlockBuilder {
spec: &ChainSpec,
) {
let mut builder = TestingVoluntaryExitBuilder::new(
state.slot.epoch(spec.slots_per_epoch),
state.slot.epoch(T::slots_per_epoch()),
validator_index,
);
@@ -234,14 +235,19 @@ impl TestingBeaconBlockBuilder {
spec: &ChainSpec,
) {
let mut builder = TestingTransferBuilder::new(from, to, amount, state.slot);
builder.sign(keypair, &state.fork, spec);
builder.sign::<T>(keypair, &state.fork, spec);
self.block.body.transfers.push(builder.build())
}
/// Signs and returns the block, consuming the builder.
pub fn build(mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) -> BeaconBlock {
self.sign(sk, fork, spec);
pub fn build<T: EthSpec>(
mut self,
sk: &SecretKey,
fork: &Fork,
spec: &ChainSpec,
) -> BeaconBlock {
self.sign::<T>(sk, fork, spec);
self.block
}
@@ -254,7 +260,7 @@ impl TestingBeaconBlockBuilder {
/// Builds an `ProposerSlashing` for some `validator_index`.
///
/// Signs the message using a `BeaconChainHarness`.
fn build_proposer_slashing(
fn build_proposer_slashing<T: EthSpec>(
validator_index: u64,
secret_key: &SecretKey,
fork: &Fork,
@@ -265,7 +271,7 @@ fn build_proposer_slashing(
Signature::new(message, domain, secret_key)
};
TestingProposerSlashingBuilder::double_vote(validator_index, signer, spec)
TestingProposerSlashingBuilder::double_vote::<T, _>(validator_index, signer)
}
/// Builds an `AttesterSlashing` for some `validator_indices`.

View File

@@ -6,7 +6,6 @@ use dirs;
use log::debug;
use rayon::prelude::*;
use std::path::{Path, PathBuf};
use std::time::SystemTime;
pub const KEYPAIRS_FILE: &str = "keypairs.raw_keypairs";
@@ -113,8 +112,8 @@ impl<T: EthSpec> TestingBeaconStateBuilder<T> {
pubkey: keypair.pk.clone(),
withdrawal_credentials,
// All validators start active.
activation_eligibility_epoch: spec.genesis_epoch,
activation_epoch: spec.genesis_epoch,
activation_eligibility_epoch: T::genesis_epoch(),
activation_epoch: T::genesis_epoch(),
exit_epoch: spec.far_future_epoch,
withdrawable_epoch: spec.far_future_epoch,
slashed: false,
@@ -123,20 +122,8 @@ impl<T: EthSpec> TestingBeaconStateBuilder<T> {
})
.collect();
// TODO: Testing only. Burn with fire later.
// set genesis to the last 30 minute block.
// this is used for testing only. Allows multiple nodes to connect within a 30min window
// and agree on a genesis
let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs();
let secs_after_last_period = now.checked_rem(30 * 60).unwrap_or(0);
// genesis is now the last 30 minute block.
let genesis_time = now - secs_after_last_period;
let mut state = BeaconState::genesis(
genesis_time,
spec.genesis_time,
Eth1Data {
deposit_root: Hash256::zero(),
deposit_count: 0,
@@ -172,8 +159,8 @@ impl<T: EthSpec> TestingBeaconStateBuilder<T> {
}
/// Sets the `BeaconState` to be in a slot, calling `teleport_to_epoch` to update the epoch.
pub fn teleport_to_slot(&mut self, slot: Slot, spec: &ChainSpec) {
self.teleport_to_epoch(slot.epoch(spec.slots_per_epoch), spec);
pub fn teleport_to_slot(&mut self, slot: Slot) {
self.teleport_to_epoch(slot.epoch(T::slots_per_epoch()));
self.state.slot = slot;
}
@@ -181,10 +168,10 @@ impl<T: EthSpec> TestingBeaconStateBuilder<T> {
///
/// Sets all justification/finalization parameters to be be as "perfect" as possible (i.e.,
/// highest justified and finalized slots, full justification bitfield, etc).
fn teleport_to_epoch(&mut self, epoch: Epoch, spec: &ChainSpec) {
fn teleport_to_epoch(&mut self, epoch: Epoch) {
let state = &mut self.state;
let slot = epoch.start_slot(spec.slots_per_epoch);
let slot = epoch.start_slot(T::slots_per_epoch());
state.slot = slot;
@@ -214,8 +201,8 @@ impl<T: EthSpec> TestingBeaconStateBuilder<T> {
let current_epoch = state.current_epoch();
let previous_epoch = state.previous_epoch();
let first_slot = previous_epoch.start_slot(spec.slots_per_epoch).as_u64();
let last_slot = current_epoch.end_slot(spec.slots_per_epoch).as_u64()
let first_slot = previous_epoch.start_slot(T::slots_per_epoch()).as_u64();
let last_slot = current_epoch.end_slot(T::slots_per_epoch()).as_u64()
- spec.min_attestation_inclusion_delay;
let last_slot = std::cmp::min(state.slot.as_u64(), last_slot);

View File

@@ -17,8 +17,9 @@ impl TestingProposerSlashingBuilder {
/// - `domain: Domain`
///
/// Where domain is a domain "constant" (e.g., `spec.domain_attestation`).
pub fn double_vote<F>(proposer_index: u64, signer: F, spec: &ChainSpec) -> ProposerSlashing
pub fn double_vote<T, F>(proposer_index: u64, signer: F) -> ProposerSlashing
where
T: EthSpec,
F: Fn(u64, &[u8], Epoch, Domain) -> Signature,
{
let slot = Slot::new(0);
@@ -40,13 +41,13 @@ impl TestingProposerSlashingBuilder {
header_1.signature = {
let message = header_1.signed_root();
let epoch = slot.epoch(spec.slots_per_epoch);
let epoch = slot.epoch(T::slots_per_epoch());
signer(proposer_index, &message[..], epoch, Domain::BeaconProposer)
};
header_2.signature = {
let message = header_2.signed_root();
let epoch = slot.epoch(spec.slots_per_epoch);
let epoch = slot.epoch(T::slots_per_epoch());
signer(proposer_index, &message[..], epoch, Domain::BeaconProposer)
};

View File

@@ -29,10 +29,10 @@ impl TestingTransferBuilder {
/// Signs the transfer.
///
/// The keypair must match that of the `from` validator index.
pub fn sign(&mut self, keypair: Keypair, fork: &Fork, spec: &ChainSpec) {
pub fn sign<T: EthSpec>(&mut self, keypair: Keypair, fork: &Fork, spec: &ChainSpec) {
self.transfer.pubkey = keypair.pk;
let message = self.transfer.signed_root();
let epoch = self.transfer.slot.epoch(spec.slots_per_epoch);
let epoch = self.transfer.slot.epoch(T::slots_per_epoch());
let domain = spec.get_domain(epoch, Domain::Transfer, fork);
self.transfer.signature = Signature::new(&message, domain, &keypair.sk);

View File

@@ -14,5 +14,5 @@ pub use rand::{
RngCore,
{prng::XorShiftRng, SeedableRng},
};
pub use serde_utils::{fork_from_hex_str, graffiti_from_hex_str, u8_from_hex_str};
pub use serde_utils::{fork_from_hex_str, graffiti_from_hex_str, u8_from_hex_str, u8_to_hex_str};
pub use test_random::TestRandom;

View File

@@ -1,5 +1,5 @@
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use serde::{Deserialize, Deserializer, Serializer};
pub const FORK_BYTES_LEN: usize = 4;
pub const GRAFFITI_BYTES_LEN: usize = 32;
@@ -13,6 +13,17 @@ where
u8::from_str_radix(&s.as_str()[2..], 16).map_err(D::Error::custom)
}
#[allow(clippy::trivially_copy_pass_by_ref)] // Serde requires the `byte` to be a ref.
pub fn u8_to_hex_str<S>(byte: &u8, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut hex: String = "0x".to_string();
hex.push_str(&hex::encode(&[*byte]));
serializer.serialize_str(&hex)
}
pub fn fork_from_hex_str<'de, D>(deserializer: D) -> Result<[u8; FORK_BYTES_LEN], D::Error>
where
D: Deserializer<'de>,