From 5cae2f9656ae54d1d5e65d4ac991501011a4817f Mon Sep 17 00:00:00 2001 From: realbigsean Date: Sat, 23 Apr 2022 09:04:33 +0200 Subject: [PATCH] separate participation cache by epoch and add it to the beacon state --- .../http_api/src/attestation_performance.rs | 4 +- .../http_api/src/validator_inclusion.rs | 3 +- consensus/state_processing/src/lib.rs | 10 +- .../src/per_epoch_processing/altair.rs | 35 ++-- .../altair/justification_and_finalization.rs | 1 + .../altair/rewards_and_penalties.rs | 1 + .../epoch_processing_summary.rs | 5 +- .../src/per_epoch_processing/errors.rs | 2 +- .../state_processing/src/upgrade/altair.rs | 1 + .../state_processing/src/upgrade/merge.rs | 1 + consensus/types/src/beacon_state.rs | 27 ++- .../src/beacon_state}/participation_cache.rs | 168 ++++++++++++++---- consensus/types/src/test_utils/test_random.rs | 1 + 13 files changed, 194 insertions(+), 65 deletions(-) rename consensus/{state_processing/src/per_epoch_processing/altair => types/src/beacon_state}/participation_cache.rs (80%) diff --git a/beacon_node/http_api/src/attestation_performance.rs b/beacon_node/http_api/src/attestation_performance.rs index 5cd9894adef..938358b8274 100644 --- a/beacon_node/http_api/src/attestation_performance.rs +++ b/beacon_node/http_api/src/attestation_performance.rs @@ -3,11 +3,11 @@ use eth2::lighthouse::{ AttestationPerformance, AttestationPerformanceQuery, AttestationPerformanceStatistics, }; use state_processing::{ - per_epoch_processing::altair::participation_cache::Error as ParticipationCacheError, - per_epoch_processing::EpochProcessingSummary, BlockReplayError, BlockReplayer, + BlockReplayer, BlockReplayError, per_epoch_processing::EpochProcessingSummary, }; use std::sync::Arc; use types::{BeaconState, BeaconStateError, EthSpec, Hash256, SignedBeaconBlock}; +use types::beacon_state::participation_cache::Error as ParticipationCacheError; use warp_utils::reject::{beacon_chain_error, custom_bad_request, custom_server_error}; const MAX_REQUEST_RANGE_EPOCHS: usize = 100; diff --git a/beacon_node/http_api/src/validator_inclusion.rs b/beacon_node/http_api/src/validator_inclusion.rs index 48dfc17ffa3..39c8dc3d684 100644 --- a/beacon_node/http_api/src/validator_inclusion.rs +++ b/beacon_node/http_api/src/validator_inclusion.rs @@ -5,10 +5,11 @@ use eth2::{ types::ValidatorId, }; use state_processing::per_epoch_processing::{ - altair::participation_cache::Error as ParticipationCacheError, process_epoch, EpochProcessingSummary, + process_epoch, }; use types::{BeaconState, ChainSpec, Epoch, EthSpec}; +use types::beacon_state::participation_cache::Error as ParticipationCacheError; /// Returns the state in the last slot of `epoch`. fn end_of_epoch_state( diff --git a/consensus/state_processing/src/lib.rs b/consensus/state_processing/src/lib.rs index cf541d45728..70f92c5a9dc 100644 --- a/consensus/state_processing/src/lib.rs +++ b/consensus/state_processing/src/lib.rs @@ -26,17 +26,17 @@ pub mod state_advance; pub mod upgrade; pub mod verify_operation; -pub use block_replayer::{BlockReplayError, BlockReplayer, StateRootStrategy}; +pub use block_replayer::{BlockReplayer, BlockReplayError, StateRootStrategy}; pub use genesis::{ eth2_genesis_time, initialize_beacon_state_from_eth1, is_valid_genesis_state, process_activations, }; pub use per_block_processing::{ - block_signature_verifier, errors::BlockProcessingError, per_block_processing, signature_sets, - BlockSignatureStrategy, BlockSignatureVerifier, VerifyBlockRoot, VerifySignatures, + altair::sync_committee, block_signature_verifier, BlockSignatureStrategy, BlockSignatureVerifier, + errors::BlockProcessingError, per_block_processing, signature_sets, VerifyBlockRoot, VerifySignatures }; pub use per_epoch_processing::{ - errors::EpochProcessingError, process_epoch as per_epoch_processing, + errors::EpochProcessingError, process_epoch as per_epoch_processing }; -pub use per_slot_processing::{per_slot_processing, Error as SlotProcessingError}; +pub use per_slot_processing::{Error as SlotProcessingError, per_slot_processing}; pub use verify_operation::{SigVerifiedOp, VerifyOperation}; diff --git a/consensus/state_processing/src/per_epoch_processing/altair.rs b/consensus/state_processing/src/per_epoch_processing/altair.rs index 1011abe28fb..9d6deb193e2 100644 --- a/consensus/state_processing/src/per_epoch_processing/altair.rs +++ b/consensus/state_processing/src/per_epoch_processing/altair.rs @@ -1,4 +1,4 @@ -use super::{process_registry_updates, process_slashings, EpochProcessingSummary, Error}; +use super::{EpochProcessingSummary, Error, process_registry_updates, process_slashings}; use crate::per_epoch_processing::{ effective_balance_updates::process_effective_balance_updates, historical_roots_update::process_historical_roots_update, @@ -6,15 +6,15 @@ use crate::per_epoch_processing::{ }; pub use inactivity_updates::process_inactivity_updates; pub use justification_and_finalization::process_justification_and_finalization; -pub use participation_cache::ParticipationCache; +pub use types::beacon_state::participation_cache::ParticipationCache; pub use participation_flag_updates::process_participation_flag_updates; pub use rewards_and_penalties::process_rewards_and_penalties; pub use sync_committee_updates::process_sync_committee_updates; use types::{BeaconState, ChainSpec, EthSpec, RelativeEpoch}; +use types::beacon_state::participation_cache::CurrentEpochParticipationCache; pub mod inactivity_updates; pub mod justification_and_finalization; -pub mod participation_cache; pub mod participation_flag_updates; pub mod rewards_and_penalties; pub mod sync_committee_updates; @@ -23,17 +23,12 @@ pub fn process_epoch( state: &mut BeaconState, spec: &ChainSpec, ) -> Result, Error> { - // Ensure the committee caches are built. - state.build_committee_cache(RelativeEpoch::Previous, spec)?; - state.build_committee_cache(RelativeEpoch::Current, spec)?; + state.build_committee_cache(RelativeEpoch::Next, spec)?; - // Pre-compute participating indices and total balances. - let participation_cache = ParticipationCache::new(state, spec)?; - let sync_committee = state.current_sync_committee()?.clone(); + let participation_cache = process_justifiable(state, spec)?; - // Justification and finalization. - process_justification_and_finalization(state, &participation_cache)?; + let sync_committee = state.current_sync_committee()?.clone(); process_inactivity_updates(state, &participation_cache, spec)?; @@ -78,3 +73,21 @@ pub fn process_epoch( sync_committee, }) } + +pub fn process_justifiable(state: &mut BeaconState, spec: &ChainSpec) -> Result { +// Ensure the committee caches are built. + state.build_committee_cache(RelativeEpoch::Previous, spec)?; + state.build_committee_cache(RelativeEpoch::Current, spec)?; + + // Pre-compute participating indices and total balances. + let prev_participation_cache = state.get_previous_epoch_participation_cache(spec)?; + + let current_participation_cache = CurrentEpochParticipationCache::new(state, spec)?; + + let participation_cache = ParticipationCache::new(prev_participation_cache, current_participation_cache); + + // Justification and finalization. + process_justification_and_finalization(state, &participation_cache)?; + + Ok(participation_cache) +} diff --git a/consensus/state_processing/src/per_epoch_processing/altair/justification_and_finalization.rs b/consensus/state_processing/src/per_epoch_processing/altair/justification_and_finalization.rs index f47d9c0e688..cec53cb5635 100644 --- a/consensus/state_processing/src/per_epoch_processing/altair/justification_and_finalization.rs +++ b/consensus/state_processing/src/per_epoch_processing/altair/justification_and_finalization.rs @@ -4,6 +4,7 @@ use crate::per_epoch_processing::Error; use safe_arith::SafeArith; use types::consts::altair::TIMELY_TARGET_FLAG_INDEX; use types::{BeaconState, EthSpec}; +use types::beacon_state::participation_cache::CurrentEpochParticipationCache; /// Update the justified and finalized checkpoints for matching target attestations. pub fn process_justification_and_finalization( diff --git a/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs b/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs index ce102694f58..86acb7f9bc5 100644 --- a/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs +++ b/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs @@ -8,6 +8,7 @@ use types::{BeaconState, ChainSpec, EthSpec}; use crate::common::{altair::get_base_reward, decrease_balance, increase_balance}; use crate::per_epoch_processing::{Delta, Error}; +use types::beacon_state::participation_cache::CurrentEpochParticipationCache; /// Apply attester and proposer rewards. /// diff --git a/consensus/state_processing/src/per_epoch_processing/epoch_processing_summary.rs b/consensus/state_processing/src/per_epoch_processing/epoch_processing_summary.rs index 81487474236..fae8d62689f 100644 --- a/consensus/state_processing/src/per_epoch_processing/epoch_processing_summary.rs +++ b/consensus/state_processing/src/per_epoch_processing/epoch_processing_summary.rs @@ -1,10 +1,11 @@ use super::{ - altair::{participation_cache::Error as ParticipationCacheError, ParticipationCache}, - base::{validator_statuses::InclusionInfo, TotalBalances, ValidatorStatus}, + altair::ParticipationCache, + base::{TotalBalances, validator_statuses::InclusionInfo, ValidatorStatus}, }; use crate::metrics; use std::sync::Arc; use types::{EthSpec, SyncCommittee}; +use types::beacon_state::participation_cache::Error as ParticipationCacheError; /// Provides a summary of validator participation during the epoch. #[derive(PartialEq, Debug)] diff --git a/consensus/state_processing/src/per_epoch_processing/errors.rs b/consensus/state_processing/src/per_epoch_processing/errors.rs index 04797c56342..0799fe3664c 100644 --- a/consensus/state_processing/src/per_epoch_processing/errors.rs +++ b/consensus/state_processing/src/per_epoch_processing/errors.rs @@ -1,4 +1,4 @@ -use crate::per_epoch_processing::altair::participation_cache::Error as ParticipationCacheError; +use types::beacon_state::participation_cache::Error as ParticipationCacheError; use types::{BeaconStateError, InconsistentFork}; #[derive(Debug, PartialEq)] diff --git a/consensus/state_processing/src/upgrade/altair.rs b/consensus/state_processing/src/upgrade/altair.rs index 5e4fcbcf55d..97e9658b4d4 100644 --- a/consensus/state_processing/src/upgrade/altair.rs +++ b/consensus/state_processing/src/upgrade/altair.rs @@ -105,6 +105,7 @@ pub fn upgrade_to_altair( pubkey_cache: mem::take(&mut pre.pubkey_cache), exit_cache: mem::take(&mut pre.exit_cache), tree_hash_cache: mem::take(&mut pre.tree_hash_cache), + previous_epoch_participation_cache: mem::take(&mut pre.previous_epoch_participation_cache), }); // Fill in previous epoch participation from the pre state's pending attestations. diff --git a/consensus/state_processing/src/upgrade/merge.rs b/consensus/state_processing/src/upgrade/merge.rs index 2e4ed441a47..09c4dc04b5a 100644 --- a/consensus/state_processing/src/upgrade/merge.rs +++ b/consensus/state_processing/src/upgrade/merge.rs @@ -64,6 +64,7 @@ pub fn upgrade_to_bellatrix( pubkey_cache: mem::take(&mut pre.pubkey_cache), exit_cache: mem::take(&mut pre.exit_cache), tree_hash_cache: mem::take(&mut pre.tree_hash_cache), + previous_epoch_participation_cache: mem::take(&mut pre.previous_epoch_participation_cache), }); *pre_state = post; diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index d182ab9ae77..8ae97116732 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -10,9 +10,9 @@ use int_to_bytes::{int_to_bytes4, int_to_bytes8}; use pubkey_cache::PubkeyCache; use safe_arith::{ArithError, SafeArith}; use serde_derive::{Deserialize, Serialize}; -use ssz::{ssz_encode, Decode, DecodeError, Encode}; +use ssz::{Decode, DecodeError, Encode, ssz_encode}; use ssz_derive::{Decode, Encode}; -use ssz_types::{typenum::Unsigned, BitVector, FixedVector}; +use ssz_types::{BitVector, FixedVector, typenum::Unsigned}; use std::convert::TryInto; use std::{fmt, mem, sync::Arc}; use superstruct::superstruct; @@ -20,10 +20,11 @@ use swap_or_not_shuffle::compute_shuffled_index; use test_random_derive::TestRandom; use tree_hash::TreeHash; use tree_hash_derive::TreeHash; +use participation_cache::PreviousParticipationCache; pub use self::committee_cache::{ - compute_committee_index_in_epoch, compute_committee_range_in_epoch, epoch_committee_count, - CommitteeCache, + CommitteeCache, compute_committee_index_in_epoch, compute_committee_range_in_epoch, + epoch_committee_count, }; pub use clone_config::CloneConfig; pub use eth_spec::*; @@ -38,6 +39,7 @@ mod iter; mod pubkey_cache; mod tests; mod tree_hash_cache; +pub mod participation_cache; pub const CACHED_EPOCHS: usize = 3; const MAX_RANDOM_BYTE: u64 = (1 << 8) - 1; @@ -311,6 +313,12 @@ where #[test_random(default)] #[derivative(Clone(clone_with = "clone_default"))] pub tree_hash_cache: BeaconTreeHashCache, + #[serde(skip_serializing, skip_deserializing)] + #[ssz(skip_serializing, skip_deserializing)] + #[tree_hash(skip_hashing)] + #[test_random(default)] + #[derivative(Clone(clone_with = "clone_default"))] + pub previous_epoch_participation_cache: PreviousParticipationCache, } impl Clone for BeaconState { @@ -376,6 +384,7 @@ impl BeaconState { pubkey_cache: PubkeyCache::default(), exit_cache: ExitCache::default(), tree_hash_cache: <_>::default(), + previous_epoch_participation_cache: <_>::default(), }) } @@ -1353,6 +1362,16 @@ impl BeaconState { Ok(()) } + pub fn get_previous_epoch_participation_cache(&mut self, spec: &ChainSpec) -> Result<&PreviousParticipationCache, BeaconStateError> { + if self.previous_epoch_participation_cache().previous_epoch() == self.slot().epoch(T::slots_per_epoch()) - 1 { + Ok(&self.previous_epoch_participation_cache()) + } else { + //rebuild cache + *self.previous_epoch_participation_cache_mut() = PreviousParticipationCache::new(self, spec)?; + Ok(&self.previous_epoch_participation_cache()) + } + } + /// Returns `true` if the committee cache for `relative_epoch` is built and ready to use. pub fn committee_cache_is_initialized(&self, relative_epoch: RelativeEpoch) -> bool { let i = Self::committee_cache_index(relative_epoch); diff --git a/consensus/state_processing/src/per_epoch_processing/altair/participation_cache.rs b/consensus/types/src/beacon_state/participation_cache.rs similarity index 80% rename from consensus/state_processing/src/per_epoch_processing/altair/participation_cache.rs rename to consensus/types/src/beacon_state/participation_cache.rs index 503dadfc708..6f3b4f89a10 100644 --- a/consensus/state_processing/src/per_epoch_processing/altair/participation_cache.rs +++ b/consensus/types/src/beacon_state/participation_cache.rs @@ -13,13 +13,15 @@ use safe_arith::{ArithError, SafeArith}; use std::collections::HashMap; -use types::{ +use crate::{ consts::altair::{ NUM_FLAG_INDICES, TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX, }, BeaconState, BeaconStateError, ChainSpec, Epoch, EthSpec, ParticipationFlags, RelativeEpoch, }; +use crate::test_utils::{RngCore, TestRandom}; +use test_random_derive::TestRandom; #[derive(Debug, PartialEq)] pub enum Error { @@ -29,7 +31,7 @@ pub enum Error { /// A balance which will never be below the specified `minimum`. /// /// This is an effort to ensure the `EFFECTIVE_BALANCE_INCREMENT` minimum is always respected. -#[derive(PartialEq, Debug, Clone, Copy)] +#[derive(PartialEq, Debug, Default, Clone, Copy)] struct Balance { raw: u64, minimum: u64, @@ -53,7 +55,7 @@ impl Balance { } /// Caches the participation values for one epoch (either the previous or current). -#[derive(PartialEq, Debug)] +#[derive(Clone, PartialEq, Default, Debug)] struct SingleEpochParticipationCache { /// Maps an active validator index to their participation flags. /// @@ -165,11 +167,8 @@ impl SingleEpochParticipationCache { } /// Maintains a cache to be used during `altair::process_epoch`. -#[derive(PartialEq, Debug)] -pub struct ParticipationCache { - current_epoch: Epoch, - /// Caches information about active validators pertaining to `self.current_epoch`. - current_epoch_participation: SingleEpochParticipationCache, +#[derive(PartialEq, Default, Debug)] +pub struct PreviousParticipationCache { previous_epoch: Epoch, /// Caches information about active validators pertaining to `self.previous_epoch`. previous_epoch_participation: SingleEpochParticipationCache, @@ -177,7 +176,7 @@ pub struct ParticipationCache { eligible_indices: Vec, } -impl ParticipationCache { +impl PreviousParticipationCache { /// Instantiate `Self`, returning a fully initialized cache. /// /// ## Errors @@ -187,20 +186,14 @@ impl ParticipationCache { state: &BeaconState, spec: &ChainSpec, ) -> Result { - let current_epoch = state.current_epoch(); let previous_epoch = state.previous_epoch(); let num_previous_epoch_active_vals = state .get_cached_active_validator_indices(RelativeEpoch::Previous)? .len(); - let num_current_epoch_active_vals = state - .get_cached_active_validator_indices(RelativeEpoch::Current)? - .len(); // Both the current/previous epoch participations are set to a capacity that is slightly // larger than required. The difference will be due slashed-but-active validators. - let mut current_epoch_participation = - SingleEpochParticipationCache::new(num_current_epoch_active_vals, spec); let mut previous_epoch_participation = SingleEpochParticipationCache::new(num_previous_epoch_active_vals, spec); // Contains the set of validators which are either: @@ -220,13 +213,6 @@ impl ParticipationCache { // Care is taken to ensure that the ordering of `eligible_indices` is the same as the // `get_eligible_validator_indices` function in the spec. for (val_index, val) in state.validators().iter().enumerate() { - if val.is_active_at(current_epoch) { - current_epoch_participation.process_active_validator( - val_index, - state, - RelativeEpoch::Current, - )?; - } if val.is_active_at(previous_epoch) { previous_epoch_participation.process_active_validator( @@ -244,14 +230,117 @@ impl ParticipationCache { } Ok(Self { - current_epoch, - current_epoch_participation, previous_epoch, previous_epoch_participation, eligible_indices, }) } + pub fn previous_epoch(&self) -> Epoch { + self.previous_epoch + } +} + +pub struct CurrentEpochParticipationCache { + current_epoch: Epoch, + /// Caches information about active validators pertaining to `self.current_epoch`. + current_epoch_participation: SingleEpochParticipationCache, +} + +impl CurrentEpochParticipationCache { + pub fn new( + state: &BeaconState, + spec: &ChainSpec, + ) -> Result { + let current_epoch = state.current_epoch(); + let num_current_epoch_active_vals = state + .get_cached_active_validator_indices(RelativeEpoch::Current)? + .len(); + let mut current_epoch_participation = + SingleEpochParticipationCache::new(num_current_epoch_active_vals, spec); + for (val_index, val) in state.validators().iter().enumerate() { + if val.is_active_at(current_epoch) { + current_epoch_participation.process_active_validator( + val_index, + state, + RelativeEpoch::Current, + )?; + } + } + Ok(Self { + current_epoch, + current_epoch_participation, + }) + } + + pub fn current_epoch_total_active_balance(&self) -> u64 { + self.current_epoch_participation.total_active_balance.get() + } + + pub fn current_epoch_target_attesting_balance(&self) -> Result { + self.current_epoch_participation + .total_flag_balance(TIMELY_TARGET_FLAG_INDEX) + } + + pub fn is_active_unslashed_in_current_epoch(&self, val_index: usize) -> bool { + self.current_epoch_participation + .unslashed_participating_indices + .contains_key(&val_index) + } + + /// Always returns false for a slashed validator. + pub fn is_current_epoch_timely_source_attester(&self, val_index: usize) -> Result { + self.current_epoch_participation + .has_flag(val_index, TIMELY_SOURCE_FLAG_INDEX) + } + + /// Always returns false for a slashed validator. + pub fn is_current_epoch_timely_target_attester(&self, val_index: usize) -> Result { + self.current_epoch_participation + .has_flag(val_index, TIMELY_TARGET_FLAG_INDEX) + } + + /// Always returns false for a slashed validator. + pub fn is_current_epoch_timely_head_attester(&self, val_index: usize) -> Result { + self.current_epoch_participation + .has_flag(val_index, TIMELY_HEAD_FLAG_INDEX) + } + + /// Equivalent to the `get_unslashed_participating_indices` function in the specification. + pub fn get_unslashed_participating_indices( + &self, + flag_index: usize, + ) -> Result { + Ok(UnslashedParticipatingIndices { + participation: &self.current_epoch_participation, + flag_index, + }) + } +} + +#[derive(Clone, PartialEq, Default, Debug)] +pub struct ParticipationCache { + current_epoch: Epoch, + /// Caches information about active validators pertaining to `self.current_epoch`. + current_epoch_participation: SingleEpochParticipationCache, + previous_epoch: Epoch, + /// Caches information about active validators pertaining to `self.previous_epoch`. + previous_epoch_participation: SingleEpochParticipationCache, + /// Caches the result of the `get_eligible_validator_indices` function. + eligible_indices: Vec, +} + +impl ParticipationCache { + pub fn new(prev_cache: &PreviousParticipationCache, current_cache: CurrentEpochParticipationCache) -> ParticipationCache { + ParticipationCache { + current_epoch: current_cache.current_epoch, + current_epoch_participation: current_cache.current_epoch_participation, + previous_epoch: prev_cache.previous_epoch, + previous_epoch_participation: prev_cache.previous_epoch_participation.clone(), + eligible_indices: prev_cache.eligible_indices.clone(), + } + } + /// Equivalent to the specification `get_eligible_validator_indices` function. pub fn eligible_validator_indices(&self) -> &[usize] { &self.eligible_indices @@ -272,7 +361,7 @@ impl ParticipationCache { }; Ok(UnslashedParticipatingIndices { - participation, + participation: &self.previous_epoch_participation, flag_index, }) } @@ -281,14 +370,6 @@ impl ParticipationCache { * Balances */ - pub fn current_epoch_total_active_balance(&self) -> u64 { - self.current_epoch_participation.total_active_balance.get() - } - - pub fn current_epoch_target_attesting_balance(&self) -> Result { - self.current_epoch_participation - .total_flag_balance(TIMELY_TARGET_FLAG_INDEX) - } pub fn previous_epoch_total_active_balance(&self) -> u64 { self.previous_epoch_participation.total_active_balance.get() @@ -319,12 +400,6 @@ impl ParticipationCache { .contains_key(&val_index) } - pub fn is_active_unslashed_in_current_epoch(&self, val_index: usize) -> bool { - self.current_epoch_participation - .unslashed_participating_indices - .contains_key(&val_index) - } - /* * Flags */ @@ -353,6 +428,21 @@ impl ParticipationCache { .has_flag(val_index, TIMELY_HEAD_FLAG_INDEX) } + pub fn current_epoch_total_active_balance(&self) -> u64 { + self.current_epoch_participation.total_active_balance.get() + } + + pub fn current_epoch_target_attesting_balance(&self) -> Result { + self.current_epoch_participation + .total_flag_balance(TIMELY_TARGET_FLAG_INDEX) + } + + pub fn is_active_unslashed_in_current_epoch(&self, val_index: usize) -> bool { + self.current_epoch_participation + .unslashed_participating_indices + .contains_key(&val_index) + } + /// Always returns false for a slashed validator. pub fn is_current_epoch_timely_source_attester(&self, val_index: usize) -> Result { self.current_epoch_participation diff --git a/consensus/types/src/test_utils/test_random.rs b/consensus/types/src/test_utils/test_random.rs index 55135a8a26f..43396dedc0d 100644 --- a/consensus/types/src/test_utils/test_random.rs +++ b/consensus/types/src/test_utils/test_random.rs @@ -129,6 +129,7 @@ macro_rules! impl_test_random_for_u8_array { }; } +impl_test_random_for_u8_array!(3); impl_test_random_for_u8_array!(4); impl_test_random_for_u8_array!(32); impl_test_random_for_u8_array!(48);