Optimise epoch building
This commit is contained in:
parent
8154397114
commit
902b80a579
@ -537,8 +537,8 @@ impl BeaconState {
|
|||||||
let cache = self.cache(relative_epoch)?;
|
let cache = self.cache(relative_epoch)?;
|
||||||
|
|
||||||
let (committee_slot_index, committee_index) = cache
|
let (committee_slot_index, committee_index) = cache
|
||||||
.shard_committee_index_map
|
.shard_committee_indices
|
||||||
.get(&attestation_data.shard)
|
.get(attestation_data.shard as usize)
|
||||||
.ok_or_else(|| Error::ShardOutOfBounds)?;
|
.ok_or_else(|| Error::ShardOutOfBounds)?;
|
||||||
let (committee, shard) = &cache.committees[*committee_slot_index][*committee_index];
|
let (committee, shard) = &cache.committees[*committee_slot_index][*committee_index];
|
||||||
|
|
||||||
@ -787,7 +787,6 @@ impl BeaconState {
|
|||||||
&self,
|
&self,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
registry_change: bool,
|
registry_change: bool,
|
||||||
|
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<Vec<Vec<usize>>, Error> {
|
) -> Result<Vec<Vec<usize>>, Error> {
|
||||||
let (_committees_per_epoch, seed, shuffling_epoch, _shuffling_start_shard) =
|
let (_committees_per_epoch, seed, shuffling_epoch, _shuffling_start_shard) =
|
||||||
@ -810,7 +809,6 @@ impl BeaconState {
|
|||||||
) -> Result<Vec<Vec<usize>>, Error> {
|
) -> Result<Vec<Vec<usize>>, Error> {
|
||||||
let active_validator_indices =
|
let active_validator_indices =
|
||||||
get_active_validator_indices(&self.validator_registry, epoch);
|
get_active_validator_indices(&self.validator_registry, epoch);
|
||||||
|
|
||||||
if active_validator_indices.is_empty() {
|
if active_validator_indices.is_empty() {
|
||||||
error!("get_shuffling: no validators.");
|
error!("get_shuffling: no validators.");
|
||||||
return Err(Error::InsufficientValidators);
|
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
|
/// Note: There are two possible shufflings for crosslink committees for a
|
||||||
/// `slot` in the next epoch: with and without a `registry_change`
|
/// `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
|
/// Spec v0.4.0
|
||||||
pub(crate) fn calculate_crosslink_committees_at_slot(
|
pub(crate) fn get_shards_for_slot(
|
||||||
&self,
|
&self,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
registry_change: bool,
|
registry_change: bool,
|
||||||
shuffling: Vec<Vec<usize>>,
|
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<Vec<(Vec<usize>, u64)>, Error> {
|
) -> Result<Vec<u64>, Error> {
|
||||||
let (committees_per_epoch, _seed, _shuffling_epoch, shuffling_start_shard) =
|
let (committees_per_epoch, _seed, _shuffling_epoch, shuffling_start_shard) =
|
||||||
self.get_committee_params_at_slot(slot, registry_change, spec)?;
|
self.get_committee_params_at_slot(slot, registry_change, spec)?;
|
||||||
|
|
||||||
@ -936,15 +930,12 @@ impl BeaconState {
|
|||||||
let slot_start_shard =
|
let slot_start_shard =
|
||||||
(shuffling_start_shard + committees_per_slot * offset) % spec.shard_count;
|
(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 {
|
for i in 0..committees_per_slot {
|
||||||
let tuple = (
|
shards_at_slot.push((slot_start_shard + i) % spec.shard_count)
|
||||||
shuffling[(committees_per_slot * offset + i) as usize].clone(),
|
|
||||||
(slot_start_shard + i) % spec.shard_count,
|
|
||||||
);
|
|
||||||
crosslinks_at_slot.push(tuple)
|
|
||||||
}
|
}
|
||||||
Ok(crosslinks_at_slot)
|
|
||||||
|
Ok(shards_at_slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `slot`, `shard` and `committee_index` for which a validator must produce an
|
/// 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> {
|
) -> Result<Option<(Slot, u64, u64)>, Error> {
|
||||||
let cache = self.cache(RelativeEpoch::Current)?;
|
let cache = self.cache(RelativeEpoch::Current)?;
|
||||||
|
|
||||||
Ok(cache
|
Ok(*cache
|
||||||
.attestation_duty_map
|
.attestation_duties
|
||||||
.get(&(validator_index as u64))
|
.get(validator_index)
|
||||||
.and_then(|tuple| Some(*tuple)))
|
.ok_or_else(|| Error::UnknownValidator)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process the slashings.
|
/// Process the slashings.
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use super::{AttestationDutyMap, BeaconState, CrosslinkCommittees, Error, ShardCommitteeIndexMap};
|
use super::{AttestationDuty, BeaconState, CrosslinkCommittees, Error};
|
||||||
use crate::{ChainSpec, Epoch};
|
use crate::{ChainSpec, Epoch};
|
||||||
use log::trace;
|
|
||||||
use serde_derive::Serialize;
|
use serde_derive::Serialize;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||||
pub struct EpochCache {
|
pub struct EpochCache {
|
||||||
@ -11,21 +9,23 @@ pub struct EpochCache {
|
|||||||
/// The crosslink committees for an epoch.
|
/// The crosslink committees for an epoch.
|
||||||
pub committees: Vec<CrosslinkCommittees>,
|
pub committees: Vec<CrosslinkCommittees>,
|
||||||
/// Maps validator index to a slot, shard and committee index for attestation.
|
/// 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`.
|
/// Maps a shard to an index of `self.committees`.
|
||||||
pub shard_committee_index_map: ShardCommitteeIndexMap,
|
pub shard_committee_indices: Vec<(usize, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EpochCache {
|
impl EpochCache {
|
||||||
|
/// Return a new, completely empty cache.
|
||||||
pub fn empty() -> EpochCache {
|
pub fn empty() -> EpochCache {
|
||||||
EpochCache {
|
EpochCache {
|
||||||
initialized: false,
|
initialized: false,
|
||||||
committees: vec![],
|
committees: vec![],
|
||||||
attestation_duty_map: AttestationDutyMap::new(),
|
attestation_duties: vec![],
|
||||||
shard_committee_index_map: ShardCommitteeIndexMap::new(),
|
shard_committee_indices: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a new, fully initialized cache.
|
||||||
pub fn initialized(
|
pub fn initialized(
|
||||||
state: &BeaconState,
|
state: &BeaconState,
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
@ -33,42 +33,36 @@ impl EpochCache {
|
|||||||
) -> Result<EpochCache, Error> {
|
) -> Result<EpochCache, Error> {
|
||||||
let mut epoch_committees: Vec<CrosslinkCommittees> =
|
let mut epoch_committees: Vec<CrosslinkCommittees> =
|
||||||
Vec::with_capacity(spec.slots_per_epoch as usize);
|
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)?;
|
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 shards = state.get_shards_for_slot(slot, false, spec)?;
|
||||||
let slot_committees = state.calculate_crosslink_committees_at_slot(
|
for shard in shards {
|
||||||
slot,
|
let committee = shuffling.remove(0);
|
||||||
false,
|
slot_committees.push((committee, shard));
|
||||||
shuffling.clone(),
|
}
|
||||||
spec,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
for (slot_committees_index, (committee, shard)) in slot_committees.iter().enumerate() {
|
for (slot_committees_index, (committee, shard)) in slot_committees.iter().enumerate() {
|
||||||
// Empty committees are not permitted.
|
|
||||||
if committee.is_empty() {
|
if committee.is_empty() {
|
||||||
return Err(Error::InsufficientValidators);
|
return Err(Error::InsufficientValidators);
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!(
|
// Store the slot and committee index for this shard.
|
||||||
"shard: {}, epoch_i: {}, slot_i: {}",
|
shard_committee_indices[*shard as usize] =
|
||||||
shard,
|
(epoch_committees_index, slot_committees_index);
|
||||||
epoch_committeess_index,
|
|
||||||
slot_committees_index
|
|
||||||
);
|
|
||||||
|
|
||||||
shard_committee_index_map
|
|
||||||
.insert(*shard, (epoch_committeess_index, slot_committees_index));
|
|
||||||
|
|
||||||
|
// For each validator, store their attestation duties.
|
||||||
for (committee_index, validator_index) in committee.iter().enumerate() {
|
for (committee_index, validator_index) in committee.iter().enumerate() {
|
||||||
attestation_duty_map.insert(
|
attestation_duties[*validator_index] =
|
||||||
*validator_index as u64,
|
Some((slot, *shard, committee_index as u64))
|
||||||
(slot, *shard, committee_index as u64),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,8 +72,8 @@ impl EpochCache {
|
|||||||
Ok(EpochCache {
|
Ok(EpochCache {
|
||||||
initialized: true,
|
initialized: true,
|
||||||
committees: epoch_committees,
|
committees: epoch_committees,
|
||||||
attestation_duty_map,
|
attestation_duties,
|
||||||
shard_committee_index_map,
|
shard_committee_indices,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,17 @@ use crate::Epoch;
|
|||||||
///
|
///
|
||||||
/// Spec v0.4.0
|
/// Spec v0.4.0
|
||||||
pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec<usize> {
|
pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec<usize> {
|
||||||
validators
|
let mut active = Vec::with_capacity(validators.len());
|
||||||
.iter()
|
|
||||||
.enumerate()
|
for (index, validator) in validators.iter().enumerate() {
|
||||||
.filter_map(|(index, validator)| {
|
|
||||||
if validator.is_active_at(epoch) {
|
if validator.is_active_at(epoch) {
|
||||||
Some(index)
|
active.push(index)
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.collect::<Vec<_>>()
|
|
||||||
|
active.shrink_to_fit();
|
||||||
|
|
||||||
|
active
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
Reference in New Issue
Block a user