mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-19 21:04:41 +00:00
Use all attestation subnets (#1257)
* Update `milagro_bls` to new release (#1183) * Update milagro_bls to new release Signed-off-by: Kirk Baird <baird.k@outlook.com> * Tidy up fake cryptos Signed-off-by: Kirk Baird <baird.k@outlook.com> * move SecretHash to bls and put plaintext back Signed-off-by: Kirk Baird <baird.k@outlook.com> * Update v0.12.0 to v0.12.1 * Add compute_subnet_for_attestation * Replace CommitteeIndex topic with Attestation * Fix warnings * Fix attestation service tests * fmt * Appease clippy * return error from validator_subscriptions * move state out of loop * Fix early break on error * Get state from slot clock * Fix beacon state in attestation tests * Add failing test for lookahead > 1 * Minor change * Address some review comments * Add subnet verification to beacon chain * Move subnet verification to processor * Pass committee_count_at_slot to ValidatorDuty and ValidatorSubscription * Pass subnet id for publishing attestations * Fix attestation service tests * Fix more tests * Fix fork choice test * Remove unused code * Remove more unused and expensive code Co-authored-by: Kirk Baird <baird.k@outlook.com> Co-authored-by: Michael Sproul <michael@sigmaprime.io> Co-authored-by: Age Manning <Age@AgeManning.com> Co-authored-by: Paul Hauner <paul@paulhauner.com>
This commit is contained in:
@@ -3,12 +3,12 @@
|
||||
//! determines whether attestations should be aggregated and/or passed to the beacon node.
|
||||
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||
use eth2_libp2p::{types::GossipKind, MessageId, NetworkGlobals, PeerId};
|
||||
use eth2_libp2p::{types::GossipKind, NetworkGlobals};
|
||||
use futures::prelude::*;
|
||||
use hashset_delay::HashSetDelay;
|
||||
use rand::seq::SliceRandom;
|
||||
use rest_types::ValidatorSubscription;
|
||||
use slog::{crit, debug, error, o, warn};
|
||||
use slog::{crit, debug, error, o, trace, warn};
|
||||
use slot_clock::SlotClock;
|
||||
use std::collections::VecDeque;
|
||||
use std::pin::Pin;
|
||||
@@ -186,18 +186,34 @@ impl<T: BeaconChainTypes> AttestationService<T> {
|
||||
pub fn validator_subscriptions(
|
||||
&mut self,
|
||||
subscriptions: Vec<ValidatorSubscription>,
|
||||
) -> Result<(), ()> {
|
||||
) -> Result<(), String> {
|
||||
for subscription in subscriptions {
|
||||
//NOTE: We assume all subscriptions have been verified before reaching this service
|
||||
|
||||
// Registers the validator with the attestation service.
|
||||
// This will subscribe to long-lived random subnets if required.
|
||||
trace!(self.log,
|
||||
"Validator subscription";
|
||||
"subscription" => format!("{:?}", subscription),
|
||||
);
|
||||
self.add_known_validator(subscription.validator_index);
|
||||
|
||||
let subnet_id = SubnetId::new(
|
||||
subscription.attestation_committee_index
|
||||
% self.beacon_chain.spec.attestation_subnet_count,
|
||||
);
|
||||
let subnet_id = match SubnetId::compute_subnet::<T::EthSpec>(
|
||||
subscription.slot,
|
||||
subscription.attestation_committee_index,
|
||||
subscription.committee_count_at_slot,
|
||||
&self.beacon_chain.spec,
|
||||
) {
|
||||
Ok(subnet_id) => subnet_id,
|
||||
Err(e) => {
|
||||
warn!(self.log,
|
||||
"Failed to compute subnet id for validator subscription";
|
||||
"error" => format!("{:?}", e),
|
||||
"validator_index" => subscription.validator_index
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let exact_subnet = ExactSubnet {
|
||||
subnet_id,
|
||||
@@ -219,9 +235,18 @@ impl<T: BeaconChainTypes> AttestationService<T> {
|
||||
|
||||
if subscription.is_aggregator {
|
||||
// set the subscription timer to subscribe to the next subnet if required
|
||||
if let Err(e) = self.subscribe_to_subnet(exact_subnet) {
|
||||
warn!(self.log, "Subscription to subnet error"; "error" => e);
|
||||
return Err(());
|
||||
if let Err(e) = self.subscribe_to_subnet(exact_subnet.clone()) {
|
||||
warn!(self.log,
|
||||
"Subscription to subnet error";
|
||||
"error" => e,
|
||||
"validator_index" => subscription.validator_index,
|
||||
);
|
||||
} else {
|
||||
trace!(self.log,
|
||||
"Subscribed to subnet for aggregator duties";
|
||||
"exact_subnet" => format!("{:?}", exact_subnet),
|
||||
"validator_index" => subscription.validator_index
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,25 +257,9 @@ impl<T: BeaconChainTypes> AttestationService<T> {
|
||||
/// verification, re-propagates and returns false.
|
||||
pub fn should_process_attestation(
|
||||
&mut self,
|
||||
_message_id: &MessageId,
|
||||
peer_id: &PeerId,
|
||||
subnet: &SubnetId,
|
||||
attestation: &Attestation<T::EthSpec>,
|
||||
) -> bool {
|
||||
// verify the attestation is on the correct subnet
|
||||
let expected_subnet = match attestation.subnet_id(&self.beacon_chain.spec) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
warn!(self.log, "Could not obtain attestation subnet_id"; "error" => format!("{:?}", e));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if expected_subnet != *subnet {
|
||||
warn!(self.log, "Received an attestation on the wrong subnet"; "subnet_received" => format!("{:?}", subnet), "subnet_expected" => format!("{:?}",expected_subnet), "peer_id" => format!("{}", peer_id));
|
||||
return false;
|
||||
}
|
||||
|
||||
let exact_subnet = ExactSubnet {
|
||||
subnet_id: subnet.clone(),
|
||||
slot: attestation.data.slot,
|
||||
@@ -511,7 +520,7 @@ impl<T: BeaconChainTypes> AttestationService<T> {
|
||||
self.random_subnets.insert(subnet_id);
|
||||
|
||||
// if we are not already subscribed, then subscribe
|
||||
let topic_kind = &GossipKind::CommitteeIndex(subnet_id);
|
||||
let topic_kind = &GossipKind::Attestation(subnet_id);
|
||||
|
||||
let already_subscribed = self
|
||||
.network_globals
|
||||
@@ -574,7 +583,7 @@ impl<T: BeaconChainTypes> AttestationService<T> {
|
||||
// we are also not un-subscribing from a subnet if the next slot requires us to be
|
||||
// subscribed. Therefore there could be the case that we are already still subscribed
|
||||
// to the required subnet. In which case we do not issue another subscription request.
|
||||
let topic_kind = &GossipKind::CommitteeIndex(exact_subnet.subnet_id);
|
||||
let topic_kind = &GossipKind::Attestation(exact_subnet.subnet_id);
|
||||
if self
|
||||
.network_globals
|
||||
.gossipsub_subscriptions
|
||||
|
||||
@@ -108,17 +108,23 @@ mod tests {
|
||||
validator_index: u64,
|
||||
attestation_committee_index: CommitteeIndex,
|
||||
slot: Slot,
|
||||
committee_count_at_slot: u64,
|
||||
) -> ValidatorSubscription {
|
||||
let is_aggregator = true;
|
||||
ValidatorSubscription {
|
||||
validator_index,
|
||||
attestation_committee_index,
|
||||
slot,
|
||||
committee_count_at_slot,
|
||||
is_aggregator,
|
||||
}
|
||||
}
|
||||
|
||||
fn _get_subscriptions(validator_count: u64, slot: Slot) -> Vec<ValidatorSubscription> {
|
||||
fn _get_subscriptions(
|
||||
validator_count: u64,
|
||||
slot: Slot,
|
||||
committee_count_at_slot: u64,
|
||||
) -> Vec<ValidatorSubscription> {
|
||||
let mut subscriptions: Vec<ValidatorSubscription> = Vec::new();
|
||||
for validator_index in 0..validator_count {
|
||||
let is_aggregator = true;
|
||||
@@ -126,6 +132,7 @@ mod tests {
|
||||
validator_index,
|
||||
attestation_committee_index: validator_index,
|
||||
slot,
|
||||
committee_count_at_slot,
|
||||
is_aggregator,
|
||||
});
|
||||
}
|
||||
@@ -167,6 +174,7 @@ mod tests {
|
||||
let committee_index = 1;
|
||||
let subscription_slot = 0;
|
||||
let no_events_expected = 4;
|
||||
let committee_count = 1;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
@@ -180,6 +188,7 @@ mod tests {
|
||||
validator_index,
|
||||
committee_index,
|
||||
current_slot + Slot::new(subscription_slot),
|
||||
committee_count,
|
||||
)];
|
||||
|
||||
// submit the subscriptions
|
||||
@@ -188,7 +197,15 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
// not enough time for peer discovery, just subscribe
|
||||
let expected = vec![AttServiceMessage::Subscribe(SubnetId::new(validator_index))];
|
||||
let expected = vec![AttServiceMessage::Subscribe(
|
||||
SubnetId::compute_subnet::<MinimalEthSpec>(
|
||||
current_slot + Slot::new(subscription_slot),
|
||||
committee_index,
|
||||
committee_count,
|
||||
&attestation_service.beacon_chain.spec,
|
||||
)
|
||||
.unwrap(),
|
||||
)];
|
||||
|
||||
let events = get_events(attestation_service, no_events_expected, 1).await;
|
||||
assert_matches!(
|
||||
@@ -215,6 +232,7 @@ mod tests {
|
||||
let committee_index = 1;
|
||||
let subscription_slot = 0;
|
||||
let no_events_expected = 5;
|
||||
let committee_count = 1;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
@@ -228,6 +246,7 @@ mod tests {
|
||||
validator_index,
|
||||
committee_index,
|
||||
current_slot + Slot::new(subscription_slot),
|
||||
committee_count,
|
||||
)];
|
||||
|
||||
// submit the subscriptions
|
||||
@@ -236,9 +255,16 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
// not enough time for peer discovery, just subscribe, unsubscribe
|
||||
let subnet_id = SubnetId::compute_subnet::<MinimalEthSpec>(
|
||||
current_slot + Slot::new(subscription_slot),
|
||||
committee_index,
|
||||
committee_count,
|
||||
&attestation_service.beacon_chain.spec,
|
||||
)
|
||||
.unwrap();
|
||||
let expected = vec![
|
||||
AttServiceMessage::Subscribe(SubnetId::new(validator_index)),
|
||||
AttServiceMessage::Unsubscribe(SubnetId::new(validator_index)),
|
||||
AttServiceMessage::Subscribe(subnet_id),
|
||||
AttServiceMessage::Unsubscribe(subnet_id),
|
||||
];
|
||||
|
||||
let events = get_events(attestation_service, no_events_expected, 2).await;
|
||||
@@ -266,6 +292,7 @@ mod tests {
|
||||
let committee_index = 1;
|
||||
let subscription_slot = 5;
|
||||
let no_events_expected = 4;
|
||||
let committee_count = 1;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
@@ -279,6 +306,7 @@ mod tests {
|
||||
validator_index,
|
||||
committee_index,
|
||||
current_slot + Slot::new(subscription_slot),
|
||||
committee_count,
|
||||
)];
|
||||
|
||||
// submit the subscriptions
|
||||
@@ -295,10 +323,14 @@ mod tests {
|
||||
);
|
||||
|
||||
// just discover peers, don't subscribe yet
|
||||
let expected = vec![AttServiceMessage::DiscoverPeers {
|
||||
subnet_id: SubnetId::new(validator_index),
|
||||
min_ttl,
|
||||
}];
|
||||
let subnet_id = SubnetId::compute_subnet::<MinimalEthSpec>(
|
||||
current_slot + Slot::new(subscription_slot),
|
||||
committee_index,
|
||||
committee_count,
|
||||
&attestation_service.beacon_chain.spec,
|
||||
)
|
||||
.unwrap();
|
||||
let expected = vec![AttServiceMessage::DiscoverPeers { subnet_id, min_ttl }];
|
||||
|
||||
let events = get_events(attestation_service, no_events_expected, 1).await;
|
||||
assert_matches!(
|
||||
@@ -325,6 +357,7 @@ mod tests {
|
||||
let committee_index = 1;
|
||||
let subscription_slot = 5;
|
||||
let no_events_expected = 5;
|
||||
let committee_count = 1;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
@@ -338,6 +371,7 @@ mod tests {
|
||||
validator_index,
|
||||
committee_index,
|
||||
current_slot + Slot::new(subscription_slot),
|
||||
committee_count,
|
||||
)];
|
||||
|
||||
// submit the subscriptions
|
||||
@@ -354,12 +388,16 @@ mod tests {
|
||||
);
|
||||
|
||||
// we should discover peers, wait, then subscribe
|
||||
let subnet_id = SubnetId::compute_subnet::<MinimalEthSpec>(
|
||||
current_slot + Slot::new(subscription_slot),
|
||||
committee_index,
|
||||
committee_count,
|
||||
&attestation_service.beacon_chain.spec,
|
||||
)
|
||||
.unwrap();
|
||||
let expected = vec![
|
||||
AttServiceMessage::DiscoverPeers {
|
||||
subnet_id: SubnetId::new(validator_index),
|
||||
min_ttl,
|
||||
},
|
||||
AttServiceMessage::Subscribe(SubnetId::new(validator_index)),
|
||||
AttServiceMessage::DiscoverPeers { subnet_id, min_ttl },
|
||||
AttServiceMessage::Subscribe(subnet_id),
|
||||
];
|
||||
|
||||
let events = get_events(attestation_service, no_events_expected, 5).await;
|
||||
@@ -387,6 +425,7 @@ mod tests {
|
||||
let committee_index = 1;
|
||||
let subscription_slot = 7;
|
||||
let no_events_expected = 3;
|
||||
let committee_count = 1;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
@@ -400,6 +439,7 @@ mod tests {
|
||||
validator_index,
|
||||
committee_index,
|
||||
current_slot + Slot::new(subscription_slot),
|
||||
committee_count,
|
||||
)];
|
||||
|
||||
// submit the subscriptions
|
||||
@@ -436,9 +476,11 @@ mod tests {
|
||||
let committee_index = 1;
|
||||
let subscription_slot = 10;
|
||||
let no_events_expected = 4;
|
||||
let committee_count = 1;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
|
||||
let current_slot = attestation_service
|
||||
.beacon_chain
|
||||
.slot_clock
|
||||
@@ -449,6 +491,7 @@ mod tests {
|
||||
validator_index,
|
||||
committee_index,
|
||||
current_slot + Slot::new(subscription_slot),
|
||||
committee_count,
|
||||
)];
|
||||
|
||||
// submit the subscriptions
|
||||
@@ -464,11 +507,17 @@ mod tests {
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let subnet_id = SubnetId::compute_subnet::<MinimalEthSpec>(
|
||||
current_slot + Slot::new(subscription_slot),
|
||||
committee_index,
|
||||
committee_count,
|
||||
&attestation_service.beacon_chain.spec,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// expect discover peers because we will enter TARGET_PEER_DISCOVERY_SLOT_LOOK_AHEAD range
|
||||
let expected: Vec<AttServiceMessage> = vec![AttServiceMessage::DiscoverPeers {
|
||||
subnet_id: SubnetId::new(validator_index),
|
||||
min_ttl,
|
||||
}];
|
||||
let expected: Vec<AttServiceMessage> =
|
||||
vec![AttServiceMessage::DiscoverPeers { subnet_id, min_ttl }];
|
||||
|
||||
let events = get_events(attestation_service, no_events_expected, 5).await;
|
||||
|
||||
@@ -494,6 +543,7 @@ mod tests {
|
||||
// subscribe 10 slots ahead so we do not produce any exact subnet messages
|
||||
let subscription_slot = 10;
|
||||
let subscription_count = 64;
|
||||
let committee_count = 1;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
@@ -503,8 +553,11 @@ mod tests {
|
||||
.now()
|
||||
.expect("Could not get current slot");
|
||||
|
||||
let subscriptions =
|
||||
_get_subscriptions(subscription_count, current_slot + subscription_slot);
|
||||
let subscriptions = _get_subscriptions(
|
||||
subscription_count,
|
||||
current_slot + subscription_slot,
|
||||
committee_count,
|
||||
);
|
||||
|
||||
// submit the subscriptions
|
||||
attestation_service
|
||||
@@ -542,6 +595,7 @@ mod tests {
|
||||
let subscription_slot = 10;
|
||||
// the 65th subscription should result in no more messages than the previous scenario
|
||||
let subscription_count = 65;
|
||||
let committee_count = 1;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
@@ -551,8 +605,11 @@ mod tests {
|
||||
.now()
|
||||
.expect("Could not get current slot");
|
||||
|
||||
let subscriptions =
|
||||
_get_subscriptions(subscription_count, current_slot + subscription_slot);
|
||||
let subscriptions = _get_subscriptions(
|
||||
subscription_count,
|
||||
current_slot + subscription_slot,
|
||||
committee_count,
|
||||
);
|
||||
|
||||
// submit the subscriptions
|
||||
attestation_service
|
||||
|
||||
@@ -234,6 +234,7 @@ impl<T: BeaconChainTypes> Router<T> {
|
||||
self.processor.verify_unaggregated_attestation_for_gossip(
|
||||
peer_id.clone(),
|
||||
subnet_attestation.1.clone(),
|
||||
subnet_attestation.0,
|
||||
)
|
||||
{
|
||||
self.propagate_message(id, peer_id.clone());
|
||||
|
||||
@@ -17,7 +17,7 @@ use std::sync::Arc;
|
||||
use tokio::sync::mpsc;
|
||||
use types::{
|
||||
Attestation, ChainSpec, Epoch, EthSpec, Hash256, SignedAggregateAndProof, SignedBeaconBlock,
|
||||
Slot,
|
||||
Slot, SubnetId,
|
||||
};
|
||||
|
||||
//TODO: Rate limit requests
|
||||
@@ -758,6 +758,18 @@ impl<T: BeaconChainTypes> Processor<T> {
|
||||
* The peer has published an invalid consensus message.
|
||||
*/
|
||||
}
|
||||
|
||||
AttnError::InvalidSubnetId { received, expected } => {
|
||||
/*
|
||||
* The attestation was received on an incorrect subnet id.
|
||||
*/
|
||||
debug!(
|
||||
self.log,
|
||||
"Received attestation on incorrect subnet";
|
||||
"expected" => format!("{:?}", expected),
|
||||
"received" => format!("{:?}", received),
|
||||
)
|
||||
}
|
||||
AttnError::Invalid(_) => {
|
||||
/*
|
||||
* The attestation failed the state_processing verification.
|
||||
@@ -833,12 +845,13 @@ impl<T: BeaconChainTypes> Processor<T> {
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
unaggregated_attestation: Attestation<T::EthSpec>,
|
||||
subnet_id: SubnetId,
|
||||
) -> Option<VerifiedUnaggregatedAttestation<T>> {
|
||||
// This is provided to the error handling function to assist with debugging.
|
||||
let beacon_block_root = unaggregated_attestation.data.beacon_block_root;
|
||||
|
||||
self.chain
|
||||
.verify_unaggregated_attestation_for_gossip(unaggregated_attestation)
|
||||
.verify_unaggregated_attestation_for_gossip(unaggregated_attestation, subnet_id)
|
||||
.map_err(|e| {
|
||||
self.handle_attestation_verification_failure(
|
||||
peer_id,
|
||||
|
||||
@@ -14,7 +14,7 @@ use eth2_libp2p::{
|
||||
use eth2_libp2p::{BehaviourEvent, Enr, MessageId, NetworkGlobals, PeerId};
|
||||
use futures::prelude::*;
|
||||
use rest_types::ValidatorSubscription;
|
||||
use slog::{debug, error, info, o, trace};
|
||||
use slog::{debug, error, info, o, trace, warn};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use store::HotColdDB;
|
||||
@@ -236,10 +236,11 @@ fn spawn_service<T: BeaconChainTypes>(
|
||||
);
|
||||
}
|
||||
NetworkMessage::Subscribe { subscriptions } => {
|
||||
// the result is dropped as it used solely for ergonomics
|
||||
let _ = service
|
||||
if let Err(e) = service
|
||||
.attestation_service
|
||||
.validator_subscriptions(subscriptions);
|
||||
.validator_subscriptions(subscriptions) {
|
||||
warn!(service.log, "Validator subscription failed"; "error" => e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,8 +328,6 @@ fn spawn_service<T: BeaconChainTypes>(
|
||||
// checks if we have an aggregator for the slot. If so, we process
|
||||
// the attestation
|
||||
if service.attestation_service.should_process_attestation(
|
||||
&id,
|
||||
&source,
|
||||
subnet,
|
||||
attestation,
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user