diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 3eecc9a0d..4429abc4c 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -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; @@ -3498,7 +3498,6 @@ impl BeaconChain { } let slot = state.slot(); - let proposer_index = state.get_beacon_proposer_index(state.slot(), &self.spec)? as u64; let sync_aggregate = if matches!(&state, BeaconState::Base(_)) { None @@ -3645,12 +3644,14 @@ impl BeaconChain { ProduceBlockVerification::VerifyRandao => BlockSignatureStrategy::VerifyRandao, ProduceBlockVerification::NoVerification => BlockSignatureStrategy::NoVerification, }; + // Use a context without block root or proposer index so that both are checked. + let mut ctxt = ConsensusContext::new(block.slot()); per_block_processing( &mut state, &block, - None, signature_strategy, VerifyBlockRoot::True, + &mut ctxt, &self.spec, )?; drop(process_timer); diff --git a/beacon_node/beacon_chain/src/block_verification.rs b/beacon_node/beacon_chain/src/block_verification.rs index f83bc535d..7f59f1cfe 100644 --- a/beacon_node/beacon_chain/src/block_verification.rs +++ b/beacon_node/beacon_chain/src/block_verification.rs @@ -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; @@ -549,7 +550,7 @@ pub fn signature_verify_chain_segment( 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() { @@ -560,10 +561,17 @@ pub fn signature_verify_chain_segment( 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::>(); @@ -582,6 +590,7 @@ pub struct GossipVerifiedBlock { pub block: Arc>, pub block_root: Hash256, parent: Option>, + consensus_context: ConsensusContext, } /// A wrapper around a `SignedBeaconBlock` that indicates that all signatures (except the deposit @@ -590,6 +599,7 @@ pub struct SignatureVerifiedBlock { block: Arc>, block_root: Hash256, parent: Option>, + consensus_context: ConsensusContext, } /// Used to await the result of executing payload with a remote EE. @@ -863,10 +873,16 @@ impl GossipVerifiedBlock { // 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, }) } @@ -926,10 +942,13 @@ impl SignatureVerifiedBlock { 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), @@ -972,13 +991,18 @@ impl SignatureVerifiedBlock { 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) @@ -1015,8 +1039,14 @@ impl IntoExecutionPendingBlock 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 { @@ -1057,6 +1087,7 @@ impl ExecutionPendingBlock { block: Arc>, block_root: Hash256, parent: PreProcessingSnapshot, + mut consensus_context: ConsensusContext, chain: &Arc>, ) -> Result> { if let Some(parent) = chain @@ -1340,10 +1371,10 @@ impl ExecutionPendingBlock { 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 { diff --git a/beacon_node/beacon_chain/src/fork_revert.rs b/beacon_node/beacon_chain/src/fork_revert.rs index 654b2713b..3d48dfd8f 100644 --- a/beacon_node/beacon_chain/src/fork_revert.rs +++ b/beacon_node/beacon_chain/src/fork_revert.rs @@ -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; @@ -172,12 +173,14 @@ pub fn reset_fork_choice_to_finalization, 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))?; diff --git a/beacon_node/beacon_chain/tests/block_verification.rs b/beacon_node/beacon_chain/tests/block_verification.rs index 0ff4e57a8..998f22f77 100644 --- a/beacon_node/beacon_chain/tests/block_verification.rs +++ b/beacon_node/beacon_chain/tests/block_verification.rs @@ -11,7 +11,7 @@ use slasher::{Config as SlasherConfig, Slasher}; use state_processing::{ common::get_indexed_attestation, per_block_processing::{per_block_processing, BlockSignatureStrategy}, - per_slot_processing, BlockProcessingError, VerifyBlockRoot, + per_slot_processing, BlockProcessingError, ConsensusContext, VerifyBlockRoot, }; use std::marker::PhantomData; use std::sync::Arc; @@ -1139,14 +1139,15 @@ async fn add_base_block_to_altair_chain() { // Ensure that it would be impossible to apply this block to `per_block_processing`. { let mut state = state; + let mut ctxt = ConsensusContext::new(base_block.slot()); per_slot_processing(&mut state, None, &harness.chain.spec).unwrap(); assert!(matches!( per_block_processing( &mut state, &base_block, - None, BlockSignatureStrategy::NoVerification, VerifyBlockRoot::True, + &mut ctxt, &harness.chain.spec, ), Err(BlockProcessingError::InconsistentBlockFork( @@ -1271,14 +1272,15 @@ async fn add_altair_block_to_base_chain() { // Ensure that it would be impossible to apply this block to `per_block_processing`. { let mut state = state; + let mut ctxt = ConsensusContext::new(altair_block.slot()); per_slot_processing(&mut state, None, &harness.chain.spec).unwrap(); assert!(matches!( per_block_processing( &mut state, &altair_block, - None, BlockSignatureStrategy::NoVerification, VerifyBlockRoot::True, + &mut ctxt, &harness.chain.spec, ), Err(BlockProcessingError::InconsistentBlockFork( diff --git a/beacon_node/store/src/reconstruct.rs b/beacon_node/store/src/reconstruct.rs index 7db2652f2..c939fd3f5 100644 --- a/beacon_node/store/src/reconstruct.rs +++ b/beacon_node/store/src/reconstruct.rs @@ -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}; @@ -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)?; diff --git a/consensus/state_processing/src/block_replayer.rs b/consensus/state_processing/src/block_replayer.rs index d4b4b067e..cc7bd17c5 100644 --- a/consensus/state_processing/src/block_replayer.rs +++ b/consensus/state_processing/src/block_replayer.rs @@ -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}; @@ -254,12 +255,16 @@ where VerifyBlockRoot::False } }); + // Proposer index was already checked when this block was originally processed, we + // can omit recomputing it during replay. + let mut ctxt = ConsensusContext::new(block.slot()) + .set_proposer_index(block.message().proposer_index()); per_block_processing( &mut self.state, block, - None, self.block_sig_strategy, verify_block_root, + &mut ctxt, self.spec, ) .map_err(BlockReplayError::from)?; diff --git a/consensus/state_processing/src/common/slash_validator.rs b/consensus/state_processing/src/common/slash_validator.rs index e9d94a106..ac2dba875 100644 --- a/consensus/state_processing/src/common/slash_validator.rs +++ b/consensus/state_processing/src/common/slash_validator.rs @@ -1,9 +1,13 @@ -use crate::common::{decrease_balance, increase_balance, initiate_validator_exit}; +use crate::{ + common::{decrease_balance, increase_balance, initiate_validator_exit}, + per_block_processing::errors::BlockProcessingError, + ConsensusContext, +}; use safe_arith::SafeArith; use std::cmp; use types::{ consts::altair::{PROPOSER_WEIGHT, WEIGHT_DENOMINATOR}, - BeaconStateError as Error, *, + *, }; /// Slash the validator with index `slashed_index`. @@ -11,8 +15,9 @@ pub fn slash_validator( state: &mut BeaconState, slashed_index: usize, opt_whistleblower_index: Option, + ctxt: &mut ConsensusContext, spec: &ChainSpec, -) -> Result<(), Error> { +) -> Result<(), BlockProcessingError> { let epoch = state.current_epoch(); initiate_validator_exit(state, slashed_index, spec)?; @@ -39,7 +44,7 @@ pub fn slash_validator( )?; // Apply proposer and whistleblower rewards - let proposer_index = state.get_beacon_proposer_index(state.slot(), spec)?; + let proposer_index = ctxt.get_proposer_index(state, spec)? as usize; let whistleblower_index = opt_whistleblower_index.unwrap_or(proposer_index); let whistleblower_reward = validator_effective_balance.safe_div(spec.whistleblower_reward_quotient)?; @@ -52,7 +57,7 @@ pub fn slash_validator( // Ensure the whistleblower index is in the validator registry. if state.validators().get(whistleblower_index).is_none() { - return Err(BeaconStateError::UnknownValidator(whistleblower_index)); + return Err(BeaconStateError::UnknownValidator(whistleblower_index).into()); } increase_balance(state, proposer_index, proposer_reward)?; diff --git a/consensus/state_processing/src/consensus_context.rs b/consensus/state_processing/src/consensus_context.rs new file mode 100644 index 000000000..fdd3f95a6 --- /dev/null +++ b/consensus/state_processing/src/consensus_context.rs @@ -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 { + /// Slot to act as an identifier/safeguard + slot: Slot, + /// Proposer index of the block at `slot`. + proposer_index: Option, + /// Block root of the block at `slot`. + current_block_root: Option, + _phantom: PhantomData, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum ContextError { + BeaconState(BeaconStateError), + SlotMismatch { slot: Slot, expected: Slot }, +} + +impl From for ContextError { + fn from(e: BeaconStateError) -> Self { + Self::BeaconState(e) + } +} + +impl ConsensusContext { + 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, + spec: &ChainSpec, + ) -> Result { + 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>( + &mut self, + block: &SignedBeaconBlock, + ) -> Result { + 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, + }) + } + } +} diff --git a/consensus/state_processing/src/lib.rs b/consensus/state_processing/src/lib.rs index cf541d457..e4f36bedd 100644 --- a/consensus/state_processing/src/lib.rs +++ b/consensus/state_processing/src/lib.rs @@ -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; @@ -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, diff --git a/consensus/state_processing/src/per_block_processing.rs b/consensus/state_processing/src/per_block_processing.rs index e409372dd..cccc8eacd 100644 --- a/consensus/state_processing/src/per_block_processing.rs +++ b/consensus/state_processing/src/per_block_processing.rs @@ -1,3 +1,4 @@ +use crate::consensus_context::ConsensusContext; use errors::{BlockOperationError, BlockProcessingError, HeaderInvalid}; use rayon::prelude::*; use safe_arith::{ArithError, SafeArith}; @@ -90,9 +91,9 @@ pub enum VerifyBlockRoot { pub fn per_block_processing>( state: &mut BeaconState, signed_block: &SignedBeaconBlock, - block_root: Option, block_signature_strategy: BlockSignatureStrategy, verify_block_root: VerifyBlockRoot, + ctxt: &mut ConsensusContext, spec: &ChainSpec, ) -> Result<(), BlockProcessingError> { let block = signed_block.message(); @@ -110,6 +111,8 @@ pub fn per_block_processing>( let verify_signatures = match block_signature_strategy { BlockSignatureStrategy::VerifyBulk => { // 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!( BlockSignatureVerifier::verify_entire_block( state, @@ -117,6 +120,7 @@ pub fn per_block_processing>( |pk_bytes| pk_bytes.decompress().ok().map(Cow::Owned), signed_block, block_root, + proposer_index, spec ) .is_ok(), @@ -133,11 +137,12 @@ pub fn per_block_processing>( state, block.temporary_block_header(), verify_block_root, + ctxt, spec, )?; if verify_signatures.is_true() { - verify_block_signature(state, signed_block, block_root, spec)?; + verify_block_signature(state, signed_block, ctxt, spec)?; } let verify_randao = if let BlockSignatureStrategy::VerifyRandao = block_signature_strategy { @@ -157,9 +162,9 @@ pub fn per_block_processing>( process_execution_payload(state, payload, spec)?; } - process_randao(state, block, verify_randao, spec)?; + process_randao(state, block, verify_randao, ctxt, spec)?; process_eth1_data(state, block.body().eth1_data())?; - process_operations(state, block.body(), proposer_index, verify_signatures, spec)?; + process_operations(state, block.body(), verify_signatures, ctxt, spec)?; if let Ok(sync_aggregate) = block.body().sync_aggregate() { process_sync_aggregate( @@ -179,6 +184,7 @@ pub fn process_block_header( state: &mut BeaconState, block_header: BeaconBlockHeader, verify_block_root: VerifyBlockRoot, + ctxt: &mut ConsensusContext, spec: &ChainSpec, ) -> Result> { // Verify that the slots match @@ -197,8 +203,8 @@ pub fn process_block_header( ); // Verify that proposer index is the correct index - let proposer_index = block_header.proposer_index as usize; - let state_proposer_index = state.get_beacon_proposer_index(block_header.slot, spec)?; + let proposer_index = block_header.proposer_index; + let state_proposer_index = ctxt.get_proposer_index(state, spec)?; verify!( proposer_index == state_proposer_index, HeaderInvalid::ProposerIndexMismatch { @@ -222,11 +228,11 @@ pub fn process_block_header( // Verify proposer is not slashed verify!( - !state.get_validator(proposer_index)?.slashed, + !state.get_validator(proposer_index as usize)?.slashed, HeaderInvalid::ProposerSlashed(proposer_index) ); - Ok(proposer_index as u64) + Ok(proposer_index) } /// Verifies the signature of a block. @@ -235,15 +241,18 @@ pub fn process_block_header( pub fn verify_block_signature>( state: &BeaconState, block: &SignedBeaconBlock, - block_root: Option, + ctxt: &mut ConsensusContext, spec: &ChainSpec, ) -> Result<(), BlockOperationError> { + let block_root = Some(ctxt.get_current_block_root(block)?); + let proposer_index = Some(ctxt.get_proposer_index(state, spec)?); verify!( block_proposal_signature_set( state, |i| get_pubkey_from_state(state, i), block, block_root, + proposer_index, spec )? .verify(), @@ -259,12 +268,21 @@ pub fn process_randao>( state: &mut BeaconState, block: BeaconBlockRef<'_, T, Payload>, verify_signatures: VerifySignatures, + ctxt: &mut ConsensusContext, spec: &ChainSpec, ) -> Result<(), BlockProcessingError> { if verify_signatures.is_true() { // Verify RANDAO reveal signature. + let proposer_index = ctxt.get_proposer_index(state, spec)?; block_verify!( - randao_signature_set(state, |i| get_pubkey_from_state(state, i), block, spec)?.verify(), + randao_signature_set( + state, + |i| get_pubkey_from_state(state, i), + block, + Some(proposer_index), + spec + )? + .verify(), BlockProcessingError::RandaoSignatureInvalid ); } diff --git a/consensus/state_processing/src/per_block_processing/block_signature_verifier.rs b/consensus/state_processing/src/per_block_processing/block_signature_verifier.rs index 78205ca92..7584df14e 100644 --- a/consensus/state_processing/src/per_block_processing/block_signature_verifier.rs +++ b/consensus/state_processing/src/per_block_processing/block_signature_verifier.rs @@ -123,10 +123,11 @@ where decompressor: D, block: &'a SignedBeaconBlock, block_root: Option, + verified_proposer_index: Option, spec: &'a ChainSpec, ) -> Result<()> { let mut verifier = Self::new(state, get_pubkey, decompressor, spec); - verifier.include_all_signatures(block, block_root)?; + verifier.include_all_signatures(block, block_root, verified_proposer_index)?; verifier.verify() } @@ -135,9 +136,10 @@ where &mut self, block: &'a SignedBeaconBlock, block_root: Option, + verified_proposer_index: Option, ) -> Result<()> { - self.include_block_proposal(block, block_root)?; - self.include_all_signatures_except_proposal(block)?; + self.include_block_proposal(block, block_root, verified_proposer_index)?; + self.include_all_signatures_except_proposal(block, verified_proposer_index)?; Ok(()) } @@ -147,8 +149,9 @@ where pub fn include_all_signatures_except_proposal>( &mut self, block: &'a SignedBeaconBlock, + verified_proposer_index: Option, ) -> Result<()> { - self.include_randao_reveal(block)?; + self.include_randao_reveal(block, verified_proposer_index)?; self.include_proposer_slashings(block)?; self.include_attester_slashings(block)?; self.include_attestations(block)?; @@ -164,12 +167,14 @@ where &mut self, block: &'a SignedBeaconBlock, block_root: Option, + verified_proposer_index: Option, ) -> Result<()> { let set = block_proposal_signature_set( self.state, self.get_pubkey.clone(), block, block_root, + verified_proposer_index, self.spec, )?; self.sets.push(set); @@ -180,11 +185,13 @@ where pub fn include_randao_reveal>( &mut self, block: &'a SignedBeaconBlock, + verified_proposer_index: Option, ) -> Result<()> { let set = randao_signature_set( self.state, self.get_pubkey.clone(), block.message(), + verified_proposer_index, self.spec, )?; self.sets.push(set); diff --git a/consensus/state_processing/src/per_block_processing/errors.rs b/consensus/state_processing/src/per_block_processing/errors.rs index e214b6e63..71bd55f88 100644 --- a/consensus/state_processing/src/per_block_processing/errors.rs +++ b/consensus/state_processing/src/per_block_processing/errors.rs @@ -1,4 +1,5 @@ use super::signature_sets::Error as SignatureSetError; +use crate::ContextError; use merkle_proof::MerkleTreeError; use safe_arith::ArithError; use types::*; @@ -70,6 +71,7 @@ pub enum BlockProcessingError { found: u64, }, ExecutionInvalid, + ConsensusContext(ContextError), } impl From for BlockProcessingError { @@ -102,6 +104,12 @@ impl From for BlockProcessingError { } } +impl From for BlockProcessingError { + fn from(e: ContextError) -> Self { + BlockProcessingError::ConsensusContext(e) + } +} + impl From> for BlockProcessingError { fn from(e: BlockOperationError) -> BlockProcessingError { match e { @@ -109,6 +117,7 @@ impl From> for BlockProcessingError { BlockOperationError::BeaconStateError(e) => BlockProcessingError::BeaconStateError(e), BlockOperationError::SignatureSetError(e) => BlockProcessingError::SignatureSetError(e), BlockOperationError::SszTypesError(e) => BlockProcessingError::SszTypesError(e), + BlockOperationError::ConsensusContext(e) => BlockProcessingError::ConsensusContext(e), BlockOperationError::ArithError(e) => BlockProcessingError::ArithError(e), } } @@ -136,6 +145,7 @@ macro_rules! impl_into_block_processing_error_with_index { BlockOperationError::BeaconStateError(e) => BlockProcessingError::BeaconStateError(e), BlockOperationError::SignatureSetError(e) => BlockProcessingError::SignatureSetError(e), BlockOperationError::SszTypesError(e) => BlockProcessingError::SszTypesError(e), + BlockOperationError::ConsensusContext(e) => BlockProcessingError::ConsensusContext(e), BlockOperationError::ArithError(e) => BlockProcessingError::ArithError(e), } } @@ -167,6 +177,7 @@ pub enum BlockOperationError { BeaconStateError(BeaconStateError), SignatureSetError(SignatureSetError), SszTypesError(ssz_types::Error), + ConsensusContext(ContextError), ArithError(ArithError), } @@ -199,6 +210,12 @@ impl From for BlockOperationError { } } +impl From for BlockOperationError { + fn from(e: ContextError) -> Self { + BlockOperationError::ConsensusContext(e) + } +} + #[derive(Debug, PartialEq, Clone)] pub enum HeaderInvalid { ProposalSignatureInvalid, @@ -208,14 +225,14 @@ pub enum HeaderInvalid { block_slot: Slot, }, ProposerIndexMismatch { - block_proposer_index: usize, - state_proposer_index: usize, + block_proposer_index: u64, + state_proposer_index: u64, }, ParentBlockRootMismatch { state: Hash256, block: Hash256, }, - ProposerSlashed(usize), + ProposerSlashed(u64), } #[derive(Debug, PartialEq, Clone)] @@ -310,6 +327,7 @@ impl From> BlockOperationError::BeaconStateError(e) => BlockOperationError::BeaconStateError(e), BlockOperationError::SignatureSetError(e) => BlockOperationError::SignatureSetError(e), BlockOperationError::SszTypesError(e) => BlockOperationError::SszTypesError(e), + BlockOperationError::ConsensusContext(e) => BlockOperationError::ConsensusContext(e), BlockOperationError::ArithError(e) => BlockOperationError::ArithError(e), } } diff --git a/consensus/state_processing/src/per_block_processing/process_operations.rs b/consensus/state_processing/src/per_block_processing/process_operations.rs index 31a4ac1fb..1000586e6 100644 --- a/consensus/state_processing/src/per_block_processing/process_operations.rs +++ b/consensus/state_processing/src/per_block_processing/process_operations.rs @@ -12,23 +12,25 @@ use types::consts::altair::{PARTICIPATION_FLAG_WEIGHTS, PROPOSER_WEIGHT, WEIGHT_ pub fn process_operations<'a, T: EthSpec, Payload: ExecPayload>( state: &mut BeaconState, block_body: BeaconBlockBodyRef<'a, T, Payload>, - proposer_index: u64, verify_signatures: VerifySignatures, + ctxt: &mut ConsensusContext, spec: &ChainSpec, ) -> Result<(), BlockProcessingError> { process_proposer_slashings( state, block_body.proposer_slashings(), verify_signatures, + ctxt, spec, )?; process_attester_slashings( state, block_body.attester_slashings(), verify_signatures, + ctxt, spec, )?; - process_attestations(state, block_body, proposer_index, verify_signatures, spec)?; + process_attestations(state, block_body, verify_signatures, ctxt, spec)?; process_deposits(state, block_body.deposits(), spec)?; process_exits(state, block_body.voluntary_exits(), verify_signatures, spec)?; Ok(()) @@ -45,12 +47,13 @@ pub mod base { state: &mut BeaconState, attestations: &[Attestation], verify_signatures: VerifySignatures, + ctxt: &mut ConsensusContext, spec: &ChainSpec, ) -> Result<(), BlockProcessingError> { // Ensure the previous epoch cache exists. state.build_committee_cache(RelativeEpoch::Previous, spec)?; - let proposer_index = state.get_beacon_proposer_index(state.slot(), spec)? as u64; + let proposer_index = ctxt.get_proposer_index(state, spec)?; // Verify and apply each attestation. for (i, attestation) in attestations.iter().enumerate() { @@ -87,10 +90,11 @@ pub mod altair { pub fn process_attestations( state: &mut BeaconState, attestations: &[Attestation], - proposer_index: u64, verify_signatures: VerifySignatures, + ctxt: &mut ConsensusContext, spec: &ChainSpec, ) -> Result<(), BlockProcessingError> { + let proposer_index = ctxt.get_proposer_index(state, spec)?; attestations .iter() .enumerate() @@ -170,6 +174,7 @@ pub fn process_proposer_slashings( state: &mut BeaconState, proposer_slashings: &[ProposerSlashing], verify_signatures: VerifySignatures, + ctxt: &mut ConsensusContext, spec: &ChainSpec, ) -> Result<(), BlockProcessingError> { // Verify and apply proposer slashings in series. @@ -186,6 +191,7 @@ pub fn process_proposer_slashings( state, proposer_slashing.signed_header_1.message.proposer_index as usize, None, + ctxt, spec, )?; @@ -201,6 +207,7 @@ pub fn process_attester_slashings( state: &mut BeaconState, attester_slashings: &[AttesterSlashing], verify_signatures: VerifySignatures, + ctxt: &mut ConsensusContext, spec: &ChainSpec, ) -> Result<(), BlockProcessingError> { for (i, attester_slashing) in attester_slashings.iter().enumerate() { @@ -211,7 +218,7 @@ pub fn process_attester_slashings( get_slashable_indices(state, attester_slashing).map_err(|e| e.into_with_index(i))?; for i in slashable_indices { - slash_validator(state, i as usize, None, spec)?; + slash_validator(state, i as usize, None, ctxt, spec)?; } } @@ -222,20 +229,26 @@ pub fn process_attester_slashings( pub fn process_attestations<'a, T: EthSpec, Payload: ExecPayload>( state: &mut BeaconState, block_body: BeaconBlockBodyRef<'a, T, Payload>, - proposer_index: u64, verify_signatures: VerifySignatures, + ctxt: &mut ConsensusContext, spec: &ChainSpec, ) -> Result<(), BlockProcessingError> { match block_body { BeaconBlockBodyRef::Base(_) => { - base::process_attestations(state, block_body.attestations(), verify_signatures, spec)?; + base::process_attestations( + state, + block_body.attestations(), + verify_signatures, + ctxt, + spec, + )?; } BeaconBlockBodyRef::Altair(_) | BeaconBlockBodyRef::Merge(_) => { altair::process_attestations( state, block_body.attestations(), - proposer_index, verify_signatures, + ctxt, spec, )?; } diff --git a/consensus/state_processing/src/per_block_processing/signature_sets.rs b/consensus/state_processing/src/per_block_processing/signature_sets.rs index 5ce1bfddd..90bbdd56f 100644 --- a/consensus/state_processing/src/per_block_processing/signature_sets.rs +++ b/consensus/state_processing/src/per_block_processing/signature_sets.rs @@ -76,6 +76,7 @@ pub fn block_proposal_signature_set<'a, T, F, Payload: ExecPayload>( get_pubkey: F, signed_block: &'a SignedBeaconBlock, block_root: Option, + verified_proposer_index: Option, spec: &'a ChainSpec, ) -> Result> where @@ -83,8 +84,12 @@ where F: Fn(usize) -> Option>, { let block = signed_block.message(); - let proposer_index = state.get_beacon_proposer_index(block.slot(), spec)? as u64; + let proposer_index = if let Some(proposer_index) = verified_proposer_index { + proposer_index + } else { + state.get_beacon_proposer_index(block.slot(), spec)? as u64 + }; if proposer_index != block.proposer_index() { return Err(Error::IncorrectBlockProposer { block: block.proposer_index(), @@ -156,13 +161,18 @@ pub fn randao_signature_set<'a, T, F, Payload: ExecPayload>( state: &'a BeaconState, get_pubkey: F, block: BeaconBlockRef<'a, T, Payload>, + verified_proposer_index: Option, spec: &'a ChainSpec, ) -> Result> where T: EthSpec, F: Fn(usize) -> Option>, { - let proposer_index = state.get_beacon_proposer_index(block.slot(), spec)?; + let proposer_index = if let Some(proposer_index) = verified_proposer_index { + proposer_index + } else { + state.get_beacon_proposer_index(block.slot(), spec)? as u64 + }; let domain = spec.get_domain( block.slot().epoch(T::slots_per_epoch()), @@ -178,7 +188,7 @@ where Ok(SignatureSet::single_pubkey( block.body().randao_reveal(), - get_pubkey(proposer_index).ok_or(Error::ValidatorUnknown(proposer_index as u64))?, + get_pubkey(proposer_index as usize).ok_or(Error::ValidatorUnknown(proposer_index))?, message, )) } diff --git a/consensus/state_processing/src/per_block_processing/tests.rs b/consensus/state_processing/src/per_block_processing/tests.rs index e244e02c2..b7d28832d 100644 --- a/consensus/state_processing/src/per_block_processing/tests.rs +++ b/consensus/state_processing/src/per_block_processing/tests.rs @@ -8,7 +8,7 @@ use crate::per_block_processing::errors::{ }; use crate::{ per_block_processing::{process_operations, verify_exit::verify_exit}, - BlockSignatureStrategy, VerifyBlockRoot, VerifySignatures, + BlockSignatureStrategy, ConsensusContext, VerifyBlockRoot, VerifySignatures, }; use beacon_chain::test_utils::{BeaconChainHarness, EphemeralHarnessType}; use lazy_static::lazy_static; @@ -67,12 +67,13 @@ async fn valid_block_ok() { .make_block_return_pre_state(state, slot + Slot::new(1)) .await; + let mut ctxt = ConsensusContext::new(block.slot()); let result = per_block_processing( &mut state, &block, - None, BlockSignatureStrategy::VerifyIndividual, VerifyBlockRoot::True, + &mut ctxt, &spec, ); @@ -91,12 +92,13 @@ async fn invalid_block_header_state_slot() { let (mut block, signature) = signed_block.deconstruct(); *block.slot_mut() = slot + Slot::new(1); + let mut ctxt = ConsensusContext::new(block.slot()); let result = per_block_processing( &mut state, &SignedBeaconBlock::from_block(block, signature), - None, BlockSignatureStrategy::VerifyIndividual, VerifyBlockRoot::True, + &mut ctxt, &spec, ); @@ -122,12 +124,13 @@ async fn invalid_parent_block_root() { let (mut block, signature) = signed_block.deconstruct(); *block.parent_root_mut() = Hash256::from([0xAA; 32]); + let mut ctxt = ConsensusContext::new(block.slot()); let result = per_block_processing( &mut state, &SignedBeaconBlock::from_block(block, signature), - None, BlockSignatureStrategy::VerifyIndividual, VerifyBlockRoot::True, + &mut ctxt, &spec, ); @@ -154,12 +157,13 @@ async fn invalid_block_signature() { .await; let (block, _) = signed_block.deconstruct(); + let mut ctxt = ConsensusContext::new(block.slot()); let result = per_block_processing( &mut state, &SignedBeaconBlock::from_block(block, Signature::empty()), - None, BlockSignatureStrategy::VerifyIndividual, VerifyBlockRoot::True, + &mut ctxt, &spec, ); @@ -186,12 +190,13 @@ async fn invalid_randao_reveal_signature() { }) .await; + let mut ctxt = ConsensusContext::new(signed_block.slot()); let result = per_block_processing( &mut state, &signed_block, - None, BlockSignatureStrategy::VerifyIndividual, VerifyBlockRoot::True, + &mut ctxt, &spec, ); @@ -386,11 +391,12 @@ async fn invalid_attestation_no_committee_for_index() { head_block.to_mut().body_mut().attestations_mut()[0] .data .index += 1; + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_attestations( &mut state, head_block.body(), - head_block.proposer_index(), VerifySignatures::True, + &mut ctxt, &spec, ); @@ -424,11 +430,12 @@ async fn invalid_attestation_wrong_justified_checkpoint() { .data .source = new_justified_checkpoint; + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_attestations( &mut state, head_block.body(), - head_block.proposer_index(), VerifySignatures::True, + &mut ctxt, &spec, ); @@ -463,11 +470,12 @@ async fn invalid_attestation_bad_aggregation_bitfield_len() { head_block.to_mut().body_mut().attestations_mut()[0].aggregation_bits = Bitfield::with_capacity(spec.target_committee_size).unwrap(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_attestations( &mut state, head_block.body(), - head_block.proposer_index(), VerifySignatures::True, + &mut ctxt, &spec, ); @@ -495,11 +503,12 @@ async fn invalid_attestation_bad_signature() { .0; head_block.to_mut().body_mut().attestations_mut()[0].signature = AggregateSignature::empty(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_attestations( &mut state, head_block.body(), - head_block.proposer_index(), VerifySignatures::True, + &mut ctxt, &spec, ); // Expecting BadSignature because we're signing with invalid secret_keys @@ -533,11 +542,12 @@ async fn invalid_attestation_included_too_early() { .data .slot = new_attesation_slot; + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_attestations( &mut state, head_block.body(), - head_block.proposer_index(), VerifySignatures::True, + &mut ctxt, &spec, ); @@ -575,11 +585,12 @@ async fn invalid_attestation_included_too_late() { .data .slot = new_attesation_slot; + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_attestations( &mut state, head_block.body(), - head_block.proposer_index(), VerifySignatures::True, + &mut ctxt, &spec, ); assert_eq!( @@ -613,11 +624,12 @@ async fn invalid_attestation_target_epoch_slot_mismatch() { .target .epoch += Epoch::new(1); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_attestations( &mut state, head_block.body(), - head_block.proposer_index(), VerifySignatures::True, + &mut ctxt, &spec, ); assert_eq!( @@ -640,10 +652,12 @@ async fn valid_insert_attester_slashing() { let attester_slashing = harness.make_attester_slashing(vec![1, 2]); let mut state = harness.get_current_state(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_attester_slashings( &mut state, &[attester_slashing], VerifySignatures::True, + &mut ctxt, &spec, ); @@ -660,10 +674,12 @@ async fn invalid_attester_slashing_not_slashable() { attester_slashing.attestation_1 = attester_slashing.attestation_2.clone(); let mut state = harness.get_current_state(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_attester_slashings( &mut state, &[attester_slashing], VerifySignatures::True, + &mut ctxt, &spec, ); @@ -686,10 +702,12 @@ async fn invalid_attester_slashing_1_invalid() { attester_slashing.attestation_1.attesting_indices = VariableList::from(vec![2, 1]); let mut state = harness.get_current_state(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_attester_slashings( &mut state, &[attester_slashing], VerifySignatures::True, + &mut ctxt, &spec, ); @@ -715,10 +733,12 @@ async fn invalid_attester_slashing_2_invalid() { attester_slashing.attestation_2.attesting_indices = VariableList::from(vec![2, 1]); let mut state = harness.get_current_state(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_attester_slashings( &mut state, &[attester_slashing], VerifySignatures::True, + &mut ctxt, &spec, ); @@ -741,10 +761,12 @@ async fn valid_insert_proposer_slashing() { let harness = get_harness::(EPOCH_OFFSET, VALIDATOR_COUNT).await; let proposer_slashing = harness.make_proposer_slashing(1); let mut state = harness.get_current_state(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_proposer_slashings( &mut state, &[proposer_slashing], VerifySignatures::True, + &mut ctxt, &spec, ); // Expecting Ok(_) because we inserted a valid proposer slashing @@ -760,10 +782,12 @@ async fn invalid_proposer_slashing_proposals_identical() { proposer_slashing.signed_header_1.message = proposer_slashing.signed_header_2.message.clone(); let mut state = harness.get_current_state(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_proposer_slashings( &mut state, &[proposer_slashing], VerifySignatures::True, + &mut ctxt, &spec, ); @@ -787,10 +811,12 @@ async fn invalid_proposer_slashing_proposer_unknown() { proposer_slashing.signed_header_2.message.proposer_index = 3_141_592; let mut state = harness.get_current_state(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_proposer_slashings( &mut state, &[proposer_slashing], VerifySignatures::True, + &mut ctxt, &spec, ); @@ -811,10 +837,12 @@ async fn invalid_proposer_slashing_duplicate_slashing() { let proposer_slashing = harness.make_proposer_slashing(1); let mut state = harness.get_current_state(); + let mut ctxt = ConsensusContext::new(state.slot()); let result_1 = process_operations::process_proposer_slashings( &mut state, &[proposer_slashing.clone()], VerifySignatures::False, + &mut ctxt, &spec, ); assert!(result_1.is_ok()); @@ -823,6 +851,7 @@ async fn invalid_proposer_slashing_duplicate_slashing() { &mut state, &[proposer_slashing], VerifySignatures::False, + &mut ctxt, &spec, ); // Expecting ProposerNotSlashable because we've already slashed the validator @@ -842,10 +871,12 @@ async fn invalid_bad_proposal_1_signature() { let mut proposer_slashing = harness.make_proposer_slashing(1); proposer_slashing.signed_header_1.signature = Signature::empty(); let mut state = harness.get_current_state(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_proposer_slashings( &mut state, &[proposer_slashing], VerifySignatures::True, + &mut ctxt, &spec, ); @@ -866,10 +897,12 @@ async fn invalid_bad_proposal_2_signature() { let mut proposer_slashing = harness.make_proposer_slashing(1); proposer_slashing.signed_header_2.signature = Signature::empty(); let mut state = harness.get_current_state(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_proposer_slashings( &mut state, &[proposer_slashing], VerifySignatures::True, + &mut ctxt, &spec, ); @@ -891,10 +924,12 @@ async fn invalid_proposer_slashing_proposal_epoch_mismatch() { proposer_slashing.signed_header_1.message.slot = Slot::new(0); proposer_slashing.signed_header_2.message.slot = Slot::new(128); let mut state = harness.get_current_state(); + let mut ctxt = ConsensusContext::new(state.slot()); let result = process_operations::process_proposer_slashings( &mut state, &[proposer_slashing], VerifySignatures::False, + &mut ctxt, &spec, ); diff --git a/lcli/src/skip_slots.rs b/lcli/src/skip_slots.rs index 28310f768..8bd9af99a 100644 --- a/lcli/src/skip_slots.rs +++ b/lcli/src/skip_slots.rs @@ -121,7 +121,7 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< }; for i in 0..runs { - let mut state = state.clone_with(CloneConfig::committee_caches_only()); + let mut state = state.clone_with(CloneConfig::all()); let start = Instant::now(); diff --git a/lcli/src/transition_blocks.rs b/lcli/src/transition_blocks.rs index dc825d2c0..b25cec81b 100644 --- a/lcli/src/transition_blocks.rs +++ b/lcli/src/transition_blocks.rs @@ -74,7 +74,7 @@ use eth2::{ use ssz::Encode; use state_processing::{ block_signature_verifier::BlockSignatureVerifier, per_block_processing, per_slot_processing, - BlockSignatureStrategy, VerifyBlockRoot, + BlockSignatureStrategy, ConsensusContext, VerifyBlockRoot, }; use std::borrow::Cow; use std::fs::File; @@ -360,6 +360,7 @@ fn do_transition( decompressor, &block, Some(block_root), + Some(block.message().proposer_index()), spec, ) .map_err(|e| format!("Invalid block signature: {:?}", e))?; @@ -367,12 +368,15 @@ fn do_transition( } let t = Instant::now(); + let mut ctxt = ConsensusContext::new(pre_state.slot()) + .set_current_block_root(block_root) + .set_proposer_index(block.message().proposer_index()); per_block_processing( &mut pre_state, &block, - None, BlockSignatureStrategy::NoVerification, VerifyBlockRoot::True, + &mut ctxt, spec, ) .map_err(|e| format!("State transition failed: {:?}", e))?; diff --git a/testing/ef_tests/src/cases/operations.rs b/testing/ef_tests/src/cases/operations.rs index 54195cc23..a351a597c 100644 --- a/testing/ef_tests/src/cases/operations.rs +++ b/testing/ef_tests/src/cases/operations.rs @@ -5,14 +5,17 @@ use crate::decode::{ssz_decode_file, ssz_decode_file_with, ssz_decode_state, yam use crate::testing_spec; use crate::type_name::TypeName; use serde_derive::Deserialize; -use state_processing::per_block_processing::{ - errors::BlockProcessingError, - process_block_header, process_execution_payload, - process_operations::{ - altair, base, process_attester_slashings, process_deposits, process_exits, - process_proposer_slashings, +use state_processing::{ + per_block_processing::{ + errors::BlockProcessingError, + process_block_header, process_execution_payload, + process_operations::{ + altair, base, process_attester_slashings, process_deposits, process_exits, + process_proposer_slashings, + }, + process_sync_aggregate, VerifyBlockRoot, VerifySignatures, }, - process_sync_aggregate, VerifyBlockRoot, VerifySignatures, + ConsensusContext, }; use std::fmt::Debug; use std::path::Path; @@ -76,11 +79,16 @@ impl Operation for Attestation { spec: &ChainSpec, _: &Operations, ) -> Result<(), BlockProcessingError> { - let proposer_index = state.get_beacon_proposer_index(state.slot(), spec)? as u64; + let mut ctxt = ConsensusContext::new(state.slot()); + let proposer_index = ctxt.get_proposer_index(state, spec)?; match state { - BeaconState::Base(_) => { - base::process_attestations(state, &[self.clone()], VerifySignatures::True, spec) - } + BeaconState::Base(_) => base::process_attestations( + state, + &[self.clone()], + VerifySignatures::True, + &mut ctxt, + spec, + ), BeaconState::Altair(_) | BeaconState::Merge(_) => altair::process_attestation( state, self, @@ -108,7 +116,14 @@ impl Operation for AttesterSlashing { spec: &ChainSpec, _: &Operations, ) -> Result<(), BlockProcessingError> { - process_attester_slashings(state, &[self.clone()], VerifySignatures::True, spec) + let mut ctxt = ConsensusContext::new(state.slot()); + process_attester_slashings( + state, + &[self.clone()], + VerifySignatures::True, + &mut ctxt, + spec, + ) } } @@ -147,7 +162,14 @@ impl Operation for ProposerSlashing { spec: &ChainSpec, _: &Operations, ) -> Result<(), BlockProcessingError> { - process_proposer_slashings(state, &[self.clone()], VerifySignatures::True, spec) + let mut ctxt = ConsensusContext::new(state.slot()); + process_proposer_slashings( + state, + &[self.clone()], + VerifySignatures::True, + &mut ctxt, + spec, + ) } } @@ -189,10 +211,12 @@ impl Operation for BeaconBlock { spec: &ChainSpec, _: &Operations, ) -> Result<(), BlockProcessingError> { + let mut ctxt = ConsensusContext::new(state.slot()); process_block_header( state, self.to_ref().temporary_block_header(), VerifyBlockRoot::True, + &mut ctxt, spec, )?; Ok(()) diff --git a/testing/ef_tests/src/cases/sanity_blocks.rs b/testing/ef_tests/src/cases/sanity_blocks.rs index 5f0db25de..8a7578972 100644 --- a/testing/ef_tests/src/cases/sanity_blocks.rs +++ b/testing/ef_tests/src/cases/sanity_blocks.rs @@ -5,7 +5,7 @@ use crate::decode::{ssz_decode_file_with, ssz_decode_state, yaml_decode_file}; use serde_derive::Deserialize; use state_processing::{ per_block_processing, per_slot_processing, BlockProcessingError, BlockSignatureStrategy, - VerifyBlockRoot, + ConsensusContext, VerifyBlockRoot, }; use types::{BeaconState, EthSpec, ForkName, RelativeEpoch, SignedBeaconBlock}; @@ -91,26 +91,28 @@ impl Case for SanityBlocks { .build_committee_cache(RelativeEpoch::Current, spec) .unwrap(); + let mut ctxt = ConsensusContext::new(indiv_state.slot()); per_block_processing( &mut indiv_state, signed_block, - None, BlockSignatureStrategy::VerifyIndividual, VerifyBlockRoot::True, + &mut ctxt, spec, )?; + let mut ctxt = ConsensusContext::new(indiv_state.slot()); per_block_processing( &mut bulk_state, signed_block, - None, BlockSignatureStrategy::VerifyBulk, VerifyBlockRoot::True, + &mut ctxt, spec, )?; - if block.state_root() == bulk_state.canonical_root() - && block.state_root() == indiv_state.canonical_root() + if block.state_root() == bulk_state.update_tree_hash_cache().unwrap() + && block.state_root() == indiv_state.update_tree_hash_cache().unwrap() { Ok(()) } else { diff --git a/testing/ef_tests/src/cases/transition.rs b/testing/ef_tests/src/cases/transition.rs index d2b1bb2c6..2c9134aba 100644 --- a/testing/ef_tests/src/cases/transition.rs +++ b/testing/ef_tests/src/cases/transition.rs @@ -4,7 +4,7 @@ use crate::decode::{ssz_decode_file_with, ssz_decode_state, yaml_decode_file}; use serde_derive::Deserialize; use state_processing::{ per_block_processing, state_advance::complete_state_advance, BlockSignatureStrategy, - VerifyBlockRoot, + ConsensusContext, VerifyBlockRoot, }; use std::str::FromStr; use types::{BeaconState, Epoch, ForkName, SignedBeaconBlock}; @@ -91,12 +91,13 @@ impl Case for TransitionTest { .map_err(|e| format!("Failed to advance: {:?}", e))?; // Apply block. + let mut ctxt = ConsensusContext::new(state.slot()); per_block_processing( &mut state, block, - None, BlockSignatureStrategy::VerifyBulk, VerifyBlockRoot::True, + &mut ctxt, spec, ) .map_err(|e| format!("Block processing failed: {:?}", e))?; diff --git a/testing/state_transition_vectors/src/exit.rs b/testing/state_transition_vectors/src/exit.rs index f485e1a26..d581eba96 100644 --- a/testing/state_transition_vectors/src/exit.rs +++ b/testing/state_transition_vectors/src/exit.rs @@ -2,7 +2,7 @@ use super::*; use beacon_chain::test_utils::{BeaconChainHarness, EphemeralHarnessType}; use state_processing::{ per_block_processing, per_block_processing::errors::ExitInvalid, BlockProcessingError, - BlockSignatureStrategy, VerifyBlockRoot, + BlockSignatureStrategy, ConsensusContext, VerifyBlockRoot, }; use types::{BeaconBlock, BeaconState, Epoch, EthSpec, SignedBeaconBlock}; @@ -64,12 +64,13 @@ impl ExitTest { block: &SignedBeaconBlock, state: &mut BeaconState, ) -> Result<(), BlockProcessingError> { + let mut ctxt = ConsensusContext::new(block.slot()); per_block_processing( state, block, - None, BlockSignatureStrategy::VerifyIndividual, VerifyBlockRoot::True, + &mut ctxt, &E::default_spec(), ) } @@ -125,7 +126,7 @@ vectors_and_tests!( ExitTest { block_modifier: Box::new(|_, block| { // Duplicate the exit - let exit = block.body().voluntary_exits()[0].clone(); + let exit = block.body().voluntary_exits().get(0).unwrap().clone(); block.body_mut().voluntary_exits_mut().push(exit).unwrap(); }), expected: Err(BlockProcessingError::ExitInvalid { @@ -144,7 +145,11 @@ vectors_and_tests!( invalid_validator_unknown, ExitTest { block_modifier: Box::new(|_, block| { - block.body_mut().voluntary_exits_mut()[0] + block + .body_mut() + .voluntary_exits_mut() + .get_mut(0) + .unwrap() .message .validator_index = VALIDATOR_COUNT as u64; }), @@ -165,7 +170,7 @@ vectors_and_tests!( invalid_exit_already_initiated, ExitTest { state_modifier: Box::new(|state| { - state.validators_mut()[0].exit_epoch = STATE_EPOCH + 1; + state.validators_mut().get_mut(0).unwrap().exit_epoch = STATE_EPOCH + 1; }), expected: Err(BlockProcessingError::ExitInvalid { index: 0, @@ -184,7 +189,8 @@ vectors_and_tests!( invalid_not_active_before_activation_epoch, ExitTest { state_modifier: Box::new(|state| { - state.validators_mut()[0].activation_epoch = E::default_spec().far_future_epoch; + state.validators_mut().get_mut(0).unwrap().activation_epoch = + E::default_spec().far_future_epoch; }), expected: Err(BlockProcessingError::ExitInvalid { index: 0, @@ -203,7 +209,7 @@ vectors_and_tests!( invalid_not_active_after_exit_epoch, ExitTest { state_modifier: Box::new(|state| { - state.validators_mut()[0].exit_epoch = STATE_EPOCH; + state.validators_mut().get_mut(0).unwrap().exit_epoch = STATE_EPOCH; }), expected: Err(BlockProcessingError::ExitInvalid { index: 0, @@ -303,7 +309,11 @@ vectors_and_tests!( block_modifier: Box::new(|_, block| { // Shift the validator index by 1 so that it's mismatched from the key that was // used to sign. - block.body_mut().voluntary_exits_mut()[0] + block + .body_mut() + .voluntary_exits_mut() + .get_mut(0) + .unwrap() .message .validator_index = VALIDATOR_INDEX + 1; }),