Cache indexed attestations

This commit is contained in:
Michael Sproul
2022-10-24 13:43:52 +11:00
parent abc62a9ef0
commit 84ae7b2976
9 changed files with 152 additions and 106 deletions

View File

@@ -140,10 +140,6 @@ const MAX_PER_SLOT_FORK_CHOICE_DISTANCE: u64 = 256;
pub const INVALID_JUSTIFIED_PAYLOAD_SHUTDOWN_REASON: &str = pub const INVALID_JUSTIFIED_PAYLOAD_SHUTDOWN_REASON: &str =
"Justified block has an invalid execution payload."; "Justified block has an invalid execution payload.";
// FIXME(sproul): decide whether to keep this
// Interval before the attestation deadline during which to consider blocks "borderline" late.
// const BORDERLINE_LATE_BLOCK_TOLERANCE: Duration = Duration::from_millis(50);
pub const INVALID_FINALIZED_MERGE_TRANSITION_BLOCK_SHUTDOWN_REASON: &str = pub const INVALID_FINALIZED_MERGE_TRANSITION_BLOCK_SHUTDOWN_REASON: &str =
"Finalized merge transition block is invalid."; "Finalized merge transition block is invalid.";
@@ -3369,10 +3365,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// This will be a lot slower but guards against bugs in block production and can be // This will be a lot slower but guards against bugs in block production and can be
// quickly rolled out without a release. // quickly rolled out without a release.
if self.config.paranoid_block_proposal { if self.config.paranoid_block_proposal {
let mut tmp_ctxt = ConsensusContext::new(state.slot());
attestations.retain(|att| { attestations.retain(|att| {
verify_attestation_for_block_inclusion( verify_attestation_for_block_inclusion(
&state, &state,
att, att,
&mut tmp_ctxt,
VerifySignatures::True, VerifySignatures::True,
&self.spec, &self.spec,
) )

View File

@@ -547,8 +547,22 @@ pub fn signature_verify_chain_segment<T: BeaconChainTypes>(
let pubkey_cache = get_validator_pubkey_cache(chain)?; let pubkey_cache = get_validator_pubkey_cache(chain)?;
let mut signature_verifier = get_signature_verifier::<T>(&state, &pubkey_cache, &chain.spec); let mut signature_verifier = get_signature_verifier::<T>(&state, &pubkey_cache, &chain.spec);
let mut signature_verified_blocks = Vec::with_capacity(chain_segment.len());
for (block_root, block) in &chain_segment { for (block_root, block) in &chain_segment {
signature_verifier.include_all_signatures(block, Some(*block_root), None)?; let mut consensus_context =
ConsensusContext::new(block.slot()).set_current_block_root(*block_root);
signature_verifier.include_all_signatures(&block, &mut consensus_context)?;
// Save the block and its consensus context. The context will have had its proposer index
// and attesting indices filled in, which can be used to accelerate later block processing.
signature_verified_blocks.push(SignatureVerifiedBlock {
block: block.clone(),
block_root: *block_root,
parent: None,
consensus_context,
});
} }
if signature_verifier.verify().is_err() { if signature_verifier.verify().is_err() {
@@ -557,22 +571,6 @@ pub fn signature_verify_chain_segment<T: BeaconChainTypes>(
drop(pubkey_cache); drop(pubkey_cache);
let mut signature_verified_blocks = chain_segment
.into_iter()
.map(|(block_root, block)| {
// Proposer index has already been verified above during signature verification.
let consensus_context = ConsensusContext::new(block.slot())
.set_current_block_root(block_root)
.set_proposer_index(block.message().proposer_index());
SignatureVerifiedBlock {
block,
block_root,
parent: None,
consensus_context,
}
})
.collect::<Vec<_>>();
if let Some(signature_verified_block) = signature_verified_blocks.first_mut() { if let Some(signature_verified_block) = signature_verified_blocks.first_mut() {
signature_verified_block.parent = Some(parent); signature_verified_block.parent = Some(parent);
} }
@@ -941,13 +939,14 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
let mut signature_verifier = let mut signature_verifier =
get_signature_verifier::<T>(&state, &pubkey_cache, &chain.spec); get_signature_verifier::<T>(&state, &pubkey_cache, &chain.spec);
signature_verifier.include_all_signatures(&block, Some(block_root), None)?; let mut consensus_context =
ConsensusContext::new(block.slot()).set_current_block_root(block_root);
signature_verifier.include_all_signatures(&block, &mut consensus_context)?;
if signature_verifier.verify().is_ok() { if signature_verifier.verify().is_ok() {
Ok(Self { Ok(Self {
consensus_context: ConsensusContext::new(block.slot()) consensus_context,
.set_current_block_root(block_root)
.set_proposer_index(block.message().proposer_index()),
block, block,
block_root, block_root,
parent: Some(parent), parent: Some(parent),
@@ -993,16 +992,16 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
// Gossip verification has already checked the proposer index. Use it to check the RANDAO // Gossip verification has already checked the proposer index. Use it to check the RANDAO
// signature. // signature.
let verified_proposer_index = Some(block.message().proposer_index()); let mut consensus_context = from.consensus_context;
signature_verifier signature_verifier
.include_all_signatures_except_proposal(&block, verified_proposer_index)?; .include_all_signatures_except_proposal(&block, &mut consensus_context)?;
if signature_verifier.verify().is_ok() { if signature_verifier.verify().is_ok() {
Ok(Self { Ok(Self {
block, block,
block_root: from.block_root, block_root: from.block_root,
parent: Some(parent), parent: Some(parent),
consensus_context: from.consensus_context, consensus_context,
}) })
} else { } else {
Err(BlockError::InvalidSignature) Err(BlockError::InvalidSignature)

View File

@@ -22,7 +22,7 @@ pub trait BitfieldBehaviour: Clone {}
/// A marker struct used to declare SSZ `Variable` behaviour on a `Bitfield`. /// A marker struct used to declare SSZ `Variable` behaviour on a `Bitfield`.
/// ///
/// See the [`Bitfield`](struct.Bitfield.html) docs for usage. /// See the [`Bitfield`](struct.Bitfield.html) docs for usage.
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct Variable<N> { pub struct Variable<N> {
_phantom: PhantomData<N>, _phantom: PhantomData<N>,
} }
@@ -30,7 +30,7 @@ pub struct Variable<N> {
/// A marker struct used to declare SSZ `Fixed` behaviour on a `Bitfield`. /// A marker struct used to declare SSZ `Fixed` behaviour on a `Bitfield`.
/// ///
/// See the [`Bitfield`](struct.Bitfield.html) docs for usage. /// See the [`Bitfield`](struct.Bitfield.html) docs for usage.
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct Fixed<N> { pub struct Fixed<N> {
_phantom: PhantomData<N>, _phantom: PhantomData<N>,
} }
@@ -96,7 +96,7 @@ pub type BitVector<N> = Bitfield<Fixed<N>>;
/// byte (by `Vec` index) stores the lowest bit-indices and the right-most bit stores the lowest /// byte (by `Vec` index) stores the lowest bit-indices and the right-most bit stores the lowest
/// bit-index. E.g., `smallvec![0b0000_0001, 0b0000_0010]` has bits `0, 9` set. /// bit-index. E.g., `smallvec![0b0000_0001, 0b0000_0010]` has bits `0, 9` set.
#[derive(Clone, Debug, Derivative)] #[derive(Clone, Debug, Derivative)]
#[derivative(PartialEq, Hash(bound = ""))] #[derivative(PartialEq, Eq, Hash(bound = ""))]
pub struct Bitfield<T> { pub struct Bitfield<T> {
bytes: SmallVec<[u8; SMALLVEC_LEN]>, bytes: SmallVec<[u8; SMALLVEC_LEN]>,
len: usize, len: usize,

View File

@@ -1,10 +1,13 @@
use crate::common::get_indexed_attestation;
use crate::per_block_processing::errors::{AttestationInvalid, BlockOperationError};
use crate::{EpochCache, EpochCacheError}; use crate::{EpochCache, EpochCacheError};
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::{hash_map::Entry, HashMap};
use std::marker::PhantomData; use std::marker::PhantomData;
use tree_hash::TreeHash; use tree_hash::TreeHash;
use types::{ use types::{
BeaconState, BeaconStateError, ChainSpec, EthSpec, ExecPayload, Hash256, SignedBeaconBlock, Attestation, AttestationData, BeaconState, BeaconStateError, BitList, ChainSpec, EthSpec,
Slot, ExecPayload, Hash256, IndexedAttestation, SignedBeaconBlock, Slot,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -17,6 +20,9 @@ pub struct ConsensusContext<T: EthSpec> {
current_block_root: Option<Hash256>, current_block_root: Option<Hash256>,
/// Epoch cache of values that are useful for block processing that are static over an epoch. /// Epoch cache of values that are useful for block processing that are static over an epoch.
epoch_cache: Option<EpochCache>, epoch_cache: Option<EpochCache>,
/// Cache of indexed attestations constructed during block processing.
indexed_attestations:
HashMap<(AttestationData, BitList<T::MaxValidatorsPerCommittee>), IndexedAttestation<T>>,
_phantom: PhantomData<T>, _phantom: PhantomData<T>,
} }
@@ -46,6 +52,7 @@ impl<T: EthSpec> ConsensusContext<T> {
proposer_index: None, proposer_index: None,
current_block_root: None, current_block_root: None,
epoch_cache: None, epoch_cache: None,
indexed_attestations: HashMap::new(),
_phantom: PhantomData, _phantom: PhantomData,
} }
} }
@@ -107,9 +114,9 @@ impl<T: EthSpec> ConsensusContext<T> {
self self
} }
pub fn get_base_reward<E: EthSpec>( pub fn get_base_reward(
&mut self, &mut self,
state: &BeaconState<E>, state: &BeaconState<T>,
validator_index: usize, validator_index: usize,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<u64, ContextError> { ) -> Result<u64, ContextError> {
@@ -126,4 +133,30 @@ impl<T: EthSpec> ConsensusContext<T> {
Ok(epoch_cache.get_base_reward(validator_index)?) Ok(epoch_cache.get_base_reward(validator_index)?)
} }
pub fn get_indexed_attestation(
&mut self,
state: &BeaconState<T>,
attestation: &Attestation<T>,
) -> Result<&IndexedAttestation<T>, BlockOperationError<AttestationInvalid>> {
let key = (
attestation.data.clone(),
attestation.aggregation_bits.clone(),
);
match self.indexed_attestations.entry(key) {
Entry::Occupied(occupied) => Ok(occupied.into_mut()),
Entry::Vacant(vacant) => {
let committee =
state.get_beacon_committee(attestation.data.slot, attestation.data.index)?;
let indexed_attestation =
get_indexed_attestation(committee.committee, attestation)?;
Ok(vacant.insert(indexed_attestation))
}
}
}
pub fn num_cached_indexed_attestations(&self) -> usize {
self.indexed_attestations.len()
}
} }

View File

@@ -111,16 +111,13 @@ pub fn per_block_processing<T: EthSpec, Payload: ExecPayload<T>>(
let verify_signatures = match block_signature_strategy { let verify_signatures = match block_signature_strategy {
BlockSignatureStrategy::VerifyBulk => { BlockSignatureStrategy::VerifyBulk => {
// Verify all signatures in the block at once. // Verify all signatures in the block at once.
let block_root = Some(ctxt.get_current_block_root(signed_block)?);
let proposer_index = Some(ctxt.get_proposer_index(state, spec)?);
block_verify!( block_verify!(
BlockSignatureVerifier::verify_entire_block( BlockSignatureVerifier::verify_entire_block(
state, state,
|i| get_pubkey_from_state(state, i), |i| get_pubkey_from_state(state, i),
|pk_bytes| pk_bytes.decompress().ok().map(Cow::Owned), |pk_bytes| pk_bytes.decompress().ok().map(Cow::Owned),
signed_block, signed_block,
block_root, ctxt,
proposer_index,
spec spec
) )
.is_ok(), .is_ok(),

View File

@@ -1,14 +1,13 @@
#![allow(clippy::integer_arithmetic)] #![allow(clippy::integer_arithmetic)]
use super::signature_sets::{Error as SignatureSetError, *}; use super::signature_sets::{Error as SignatureSetError, *};
use crate::common::get_indexed_attestation;
use crate::per_block_processing::errors::{AttestationInvalid, BlockOperationError}; use crate::per_block_processing::errors::{AttestationInvalid, BlockOperationError};
use crate::{ConsensusContext, ContextError};
use bls::{verify_signature_sets, PublicKey, PublicKeyBytes, SignatureSet}; use bls::{verify_signature_sets, PublicKey, PublicKeyBytes, SignatureSet};
use rayon::prelude::*; use rayon::prelude::*;
use std::borrow::Cow; use std::borrow::Cow;
use types::{ use types::{
BeaconState, BeaconStateError, ChainSpec, EthSpec, ExecPayload, Hash256, IndexedAttestation, BeaconState, BeaconStateError, ChainSpec, EthSpec, ExecPayload, Hash256, SignedBeaconBlock,
SignedBeaconBlock,
}; };
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
@@ -28,6 +27,8 @@ pub enum Error {
IncorrectBlockProposer { block: u64, local_shuffling: u64 }, IncorrectBlockProposer { block: u64, local_shuffling: u64 },
/// Failed to load a signature set. The block may be invalid or we failed to process it. /// Failed to load a signature set. The block may be invalid or we failed to process it.
SignatureSetError(SignatureSetError), SignatureSetError(SignatureSetError),
/// Error related to the consensus context, likely the proposer index or block root calc.
ContextError(ContextError),
} }
impl From<BeaconStateError> for Error { impl From<BeaconStateError> for Error {
@@ -36,6 +37,12 @@ impl From<BeaconStateError> for Error {
} }
} }
impl From<ContextError> for Error {
fn from(e: ContextError) -> Error {
Error::ContextError(e)
}
}
impl From<SignatureSetError> for Error { impl From<SignatureSetError> for Error {
fn from(e: SignatureSetError) -> Error { fn from(e: SignatureSetError) -> Error {
match e { match e {
@@ -122,12 +129,11 @@ where
get_pubkey: F, get_pubkey: F,
decompressor: D, decompressor: D,
block: &'a SignedBeaconBlock<T, Payload>, block: &'a SignedBeaconBlock<T, Payload>,
block_root: Option<Hash256>, ctxt: &mut ConsensusContext<T>,
verified_proposer_index: Option<u64>,
spec: &'a ChainSpec, spec: &'a ChainSpec,
) -> Result<()> { ) -> Result<()> {
let mut verifier = Self::new(state, get_pubkey, decompressor, spec); let mut verifier = Self::new(state, get_pubkey, decompressor, spec);
verifier.include_all_signatures(block, block_root, verified_proposer_index)?; verifier.include_all_signatures(block, ctxt)?;
verifier.verify() verifier.verify()
} }
@@ -135,11 +141,13 @@ where
pub fn include_all_signatures<Payload: ExecPayload<T>>( pub fn include_all_signatures<Payload: ExecPayload<T>>(
&mut self, &mut self,
block: &'a SignedBeaconBlock<T, Payload>, block: &'a SignedBeaconBlock<T, Payload>,
block_root: Option<Hash256>, ctxt: &mut ConsensusContext<T>,
verified_proposer_index: Option<u64>,
) -> Result<()> { ) -> Result<()> {
let block_root = Some(ctxt.get_current_block_root(block)?);
let verified_proposer_index = Some(ctxt.get_proposer_index(self.state, self.spec)?);
self.include_block_proposal(block, block_root, verified_proposer_index)?; self.include_block_proposal(block, block_root, verified_proposer_index)?;
self.include_all_signatures_except_proposal(block, verified_proposer_index)?; self.include_all_signatures_except_proposal(block, ctxt)?;
Ok(()) Ok(())
} }
@@ -149,12 +157,13 @@ where
pub fn include_all_signatures_except_proposal<Payload: ExecPayload<T>>( pub fn include_all_signatures_except_proposal<Payload: ExecPayload<T>>(
&mut self, &mut self,
block: &'a SignedBeaconBlock<T, Payload>, block: &'a SignedBeaconBlock<T, Payload>,
verified_proposer_index: Option<u64>, ctxt: &mut ConsensusContext<T>,
) -> Result<()> { ) -> Result<()> {
let verified_proposer_index = Some(ctxt.get_proposer_index(self.state, self.spec)?);
self.include_randao_reveal(block, verified_proposer_index)?; self.include_randao_reveal(block, verified_proposer_index)?;
self.include_proposer_slashings(block)?; self.include_proposer_slashings(block)?;
self.include_attester_slashings(block)?; self.include_attester_slashings(block)?;
self.include_attestations(block)?; self.include_attestations(block, ctxt)?;
// Deposits are not included because they can legally have invalid signatures. // Deposits are not included because they can legally have invalid signatures.
self.include_exits(block)?; self.include_exits(block)?;
self.include_sync_aggregate(block)?; self.include_sync_aggregate(block)?;
@@ -260,7 +269,8 @@ where
pub fn include_attestations<Payload: ExecPayload<T>>( pub fn include_attestations<Payload: ExecPayload<T>>(
&mut self, &mut self,
block: &'a SignedBeaconBlock<T, Payload>, block: &'a SignedBeaconBlock<T, Payload>,
) -> Result<Vec<IndexedAttestation<T>>> { ctxt: &mut ConsensusContext<T>,
) -> Result<()> {
self.sets self.sets
.sets .sets
.reserve(block.message().body().attestations().len()); .reserve(block.message().body().attestations().len());
@@ -270,28 +280,18 @@ where
.body() .body()
.attestations() .attestations()
.iter() .iter()
.try_fold( .try_for_each(|attestation| {
Vec::with_capacity(block.message().body().attestations().len()), let indexed_attestation = ctxt.get_indexed_attestation(&self.state, attestation)?;
|mut vec, attestation| {
let committee = self
.state
.get_beacon_committee(attestation.data.slot, attestation.data.index)?;
let indexed_attestation =
get_indexed_attestation(committee.committee, attestation)?;
self.sets.push(indexed_attestation_signature_set( self.sets.push(indexed_attestation_signature_set(
self.state, self.state,
self.get_pubkey.clone(), self.get_pubkey.clone(),
&attestation.signature, &attestation.signature,
&indexed_attestation, indexed_attestation,
self.spec, self.spec,
)?); )?);
Ok(())
vec.push(indexed_attestation); })
Ok(vec)
},
)
.map_err(Error::into) .map_err(Error::into)
} }

View File

@@ -57,8 +57,14 @@ pub mod base {
// Verify and apply each attestation. // Verify and apply each attestation.
for (i, attestation) in attestations.iter().enumerate() { for (i, attestation) in attestations.iter().enumerate() {
verify_attestation_for_block_inclusion(state, attestation, verify_signatures, spec) verify_attestation_for_block_inclusion(
.map_err(|e| e.into_with_index(i))?; state,
attestation,
ctxt,
verify_signatures,
spec,
)
.map_err(|e| e.into_with_index(i))?;
let pending_attestation = PendingAttestation { let pending_attestation = PendingAttestation {
aggregation_bits: attestation.aggregation_bits.clone(), aggregation_bits: attestation.aggregation_bits.clone(),
@@ -115,9 +121,16 @@ pub mod altair {
let proposer_index = ctxt.get_proposer_index(state, spec)?; let proposer_index = ctxt.get_proposer_index(state, spec)?;
let indexed_attestation = let attesting_indices = verify_attestation_for_block_inclusion(
verify_attestation_for_block_inclusion(state, attestation, verify_signatures, spec) state,
.map_err(|e| e.into_with_index(att_index))?; attestation,
ctxt,
verify_signatures,
spec,
)
.map_err(|e| e.into_with_index(att_index))?
.attesting_indices
.clone();
// Matching roots, participation flag indices // Matching roots, participation flag indices
let data = &attestation.data; let data = &attestation.data;
@@ -127,7 +140,7 @@ pub mod altair {
// Update epoch participation flags. // Update epoch participation flags.
let mut proposer_reward_numerator = 0; let mut proposer_reward_numerator = 0;
for index in &indexed_attestation.attesting_indices { for index in &attesting_indices {
let index = *index as usize; let index = *index as usize;
for (flag_index, &weight) in PARTICIPATION_FLAG_WEIGHTS.iter().enumerate() { for (flag_index, &weight) in PARTICIPATION_FLAG_WEIGHTS.iter().enumerate() {

View File

@@ -1,7 +1,7 @@
use super::errors::{AttestationInvalid as Invalid, BlockOperationError}; use super::errors::{AttestationInvalid as Invalid, BlockOperationError};
use super::VerifySignatures; use super::VerifySignatures;
use crate::common::get_indexed_attestation;
use crate::per_block_processing::is_valid_indexed_attestation; use crate::per_block_processing::is_valid_indexed_attestation;
use crate::ConsensusContext;
use safe_arith::SafeArith; use safe_arith::SafeArith;
use types::*; use types::*;
@@ -15,12 +15,13 @@ fn error(reason: Invalid) -> BlockOperationError<Invalid> {
/// to `state`. Otherwise, returns a descriptive `Err`. /// to `state`. Otherwise, returns a descriptive `Err`.
/// ///
/// Optionally verifies the aggregate signature, depending on `verify_signatures`. /// Optionally verifies the aggregate signature, depending on `verify_signatures`.
pub fn verify_attestation_for_block_inclusion<T: EthSpec>( pub fn verify_attestation_for_block_inclusion<'ctxt, T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
attestation: &Attestation<T>, attestation: &Attestation<T>,
ctxt: &'ctxt mut ConsensusContext<T>,
verify_signatures: VerifySignatures, verify_signatures: VerifySignatures,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<IndexedAttestation<T>> { ) -> Result<&'ctxt IndexedAttestation<T>> {
let data = &attestation.data; let data = &attestation.data;
verify!( verify!(
@@ -39,7 +40,7 @@ pub fn verify_attestation_for_block_inclusion<T: EthSpec>(
} }
); );
verify_attestation_for_state(state, attestation, verify_signatures, spec) verify_attestation_for_state(state, attestation, ctxt, verify_signatures, spec)
} }
/// Returns `Ok(())` if `attestation` is a valid attestation to the chain that precedes the given /// Returns `Ok(())` if `attestation` is a valid attestation to the chain that precedes the given
@@ -49,12 +50,13 @@ pub fn verify_attestation_for_block_inclusion<T: EthSpec>(
/// prior blocks in `state`. /// prior blocks in `state`.
/// ///
/// Spec v0.12.1 /// Spec v0.12.1
pub fn verify_attestation_for_state<T: EthSpec>( pub fn verify_attestation_for_state<'ctxt, T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
attestation: &Attestation<T>, attestation: &Attestation<T>,
ctxt: &'ctxt mut ConsensusContext<T>,
verify_signatures: VerifySignatures, verify_signatures: VerifySignatures,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<IndexedAttestation<T>> { ) -> Result<&'ctxt IndexedAttestation<T>> {
let data = &attestation.data; let data = &attestation.data;
verify!( verify!(
@@ -66,9 +68,8 @@ pub fn verify_attestation_for_state<T: EthSpec>(
verify_casper_ffg_vote(attestation, state)?; verify_casper_ffg_vote(attestation, state)?;
// Check signature and bitfields // Check signature and bitfields
let committee = state.get_beacon_committee(attestation.data.slot, attestation.data.index)?; let indexed_attestation = ctxt.get_indexed_attestation(state, attestation)?;
let indexed_attestation = get_indexed_attestation(committee.committee, attestation)?; is_valid_indexed_attestation(state, indexed_attestation, verify_signatures, spec)?;
is_valid_indexed_attestation(state, &indexed_attestation, verify_signatures, spec)?;
Ok(indexed_attestation) Ok(indexed_attestation)
} }

View File

@@ -347,6 +347,23 @@ fn do_transition<T: EthSpec>(
.map_err(|e| format!("Unable to build caches: {:?}", e))?; .map_err(|e| format!("Unable to build caches: {:?}", e))?;
debug!("Build all caches (again): {:?}", t.elapsed()); debug!("Build all caches (again): {:?}", t.elapsed());
let mut ctxt = if let Some(ctxt) = saved_ctxt {
ctxt.clone()
} else {
let mut ctxt = ConsensusContext::new(pre_state.slot())
.set_current_block_root(block_root)
.set_proposer_index(block.message().proposer_index());
if config.exclude_cache_builds {
ctxt = ctxt.set_epoch_cache(
EpochCache::new(&pre_state, spec)
.map_err(|e| format!("unable to build epoch cache: {e:?}"))?,
);
*saved_ctxt = Some(ctxt.clone());
}
ctxt
};
if !config.no_signature_verification { if !config.no_signature_verification {
let get_pubkey = move |validator_index| { let get_pubkey = move |validator_index| {
validator_pubkey_cache validator_pubkey_cache
@@ -367,31 +384,19 @@ fn do_transition<T: EthSpec>(
get_pubkey, get_pubkey,
decompressor, decompressor,
&block, &block,
Some(block_root), &mut ctxt,
Some(block.message().proposer_index()),
spec, spec,
) )
.map_err(|e| format!("Invalid block signature: {:?}", e))?; .map_err(|e| format!("Invalid block signature: {:?}", e))?;
debug!("Batch verify block signatures: {:?}", t.elapsed()); debug!("Batch verify block signatures: {:?}", t.elapsed());
// Signature verification should prime the indexed attestation cache.
assert_eq!(
ctxt.num_cached_indexed_attestations(),
block.message().body().attestations().len()
);
} }
let mut ctxt = if let Some(ctxt) = saved_ctxt {
ctxt.clone()
} else {
let mut ctxt = ConsensusContext::new(pre_state.slot())
.set_current_block_root(block_root)
.set_proposer_index(block.message().proposer_index());
if config.exclude_cache_builds {
ctxt = ctxt.set_epoch_cache(
EpochCache::new(&pre_state, spec)
.map_err(|e| format!("unable to build epoch cache: {e:?}"))?,
);
*saved_ctxt = Some(ctxt.clone());
}
ctxt
};
let t = Instant::now(); let t = Instant::now();
per_block_processing( per_block_processing(