Update VC and BN APIs for naive aggregation (#950)

* Refactor `Attestation` production

* Add constant

* Start refactor for aggregation

* Return early when no attesting validators

* Refactor into individual functions

* Tidy, add comments

* Add first draft of NaiveAggregationPool

* Further progress on naive aggregation pool

* Fix compile errors in VC

* Change locking logic for naive pool

* Introduce AttesationType

* Add pruning, comments

* Add MAX_ATTESTATIONS_PER_SLOT restriction

* Add pruning based on slot

* Update BN for new aggregation fns

* Fix test compile errors

* Fix failing rest_api test

* Move SignedAggregateAndProof into own file

* Update docs, fix warning

* Tidy some formatting in validator API

* Remove T::default_spec from signing

* Fix failing rest test

* Tidy

* Add test, fix bug

* Improve naive pool tests

* Add max attestations test

* Revert changes to the op_pool

* Refactor timer
This commit is contained in:
Paul Hauner
2020-03-25 21:14:05 +11:00
committed by GitHub
parent 58111cddb2
commit fbcf0f8e2e
30 changed files with 1407 additions and 752 deletions

View File

@@ -1,4 +1,6 @@
use super::{Attestation, Domain, EthSpec, Fork, PublicKey, SecretKey, Signature, SignedRoot};
use super::{
Attestation, ChainSpec, Domain, EthSpec, Fork, PublicKey, SecretKey, Signature, SignedRoot,
};
use crate::test_utils::TestRandom;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
@@ -21,60 +23,45 @@ pub struct AggregateAndProof<T: EthSpec> {
}
impl<T: EthSpec> AggregateAndProof<T> {
pub fn is_valid_selection_proof(&self, validator_pubkey: &PublicKey, fork: &Fork) -> bool {
/// Produces a new `AggregateAndProof` with a `selection_proof` generated by signing
/// `aggregate.data.slot` with `secret_key`.
pub fn from_aggregate(
aggregator_index: u64,
aggregate: Attestation<T>,
secret_key: &SecretKey,
fork: &Fork,
spec: &ChainSpec,
) -> Self {
let slot = aggregate.data.slot;
let domain = spec.get_domain(
slot.epoch(T::slots_per_epoch()),
Domain::SelectionProof,
fork,
);
let message = slot.signing_root(domain);
Self {
aggregator_index,
aggregate,
selection_proof: Signature::new(message.as_bytes(), secret_key),
}
}
/// Returns `true` if `validator_pubkey` signed over `self.aggregate.data.slot`.
pub fn is_valid_selection_proof(
&self,
validator_pubkey: &PublicKey,
fork: &Fork,
spec: &ChainSpec,
) -> bool {
let target_epoch = self.aggregate.data.slot.epoch(T::slots_per_epoch());
let domain = T::default_spec().get_domain(target_epoch, Domain::SelectionProof, fork);
let domain = spec.get_domain(target_epoch, Domain::SelectionProof, fork);
let message = self.aggregate.data.slot.signing_root(domain);
self.selection_proof
.verify(message.as_bytes(), validator_pubkey)
}
/// Converts Self into a SignedAggregateAndProof.
pub fn into_signed(self, secret_key: &SecretKey, fork: &Fork) -> SignedAggregateAndProof<T> {
let target_epoch = self.aggregate.data.slot.epoch(T::slots_per_epoch());
let domain = T::default_spec().get_domain(target_epoch, Domain::AggregateAndProof, fork);
let sign_message = self.signing_root(domain);
let signature = Signature::new(sign_message.as_bytes(), &secret_key);
SignedAggregateAndProof {
message: self,
signature,
}
}
}
impl<T: EthSpec> SignedRoot for AggregateAndProof<T> {}
/// A Validators signed aggregate proof to publish on the `beacon_aggregate_and_proof`
/// gossipsub topic.
///
/// Spec v0.10.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)]
#[serde(bound = "T: EthSpec")]
pub struct SignedAggregateAndProof<T: EthSpec> {
/// The `AggregateAndProof` that was signed.
pub message: AggregateAndProof<T>,
/// The aggregate attestation.
pub signature: Signature,
}
impl<T: EthSpec> SignedRoot for SignedAggregateAndProof<T> {}
impl<T: EthSpec> SignedAggregateAndProof<T> {
/// Verifies the signature of the `AggregateAndProof`
pub fn is_valid_signature(&self, validator_pubkey: &PublicKey, fork: &Fork) -> bool {
let target_epoch = self.message.aggregate.data.slot.epoch(T::slots_per_epoch());
let domain = T::default_spec().get_domain(target_epoch, Domain::AggregateAndProof, fork);
let message = self.signing_root(domain);
self.signature.verify(message.as_bytes(), validator_pubkey)
}
/// Verifies the signature of the `AggregateAndProof` as well the underlying selection_proof in
/// the contained `AggregateAndProof`.
pub fn is_valid(&self, validator_pubkey: &PublicKey, fork: &Fork) -> bool {
self.is_valid_signature(validator_pubkey, fork)
&& self
.message
.is_valid_selection_proof(validator_pubkey, fork)
}
}

View File

@@ -31,6 +31,7 @@ pub mod indexed_attestation;
pub mod pending_attestation;
pub mod proposer_slashing;
pub mod relative_epoch;
pub mod signed_aggregate_and_proof;
pub mod signed_beacon_block;
pub mod signed_beacon_block_header;
pub mod signed_voluntary_exit;
@@ -46,7 +47,7 @@ mod tree_hash_impls;
use ethereum_types::{H160, H256};
pub use crate::aggregate_and_proof::{AggregateAndProof, SignedAggregateAndProof};
pub use crate::aggregate_and_proof::AggregateAndProof;
pub use crate::attestation::{Attestation, Error as AttestationError};
pub use crate::attestation_data::AttestationData;
pub use crate::attestation_duty::AttestationDuty;
@@ -70,6 +71,7 @@ pub use crate::indexed_attestation::IndexedAttestation;
pub use crate::pending_attestation::PendingAttestation;
pub use crate::proposer_slashing::ProposerSlashing;
pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
pub use crate::signed_aggregate_and_proof::SignedAggregateAndProof;
pub use crate::signed_beacon_block::SignedBeaconBlock;
pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader;
pub use crate::signed_voluntary_exit::SignedVoluntaryExit;

View File

@@ -0,0 +1,68 @@
use super::{
AggregateAndProof, Attestation, ChainSpec, Domain, EthSpec, Fork, PublicKey, SecretKey,
Signature, SignedRoot,
};
use crate::test_utils::TestRandom;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
/// A Validators signed aggregate proof to publish on the `beacon_aggregate_and_proof`
/// gossipsub topic.
///
/// Spec v0.10.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)]
#[serde(bound = "T: EthSpec")]
pub struct SignedAggregateAndProof<T: EthSpec> {
/// The `AggregateAndProof` that was signed.
pub message: AggregateAndProof<T>,
/// The aggregate attestation.
pub signature: Signature,
}
impl<T: EthSpec> SignedAggregateAndProof<T> {
/// Produces a new `SignedAggregateAndProof` with a `selection_proof` generated by signing
/// `aggregate.data.slot` with `secret_key`.
pub fn from_aggregate(
aggregator_index: u64,
aggregate: Attestation<T>,
secret_key: &SecretKey,
fork: &Fork,
spec: &ChainSpec,
) -> Self {
let message =
AggregateAndProof::from_aggregate(aggregator_index, aggregate, secret_key, fork, spec);
let target_epoch = message.aggregate.data.slot.epoch(T::slots_per_epoch());
let domain = spec.get_domain(target_epoch, Domain::AggregateAndProof, fork);
let signing_message = message.signing_root(domain);
SignedAggregateAndProof {
message,
signature: Signature::new(signing_message.as_bytes(), &secret_key),
}
}
/// Verifies the signature of the `AggregateAndProof`
pub fn is_valid_signature(
&self,
validator_pubkey: &PublicKey,
fork: &Fork,
spec: &ChainSpec,
) -> bool {
let target_epoch = self.message.aggregate.data.slot.epoch(T::slots_per_epoch());
let domain = spec.get_domain(target_epoch, Domain::AggregateAndProof, fork);
let message = self.message.signing_root(domain);
self.signature.verify(message.as_bytes(), validator_pubkey)
}
/// Verifies the signature of the `AggregateAndProof` as well the underlying selection_proof in
/// the contained `AggregateAndProof`.
pub fn is_valid(&self, validator_pubkey: &PublicKey, fork: &Fork, spec: &ChainSpec) -> bool {
self.is_valid_signature(validator_pubkey, fork, spec)
&& self
.message
.is_valid_selection_proof(validator_pubkey, fork, spec)
}
}

View File

@@ -12,4 +12,4 @@ pub use generate_deterministic_keypairs::load_keypairs_from_yaml;
pub use keypairs_file::KeypairsFile;
pub use rand::{RngCore, SeedableRng};
pub use rand_xorshift::XorShiftRng;
pub use test_random::TestRandom;
pub use test_random::{test_random_instance, TestRandom};

View File

@@ -1,5 +1,7 @@
use crate::*;
use rand::RngCore;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
use ssz_types::typenum::Unsigned;
mod address;
@@ -12,6 +14,11 @@ mod secret_key;
mod signature;
mod signature_bytes;
pub fn test_random_instance<T: TestRandom>() -> T {
let mut rng = XorShiftRng::from_seed([0x42; 16]);
T::random_for_test(&mut rng)
}
pub trait TestRandom {
fn random_for_test(rng: &mut impl RngCore) -> Self;
}