Optimise epoch building

This commit is contained in:
Paul Hauner 2019-03-14 22:16:21 +11:00
parent 8154397114
commit 902b80a579
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
3 changed files with 51 additions and 66 deletions

View File

@ -537,8 +537,8 @@ impl BeaconState {
let cache = self.cache(relative_epoch)?;
let (committee_slot_index, committee_index) = cache
.shard_committee_index_map
.get(&attestation_data.shard)
.shard_committee_indices
.get(attestation_data.shard as usize)
.ok_or_else(|| Error::ShardOutOfBounds)?;
let (committee, shard) = &cache.committees[*committee_slot_index][*committee_index];
@ -787,7 +787,6 @@ impl BeaconState {
&self,
slot: Slot,
registry_change: bool,
spec: &ChainSpec,
) -> Result<Vec<Vec<usize>>, Error> {
let (_committees_per_epoch, seed, shuffling_epoch, _shuffling_start_shard) =
@ -810,7 +809,6 @@ impl BeaconState {
) -> Result<Vec<Vec<usize>>, Error> {
let active_validator_indices =
get_active_validator_indices(&self.validator_registry, epoch);
if active_validator_indices.is_empty() {
error!("get_shuffling: no validators.");
return Err(Error::InsufficientValidators);
@ -912,22 +910,18 @@ impl BeaconState {
}
}
/// Return the list of ``(committee, shard)`` tuples for the ``slot``.
/// Return the ordered list of shards tuples for the `slot`.
///
/// Note: There are two possible shufflings for crosslink committees for a
/// `slot` in the next epoch: with and without a `registry_change`
///
/// Note: does not utilize the cache, `get_crosslink_committees_at_slot` is an equivalent
/// function which uses the cache.
///
/// Spec v0.4.0
pub(crate) fn calculate_crosslink_committees_at_slot(
pub(crate) fn get_shards_for_slot(
&self,
slot: Slot,
registry_change: bool,
shuffling: Vec<Vec<usize>>,
spec: &ChainSpec,
) -> Result<Vec<(Vec<usize>, u64)>, Error> {
) -> Result<Vec<u64>, Error> {
let (committees_per_epoch, _seed, _shuffling_epoch, shuffling_start_shard) =
self.get_committee_params_at_slot(slot, registry_change, spec)?;
@ -936,15 +930,12 @@ impl BeaconState {
let slot_start_shard =
(shuffling_start_shard + committees_per_slot * offset) % spec.shard_count;
let mut crosslinks_at_slot = vec![];
let mut shards_at_slot = vec![];
for i in 0..committees_per_slot {
let tuple = (
shuffling[(committees_per_slot * offset + i) as usize].clone(),
(slot_start_shard + i) % spec.shard_count,
);
crosslinks_at_slot.push(tuple)
shards_at_slot.push((slot_start_shard + i) % spec.shard_count)
}
Ok(crosslinks_at_slot)
Ok(shards_at_slot)
}
/// Returns the `slot`, `shard` and `committee_index` for which a validator must produce an
@ -962,10 +953,10 @@ impl BeaconState {
) -> Result<Option<(Slot, u64, u64)>, Error> {
let cache = self.cache(RelativeEpoch::Current)?;
Ok(cache
.attestation_duty_map
.get(&(validator_index as u64))
.and_then(|tuple| Some(*tuple)))
Ok(*cache
.attestation_duties
.get(validator_index)
.ok_or_else(|| Error::UnknownValidator)?)
}
/// Process the slashings.

View File

@ -1,8 +1,6 @@
use super::{AttestationDutyMap, BeaconState, CrosslinkCommittees, Error, ShardCommitteeIndexMap};
use super::{AttestationDuty, BeaconState, CrosslinkCommittees, Error};
use crate::{ChainSpec, Epoch};
use log::trace;
use serde_derive::Serialize;
use std::collections::HashMap;
#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct EpochCache {
@ -11,21 +9,23 @@ pub struct EpochCache {
/// The crosslink committees for an epoch.
pub committees: Vec<CrosslinkCommittees>,
/// Maps validator index to a slot, shard and committee index for attestation.
pub attestation_duty_map: AttestationDutyMap,
pub attestation_duties: Vec<Option<AttestationDuty>>,
/// Maps a shard to an index of `self.committees`.
pub shard_committee_index_map: ShardCommitteeIndexMap,
pub shard_committee_indices: Vec<(usize, usize)>,
}
impl EpochCache {
/// Return a new, completely empty cache.
pub fn empty() -> EpochCache {
EpochCache {
initialized: false,
committees: vec![],
attestation_duty_map: AttestationDutyMap::new(),
shard_committee_index_map: ShardCommitteeIndexMap::new(),
attestation_duties: vec![],
shard_committee_indices: vec![],
}
}
/// Return a new, fully initialized cache.
pub fn initialized(
state: &BeaconState,
epoch: Epoch,
@ -33,42 +33,36 @@ impl EpochCache {
) -> Result<EpochCache, Error> {
let mut epoch_committees: Vec<CrosslinkCommittees> =
Vec::with_capacity(spec.slots_per_epoch as usize);
let mut shard_committee_index_map: ShardCommitteeIndexMap = HashMap::new();
let shuffling =
let mut attestation_duties = vec![None; state.validator_registry.len()];
let mut shard_committee_indices = vec![(0, 0); spec.shard_count as usize];
let mut shuffling =
state.get_shuffling_for_slot(epoch.start_slot(spec.slots_per_epoch), false, spec)?;
let mut attestation_duty_map: AttestationDutyMap = HashMap::with_capacity(shuffling.len());
for (epoch_committees_index, slot) in epoch.slot_iter(spec.slots_per_epoch).enumerate() {
let mut slot_committees: Vec<(Vec<usize>, u64)> = vec![];
for (epoch_committeess_index, slot) in epoch.slot_iter(spec.slots_per_epoch).enumerate() {
let slot_committees = state.calculate_crosslink_committees_at_slot(
slot,
false,
shuffling.clone(),
spec,
)?;
let shards = state.get_shards_for_slot(slot, false, spec)?;
for shard in shards {
let committee = shuffling.remove(0);
slot_committees.push((committee, shard));
}
for (slot_committees_index, (committee, shard)) in slot_committees.iter().enumerate() {
// Empty committees are not permitted.
if committee.is_empty() {
return Err(Error::InsufficientValidators);
}
trace!(
"shard: {}, epoch_i: {}, slot_i: {}",
shard,
epoch_committeess_index,
slot_committees_index
);
shard_committee_index_map
.insert(*shard, (epoch_committeess_index, slot_committees_index));
// Store the slot and committee index for this shard.
shard_committee_indices[*shard as usize] =
(epoch_committees_index, slot_committees_index);
// For each validator, store their attestation duties.
for (committee_index, validator_index) in committee.iter().enumerate() {
attestation_duty_map.insert(
*validator_index as u64,
(slot, *shard, committee_index as u64),
);
attestation_duties[*validator_index] =
Some((slot, *shard, committee_index as u64))
}
}
@ -78,8 +72,8 @@ impl EpochCache {
Ok(EpochCache {
initialized: true,
committees: epoch_committees,
attestation_duty_map,
shard_committee_index_map,
attestation_duties,
shard_committee_indices,
})
}
}

View File

@ -7,17 +7,17 @@ use crate::Epoch;
///
/// Spec v0.4.0
pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec<usize> {
validators
.iter()
.enumerate()
.filter_map(|(index, validator)| {
if validator.is_active_at(epoch) {
Some(index)
} else {
None
}
})
.collect::<Vec<_>>()
let mut active = Vec::with_capacity(validators.len());
for (index, validator) in validators.iter().enumerate() {
if validator.is_active_at(epoch) {
active.push(index)
}
}
active.shrink_to_fit();
active
}
#[cfg(test)]