Optimize attestation processing (#841)

* Start updating types

* WIP

* Signature hacking

* Existing EF tests passing with fake_crypto

* Updates

* Delete outdated API spec

* The refactor continues

* It compiles

* WIP test fixes

* All release tests passing bar genesis state parsing

* Update and test YamlConfig

* Update to spec v0.10 compatible BLS

* Updates to BLS EF tests

* Add EF test for AggregateVerify

And delete unused hash2curve tests for uncompressed points

* Update EF tests to v0.10.1

* Use optional block root correctly in block proc

* Use genesis fork in deposit domain. All tests pass

* Cargo fmt

* Fast aggregate verify test

* Update REST API docs

* Cargo fmt

* Fix unused import

* Bump spec tags to v0.10.1

* Add `seconds_per_eth1_block` to chainspec

* Update to timestamp based eth1 voting scheme

* Return None from `get_votes_to_consider` if block cache is empty

* Handle overflows in `is_candidate_block`

* Revert to failing tests

* Fix eth1 data sets test

* Choose default vote according to spec

* Fix collect_valid_votes tests

* Fix `get_votes_to_consider` to choose all eligible blocks

* Uncomment winning_vote tests

* Add comments; remove unused code

* Reduce seconds_per_eth1_block for simulation

* Addressed review comments

* Add test for default vote case

* Fix logs

* Remove unused functions

* Meter default eth1 votes

* Fix comments

* Address review comments; remove unused dependency

* Add first attempt at attestation proc. re-write

* Add version 2 of attestation processing

* Minor fixes

* Add validator pubkey cache

* Make get_indexed_attestation take a committee

* Link signature processing into new attn verification

* First working version

* Ensure pubkey cache is updated

* Add more metrics, slight optimizations

* Clone committee cache during attestation processing

* Update shuffling cache during block processing

* Remove old commented-out code

* Fix shuffling cache insert bug

* Used indexed attestation in fork choice

* Restructure attn processing, add metrics

* Add more detailed metrics

* Tidy, fix failing tests

* Fix failing tests, tidy

* Disable/delete two outdated tests

* Tidy

* Add pubkey cache persistence file

* Add more comments

* Integrate persistence file into builder

* Add pubkey cache tests

* Add data_dir to beacon chain builder

* Remove Option in pubkey cache persistence file

* Ensure consistency between datadir/data_dir

* Fix failing network test

* Tidy

* Fix todos

* Add attestation processing tests

* Add another test

* Only run attestation tests in release

* Make attestation tests MainnetEthSpec

* Address Michael's comments

* Remove redundant check

* Fix warning

* Fix failing test

Co-authored-by: Michael Sproul <micsproul@gmail.com>
Co-authored-by: Pawan Dhananjay <pawandhananjay@gmail.com>
This commit is contained in:
Paul Hauner
2020-03-05 17:19:35 +11:00
committed by GitHub
parent c141f1cc03
commit 6656cb00e4
38 changed files with 1226 additions and 344 deletions

View File

@@ -5,18 +5,14 @@ use types::*;
///
/// Spec v0.10.1
pub fn get_attesting_indices<T: EthSpec>(
state: &BeaconState<T>,
attestation_data: &AttestationData,
committee: &[usize],
bitlist: &BitList<T::MaxValidatorsPerCommittee>,
) -> Result<BTreeSet<usize>, BeaconStateError> {
let committee = state.get_beacon_committee(attestation_data.slot, attestation_data.index)?;
if bitlist.len() != committee.committee.len() {
if bitlist.len() != committee.len() {
return Err(BeaconStateError::InvalidBitfield);
}
Ok(committee
.committee
.iter()
.enumerate()
.filter_map(|(i, validator_index)| match bitlist.get(i) {

View File

@@ -8,11 +8,10 @@ type Result<T> = std::result::Result<T, BlockOperationError<Invalid>>;
///
/// Spec v0.10.1
pub fn get_indexed_attestation<T: EthSpec>(
state: &BeaconState<T>,
committee: &[usize],
attestation: &Attestation<T>,
) -> Result<IndexedAttestation<T>> {
let attesting_indices =
get_attesting_indices(state, &attestation.data, &attestation.aggregation_bits)?;
let attesting_indices = get_attesting_indices::<T>(committee, &attestation.aggregation_bits)?;
Ok(IndexedAttestation {
attesting_indices: VariableList::new(

View File

@@ -10,7 +10,8 @@ pub mod test_utils;
pub use genesis::{initialize_beacon_state_from_eth1, is_valid_genesis_state, process_activations};
pub use per_block_processing::{
errors::BlockProcessingError, per_block_processing, BlockSignatureStrategy, VerifySignatures,
errors::BlockProcessingError, per_block_processing, signature_sets, BlockSignatureStrategy,
VerifySignatures,
};
pub use per_epoch_processing::{errors::EpochProcessingError, per_epoch_processing};
pub use per_slot_processing::{per_slot_processing, Error as SlotProcessingError};

View File

@@ -24,7 +24,7 @@ pub mod block_processing_builder;
mod block_signature_verifier;
pub mod errors;
mod is_valid_indexed_attestation;
mod signature_sets;
pub mod signature_sets;
pub mod tests;
mod verify_attestation;
mod verify_attester_slashing;

View File

@@ -189,7 +189,11 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> {
.attestations
.iter()
.map(|attestation| {
let indexed_attestation = get_indexed_attestation(self.state, attestation)?;
let committee = self
.state
.get_beacon_committee(attestation.data.slot, attestation.data.index)?;
let indexed_attestation =
get_indexed_attestation(committee.committee, attestation)?;
self.sets.push(indexed_attestation_signature_set(
&self.state,

View File

@@ -8,7 +8,7 @@ use std::convert::TryInto;
use tree_hash::TreeHash;
use types::{
AggregateSignature, AttesterSlashing, BeaconBlock, BeaconState, BeaconStateError, ChainSpec,
DepositData, Domain, EthSpec, Hash256, IndexedAttestation, ProposerSlashing, PublicKey,
DepositData, Domain, EthSpec, Fork, Hash256, IndexedAttestation, ProposerSlashing, PublicKey,
Signature, SignedBeaconBlock, SignedBeaconBlockHeader, SignedRoot, SignedVoluntaryExit,
SigningRoot,
};
@@ -170,6 +170,32 @@ pub fn indexed_attestation_signature_set<'a, 'b, T: EthSpec>(
Ok(SignatureSet::new(signature, vec![signed_message]))
}
/// Returns the signature set for the given `indexed_attestation` but pubkeys are supplied directly
/// instead of from the state.
pub fn indexed_attestation_signature_set_from_pubkeys<'a, 'b, T: EthSpec>(
pubkeys: Vec<&'a PublicKey>,
signature: &'a AggregateSignature,
indexed_attestation: &'b IndexedAttestation<T>,
fork: &Fork,
spec: &'a ChainSpec,
) -> Result<SignatureSet<'a>> {
let pubkeys = pubkeys
.into_iter()
.map(|pubkey| Cow::Borrowed(&pubkey.as_raw().point))
.collect();
let domain = spec.get_domain(
indexed_attestation.data.target.epoch,
Domain::BeaconAttester,
&fork,
);
let message = indexed_attestation.data.signing_root(domain);
let signed_message = SignedMessage::new(pubkeys, message.as_bytes().to_vec());
Ok(SignatureSet::new(signature, vec![signed_message]))
}
/// Returns the signature set for the given `attester_slashing` and corresponding `pubkeys`.
pub fn attester_slashing_signature_sets<'a, T: EthSpec>(
state: &'a BeaconState<T>,

View File

@@ -67,7 +67,8 @@ pub fn verify_attestation_for_state<T: EthSpec>(
verify_casper_ffg_vote(attestation, state)?;
// Check signature and bitfields
let indexed_attestation = get_indexed_attestation(state, attestation)?;
let committee = state.get_beacon_committee(attestation.data.slot, attestation.data.index)?;
let indexed_attestation = get_indexed_attestation(committee.committee, attestation)?;
is_valid_indexed_attestation(state, &indexed_attestation, verify_signatures, spec)?;
Ok(())

View File

@@ -195,7 +195,9 @@ impl ValidatorStatuses {
.iter()
.chain(state.current_epoch_attestations.iter())
{
let attesting_indices = get_attesting_indices(state, &a.data, &a.aggregation_bits)?;
let committee = state.get_beacon_committee(a.data.slot, a.data.index)?;
let attesting_indices =
get_attesting_indices::<T>(committee.committee, &a.aggregation_bits)?;
let mut status = ValidatorStatus::default();