Merge branch 'v0.8.3' into interop-v0.8.3

This commit is contained in:
Paul Hauner
2019-09-05 17:39:23 +10:00
54 changed files with 1695 additions and 1488 deletions
@@ -17,11 +17,9 @@ pub fn get_attesting_indices<T: EthSpec>(
target_relative_epoch,
)?;
/* TODO(freeze): re-enable this?
if bitlist.len() > committee.committee.len() {
if bitlist.len() != committee.committee.len() {
return Err(BeaconStateError::InvalidBitfield);
}
*/
Ok(committee
.committee
@@ -3,7 +3,7 @@ use types::*;
/// Return the compact committee root at `relative_epoch`.
///
/// Spec v0.8.0
/// Spec v0.8.3
pub fn get_compact_committees_root<T: EthSpec>(
state: &BeaconState<T>,
relative_epoch: RelativeEpoch,
@@ -11,28 +11,13 @@ pub fn get_compact_committees_root<T: EthSpec>(
) -> Result<Hash256, BeaconStateError> {
let mut committees =
FixedVector::<_, T::ShardCount>::from_elem(CompactCommittee::<T>::default());
// FIXME: this is a spec bug, whereby the start shard for the epoch after the next epoch
// is mistakenly used. The start shard from the cache SHOULD work.
// Waiting on a release to fix https://github.com/ethereum/eth2.0-specs/issues/1315
let start_shard = if relative_epoch == RelativeEpoch::Next {
state.next_epoch_start_shard(spec)?
} else {
state.get_epoch_start_shard(relative_epoch)?
};
let start_shard = state.get_epoch_start_shard(relative_epoch)?;
for committee_number in 0..state.get_committee_count(relative_epoch)? {
let shard = (start_shard + committee_number) % T::ShardCount::to_u64();
// FIXME: this is a partial workaround for the above, but it only works in the case
// where there's a committee for every shard in every epoch. It works for the minimal
// tests but not the mainnet ones.
let fake_shard = if relative_epoch == RelativeEpoch::Next {
(shard + 1) % T::ShardCount::to_u64()
} else {
shard
};
for &index in state
.get_crosslink_committee_for_shard(fake_shard, relative_epoch)?
.get_crosslink_committee_for_shard(shard, relative_epoch)?
.committee
{
let validator = state
@@ -11,6 +11,8 @@ pub fn get_indexed_attestation<T: EthSpec>(
state: &BeaconState<T>,
attestation: &Attestation<T>,
) -> Result<IndexedAttestation<T>> {
// Note: we rely on both calls to `get_attesting_indices` to check the bitfield lengths
// against the committee length
let attesting_indices =
get_attesting_indices(state, &attestation.data, &attestation.aggregation_bits)?;
@@ -1,8 +1,5 @@
use crate::common::get_compact_committees_root;
use apply_rewards::process_rewards_and_penalties;
use errors::EpochProcessingError as Error;
use process_slashings::process_slashings;
use registry_updates::process_registry_updates;
use std::collections::HashMap;
use tree_hash::TreeHash;
use types::*;
@@ -17,6 +14,10 @@ pub mod tests;
pub mod validator_statuses;
pub mod winning_root;
pub use apply_rewards::process_rewards_and_penalties;
pub use process_slashings::process_slashings;
pub use registry_updates::process_registry_updates;
/// Maps a shard to a winning root.
///
/// It is generated during crosslink processing and later used to reward/penalize validators.
@@ -218,45 +219,29 @@ pub fn process_final_updates<T: EthSpec>(
}
}
// Update start shard.
state.start_shard = state.next_epoch_start_shard(spec)?;
// This is a hack to allow us to update index roots and slashed balances for the next epoch.
//
// The indentation here is to make it obvious where the weird stuff happens.
{
state.slot += 1;
// Set active index root
let index_epoch = next_epoch + spec.activation_exit_delay;
let indices_list = VariableList::<usize, T::ValidatorRegistryLimit>::from(
state.get_active_validator_indices(index_epoch),
);
state.set_active_index_root(
index_epoch,
Hash256::from_slice(&indices_list.tree_hash_root()),
spec,
)?;
// Reset slashings
state.set_slashings(next_epoch, 0)?;
// Set randao mix
state.set_randao_mix(next_epoch, *state.get_randao_mix(current_epoch)?)?;
state.slot -= 1;
}
// Set active index root
let index_epoch = next_epoch + spec.activation_exit_delay;
let indices_list = VariableList::<usize, T::ValidatorRegistryLimit>::from(
state.get_active_validator_indices(index_epoch),
);
state.set_active_index_root(
index_epoch,
Hash256::from_slice(&indices_list.tree_hash_root()),
spec,
)?;
// Set committees root
// Note: we do this out-of-order w.r.t. to the spec, because we don't want the slot to be
// incremented. It's safe because the updates to slashings and the RANDAO mix (above) don't
// affect this.
state.set_compact_committee_root(
next_epoch,
get_compact_committees_root(state, RelativeEpoch::Next, spec)?,
spec,
)?;
// Reset slashings
state.set_slashings(next_epoch, 0)?;
// Set randao mix
state.set_randao_mix(next_epoch, *state.get_randao_mix(current_epoch)?)?;
// Set historical root accumulator
if next_epoch.as_u64() % (T::SlotsPerHistoricalRoot::to_u64() / T::slots_per_epoch()) == 0 {
let historical_batch = state.historical_batch();
@@ -265,6 +250,9 @@ pub fn process_final_updates<T: EthSpec>(
.push(Hash256::from_slice(&historical_batch.tree_hash_root()))?;
}
// Update start shard.
state.start_shard = state.get_epoch_start_shard(RelativeEpoch::Next)?;
// Rotate current/previous epoch attestations
state.previous_epoch_attestations =
std::mem::replace(&mut state.current_epoch_attestations, VariableList::empty());
+2 -14
View File
@@ -4,25 +4,13 @@ use crate::{Checkpoint, Crosslink, Hash256};
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::TreeHash;
/// The data upon which an attestation is based.
///
/// Spec v0.8.0
#[derive(
Debug,
Clone,
PartialEq,
Eq,
Serialize,
Deserialize,
Hash,
Encode,
Decode,
TreeHash,
TestRandom,
SignedRoot,
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Encode, Decode, TreeHash, TestRandom,
)]
pub struct AttestationData {
// LMD GHOST vote
+65 -47
View File
@@ -60,6 +60,22 @@ pub enum Error {
SszTypesError(ssz_types::Error),
}
/// Control whether an epoch-indexed field can be indexed at the next epoch or not.
#[derive(Debug, PartialEq, Clone, Copy)]
enum AllowNextEpoch {
True,
False,
}
impl AllowNextEpoch {
fn upper_bound_of(self, current_epoch: Epoch) -> Epoch {
match self {
AllowNextEpoch::True => current_epoch + 1,
AllowNextEpoch::False => current_epoch,
}
}
}
/// The state of the `BeaconChain` at some slot.
///
/// Spec v0.8.0
@@ -108,12 +124,12 @@ where
pub start_shard: u64,
pub randao_mixes: FixedVector<Hash256, T::EpochsPerHistoricalVector>,
#[compare_fields(as_slice)]
active_index_roots: FixedVector<Hash256, T::EpochsPerHistoricalVector>,
pub active_index_roots: FixedVector<Hash256, T::EpochsPerHistoricalVector>,
#[compare_fields(as_slice)]
compact_committees_roots: FixedVector<Hash256, T::EpochsPerHistoricalVector>,
pub compact_committees_roots: FixedVector<Hash256, T::EpochsPerHistoricalVector>,
// Slashings
slashings: FixedVector<u64, T::EpochsPerSlashingsVector>,
pub slashings: FixedVector<u64, T::EpochsPerSlashingsVector>,
// Attestations
pub previous_epoch_attestations: VariableList<PendingAttestation<T>, T::MaxPendingAttestations>,
@@ -282,14 +298,6 @@ impl<T: EthSpec> BeaconState<T> {
Ok(cache.epoch_start_shard())
}
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, spec.target_committee_size);
Ok((self.start_shard + shard_delta) % T::ShardCount::to_u64())
}
/// Get the slot of an attestation.
///
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
@@ -463,12 +471,16 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtains the index for `randao_mixes`
///
/// Spec v0.8.0
fn get_randao_mix_index(&self, epoch: Epoch) -> Result<usize, Error> {
/// Spec v0.8.1
fn get_randao_mix_index(
&self,
epoch: Epoch,
allow_next_epoch: AllowNextEpoch,
) -> Result<usize, Error> {
let current_epoch = self.current_epoch();
let len = T::EpochsPerHistoricalVector::to_u64();
if epoch + len > current_epoch && epoch <= current_epoch {
if current_epoch < epoch + len && epoch <= allow_next_epoch.upper_bound_of(current_epoch) {
Ok(epoch.as_usize() % len as usize)
} else {
Err(Error::EpochOutOfBounds)
@@ -496,7 +508,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Spec v0.8.1
pub fn get_randao_mix(&self, epoch: Epoch) -> Result<&Hash256, Error> {
let i = self.get_randao_mix_index(epoch)?;
let i = self.get_randao_mix_index(epoch, AllowNextEpoch::False)?;
Ok(&self.randao_mixes[i])
}
@@ -504,21 +516,29 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Spec v0.8.1
pub fn set_randao_mix(&mut self, epoch: Epoch, mix: Hash256) -> Result<(), Error> {
let i = self.get_randao_mix_index(epoch)?;
let i = self.get_randao_mix_index(epoch, AllowNextEpoch::True)?;
self.randao_mixes[i] = mix;
Ok(())
}
/// Safely obtains the index for `active_index_roots`, given some `epoch`.
///
/// If `allow_next_epoch` is `True`, then we allow an _extra_ one epoch of lookahead.
///
/// Spec v0.8.1
fn get_active_index_root_index(&self, epoch: Epoch, spec: &ChainSpec) -> Result<usize, Error> {
fn get_active_index_root_index(
&self,
epoch: Epoch,
spec: &ChainSpec,
allow_next_epoch: AllowNextEpoch,
) -> Result<usize, Error> {
let current_epoch = self.current_epoch();
let lookahead = spec.activation_exit_delay;
let lookback = self.active_index_roots.len() as u64 - lookahead;
let epoch_upper_bound = allow_next_epoch.upper_bound_of(current_epoch) + lookahead;
if epoch + lookback > current_epoch && current_epoch + lookahead >= epoch {
if current_epoch < epoch + lookback && epoch <= epoch_upper_bound {
Ok(epoch.as_usize() % self.active_index_roots.len())
} else {
Err(Error::EpochOutOfBounds)
@@ -529,7 +549,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Spec v0.8.1
pub fn get_active_index_root(&self, epoch: Epoch, spec: &ChainSpec) -> Result<Hash256, Error> {
let i = self.get_active_index_root_index(epoch, spec)?;
let i = self.get_active_index_root_index(epoch, spec, AllowNextEpoch::False)?;
Ok(self.active_index_roots[i])
}
@@ -542,7 +562,7 @@ impl<T: EthSpec> BeaconState<T> {
index_root: Hash256,
spec: &ChainSpec,
) -> Result<(), Error> {
let i = self.get_active_index_root_index(epoch, spec)?;
let i = self.get_active_index_root_index(epoch, spec, AllowNextEpoch::True)?;
self.active_index_roots[i] = index_root;
Ok(())
}
@@ -556,19 +576,17 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtains the index for `compact_committees_roots`, given some `epoch`.
///
/// Spec v0.8.0
/// Spec v0.8.1
fn get_compact_committee_root_index(
&self,
epoch: Epoch,
spec: &ChainSpec,
allow_next_epoch: AllowNextEpoch,
) -> Result<usize, Error> {
let current_epoch = self.current_epoch();
let len = T::EpochsPerHistoricalVector::to_u64();
let lookahead = spec.activation_exit_delay;
let lookback = self.compact_committees_roots.len() as u64 - lookahead;
if epoch + lookback > current_epoch && current_epoch + lookahead >= epoch {
Ok(epoch.as_usize() % self.compact_committees_roots.len())
if current_epoch < epoch + len && epoch <= allow_next_epoch.upper_bound_of(current_epoch) {
Ok(epoch.as_usize() % len as usize)
} else {
Err(Error::EpochOutOfBounds)
}
@@ -576,26 +594,21 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the `compact_committee_root` at a recent `epoch`.
///
/// Spec v0.8.0
pub fn get_compact_committee_root(
&self,
epoch: Epoch,
spec: &ChainSpec,
) -> Result<Hash256, Error> {
let i = self.get_compact_committee_root_index(epoch, spec)?;
/// Spec v0.8.1
pub fn get_compact_committee_root(&self, epoch: Epoch) -> Result<Hash256, Error> {
let i = self.get_compact_committee_root_index(epoch, AllowNextEpoch::False)?;
Ok(self.compact_committees_roots[i])
}
/// Set the `compact_committee_root` at a recent `epoch`.
///
/// Spec v0.8.0
/// Spec v0.8.1
pub fn set_compact_committee_root(
&mut self,
epoch: Epoch,
index_root: Hash256,
spec: &ChainSpec,
) -> Result<(), Error> {
let i = self.get_compact_committee_root_index(epoch, spec)?;
let i = self.get_compact_committee_root_index(epoch, AllowNextEpoch::True)?;
self.compact_committees_roots[i] = index_root;
Ok(())
}
@@ -646,14 +659,19 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtain the index for `slashings`, given some `epoch`.
///
/// Spec v0.8.0
fn get_slashings_index(&self, epoch: Epoch) -> Result<usize, Error> {
/// Spec v0.8.1
fn get_slashings_index(
&self,
epoch: Epoch,
allow_next_epoch: AllowNextEpoch,
) -> Result<usize, Error> {
// We allow the slashings vector to be accessed at any cached epoch at or before
// the current epoch.
if epoch <= self.current_epoch()
&& epoch + T::EpochsPerSlashingsVector::to_u64() >= self.current_epoch() + 1
// the current epoch, or the next epoch if `AllowNextEpoch::True` is passed.
let current_epoch = self.current_epoch();
if current_epoch < epoch + T::EpochsPerSlashingsVector::to_u64()
&& epoch <= allow_next_epoch.upper_bound_of(current_epoch)
{
Ok((epoch.as_u64() % T::EpochsPerSlashingsVector::to_u64()) as usize)
Ok(epoch.as_usize() % T::EpochsPerSlashingsVector::to_usize())
} else {
Err(Error::EpochOutOfBounds)
}
@@ -668,17 +686,17 @@ impl<T: EthSpec> BeaconState<T> {
/// Get the total slashed balances for some epoch.
///
/// Spec v0.8.0
/// Spec v0.8.1
pub fn get_slashings(&self, epoch: Epoch) -> Result<u64, Error> {
let i = self.get_slashings_index(epoch)?;
let i = self.get_slashings_index(epoch, AllowNextEpoch::False)?;
Ok(self.slashings[i])
}
/// Set the total slashed balances for some epoch.
///
/// Spec v0.8.0
/// Spec v0.8.1
pub fn set_slashings(&mut self, epoch: Epoch, value: u64) -> Result<(), Error> {
let i = self.get_slashings_index(epoch)?;
let i = self.get_slashings_index(epoch, AllowNextEpoch::True)?;
self.slashings[i] = value;
Ok(())
}
+4 -4
View File
@@ -90,11 +90,11 @@ fn test_active_index<T: EthSpec>(state_slot: Slot) {
// Test the start and end of the range.
assert_eq!(
state.get_active_index_root_index(*range.start(), &spec),
state.get_active_index_root_index(*range.start(), &spec, AllowNextEpoch::False),
Ok(modulo(*range.start()))
);
assert_eq!(
state.get_active_index_root_index(*range.end(), &spec),
state.get_active_index_root_index(*range.end(), &spec, AllowNextEpoch::False),
Ok(modulo(*range.end()))
);
@@ -102,12 +102,12 @@ fn test_active_index<T: EthSpec>(state_slot: Slot) {
if state.current_epoch() > 0 {
// Test is invalid on epoch zero, cannot subtract from zero.
assert_eq!(
state.get_active_index_root_index(*range.start() - 1, &spec),
state.get_active_index_root_index(*range.start() - 1, &spec, AllowNextEpoch::False),
Err(Error::EpochOutOfBounds)
);
}
assert_eq!(
state.get_active_index_root_index(*range.end() + 1, &spec),
state.get_active_index_root_index(*range.end() + 1, &spec, AllowNextEpoch::False),
Err(Error::EpochOutOfBounds)
);
}
+1 -3
View File
@@ -3,8 +3,7 @@ use crate::{Epoch, Hash256};
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::TreeHash;
/// Casper FFG checkpoint, used in attestations.
///
@@ -22,7 +21,6 @@ use tree_hash_derive::{SignedRoot, TreeHash};
Decode,
TreeHash,
TestRandom,
SignedRoot,
)]
pub struct Checkpoint {
pub epoch: Epoch,
+2 -1
View File
@@ -5,7 +5,8 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[dependencies]
milagro_bls = { git = "https://github.com/sigp/milagro_bls", tag = "v0.10.0" }
# FIXME: update sigp repo
milagro_bls = { git = "https://github.com/michaelsproul/milagro_bls", branch = "little-endian-v0.10" }
eth2_hashing = { path = "../eth2_hashing" }
hex = "0.3"
rand = "^0.5"
+15 -2
View File
@@ -220,13 +220,26 @@ where
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
if bytes.is_empty() {
Ok(FixedVector::from(vec![]))
Err(ssz::DecodeError::InvalidByteLength {
len: 0,
expected: 1,
})
} else if T::is_ssz_fixed_len() {
bytes
.chunks(T::ssz_fixed_len())
.map(|chunk| T::from_ssz_bytes(chunk))
.collect::<Result<Vec<T>, _>>()
.and_then(|vec| Ok(vec.into()))
.and_then(|vec| {
if vec.len() == N::to_usize() {
Ok(vec.into())
} else {
Err(ssz::DecodeError::BytesInvalid(format!(
"wrong number of vec elements, got: {}, expected: {}",
vec.len(),
N::to_usize()
)))
}
})
} else {
ssz::decode_list_of_variable_length_items(bytes).and_then(|vec| Ok(vec.into()))
}
+41 -1
View File
@@ -1,5 +1,5 @@
use super::*;
use ethereum_types::H256;
use ethereum_types::{H256, U128, U256};
macro_rules! impl_for_bitsize {
($type: ident, $bit_size: expr) => {
@@ -73,6 +73,46 @@ macro_rules! impl_for_u8_array {
impl_for_u8_array!(4);
impl_for_u8_array!(32);
impl TreeHash for U128 {
fn tree_hash_type() -> TreeHashType {
TreeHashType::Basic
}
fn tree_hash_packed_encoding(&self) -> Vec<u8> {
let mut result = vec![0; 16];
self.to_little_endian(&mut result);
result
}
fn tree_hash_packing_factor() -> usize {
2
}
fn tree_hash_root(&self) -> Vec<u8> {
merkle_root(&self.tree_hash_packed_encoding(), 0)
}
}
impl TreeHash for U256 {
fn tree_hash_type() -> TreeHashType {
TreeHashType::Basic
}
fn tree_hash_packed_encoding(&self) -> Vec<u8> {
let mut result = vec![0; 32];
self.to_little_endian(&mut result);
result
}
fn tree_hash_packing_factor() -> usize {
1
}
fn tree_hash_root(&self) -> Vec<u8> {
merkle_root(&self.tree_hash_packed_encoding(), 0)
}
}
impl TreeHash for H256 {
fn tree_hash_type() -> TreeHashType {
TreeHashType::Vector