Consensus context with proposer index caching (#3604)

## Issue Addressed

Closes https://github.com/sigp/lighthouse/issues/2371

## Proposed Changes

Backport some changes from `tree-states` that remove duplicated calculations of the `proposer_index`.

With this change the proposer index should be calculated only once for each block, and then plumbed through to every place it is required.

## Additional Info

In future I hope to add more data to the consensus context that is cached on a per-epoch basis, like the effective balances of validators and the base rewards.

There are some other changes to remove indexing in tests that were also useful for `tree-states` (the `tree-states` types don't implement `Index`).
This commit is contained in:
Michael Sproul
2022-10-15 22:25:54 +00:00
parent e4cbdc1c77
commit 59ec6b71b8
21 changed files with 388 additions and 100 deletions

View File

@@ -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<T: EthSpec, Payload: ExecPayload<T>>(
state: &mut BeaconState<T>,
signed_block: &SignedBeaconBlock<T, Payload>,
block_root: Option<Hash256>,
block_signature_strategy: BlockSignatureStrategy,
verify_block_root: VerifyBlockRoot,
ctxt: &mut ConsensusContext<T>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
let block = signed_block.message();
@@ -110,6 +111,8 @@ pub fn per_block_processing<T: EthSpec, Payload: ExecPayload<T>>(
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<T: EthSpec, Payload: ExecPayload<T>>(
|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<T: EthSpec, Payload: ExecPayload<T>>(
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<T: EthSpec, Payload: ExecPayload<T>>(
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<T: EthSpec>(
state: &mut BeaconState<T>,
block_header: BeaconBlockHeader,
verify_block_root: VerifyBlockRoot,
ctxt: &mut ConsensusContext<T>,
spec: &ChainSpec,
) -> Result<u64, BlockOperationError<HeaderInvalid>> {
// Verify that the slots match
@@ -197,8 +203,8 @@ pub fn process_block_header<T: EthSpec>(
);
// 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<T: EthSpec>(
// 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<T: EthSpec>(
pub fn verify_block_signature<T: EthSpec, Payload: ExecPayload<T>>(
state: &BeaconState<T>,
block: &SignedBeaconBlock<T, Payload>,
block_root: Option<Hash256>,
ctxt: &mut ConsensusContext<T>,
spec: &ChainSpec,
) -> Result<(), BlockOperationError<HeaderInvalid>> {
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<T: EthSpec, Payload: ExecPayload<T>>(
state: &mut BeaconState<T>,
block: BeaconBlockRef<'_, T, Payload>,
verify_signatures: VerifySignatures,
ctxt: &mut ConsensusContext<T>,
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
);
}