Merge remote-tracking branch 'origin/master' into spec-0.6

This commit is contained in:
Michael Sproul
2019-05-14 12:09:59 +10:00
161 changed files with 1785 additions and 4645 deletions

View File

@@ -14,7 +14,6 @@ env_logger = "0.6.0"
serde = "1.0"
serde_derive = "1.0"
serde_yaml = "0.8"
yaml-utils = { path = "yaml_utils" }
[dependencies]
bls = { path = "../utils/bls" }
@@ -31,6 +30,3 @@ tree_hash = { path = "../utils/tree_hash" }
tree_hash_derive = { path = "../utils/tree_hash_derive" }
types = { path = "../types" }
rayon = "1.0"
[features]
fake_crypto = ["bls/fake_crypto"]

View File

@@ -1 +0,0 @@
../utils/bls/build.rs

View File

@@ -4,8 +4,8 @@ use types::{BeaconStateError as Error, *};
/// Initiate the exit of the validator of the given `index`.
///
/// Spec v0.6.1
pub fn initiate_validator_exit(
state: &mut BeaconState,
pub fn initiate_validator_exit<T: EthSpec>(
state: &mut BeaconState<T>,
index: usize,
spec: &ChainSpec,
) -> Result<(), Error> {

View File

@@ -0,0 +1,22 @@
use types::{BeaconStateError as Error, *};
/// Exit the validator of the given `index`.
///
/// Spec v0.5.1
pub fn exit_validator<T: EthSpec>(
state: &mut BeaconState<T>,
validator_index: usize,
spec: &ChainSpec,
) -> Result<(), Error> {
if validator_index >= state.validator_registry.len() {
return Err(Error::UnknownValidator);
}
let delayed_epoch = state.get_delayed_activation_exit_epoch(state.current_epoch(spec), spec);
if state.validator_registry[validator_index].exit_epoch > delayed_epoch {
state.validator_registry[validator_index].exit_epoch = delayed_epoch;
}
Ok(())
}

View File

@@ -4,8 +4,8 @@ use types::{BeaconStateError as Error, *};
/// Slash the validator with index ``index``.
///
/// Spec v0.6.1
pub fn slash_validator(
state: &mut BeaconState,
pub fn slash_validator<T: EthSpec>(
state: &mut BeaconState<T>,
slashed_index: usize,
opt_whistleblower_index: Option<usize>,
spec: &ChainSpec,
@@ -20,13 +20,12 @@ pub fn slash_validator(
state.validator_registry[slashed_index].slashed = true;
state.validator_registry[slashed_index].withdrawable_epoch =
current_epoch + Epoch::from(spec.latest_slashed_exit_length);
current_epoch + Epoch::from(T::latest_slashed_exit_length());
let slashed_balance = state.get_effective_balance(slashed_index, spec)?;
state.set_slashed_balance(
current_epoch,
state.get_slashed_balance(current_epoch, spec)? + slashed_balance,
spec,
state.get_slashed_balance(current_epoch)? + slashed_balance,
)?;
let proposer_index =

View File

@@ -10,12 +10,12 @@ pub enum GenesisError {
/// Returns the genesis `BeaconState`
///
/// Spec v0.5.1
pub fn get_genesis_state(
pub fn get_genesis_state<T: EthSpec>(
genesis_validator_deposits: &[Deposit],
genesis_time: u64,
genesis_eth1_data: Eth1Data,
spec: &ChainSpec,
) -> Result<BeaconState, BlockProcessingError> {
) -> Result<BeaconState<T>, BlockProcessingError> {
// Get the genesis `BeaconState`
let mut state = BeaconState::genesis(genesis_time, genesis_eth1_data, spec);
@@ -37,7 +37,7 @@ pub fn get_genesis_state(
.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?
.to_vec();
let genesis_active_index_root = Hash256::from_slice(&active_validator_indices.tree_hash_root());
state.fill_active_index_roots_with(genesis_active_index_root, spec);
state.fill_active_index_roots_with(genesis_active_index_root);
// Generate the current shuffling seed.
state.current_shuffling_seed = state.generate_seed(spec.genesis_epoch, spec)?;

View File

@@ -40,8 +40,8 @@ const VERIFY_DEPOSIT_MERKLE_PROOFS: bool = false;
/// returns an error describing why the block was invalid or how the function failed to execute.
///
/// Spec v0.5.1
pub fn per_block_processing(
state: &mut BeaconState,
pub fn per_block_processing<T: EthSpec>(
state: &mut BeaconState<T>,
block: &BeaconBlock,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -55,8 +55,8 @@ pub fn per_block_processing(
/// returns an error describing why the block was invalid or how the function failed to execute.
///
/// Spec v0.5.1
pub fn per_block_processing_without_verifying_block_signature(
state: &mut BeaconState,
pub fn per_block_processing_without_verifying_block_signature<T: EthSpec>(
state: &mut BeaconState<T>,
block: &BeaconBlock,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -70,8 +70,8 @@ pub fn per_block_processing_without_verifying_block_signature(
/// returns an error describing why the block was invalid or how the function failed to execute.
///
/// Spec v0.5.1
fn per_block_processing_signature_optional(
mut state: &mut BeaconState,
fn per_block_processing_signature_optional<T: EthSpec>(
mut state: &mut BeaconState<T>,
block: &BeaconBlock,
should_verify_block_signature: bool,
spec: &ChainSpec,
@@ -100,8 +100,8 @@ fn per_block_processing_signature_optional(
/// Processes the block header.
///
/// Spec v0.5.1
pub fn process_block_header(
state: &mut BeaconState,
pub fn process_block_header<T: EthSpec>(
state: &mut BeaconState<T>,
block: &BeaconBlock,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -125,8 +125,8 @@ pub fn process_block_header(
/// Verifies the signature of a block.
///
/// Spec v0.5.1
pub fn verify_block_signature(
state: &BeaconState,
pub fn verify_block_signature<T: EthSpec>(
state: &BeaconState<T>,
block: &BeaconBlock,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -153,8 +153,8 @@ pub fn verify_block_signature(
/// `state.latest_randao_mixes`.
///
/// Spec v0.5.1
pub fn process_randao(
state: &mut BeaconState,
pub fn process_randao<T: EthSpec>(
state: &mut BeaconState<T>,
block: &BeaconBlock,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -184,7 +184,10 @@ pub fn process_randao(
/// Update the `state.eth1_data_votes` based upon the `eth1_data` provided.
///
/// Spec v0.5.1
pub fn process_eth1_data(state: &mut BeaconState, eth1_data: &Eth1Data) -> Result<(), Error> {
pub fn process_eth1_data<T: EthSpec>(
state: &mut BeaconState<T>,
eth1_data: &Eth1Data,
) -> Result<(), Error> {
// Attempt to find a `Eth1DataVote` with matching `Eth1Data`.
let matching_eth1_vote_index = state
.eth1_data_votes
@@ -210,8 +213,8 @@ pub fn process_eth1_data(state: &mut BeaconState, eth1_data: &Eth1Data) -> Resul
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.5.1
pub fn process_proposer_slashings(
state: &mut BeaconState,
pub fn process_proposer_slashings<T: EthSpec>(
state: &mut BeaconState<T>,
proposer_slashings: &[ProposerSlashing],
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -243,8 +246,8 @@ pub fn process_proposer_slashings(
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.5.1
pub fn process_attester_slashings(
state: &mut BeaconState,
pub fn process_attester_slashings<T: EthSpec>(
state: &mut BeaconState<T>,
attester_slashings: &[AttesterSlashing],
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -301,8 +304,8 @@ pub fn process_attester_slashings(
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.5.1
pub fn process_attestations(
state: &mut BeaconState,
pub fn process_attestations<T: EthSpec>(
state: &mut BeaconState<T>,
attestations: &[Attestation],
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -343,8 +346,8 @@ pub fn process_attestations(
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.5.1
pub fn process_deposits(
state: &mut BeaconState,
pub fn process_deposits<T: EthSpec>(
state: &mut BeaconState<T>,
deposits: &[Deposit],
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -413,8 +416,8 @@ pub fn process_deposits(
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.5.1
pub fn process_exits(
state: &mut BeaconState,
pub fn process_exits<T: EthSpec>(
state: &mut BeaconState<T>,
voluntary_exits: &[VoluntaryExit],
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -445,8 +448,8 @@ pub fn process_exits(
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.5.1
pub fn process_transfers(
state: &mut BeaconState,
pub fn process_transfers<T: EthSpec>(
state: &mut BeaconState<T>,
transfers: &[Transfer],
spec: &ChainSpec,
) -> Result<(), Error> {

View File

@@ -9,8 +9,8 @@ use types::*;
/// Returns `Ok(())` if the `Attestation` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.5.1
pub fn validate_attestation(
state: &BeaconState,
pub fn validate_attestation<T: EthSpec>(
state: &BeaconState<T>,
attestation: &Attestation,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -18,8 +18,8 @@ pub fn validate_attestation(
}
/// Like `validate_attestation` but doesn't run checks which may become true in future states.
pub fn validate_attestation_time_independent_only(
state: &BeaconState,
pub fn validate_attestation_time_independent_only<T: EthSpec>(
state: &BeaconState<T>,
attestation: &Attestation,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -32,8 +32,8 @@ pub fn validate_attestation_time_independent_only(
/// Returns `Ok(())` if the `Attestation` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.5.1
pub fn validate_attestation_without_signature(
state: &BeaconState,
pub fn validate_attestation_without_signature<T: EthSpec>(
state: &BeaconState<T>,
attestation: &Attestation,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -45,8 +45,8 @@ pub fn validate_attestation_without_signature(
///
///
/// Spec v0.5.1
fn validate_attestation_parametric(
state: &BeaconState,
fn validate_attestation_parametric<T: EthSpec>(
state: &BeaconState<T>,
attestation: &Attestation,
spec: &ChainSpec,
verify_signature: bool,
@@ -168,9 +168,9 @@ fn validate_attestation_parametric(
/// match the current (or previous) justified epoch and root from the state.
///
/// Spec v0.5.1
fn verify_justified_epoch_and_root(
fn verify_justified_epoch_and_root<T: EthSpec>(
attestation: &Attestation,
state: &BeaconState,
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Result<(), Error> {
let state_epoch = state.slot.epoch(spec.slots_per_epoch);
@@ -223,8 +223,8 @@ fn verify_justified_epoch_and_root(
/// - A `validator_index` in `committee` is not in `state.validator_registry`.
///
/// Spec v0.5.1
fn verify_attestation_signature(
state: &BeaconState,
fn verify_attestation_signature<T: EthSpec>(
state: &BeaconState<T>,
committee: &[usize],
a: &Attestation,
spec: &ChainSpec,

View File

@@ -8,8 +8,8 @@ use types::*;
/// Returns `Ok(())` if the `AttesterSlashing` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.5.1
pub fn verify_attester_slashing(
state: &BeaconState,
pub fn verify_attester_slashing<T: EthSpec>(
state: &BeaconState<T>,
attester_slashing: &AttesterSlashing,
should_verify_indexed_attestations: bool,
spec: &ChainSpec,
@@ -42,8 +42,8 @@ pub fn verify_attester_slashing(
/// Returns Ok(indices) if `indices.len() > 0`.
///
/// Spec v0.5.1
pub fn gather_attester_slashing_indices(
state: &BeaconState,
pub fn gather_attester_slashing_indices<T: EthSpec>(
state: &BeaconState<T>,
attester_slashing: &AttesterSlashing,
spec: &ChainSpec,
) -> Result<Vec<u64>, Error> {
@@ -57,8 +57,8 @@ pub fn gather_attester_slashing_indices(
/// Same as `gather_attester_slashing_indices` but allows the caller to specify the criteria
/// for determining whether a given validator should be considered slashed.
pub fn gather_attester_slashing_indices_modular<F>(
state: &BeaconState,
pub fn gather_attester_slashing_indices_modular<F, T: EthSpec>(
state: &BeaconState<T>,
attester_slashing: &AttesterSlashing,
is_slashed: F,
spec: &ChainSpec,

View File

@@ -16,8 +16,8 @@ use types::*;
/// Note: this function is incomplete.
///
/// Spec v0.5.1
pub fn verify_deposit(
state: &BeaconState,
pub fn verify_deposit<T: EthSpec>(
state: &BeaconState<T>,
deposit: &Deposit,
verify_merkle_branch: bool,
spec: &ChainSpec,
@@ -47,7 +47,10 @@ pub fn verify_deposit(
/// Verify that the `Deposit` index is correct.
///
/// Spec v0.5.1
pub fn verify_deposit_index(state: &BeaconState, deposit: &Deposit) -> Result<(), Error> {
pub fn verify_deposit_index<T: EthSpec>(
state: &BeaconState<T>,
deposit: &Deposit,
) -> Result<(), Error> {
verify!(
deposit.index == state.deposit_index,
Invalid::BadIndex {
@@ -65,8 +68,8 @@ pub fn verify_deposit_index(state: &BeaconState, deposit: &Deposit) -> Result<()
/// ## Errors
///
/// Errors if the state's `pubkey_cache` is not current.
pub fn get_existing_validator_index(
state: &BeaconState,
pub fn get_existing_validator_index<T: EthSpec>(
state: &BeaconState<T>,
deposit: &Deposit,
) -> Result<Option<u64>, Error> {
let deposit_input = &deposit.deposit_data.deposit_input;
@@ -89,11 +92,15 @@ pub fn get_existing_validator_index(
/// Verify that a deposit is included in the state's eth1 deposit root.
///
/// Spec v0.6.0
fn verify_deposit_merkle_proof(state: &BeaconState, deposit: &Deposit, spec: &ChainSpec) -> bool {
fn verify_deposit_merkle_proof<T: EthSpec>(
state: &BeaconState<T>,
deposit: &Deposit,
spec: &ChainSpec,
) -> bool {
let leaf = deposit.data.tree_hash_root();
verify_merkle_proof(
Hash256::from_slice(&leaf),
&deposit.proof,
&deposit.proof[..],
spec.deposit_contract_tree_depth as usize,
deposit.index as usize,
state.latest_eth1_data.deposit_root,

View File

@@ -8,8 +8,8 @@ use types::*;
/// Returns `Ok(())` if the `Exit` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.5.1
pub fn verify_exit(
state: &BeaconState,
pub fn verify_exit<T: EthSpec>(
state: &BeaconState<T>,
exit: &VoluntaryExit,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -17,8 +17,8 @@ pub fn verify_exit(
}
/// Like `verify_exit` but doesn't run checks which may become true in future states.
pub fn verify_exit_time_independent_only(
state: &BeaconState,
pub fn verify_exit_time_independent_only<T: EthSpec>(
state: &BeaconState<T>,
exit: &VoluntaryExit,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -26,8 +26,8 @@ pub fn verify_exit_time_independent_only(
}
/// Parametric version of `verify_exit` that skips some checks if `time_independent_only` is true.
fn verify_exit_parametric(
state: &BeaconState,
fn verify_exit_parametric<T: EthSpec>(
state: &BeaconState<T>,
exit: &VoluntaryExit,
spec: &ChainSpec,
time_independent_only: bool,

View File

@@ -11,8 +11,8 @@ use types::*;
/// Returns `Ok(())` if the `IndexedAttestation` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.5.1
pub fn verify_indexed_attestation(
state: &BeaconState,
pub fn verify_indexed_attestation<T: EthSpec>(
state: &BeaconState<T>,
indexed_attestation: &IndexedAttestation,
spec: &ChainSpec,
) -> Result<(), Error> {

View File

@@ -8,9 +8,9 @@ use types::*;
/// Returns `Ok(())` if the `ProposerSlashing` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.5.1
pub fn verify_proposer_slashing(
pub fn verify_proposer_slashing<T: EthSpec>(
proposer_slashing: &ProposerSlashing,
state: &BeaconState,
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Result<(), Error> {
let proposer = state

View File

@@ -11,8 +11,8 @@ use types::*;
/// Note: this function is incomplete.
///
/// Spec v0.5.1
pub fn verify_transfer(
state: &BeaconState,
pub fn verify_transfer<T: EthSpec>(
state: &BeaconState<T>,
transfer: &Transfer,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -20,8 +20,8 @@ pub fn verify_transfer(
}
/// Like `verify_transfer` but doesn't run checks which may become true in future states.
pub fn verify_transfer_time_independent_only(
state: &BeaconState,
pub fn verify_transfer_time_independent_only<T: EthSpec>(
state: &BeaconState<T>,
transfer: &Transfer,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -29,8 +29,8 @@ pub fn verify_transfer_time_independent_only(
}
/// Parametric version of `verify_transfer` that allows some checks to be skipped.
fn verify_transfer_parametric(
state: &BeaconState,
fn verify_transfer_parametric<T: EthSpec>(
state: &BeaconState<T>,
transfer: &Transfer,
spec: &ChainSpec,
time_independent_only: bool,
@@ -123,8 +123,8 @@ fn verify_transfer_parametric(
/// Does not check that the transfer is valid, however checks for overflow in all actions.
///
/// Spec v0.5.1
pub fn execute_transfer(
state: &mut BeaconState,
pub fn execute_transfer<T: EthSpec>(
state: &mut BeaconState<T>,
transfer: &Transfer,
spec: &ChainSpec,
) -> Result<(), Error> {

View File

@@ -33,7 +33,10 @@ pub type WinningRootHashSet = HashMap<u64, WinningRoot>;
/// returned, a state might be "half-processed" and therefore in an invalid state.
///
/// Spec v0.5.1
pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> {
pub fn per_epoch_processing<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
) -> Result<(), Error> {
// Ensure the previous and next epoch caches are built.
state.build_epoch_cache(RelativeEpoch::Previous, spec)?;
state.build_epoch_cache(RelativeEpoch::Current, spec)?;
@@ -83,7 +86,7 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result
/// Maybe resets the eth1 period.
///
/// Spec v0.5.1
pub fn maybe_reset_eth1_period(state: &mut BeaconState, spec: &ChainSpec) {
pub fn maybe_reset_eth1_period<T: EthSpec>(state: &mut BeaconState<T>, spec: &ChainSpec) {
/* FIXME(sproul)
let next_epoch = state.next_epoch(spec);
let voting_period = spec.epochs_per_eth1_voting_period;
@@ -110,8 +113,8 @@ pub fn maybe_reset_eth1_period(state: &mut BeaconState, spec: &ChainSpec) {
/// - `finalized_root`
///
/// Spec v0.6.1
pub fn process_justification_and_finalization(
state: &mut BeaconState,
pub fn process_justification_and_finalization<T: EthSpec>(
state: &mut BeaconState<T>,
total_balances: &TotalBalances,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -178,8 +181,8 @@ pub fn process_justification_and_finalization(
/// Also returns a `WinningRootHashSet` for later use during epoch processing.
///
/// Spec v0.6.1
pub fn process_crosslinks(
state: &mut BeaconState,
pub fn process_crosslinks<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
) -> Result<WinningRootHashSet, Error> {
let mut winning_root_for_shards: WinningRootHashSet = HashMap::new();
@@ -211,7 +214,10 @@ pub fn process_crosslinks(
/// Finish up an epoch update.
///
/// Spec v0.5.1
pub fn finish_epoch_update(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> {
pub fn finish_epoch_update<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
) -> Result<(), Error> {
let current_epoch = state.current_epoch(spec);
let next_epoch = state.next_epoch(spec);
@@ -230,11 +236,7 @@ pub fn finish_epoch_update(state: &mut BeaconState, spec: &ChainSpec) -> Result<
state.set_active_index_root(next_epoch, active_index_root, spec)?;
// Set total slashed balances
state.set_slashed_balance(
next_epoch,
state.get_slashed_balance(current_epoch, spec)?,
spec,
)?;
state.set_slashed_balance(next_epoch, state.get_slashed_balance(current_epoch)?)?;
// Set randao mix
state.set_randao_mix(
@@ -246,8 +248,8 @@ pub fn finish_epoch_update(state: &mut BeaconState, spec: &ChainSpec) -> Result<
state.slot -= 1;
}
if next_epoch.as_u64() % (spec.slots_per_historical_root as u64 / spec.slots_per_epoch) == 0 {
let historical_batch: HistoricalBatch = state.historical_batch();
if next_epoch.as_u64() % (T::SlotsPerHistoricalRoot::to_u64() / spec.slots_per_epoch) == 0 {
let historical_batch = state.historical_batch();
state
.historical_roots
.push(Hash256::from_slice(&historical_batch.tree_hash_root()[..]));

View File

@@ -33,8 +33,8 @@ impl std::ops::AddAssign for Delta {
/// Apply attester and proposer rewards.
///
/// Spec v0.6.1
pub fn process_rewards_and_penalties(
state: &mut BeaconState,
pub fn process_rewards_and_penalties<T: EthSpec>(
state: &mut BeaconState<T>,
validator_statuses: &mut ValidatorStatuses,
winning_root_for_shards: &WinningRootHashSet,
spec: &ChainSpec,
@@ -75,9 +75,9 @@ pub fn process_rewards_and_penalties(
/// For each attesting validator, reward the proposer who was first to include their attestation.
///
/// Spec v0.6.1
fn get_proposer_deltas(
fn get_proposer_deltas<T: EthSpec>(
deltas: &mut Vec<Delta>,
state: &BeaconState,
state: &BeaconState<T>,
validator_statuses: &mut ValidatorStatuses,
winning_root_for_shards: &WinningRootHashSet,
spec: &ChainSpec,
@@ -112,9 +112,9 @@ fn get_proposer_deltas(
/// Apply rewards for participation in attestations during the previous epoch.
///
/// Spec v0.6.1
fn get_attestation_deltas(
fn get_attestation_deltas<T: EthSpec>(
deltas: &mut Vec<Delta>,
state: &BeaconState,
state: &BeaconState<T>,
validator_statuses: &ValidatorStatuses,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -225,9 +225,9 @@ fn get_attestation_delta(
/// Calculate the deltas based upon the winning roots for attestations during the previous epoch.
///
/// Spec v0.6.1
fn get_crosslink_deltas(
fn get_crosslink_deltas<T: EthSpec>(
deltas: &mut Vec<Delta>,
state: &BeaconState,
state: &BeaconState<T>,
validator_statuses: &ValidatorStatuses,
spec: &ChainSpec,
) -> Result<(), Error> {
@@ -259,8 +259,8 @@ fn get_crosslink_deltas(
/// Returns the base reward for some validator.
///
/// Spec v0.6.1
fn get_base_reward(
state: &BeaconState,
fn get_base_reward<T: EthSpec>(
state: &BeaconState<T>,
index: usize,
// Should be == get_total_active_balance(state, spec)
total_active_balance: u64,

View File

@@ -0,0 +1,38 @@
use crate::common::verify_bitfield_length;
use types::*;
/// Returns validator indices which participated in the attestation.
///
/// Spec v0.5.1
pub fn get_attestation_participants<T: EthSpec>(
state: &BeaconState<T>,
attestation_data: &AttestationData,
bitfield: &Bitfield,
spec: &ChainSpec,
) -> Result<Vec<usize>, BeaconStateError> {
let epoch = attestation_data.slot.epoch(spec.slots_per_epoch);
let crosslink_committee =
state.get_crosslink_committee_for_shard(epoch, attestation_data.shard, spec)?;
if crosslink_committee.slot != attestation_data.slot {
return Err(BeaconStateError::NoCommitteeForShard);
}
let committee = &crosslink_committee.committee;
if !verify_bitfield_length(&bitfield, committee.len()) {
return Err(BeaconStateError::InvalidBitfield);
}
let mut participants = Vec::with_capacity(committee.len());
for (i, validator_index) in committee.iter().enumerate() {
match bitfield.get(i) {
Ok(bit) if bit => participants.push(*validator_index),
_ => {}
}
}
participants.shrink_to_fit();
Ok(participants)
}

View File

@@ -4,8 +4,8 @@ use types::*;
/// Returns validator indices which participated in the attestation.
///
/// Spec v0.6.1
pub fn get_attesting_indices_unsorted(
state: &BeaconState,
pub fn get_attesting_indices_unsorted<T: EthSpec>(
state: &BeaconState<T>,
attestation_data: &AttestationData,
bitfield: &Bitfield,
spec: &ChainSpec,

View File

@@ -5,8 +5,8 @@ use types::*;
/// slot.
///
/// Spec v0.5.1
pub fn inclusion_distance(
state: &BeaconState,
pub fn inclusion_distance<T: EthSpec>(
state: &BeaconState<T>,
attestations: &[&PendingAttestation],
validator_index: usize,
spec: &ChainSpec,
@@ -20,8 +20,8 @@ pub fn inclusion_distance(
/// Returns the slot of the earliest included attestation for some validator.
///
/// Spec v0.5.1
pub fn inclusion_slot(
state: &BeaconState,
pub fn inclusion_slot<T: EthSpec>(
state: &BeaconState<T>,
attestations: &[&PendingAttestation],
validator_index: usize,
spec: &ChainSpec,
@@ -36,8 +36,8 @@ pub fn inclusion_slot(
/// Finds the earliest included attestation for some validator.
///
/// Spec v0.5.1
fn earliest_included_attestation(
state: &BeaconState,
fn earliest_included_attestation<T: EthSpec>(
state: &BeaconState<T>,
attestations: &[&PendingAttestation],
validator_index: usize,
spec: &ChainSpec,

View File

@@ -5,7 +5,10 @@ use types::{BeaconStateError as Error, *};
/// ``EJECTION_BALANCE``.
///
/// Spec v0.5.1
pub fn process_ejections(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> {
pub fn process_ejections<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
) -> Result<(), Error> {
// 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.
let exitable: Vec<usize> = state

View File

@@ -3,7 +3,7 @@ use types::*;
/// Process the exit queue.
///
/// Spec v0.5.1
pub fn process_exit_queue(state: &mut BeaconState, spec: &ChainSpec) {
pub fn process_exit_queue<T: EthSpec>(state: &mut BeaconState<T>, spec: &ChainSpec) {
let current_epoch = state.current_epoch(spec);
let eligible = |index: usize| {
@@ -34,8 +34,8 @@ pub fn process_exit_queue(state: &mut BeaconState, spec: &ChainSpec) {
/// Initiate an exit for the validator of the given `index`.
///
/// Spec v0.5.1
fn prepare_validator_for_withdrawal(
state: &mut BeaconState,
fn prepare_validator_for_withdrawal<T: EthSpec>(
state: &mut BeaconState<T>,
validator_index: usize,
spec: &ChainSpec,
) {

View File

@@ -3,20 +3,20 @@ use types::{BeaconStateError as Error, *};
/// Process slashings.
///
/// Spec v0.5.1
pub fn process_slashings(
state: &mut BeaconState,
pub fn process_slashings<T: EthSpec>(
state: &mut BeaconState<T>,
current_total_balance: u64,
spec: &ChainSpec,
) -> Result<(), Error> {
let current_epoch = state.current_epoch(spec);
let total_at_start = state.get_slashed_balance(current_epoch + 1, spec)?;
let total_at_end = state.get_slashed_balance(current_epoch, spec)?;
let total_at_start = state.get_slashed_balance(current_epoch + 1)?;
let total_at_end = state.get_slashed_balance(current_epoch)?;
let total_penalities = total_at_end - total_at_start;
for (index, validator) in state.validator_registry.iter().enumerate() {
let should_penalize = current_epoch.as_usize()
== validator.withdrawable_epoch.as_usize() - spec.latest_slashed_exit_length / 2;
== validator.withdrawable_epoch.as_usize() - T::LatestSlashedExitLength::to_usize() / 2;
if validator.slashed && should_penalize {
let effective_balance = state.get_effective_balance(index, spec)?;

View File

@@ -6,8 +6,8 @@ use types::*;
/// Peforms a validator registry update, if required.
///
/// Spec v0.6.1
pub fn process_registry_updates(
state: &mut BeaconState,
pub fn process_registry_updates<T: EthSpec>(
state: &mut BeaconState<T>,
current_total_balance: u64,
spec: &ChainSpec,
) -> Result<(), Error> {

View File

@@ -8,9 +8,10 @@ use types::*;
fn runs_without_error() {
Builder::from_env(Env::default().default_filter_or("error")).init();
let spec = ChainSpec::few_validators();
let spec = FewValidatorsEthSpec::spec();
let mut builder = TestingBeaconStateBuilder::from_deterministic_keypairs(8, &spec);
let mut builder: TestingBeaconStateBuilder<FewValidatorsEthSpec> =
TestingBeaconStateBuilder::from_deterministic_keypairs(8, &spec);
let target_slot = (spec.genesis_epoch + 4).end_slot(spec.slots_per_epoch);
builder.teleport_to_slot(target_slot, &spec);

View File

@@ -0,0 +1,150 @@
use super::super::common::exit_validator;
use super::Error;
use types::*;
/// Peforms a validator registry update, if required.
///
/// Spec v0.5.1
pub fn update_registry_and_shuffling_data<T: EthSpec>(
state: &mut BeaconState<T>,
current_total_balance: u64,
spec: &ChainSpec,
) -> Result<(), Error> {
// First set previous shuffling data to current shuffling data.
state.previous_shuffling_epoch = state.current_shuffling_epoch;
state.previous_shuffling_start_shard = state.previous_shuffling_start_shard;
state.previous_shuffling_seed = state.previous_shuffling_seed;
let current_epoch = state.current_epoch(spec);
let next_epoch = current_epoch + 1;
// Check we should update, and if so, update.
if should_update_validator_registry(state, spec)? {
update_validator_registry(state, current_total_balance, spec)?;
// If we update the registry, update the shuffling data and shards as well.
state.current_shuffling_epoch = next_epoch;
state.current_shuffling_start_shard = {
let active_validators =
state.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?;
let epoch_committee_count = spec.get_epoch_committee_count(active_validators.len());
(state.current_shuffling_start_shard + epoch_committee_count) % spec.shard_count
};
state.current_shuffling_seed = state.generate_seed(state.current_shuffling_epoch, spec)?;
} else {
// If processing at least on crosslink keeps failing, the reshuffle every power of two, but
// don't update the current_shuffling_start_shard.
let epochs_since_last_update = current_epoch - state.validator_registry_update_epoch;
if epochs_since_last_update > 1 && epochs_since_last_update.is_power_of_two() {
state.current_shuffling_epoch = next_epoch;
state.current_shuffling_seed =
state.generate_seed(state.current_shuffling_epoch, spec)?;
}
}
Ok(())
}
/// Returns `true` if the validator registry should be updated during an epoch processing.
///
/// Spec v0.5.1
pub fn should_update_validator_registry<T: EthSpec>(
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Result<bool, BeaconStateError> {
if state.finalized_epoch <= state.validator_registry_update_epoch {
return Ok(false);
}
let num_active_validators = state
.get_cached_active_validator_indices(RelativeEpoch::Current, spec)?
.len();
let current_epoch_committee_count = spec.get_epoch_committee_count(num_active_validators);
for shard in (0..current_epoch_committee_count)
.map(|i| (state.current_shuffling_start_shard + i as u64) % spec.shard_count)
{
if state.latest_crosslinks[shard as usize].epoch <= state.validator_registry_update_epoch {
return Ok(false);
}
}
Ok(true)
}
/// Update validator registry, activating/exiting validators if possible.
///
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
///
/// Spec v0.5.1
pub fn update_validator_registry<T: EthSpec>(
state: &mut BeaconState<T>,
current_total_balance: u64,
spec: &ChainSpec,
) -> Result<(), Error> {
let current_epoch = state.current_epoch(spec);
let max_balance_churn = std::cmp::max(
spec.max_deposit_amount,
current_total_balance / (2 * spec.max_balance_churn_quotient),
);
// Activate validators within the allowable balance churn.
let mut balance_churn = 0;
for index in 0..state.validator_registry.len() {
let not_activated =
state.validator_registry[index].activation_epoch == spec.far_future_epoch;
let has_enough_balance = state.validator_balances[index] >= spec.max_deposit_amount;
if not_activated && has_enough_balance {
// Check the balance churn would be within the allowance.
balance_churn += state.get_effective_balance(index, spec)?;
if balance_churn > max_balance_churn {
break;
}
activate_validator(state, index, false, spec);
}
}
// Exit validators within the allowable balance churn.
let mut balance_churn = 0;
for index in 0..state.validator_registry.len() {
let not_exited = state.validator_registry[index].exit_epoch == spec.far_future_epoch;
let has_initiated_exit = state.validator_registry[index].initiated_exit;
if not_exited && has_initiated_exit {
// Check the balance churn would be within the allowance.
balance_churn += state.get_effective_balance(index, spec)?;
if balance_churn > max_balance_churn {
break;
}
exit_validator(state, index, spec)?;
}
}
state.validator_registry_update_epoch = current_epoch;
Ok(())
}
/// Activate the validator of the given ``index``.
///
/// Spec v0.5.1
pub fn activate_validator<T: EthSpec>(
state: &mut BeaconState<T>,
validator_index: usize,
is_genesis: bool,
spec: &ChainSpec,
) {
let current_epoch = state.current_epoch(spec);
state.validator_registry[validator_index].activation_epoch = if is_genesis {
spec.genesis_epoch
} else {
state.get_delayed_activation_exit_epoch(current_epoch, spec)
}
}

View File

@@ -163,7 +163,10 @@ impl ValidatorStatuses {
/// - Total balances for the current and previous epochs.
///
/// Spec v0.6.1
pub fn new(state: &BeaconState, spec: &ChainSpec) -> Result<Self, BeaconStateError> {
pub fn new<T: EthSpec>(
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Result<Self, BeaconStateError> {
let mut statuses = Vec::with_capacity(state.validator_registry.len());
let mut total_balances = TotalBalances::default();
@@ -200,9 +203,9 @@ impl ValidatorStatuses {
/// `total_balances` fields.
///
/// Spec v0.6.1
pub fn process_attestations(
pub fn process_attestations<T: EthSpec>(
&mut self,
state: &BeaconState,
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Result<(), BeaconStateError> {
for a in state
@@ -286,9 +289,9 @@ impl ValidatorStatuses {
/// "winning" shard block root for the previous epoch.
///
/// Spec v0.6.1
pub fn process_winning_roots(
pub fn process_winning_roots<T: EthSpec>(
&mut self,
state: &BeaconState,
state: &BeaconState<T>,
winning_roots: &WinningRootHashSet,
spec: &ChainSpec,
) -> Result<(), BeaconStateError> {
@@ -329,14 +332,14 @@ fn is_from_epoch(a: &PendingAttestation, epoch: Epoch) -> bool {
/// beacon block in the given `epoch`.
///
/// Spec v0.6.1
fn target_matches_epoch_start_block(
fn target_matches_epoch_start_block<T: EthSpec>(
a: &PendingAttestation,
state: &BeaconState,
state: &BeaconState<T>,
epoch: Epoch,
spec: &ChainSpec,
) -> Result<bool, BeaconStateError> {
let slot = epoch.start_slot(spec.slots_per_epoch);
let state_boundary_root = *state.get_block_root(slot, spec)?;
let state_boundary_root = *state.get_block_root(slot)?;
Ok(a.data.target_root == state_boundary_root)
}
@@ -345,13 +348,13 @@ fn target_matches_epoch_start_block(
/// the current slot of the `PendingAttestation`.
///
/// Spec v0.6.1
fn has_common_beacon_block_root(
fn has_common_beacon_block_root<T: EthSpec>(
a: &PendingAttestation,
state: &BeaconState,
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Result<bool, BeaconStateError> {
let attestation_slot = state.get_attestation_slot(&a.data, spec)?;
let state_block_root = *state.get_block_root(attestation_slot, spec)?;
let state_block_root = *state.get_block_root(attestation_slot)?;
Ok(a.data.beacon_block_root == state_block_root)
}

View File

@@ -35,8 +35,8 @@ impl WinningRoot {
/// per-epoch processing.
///
/// Spec v0.6.1
pub fn winning_root(
state: &BeaconState,
pub fn winning_root<T: EthSpec>(
state: &BeaconState<T>,
shard: u64,
epoch: Epoch,
spec: &ChainSpec,
@@ -99,8 +99,8 @@ pub fn winning_root(
Ok(winning_root)
}
pub fn get_unslashed_attesting_indices_unsorted(
state: &BeaconState,
pub fn get_unslashed_attesting_indices_unsorted<T: EthSpec>(
state: &BeaconState<T>,
attestations: &[&PendingAttestation],
spec: &ChainSpec,
) -> Result<Vec<usize>, BeaconStateError> {

View File

@@ -11,7 +11,10 @@ pub enum Error {
/// Advances a state forward by one slot, performing per-epoch processing if required.
///
/// Spec v0.5.1
pub fn per_slot_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> {
pub fn per_slot_processing<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
) -> Result<(), Error> {
cache_state(state, spec)?;
if (state.slot + 1) % spec.slots_per_epoch == 0 {
@@ -23,7 +26,7 @@ pub fn per_slot_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result<
Ok(())
}
fn cache_state(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> {
fn cache_state<T: EthSpec>(state: &mut BeaconState<T>, spec: &ChainSpec) -> Result<(), Error> {
let previous_slot_state_root = state.update_tree_hash_cache()?;
// Note: increment the state slot here to allow use of our `state_root` and `block_root`
@@ -39,10 +42,10 @@ fn cache_state(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), Error> {
}
// Store the previous slot's post state transition root.
state.set_state_root(previous_slot, previous_slot_state_root, spec)?;
state.set_state_root(previous_slot, previous_slot_state_root)?;
let latest_block_root = Hash256::from_slice(&state.latest_block_header.signed_root()[..]);
state.set_block_root(previous_slot, latest_block_root, spec)?;
state.set_block_root(previous_slot, latest_block_root)?;
// Set the state slot back to what it should be.
state.slot -= 1;

View File

@@ -1,153 +0,0 @@
#![cfg(not(debug_assertions))]
use serde_derive::Deserialize;
use serde_yaml;
use state_processing::{per_block_processing, per_slot_processing};
use std::{fs::File, io::prelude::*, path::PathBuf};
use types::*;
#[derive(Debug, Deserialize)]
pub struct ExpectedState {
pub slot: Option<Slot>,
pub genesis_time: Option<u64>,
pub fork: Option<Fork>,
pub validator_registry: Option<Vec<Validator>>,
pub validator_balances: Option<Vec<u64>>,
pub previous_epoch_attestations: Option<Vec<PendingAttestation>>,
pub current_epoch_attestations: Option<Vec<PendingAttestation>>,
pub historical_roots: Option<Vec<Hash256>>,
pub finalized_epoch: Option<Epoch>,
pub latest_block_roots: Option<TreeHashVector<Hash256>>,
}
impl ExpectedState {
// Return a list of fields that differ, and a string representation of the beacon state's field.
fn check(&self, state: &BeaconState) -> Vec<(&str, String)> {
// Check field equality
macro_rules! cfe {
($field_name:ident) => {
if self.$field_name.as_ref().map_or(true, |$field_name| {
println!(" > Checking {}", stringify!($field_name));
$field_name == &state.$field_name
}) {
vec![]
} else {
vec![(stringify!($field_name), format!("{:#?}", state.$field_name))]
}
};
}
vec![
cfe!(slot),
cfe!(genesis_time),
cfe!(fork),
cfe!(validator_registry),
cfe!(validator_balances),
cfe!(previous_epoch_attestations),
cfe!(current_epoch_attestations),
cfe!(historical_roots),
cfe!(finalized_epoch),
cfe!(latest_block_roots),
]
.into_iter()
.flat_map(|x| x)
.collect()
}
}
#[derive(Debug, Deserialize)]
pub struct TestCase {
pub name: String,
pub config: ChainSpec,
pub verify_signatures: bool,
pub initial_state: BeaconState,
pub blocks: Vec<BeaconBlock>,
pub expected_state: ExpectedState,
}
#[derive(Debug, Deserialize)]
pub struct TestDoc {
pub title: String,
pub summary: String,
pub fork: String,
pub test_cases: Vec<TestCase>,
}
fn load_test_case(test_name: &str) -> TestDoc {
let mut file = {
let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
file_path_buf.push(format!("yaml_utils/specs/{}", test_name));
File::open(file_path_buf).unwrap()
};
let mut yaml_str = String::new();
file.read_to_string(&mut yaml_str).unwrap();
yaml_str = yaml_str.to_lowercase();
serde_yaml::from_str(&yaml_str.as_str()).unwrap()
}
fn run_state_transition_test(test_name: &str) {
let doc = load_test_case(test_name);
// Run Tests
let mut ok = true;
for (i, test_case) in doc.test_cases.iter().enumerate() {
let fake_crypto = cfg!(feature = "fake_crypto");
if !test_case.verify_signatures == fake_crypto {
println!("Running {}", test_case.name);
} else {
println!(
"Skipping {} (fake_crypto: {}, need fake: {})",
test_case.name, fake_crypto, !test_case.verify_signatures
);
continue;
}
let mut state = test_case.initial_state.clone();
for (j, block) in test_case.blocks.iter().enumerate() {
while block.slot > state.slot {
per_slot_processing(&mut state, &test_case.config).unwrap();
}
let res = per_block_processing(&mut state, &block, &test_case.config);
if res.is_err() {
println!("Error in {} (#{}), on block {}", test_case.name, i, j);
println!("{:?}", res);
ok = false;
}
}
let mismatched_fields = test_case.expected_state.check(&state);
if !mismatched_fields.is_empty() {
println!(
"Error in expected state, these fields didn't match: {:?}",
mismatched_fields.iter().map(|(f, _)| f).collect::<Vec<_>>()
);
for (field_name, state_val) in mismatched_fields {
println!("state.{} was: {}", field_name, state_val);
}
ok = false;
}
}
assert!(ok, "one or more tests failed, see above");
}
#[test]
#[cfg(not(debug_assertions))]
fn test_read_yaml() {
load_test_case("sanity-check_small-config_32-vals.yaml");
load_test_case("sanity-check_default-config_100-vals.yaml");
}
#[test]
#[cfg(not(debug_assertions))]
fn run_state_transition_tests_small() {
run_state_transition_test("sanity-check_small-config_32-vals.yaml");
}
// Run with --ignored to run this test
#[test]
#[ignore]
fn run_state_transition_tests_large() {
run_state_transition_test("sanity-check_default-config_100-vals.yaml");
}

View File

@@ -1,14 +0,0 @@
[package]
name = "yaml-utils"
version = "0.1.0"
authors = ["Kirk Baird <baird.k@outlook.com>"]
edition = "2018"
[build-dependencies]
reqwest = "0.9"
[dependencies]
[lib]
name = "yaml_utils"
path = "src/lib.rs"

View File

@@ -1,27 +0,0 @@
extern crate reqwest;
use std::fs::File;
use std::io::copy;
fn main() {
// These test files are not to be stored in the lighthouse repo as they are quite large (32MB).
// They will be downloaded at build time by yaml-utils crate (in build.rs)
let git_path = "https://raw.githubusercontent.com/ethereum/eth2.0-tests/master/state/";
let test_names = vec![
"sanity-check_default-config_100-vals.yaml",
"sanity-check_small-config_32-vals.yaml",
];
for test in test_names {
let mut target = String::from(git_path);
target.push_str(test);
let mut response = reqwest::get(target.as_str()).unwrap();
let mut dest = {
let mut file_name = String::from("specs/");
file_name.push_str(test);
File::create(file_name).unwrap()
};
copy(&mut response, &mut dest).unwrap();
}
}

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env python3
# Script to extract all the fields of the state mentioned in `expected_state` fields of tests
# in the `spec` directory. These fields can then be added to the `ExpectedState` struct.
# Might take a while to run.
import os, yaml
if __name__ == "__main__":
yaml_files = (filename for filename in os.listdir("specs") if filename.endswith(".yaml"))
parsed_yaml = (yaml.load(open("specs/" + filename, "r")) for filename in yaml_files)
all_fields = set()
for y in parsed_yaml:
all_fields.update(*({key for key in case["expected_state"]} for case in y["test_cases"]))
print(all_fields)

View File

@@ -1 +0,0 @@
*.yaml

View File

@@ -1 +0,0 @@
// This is a place holder such that yaml-utils is now a crate hence build.rs will be run when 'cargo test' is called