From 3f988493622ab0221649b91682e4ad8296f86542 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 10 Mar 2019 08:55:45 +1100 Subject: [PATCH] Optimise attester slashing processing. --- .../src/per_block_processing.rs | 32 ++++++++++++++++--- .../src/per_block_processing/errors.rs | 9 ++++++ .../verify_attester_slashing.rs | 11 ++++--- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index d871914d9..7b5aafa7f 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -13,6 +13,7 @@ pub use verify_deposit::{ build_public_key_hashmap, get_existing_validator_index, verify_deposit, verify_deposit_index, }; pub use verify_exit::verify_exit; +pub use verify_slashable_attestation::verify_slashable_attestation; pub use verify_transfer::{execute_transfer, verify_transfer}; pub mod errors; @@ -264,19 +265,40 @@ pub fn process_attester_slashings( Invalid::MaxAttesterSlashingsExceed ); - // Verify attester slashings in parallel. - attester_slashings + // Verify the `SlashableAttestation`s in parallel (these are the resource-consuming objects, not + // the `AttesterSlashing`s themselves). + let mut slashable_attestations: Vec<&SlashableAttestation> = + Vec::with_capacity(attester_slashings.len() * 2); + for attester_slashing in attester_slashings { + slashable_attestations.push(&attester_slashing.slashable_attestation_1); + slashable_attestations.push(&attester_slashing.slashable_attestation_2); + } + + // Verify slashable attestations in parallel. + slashable_attestations .par_iter() .enumerate() - .try_for_each(|(i, attester_slashing)| { - verify_attester_slashing(&state, &attester_slashing, spec) + .try_for_each(|(i, slashable_attestation)| { + verify_slashable_attestation(&state, slashable_attestation, spec) .map_err(|e| e.into_with_index(i)) })?; + let all_slashable_attestations_have_been_checked = true; - // Gather the slashable indices and update the state in series. + // Gather the slashable indices and preform the final verification and update the state in series. for (i, attester_slashing) in attester_slashings.iter().enumerate() { + let should_verify_slashable_attestations = !all_slashable_attestations_have_been_checked; + + verify_attester_slashing( + &state, + &attester_slashing, + should_verify_slashable_attestations, + spec, + ) + .map_err(|e| e.into_with_index(i))?; + let slashable_indices = gather_attester_slashing_indices(&state, &attester_slashing) .map_err(|e| e.into_with_index(i))?; + for i in slashable_indices { state.slash_validator(i as usize, spec)?; } diff --git a/eth2/state_processing/src/per_block_processing/errors.rs b/eth2/state_processing/src/per_block_processing/errors.rs index f64a3f8aa..a3e3ebad1 100644 --- a/eth2/state_processing/src/per_block_processing/errors.rs +++ b/eth2/state_processing/src/per_block_processing/errors.rs @@ -76,6 +76,10 @@ pub enum BlockInvalid { MaxExitsExceeded, MaxTransfersExceed, AttestationInvalid(usize, AttestationInvalid), + /// A `SlashableAttestation` inside an `AttesterSlashing` was invalid. + /// + /// To determine the offending `AttesterSlashing` index, divide the error message `usize` by two. + SlashableAttestationInvalid(usize, SlashableAttestationInvalid), AttesterSlashingInvalid(usize, AttesterSlashingInvalid), ProposerSlashingInvalid(usize, ProposerSlashingInvalid), DepositInvalid(usize, DepositInvalid), @@ -235,6 +239,11 @@ impl Into for SlashableAttestationValidationError { } } +impl_into_with_index_without_beacon_error!( + SlashableAttestationValidationError, + SlashableAttestationInvalid +); + /* * `ProposerSlashing` Validation */ diff --git a/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs b/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs index 2970712c5..d126849b6 100644 --- a/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs +++ b/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs @@ -11,6 +11,7 @@ use types::*; pub fn verify_attester_slashing( state: &BeaconState, attester_slashing: &AttesterSlashing, + should_verify_slashable_attestations: bool, spec: &ChainSpec, ) -> Result<(), Error> { let slashable_attestation_1 = &attester_slashing.slashable_attestation_1; @@ -26,10 +27,12 @@ pub fn verify_attester_slashing( Invalid::NotSlashable ); - verify_slashable_attestation(state, &slashable_attestation_1, spec) - .map_err(|e| Error::Invalid(Invalid::SlashableAttestation1Invalid(e.into())))?; - verify_slashable_attestation(state, &slashable_attestation_2, spec) - .map_err(|e| Error::Invalid(Invalid::SlashableAttestation2Invalid(e.into())))?; + if should_verify_slashable_attestations { + verify_slashable_attestation(state, &slashable_attestation_1, spec) + .map_err(|e| Error::Invalid(Invalid::SlashableAttestation1Invalid(e.into())))?; + verify_slashable_attestation(state, &slashable_attestation_2, spec) + .map_err(|e| Error::Invalid(Invalid::SlashableAttestation2Invalid(e.into())))?; + } Ok(()) }