Allow state processing to compile under v0.5.0

This commit is contained in:
Paul Hauner
2019-03-17 17:47:12 +11:00
parent 3b8c1df5da
commit 3a384d93f8
13 changed files with 422 additions and 242 deletions

View File

@@ -1,8 +1,7 @@
use self::epoch_cache::EpochCache;
use crate::test_utils::TestRandom;
use crate::{validator_registry::get_active_validator_indices, *};
use crate::*;
use int_to_bytes::int_to_bytes32;
use log::trace;
use pubkey_cache::PubkeyCache;
use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
@@ -39,6 +38,7 @@ pub enum Error {
InsufficientAttestations,
InsufficientCommittees,
InsufficientSlashedBalances,
NoCommitteeForShard,
EpochCacheUninitialized(RelativeEpoch),
PubkeyCacheInconsistent,
PubkeyCacheIncomplete {
@@ -349,17 +349,49 @@ impl BeaconState {
self.current_epoch(spec) + 1
}
/// Returns the active validator indices for the given epoch, assuming there is no validator
/// registry update in the next epoch.
///
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
///
/// Spec v0.5.0
pub fn get_active_validator_indices(
&self,
epoch: Epoch,
spec: &ChainSpec,
) -> Result<&[usize], Error> {
// If the slot is in the next epoch, assume there was no validator registry update.
let relative_epoch =
match RelativeEpoch::from_epoch(self.slot.epoch(spec.slots_per_epoch), epoch) {
Err(RelativeEpochError::AmbiguiousNextEpoch) => {
Ok(RelativeEpoch::NextWithoutRegistryChange)
}
e => e,
}?;
let cache = self.cache(relative_epoch, spec)?;
Ok(&cache.active_validator_indices)
}
/// Returns the crosslink committees for some slot.
///
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
///
/// Spec v0.4.0
/// Spec v0.5.0
pub fn get_crosslink_committees_at_slot(
&self,
slot: Slot,
relative_epoch: RelativeEpoch,
spec: &ChainSpec,
) -> Result<&Vec<CrosslinkCommittee>, Error> {
// If the slot is in the next epoch, assume there was no validator registry update.
let relative_epoch = match RelativeEpoch::from_slot(self.slot, slot, spec) {
Err(RelativeEpochError::AmbiguiousNextEpoch) => {
Ok(RelativeEpoch::NextWithoutRegistryChange)
}
e => e,
}?;
let cache = self.cache(relative_epoch, spec)?;
Ok(cache
@@ -367,15 +399,46 @@ impl BeaconState {
.ok_or_else(|| Error::SlotOutOfBounds)?)
}
/// Returns the crosslink committees for some shard in an epoch.
///
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
///
/// Spec v0.4.0
pub fn get_crosslink_committee_for_shard(
&self,
epoch: Epoch,
shard: Shard,
spec: &ChainSpec,
) -> Result<&CrosslinkCommittee, Error> {
// If the slot is in the next epoch, assume there was no validator registry update.
let relative_epoch = match RelativeEpoch::from_epoch(self.current_epoch(spec), epoch) {
Err(RelativeEpochError::AmbiguiousNextEpoch) => {
Ok(RelativeEpoch::NextWithoutRegistryChange)
}
e => e,
}?;
let cache = self.cache(relative_epoch, spec)?;
Ok(cache
.get_crosslink_committee_for_shard(shard, spec)
.ok_or_else(|| Error::NoCommitteeForShard)?)
}
/// Return the block root at a recent `slot`.
///
/// Spec v0.5.0
pub fn get_block_root(&self, slot: Slot, spec: &ChainSpec) -> Option<&Hash256> {
pub fn get_block_root(
&self,
slot: Slot,
spec: &ChainSpec,
) -> Result<&Hash256, BeaconStateError> {
if (self.slot <= slot + spec.slots_per_historical_root as u64) && (slot < self.slot) {
self.latest_block_roots
.get(slot.as_usize() % spec.slots_per_historical_root)
.ok_or_else(|| Error::InsufficientBlockRoots)
} else {
None
Err(Error::EpochOutOfBounds)
}
}
@@ -476,12 +539,12 @@ impl BeaconState {
relative_epoch: RelativeEpoch,
spec: &ChainSpec,
) -> Result<usize, Error> {
let committees = self.get_crosslink_committees_at_slot(slot, relative_epoch, spec)?;
trace!(
"get_beacon_proposer_index: slot: {}, committees_count: {}",
slot,
committees.len()
);
let cache = self.cache(relative_epoch, spec)?;
let committees = cache
.get_crosslink_committees_at_slot(slot, spec)
.ok_or_else(|| Error::SlotOutOfBounds)?;
committees
.first()
.ok_or(Error::InsufficientValidators)
@@ -751,13 +814,14 @@ impl BeaconState {
.ok_or_else(|| Error::UnknownValidator)?)
}
/// Process the slashings.
/// Process slashings.
///
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
///
/// Spec v0.4.0
pub fn process_slashings(&mut self, spec: &ChainSpec) -> Result<(), Error> {
let current_epoch = self.current_epoch(spec);
let active_validator_indices =
get_active_validator_indices(&self.validator_registry, current_epoch);
let active_validator_indices = self.get_active_validator_indices(current_epoch, spec)?;
let total_balance = self.get_total_balance(&active_validator_indices[..], spec)?;
for (index, validator) in self.validator_registry.iter().enumerate() {
@@ -818,11 +882,12 @@ impl BeaconState {
/// Update validator registry, activating/exiting validators if possible.
///
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
///
/// Spec v0.4.0
pub fn update_validator_registry(&mut self, spec: &ChainSpec) -> Result<(), Error> {
let current_epoch = self.current_epoch(spec);
let active_validator_indices =
get_active_validator_indices(&self.validator_registry, current_epoch);
let active_validator_indices = self.get_active_validator_indices(current_epoch, spec)?;
let total_balance = self.get_total_balance(&active_validator_indices[..], spec)?;
let max_balance_churn = std::cmp::max(
@@ -867,54 +932,32 @@ impl BeaconState {
/// Iterate through the validator registry and eject active validators with balance below
/// ``EJECTION_BALANCE``.
///
/// Spec v0.4.0
pub fn process_ejections(&mut self, spec: &ChainSpec) {
for validator_index in
get_active_validator_indices(&self.validator_registry, self.current_epoch(spec))
{
if self.validator_balances[validator_index] < spec.ejection_balance {
self.exit_validator(validator_index, spec)
}
/// Spec v0.5.0
pub fn process_ejections(&mut self, 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> = self
.get_active_validator_indices(self.current_epoch(spec), spec)?
.iter()
.filter_map(|&i| {
if self.validator_balances[i as usize] < spec.ejection_balance {
Some(i)
} else {
None
}
})
.collect();
for validator_index in exitable {
self.exit_validator(validator_index, spec)
}
}
/// Returns the penality that should be applied to some validator for inactivity.
///
/// Note: this is defined "inline" in the spec, not as a helper function.
///
/// Spec v0.4.0
pub fn inactivity_penalty(
&self,
validator_index: usize,
epochs_since_finality: Epoch,
base_reward_quotient: u64,
spec: &ChainSpec,
) -> Result<u64, Error> {
let effective_balance = self.get_effective_balance(validator_index, spec)?;
let base_reward = self.base_reward(validator_index, base_reward_quotient, spec)?;
Ok(base_reward
+ effective_balance * epochs_since_finality.as_u64()
/ spec.inactivity_penalty_quotient
/ 2)
}
/// Returns the base reward for some validator.
///
/// Note: In the spec this is defined "inline", not as a helper function.
///
/// Spec v0.4.0
pub fn base_reward(
&self,
validator_index: usize,
base_reward_quotient: u64,
spec: &ChainSpec,
) -> Result<u64, Error> {
Ok(self.get_effective_balance(validator_index, spec)? / base_reward_quotient / 5)
Ok(())
}
/// Return the combined effective balance of an array of validators.
///
/// Spec v0.4.0
/// Spec v0.5.0
pub fn get_total_balance(
&self,
validator_indices: &[usize],

View File

@@ -13,7 +13,9 @@ pub struct EpochCache {
/// Maps validator index to a slot, shard and committee index for attestation.
pub attestation_duties: Vec<Option<AttestationDuty>>,
/// Maps a shard to an index of `self.committees`.
pub shard_committee_indices: Vec<(Slot, usize)>,
pub shard_committee_indices: Vec<Option<(Slot, usize)>>,
/// Indices of all active validators in the epoch
pub active_validator_indices: Vec<usize>,
}
impl EpochCache {
@@ -31,18 +33,18 @@ impl EpochCache {
let builder = match relative_epoch {
RelativeEpoch::Previous => EpochCrosslinkCommitteesBuilder::for_previous_epoch(
state,
active_validator_indices,
active_validator_indices.clone(),
spec,
),
RelativeEpoch::Current => EpochCrosslinkCommitteesBuilder::for_current_epoch(
state,
active_validator_indices,
active_validator_indices.clone(),
spec,
),
RelativeEpoch::NextWithRegistryChange => {
EpochCrosslinkCommitteesBuilder::for_next_epoch(
state,
active_validator_indices,
active_validator_indices.clone(),
true,
spec,
)?
@@ -50,7 +52,7 @@ impl EpochCache {
RelativeEpoch::NextWithoutRegistryChange => {
EpochCrosslinkCommitteesBuilder::for_next_epoch(
state,
active_validator_indices,
active_validator_indices.clone(),
false,
spec,
)?
@@ -64,7 +66,7 @@ impl EpochCache {
// 2. `shard_committee_indices`: maps `Shard` into a `CrosslinkCommittee` in
// `EpochCrosslinkCommittees`.
let mut attestation_duties = vec![None; state.validator_registry.len()];
let mut shard_committee_indices = vec![(Slot::default(), 0); spec.shard_count as usize];
let mut shard_committee_indices = vec![None; spec.shard_count as usize];
for (i, slot_committees) in epoch_crosslink_committees
.crosslink_committees
.iter()
@@ -75,7 +77,7 @@ impl EpochCache {
for (j, crosslink_committee) in slot_committees.iter().enumerate() {
let shard = crosslink_committee.shard;
shard_committee_indices[shard as usize] = (slot, j);
shard_committee_indices[shard as usize] = Some((slot, j));
for (k, validator_index) in crosslink_committee.committee.iter().enumerate() {
let attestation_duty = AttestationDuty {
@@ -93,6 +95,7 @@ impl EpochCache {
epoch_crosslink_committees,
attestation_duties,
shard_committee_indices,
active_validator_indices,
})
}
@@ -110,9 +113,13 @@ impl EpochCache {
shard: Shard,
spec: &ChainSpec,
) -> Option<&CrosslinkCommittee> {
let (slot, committee) = self.shard_committee_indices.get(shard as usize)?;
let slot_committees = self.get_crosslink_committees_at_slot(*slot, spec)?;
slot_committees.get(*committee)
if shard > self.shard_committee_indices.len() as u64 {
None
} else {
let (slot, committee) = self.shard_committee_indices[shard as usize]?;
let slot_committees = self.get_crosslink_committees_at_slot(slot, spec)?;
slot_committees.get(committee)
}
}
}
@@ -261,13 +268,14 @@ impl EpochCrosslinkCommitteesBuilder {
let committees_per_slot = (self.committees_per_epoch / spec.slots_per_epoch) as usize;
for i in 0..spec.slots_per_epoch as usize {
for (i, slot) in self.epoch.slot_iter(spec.slots_per_epoch).enumerate() {
for j in (0..committees.len())
.into_iter()
.skip(i * committees_per_slot)
.take(committees_per_slot)
{
let crosslink_committee = CrosslinkCommittee {
slot,
shard,
committee: committees.remove(j),
};

View File

@@ -4,6 +4,7 @@ use ssz_derive::{Decode, Encode, TreeHash};
#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize, Decode, Encode, TreeHash)]
pub struct CrosslinkCommittee {
pub slot: Slot,
pub shard: Shard,
pub committee: Vec<usize>,
}

View File

@@ -109,10 +109,7 @@ impl TestingBeaconBlockBuilder {
break;
}
let relative_epoch = RelativeEpoch::from_slot(state.slot, slot, spec).unwrap();
for crosslink_committee in
state.get_crosslink_committees_at_slot(slot, relative_epoch, spec)?
{
for crosslink_committee in state.get_crosslink_committees_at_slot(slot, spec)? {
if attestations_added >= num_attestations {
break;
}

View File

@@ -223,9 +223,8 @@ impl TestingBeaconStateBuilder {
for slot in first_slot..last_slot + 1 {
let slot = Slot::from(slot);
let relative_epoch = RelativeEpoch::from_slot(state.slot, slot, spec).unwrap();
let committees = state
.get_crosslink_committees_at_slot(slot, relative_epoch, spec)
.get_crosslink_committees_at_slot(slot, spec)
.unwrap()
.clone();