mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-17 20:02:43 +00:00
Bulk signature verification (#507)
* Add basic block processing benches * Start reviving state processing benches * Fix old block builders * Add optimization for faster pubkey add * Tidy benches, add another * Add extra block processing bench * Start working on faster BLS scheme * Add partially complete sig verify optimization * Add .gitignore to state processing * Add progress on faster signature verification * Fix SignatureSet for fake_crypto * Tidy attester slashings sig set * Tidy bulk signature verifier * Refactor signature sets to be cleaner * Start threading SignatureStrategy through code * Add (empty) test dir * Move BenchingBlockBuilder * Add initial block signature verification tests * Add tests for bulk signature verification * Start threading SignatureStrategy in block proc. * Refactor per_block_processing errors * Use sig set tuples instead of lists of two * Remove dead code * Thread VerifySignatures through per_block_processing * Add bulk signature verification * Introduce parallel bulk signature verification * Expand state processing benches * Fix additional compile errors * Fix issue where par iter chunks is 0 * Update milagro_bls dep * Remove debugs, code fragment in beacon chain * Tidy, add comments to block sig verifier * Fix various PR comments * Add block_root option to per_block_processing * Fix comment in block signature verifier * Fix comments from PR review * Remove old comment * Fix comment
This commit is contained in:
@@ -1,8 +1,15 @@
|
||||
use super::errors::{TransferInvalid as Invalid, TransferValidationError as Error};
|
||||
use super::errors::{BlockOperationError, TransferInvalid as Invalid};
|
||||
use crate::per_block_processing::signature_sets::transfer_signature_set;
|
||||
use crate::per_block_processing::VerifySignatures;
|
||||
use bls::get_withdrawal_credentials;
|
||||
use tree_hash::SignedRoot;
|
||||
use types::*;
|
||||
|
||||
type Result<T> = std::result::Result<T, BlockOperationError<Invalid>>;
|
||||
|
||||
fn error(reason: Invalid) -> BlockOperationError<Invalid> {
|
||||
BlockOperationError::invalid(reason)
|
||||
}
|
||||
|
||||
/// Indicates if a `Transfer` is valid to be included in a block in the current epoch of the given
|
||||
/// state.
|
||||
///
|
||||
@@ -12,9 +19,10 @@ use types::*;
|
||||
pub fn verify_transfer<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
transfer: &Transfer,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
verify_transfer_parametric(state, transfer, spec, false)
|
||||
) -> Result<()> {
|
||||
verify_transfer_parametric(state, transfer, verify_signatures, spec, false)
|
||||
}
|
||||
|
||||
/// Like `verify_transfer` but doesn't run checks which may become true in future states.
|
||||
@@ -23,9 +31,10 @@ pub fn verify_transfer<T: EthSpec>(
|
||||
pub fn verify_transfer_time_independent_only<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
transfer: &Transfer,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
verify_transfer_parametric(state, transfer, spec, true)
|
||||
) -> Result<()> {
|
||||
verify_transfer_parametric(state, transfer, verify_signatures, spec, true)
|
||||
}
|
||||
|
||||
/// Parametric version of `verify_transfer` that allows some checks to be skipped.
|
||||
@@ -41,24 +50,25 @@ pub fn verify_transfer_time_independent_only<T: EthSpec>(
|
||||
fn verify_transfer_parametric<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
transfer: &Transfer,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
time_independent_only: bool,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<()> {
|
||||
let sender_balance = *state
|
||||
.balances
|
||||
.get(transfer.sender as usize)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.sender)))?;
|
||||
.ok_or_else(|| error(Invalid::FromValidatorUnknown(transfer.sender)))?;
|
||||
|
||||
let recipient_balance = *state
|
||||
.balances
|
||||
.get(transfer.recipient as usize)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.recipient)))?;
|
||||
.ok_or_else(|| error(Invalid::FromValidatorUnknown(transfer.recipient)))?;
|
||||
|
||||
// Safely determine `amount + fee`.
|
||||
let total_amount = transfer
|
||||
.amount
|
||||
.checked_add(transfer.fee)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?;
|
||||
.ok_or_else(|| error(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?;
|
||||
|
||||
// Verify the sender has adequate balance.
|
||||
verify!(
|
||||
@@ -99,7 +109,7 @@ fn verify_transfer_parametric<T: EthSpec>(
|
||||
let sender_validator = state
|
||||
.validators
|
||||
.get(transfer.sender as usize)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.sender)))?;
|
||||
.ok_or_else(|| error(Invalid::FromValidatorUnknown(transfer.sender)))?;
|
||||
|
||||
// Ensure one of the following is met:
|
||||
//
|
||||
@@ -131,19 +141,12 @@ fn verify_transfer_parametric<T: EthSpec>(
|
||||
)
|
||||
);
|
||||
|
||||
// Verify the transfer signature.
|
||||
let message = transfer.signed_root();
|
||||
let domain = spec.get_domain(
|
||||
transfer.slot.epoch(T::slots_per_epoch()),
|
||||
Domain::Transfer,
|
||||
&state.fork,
|
||||
);
|
||||
verify!(
|
||||
transfer
|
||||
.signature
|
||||
.verify(&message[..], domain, &transfer.pubkey),
|
||||
Invalid::BadSignature
|
||||
);
|
||||
if verify_signatures.is_true() {
|
||||
verify!(
|
||||
transfer_signature_set(state, transfer, spec)?.is_valid(),
|
||||
Invalid::BadSignature
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -157,15 +160,15 @@ pub fn execute_transfer<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
transfer: &Transfer,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<()> {
|
||||
let sender_balance = *state
|
||||
.balances
|
||||
.get(transfer.sender as usize)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.sender)))?;
|
||||
.ok_or_else(|| error(Invalid::FromValidatorUnknown(transfer.sender)))?;
|
||||
let recipient_balance = *state
|
||||
.balances
|
||||
.get(transfer.recipient as usize)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::ToValidatorUnknown(transfer.recipient)))?;
|
||||
.ok_or_else(|| error(Invalid::ToValidatorUnknown(transfer.recipient)))?;
|
||||
|
||||
let proposer_index =
|
||||
state.get_beacon_proposer_index(state.slot, RelativeEpoch::Current, spec)?;
|
||||
@@ -174,11 +177,11 @@ pub fn execute_transfer<T: EthSpec>(
|
||||
let total_amount = transfer
|
||||
.amount
|
||||
.checked_add(transfer.fee)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?;
|
||||
.ok_or_else(|| error(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?;
|
||||
|
||||
state.balances[transfer.sender as usize] =
|
||||
sender_balance.checked_sub(total_amount).ok_or_else(|| {
|
||||
Error::Invalid(Invalid::FromBalanceInsufficient(
|
||||
error(Invalid::FromBalanceInsufficient(
|
||||
total_amount,
|
||||
sender_balance,
|
||||
))
|
||||
@@ -187,7 +190,7 @@ pub fn execute_transfer<T: EthSpec>(
|
||||
state.balances[transfer.recipient as usize] = recipient_balance
|
||||
.checked_add(transfer.amount)
|
||||
.ok_or_else(|| {
|
||||
Error::Invalid(Invalid::ToBalanceOverflow(
|
||||
error(Invalid::ToBalanceOverflow(
|
||||
recipient_balance,
|
||||
transfer.amount,
|
||||
))
|
||||
@@ -195,7 +198,7 @@ pub fn execute_transfer<T: EthSpec>(
|
||||
|
||||
state.balances[proposer_index] =
|
||||
proposer_balance.checked_add(transfer.fee).ok_or_else(|| {
|
||||
Error::Invalid(Invalid::ProposerBalanceOverflow(
|
||||
error(Invalid::ProposerBalanceOverflow(
|
||||
proposer_balance,
|
||||
transfer.fee,
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user