Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Consensus context with proposer index caching #3604

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ use state_processing::{
},
per_slot_processing,
state_advance::{complete_state_advance, partial_state_advance},
BlockSignatureStrategy, SigVerifiedOp, VerifyBlockRoot, VerifyOperation,
BlockSignatureStrategy, ConsensusContext, SigVerifiedOp, VerifyBlockRoot, VerifyOperation,
};
use std::cmp::Ordering;
use std::collections::HashMap;
Expand Down Expand Up @@ -3645,12 +3645,13 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
ProduceBlockVerification::VerifyRandao => BlockSignatureStrategy::VerifyRandao,
ProduceBlockVerification::NoVerification => BlockSignatureStrategy::NoVerification,
};
let mut ctxt = ConsensusContext::new(block.slot()).set_proposer_index(proposer_index);
michaelsproul marked this conversation as resolved.
Show resolved Hide resolved
per_block_processing(
&mut state,
&block,
None,
signature_strategy,
VerifyBlockRoot::True,
&mut ctxt,
&self.spec,
)?;
drop(process_timer);
Expand Down
53 changes: 42 additions & 11 deletions beacon_node/beacon_chain/src/block_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ use state_processing::{
block_signature_verifier::{BlockSignatureVerifier, Error as BlockSignatureVerifierError},
per_block_processing, per_slot_processing,
state_advance::partial_state_advance,
BlockProcessingError, BlockSignatureStrategy, SlotProcessingError, VerifyBlockRoot,
BlockProcessingError, BlockSignatureStrategy, ConsensusContext, SlotProcessingError,
VerifyBlockRoot,
};
use std::borrow::Cow;
use std::fs;
Expand Down Expand Up @@ -549,7 +550,7 @@ pub fn signature_verify_chain_segment<T: BeaconChainTypes>(
let mut signature_verifier = get_signature_verifier(&state, &pubkey_cache, &chain.spec);

for (block_root, block) in &chain_segment {
signature_verifier.include_all_signatures(block, Some(*block_root))?;
signature_verifier.include_all_signatures(block, Some(*block_root), None)?;
}

if signature_verifier.verify().is_err() {
Expand All @@ -560,10 +561,17 @@ pub fn signature_verify_chain_segment<T: BeaconChainTypes>(

let mut signature_verified_blocks = chain_segment
.into_iter()
.map(|(block_root, block)| SignatureVerifiedBlock {
block,
block_root,
parent: None,
.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<_>>();

Expand All @@ -582,6 +590,7 @@ pub struct GossipVerifiedBlock<T: BeaconChainTypes> {
pub block: Arc<SignedBeaconBlock<T::EthSpec>>,
pub block_root: Hash256,
parent: Option<PreProcessingSnapshot<T::EthSpec>>,
consensus_context: ConsensusContext<T::EthSpec>,
}

/// A wrapper around a `SignedBeaconBlock` that indicates that all signatures (except the deposit
Expand All @@ -590,6 +599,7 @@ pub struct SignatureVerifiedBlock<T: BeaconChainTypes> {
block: Arc<SignedBeaconBlock<T::EthSpec>>,
block_root: Hash256,
parent: Option<PreProcessingSnapshot<T::EthSpec>>,
consensus_context: ConsensusContext<T::EthSpec>,
}

/// Used to await the result of executing payload with a remote EE.
Expand Down Expand Up @@ -863,10 +873,16 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
// Validate the block's execution_payload (if any).
validate_execution_payload_for_gossip(&parent_block, block.message(), chain)?;

// Having checked the proposer index and the block root we can cache them.
let consensus_context = ConsensusContext::new(block.slot())
.set_current_block_root(block_root)
.set_proposer_index(block.message().proposer_index());

Ok(Self {
block,
block_root,
parent,
consensus_context,
})
}

Expand Down Expand Up @@ -926,10 +942,13 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {

let mut signature_verifier = get_signature_verifier(&state, &pubkey_cache, &chain.spec);

signature_verifier.include_all_signatures(&block, Some(block_root))?;
signature_verifier.include_all_signatures(&block, Some(block_root), None)?;

if signature_verifier.verify().is_ok() {
Ok(Self {
consensus_context: ConsensusContext::new(block.slot())
.set_current_block_root(block_root)
.set_proposer_index(block.message().proposer_index()),
block,
block_root,
parent: Some(parent),
Expand Down Expand Up @@ -972,13 +991,18 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {

let mut signature_verifier = get_signature_verifier(&state, &pubkey_cache, &chain.spec);

signature_verifier.include_all_signatures_except_proposal(&block)?;
// Gossip verification has already checked the proposer index. Use it to check the RANDAO
// signature.
let verified_proposer_index = Some(block.message().proposer_index());
signature_verifier
.include_all_signatures_except_proposal(&block, verified_proposer_index)?;

if signature_verifier.verify().is_ok() {
Ok(Self {
block,
block_root: from.block_root,
parent: Some(parent),
consensus_context: from.consensus_context,
})
} else {
Err(BlockError::InvalidSignature)
Expand Down Expand Up @@ -1015,8 +1039,14 @@ impl<T: BeaconChainTypes> IntoExecutionPendingBlock<T> for SignatureVerifiedBloc
.map_err(|e| BlockSlashInfo::SignatureValid(header.clone(), e))?
};

ExecutionPendingBlock::from_signature_verified_components(block, block_root, parent, chain)
.map_err(|e| BlockSlashInfo::SignatureValid(header, e))
ExecutionPendingBlock::from_signature_verified_components(
block,
block_root,
parent,
self.consensus_context,
chain,
)
.map_err(|e| BlockSlashInfo::SignatureValid(header, e))
}

fn block(&self) -> &SignedBeaconBlock<T::EthSpec> {
Expand Down Expand Up @@ -1057,6 +1087,7 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
block: Arc<SignedBeaconBlock<T::EthSpec>>,
block_root: Hash256,
parent: PreProcessingSnapshot<T::EthSpec>,
mut consensus_context: ConsensusContext<T::EthSpec>,
chain: &Arc<BeaconChain<T>>,
) -> Result<Self, BlockError<T::EthSpec>> {
if let Some(parent) = chain
Expand Down Expand Up @@ -1340,10 +1371,10 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
if let Err(err) = per_block_processing(
&mut state,
&block,
Some(block_root),
// Signatures were verified earlier in this function.
BlockSignatureStrategy::NoVerification,
VerifyBlockRoot::True,
&mut consensus_context,
&chain.spec,
) {
match err {
Expand Down
7 changes: 5 additions & 2 deletions beacon_node/beacon_chain/src/fork_revert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use proto_array::CountUnrealizedFull;
use slog::{info, warn, Logger};
use state_processing::state_advance::complete_state_advance;
use state_processing::{
per_block_processing, per_block_processing::BlockSignatureStrategy, VerifyBlockRoot,
per_block_processing, per_block_processing::BlockSignatureStrategy, ConsensusContext,
VerifyBlockRoot,
};
use std::sync::Arc;
use std::time::Duration;
Expand Down Expand Up @@ -172,12 +173,14 @@ pub fn reset_fork_choice_to_finalization<E: EthSpec, Hot: ItemStore<E>, Cold: It
complete_state_advance(&mut state, None, block.slot(), spec)
.map_err(|e| format!("State advance failed: {:?}", e))?;

let mut ctxt = ConsensusContext::new(block.slot())
.set_proposer_index(block.message().proposer_index());
per_block_processing(
&mut state,
&block,
None,
BlockSignatureStrategy::NoVerification,
VerifyBlockRoot::True,
&mut ctxt,
spec,
)
.map_err(|e| format!("Error replaying block: {:?}", e))?;
Expand Down
9 changes: 7 additions & 2 deletions beacon_node/store/src/reconstruct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use crate::{Error, ItemStore, KeyValueStore};
use itertools::{process_results, Itertools};
use slog::info;
use state_processing::{
per_block_processing, per_slot_processing, BlockSignatureStrategy, VerifyBlockRoot,
per_block_processing, per_slot_processing, BlockSignatureStrategy, ConsensusContext,
VerifyBlockRoot,
};
use std::sync::Arc;
use types::{EthSpec, Hash256};
Expand Down Expand Up @@ -87,12 +88,16 @@ where

// Apply block.
if let Some(block) = block {
let mut ctxt = ConsensusContext::new(block.slot())
.set_current_block_root(block_root)
.set_proposer_index(block.message().proposer_index());

per_block_processing(
&mut state,
&block,
Some(block_root),
BlockSignatureStrategy::NoVerification,
VerifyBlockRoot::True,
&mut ctxt,
&self.spec,
)
.map_err(HotColdDBError::BlockReplayBlockError)?;
Expand Down
6 changes: 4 additions & 2 deletions consensus/state_processing/src/block_replayer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
per_block_processing, per_epoch_processing::EpochProcessingSummary, per_slot_processing,
BlockProcessingError, BlockSignatureStrategy, SlotProcessingError, VerifyBlockRoot,
BlockProcessingError, BlockSignatureStrategy, ConsensusContext, SlotProcessingError,
VerifyBlockRoot,
};
use std::marker::PhantomData;
use types::{BeaconState, BlindedPayload, ChainSpec, EthSpec, Hash256, SignedBeaconBlock, Slot};
Expand Down Expand Up @@ -254,12 +255,13 @@ where
VerifyBlockRoot::False
}
});
let mut ctxt = ConsensusContext::new(block.slot());
per_block_processing(
&mut self.state,
block,
None,
self.block_sig_strategy,
verify_block_root,
&mut ctxt,
self.spec,
)
.map_err(BlockReplayError::from)?;
Expand Down
92 changes: 92 additions & 0 deletions consensus/state_processing/src/consensus_context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use std::marker::PhantomData;
use tree_hash::TreeHash;
use types::{
BeaconState, BeaconStateError, ChainSpec, EthSpec, ExecPayload, Hash256, SignedBeaconBlock,
Slot,
};

#[derive(Debug)]
pub struct ConsensusContext<T: EthSpec> {
/// Slot to act as an identifier/safeguard
slot: Slot,
/// Proposer index of the block at `slot`.
proposer_index: Option<u64>,
/// Block root of the block at `slot`.
current_block_root: Option<Hash256>,
_phantom: PhantomData<T>,
}

#[derive(Debug, PartialEq, Clone)]
pub enum ContextError {
BeaconState(BeaconStateError),
SlotMismatch { slot: Slot, expected: Slot },
}

impl From<BeaconStateError> for ContextError {
fn from(e: BeaconStateError) -> Self {
Self::BeaconState(e)
}
}

impl<T: EthSpec> ConsensusContext<T> {
pub fn new(slot: Slot) -> Self {
Self {
slot,
proposer_index: None,
current_block_root: None,
_phantom: PhantomData,
}
}

pub fn set_proposer_index(mut self, proposer_index: u64) -> Self {
self.proposer_index = Some(proposer_index);
self
}

pub fn get_proposer_index(
&mut self,
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Result<u64, ContextError> {
self.check_slot(state.slot())?;

if let Some(proposer_index) = self.proposer_index {
return Ok(proposer_index);
}

let proposer_index = state.get_beacon_proposer_index(self.slot, spec)? as u64;
self.proposer_index = Some(proposer_index);
Ok(proposer_index)
}

pub fn set_current_block_root(mut self, block_root: Hash256) -> Self {
self.current_block_root = Some(block_root);
self
}

pub fn get_current_block_root<Payload: ExecPayload<T>>(
&mut self,
block: &SignedBeaconBlock<T, Payload>,
) -> Result<Hash256, ContextError> {
self.check_slot(block.slot())?;

if let Some(current_block_root) = self.current_block_root {
return Ok(current_block_root);
}

let current_block_root = block.message().tree_hash_root();
self.current_block_root = Some(current_block_root);
Ok(current_block_root)
}

fn check_slot(&self, slot: Slot) -> Result<(), ContextError> {
if slot == self.slot {
Ok(())
} else {
Err(ContextError::SlotMismatch {
slot,
expected: self.slot,
})
}
}
}
2 changes: 2 additions & 0 deletions consensus/state_processing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod metrics;

pub mod block_replayer;
pub mod common;
pub mod consensus_context;
pub mod genesis;
pub mod per_block_processing;
pub mod per_epoch_processing;
Expand All @@ -27,6 +28,7 @@ pub mod upgrade;
pub mod verify_operation;

pub use block_replayer::{BlockReplayError, BlockReplayer, StateRootStrategy};
pub use consensus_context::{ConsensusContext, ContextError};
pub use genesis::{
eth2_genesis_time, initialize_beacon_state_from_eth1, is_valid_genesis_state,
process_activations,
Expand Down
Loading