mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-23 23:04:53 +00:00
Subscribe to subnets only when needed (#3419)
## Issue Addressed We currently subscribe to attestation subnets as soon as the subscription arrives (one epoch in advance), this makes it so that subscriptions for future slots are scheduled instead of done immediately. ## Proposed Changes - Schedule subscriptions to subnets for future slots. - Finish removing hashmap_delay, in favor of [delay_map](https://github.com/AgeManning/delay_map). This was the only remaining service to do this. - Subscriptions for past slots are rejected, before we would subscribe for one slot. - Add a new test for subscriptions that are not consecutive. ## Additional Info This is also an effort in making the code easier to understand
This commit is contained in:
@@ -8,7 +8,7 @@ use futures::prelude::*;
|
||||
use genesis::{generate_deterministic_keypairs, interop_genesis_state, DEFAULT_ETH1_BLOCK_HASH};
|
||||
use lazy_static::lazy_static;
|
||||
use lighthouse_network::NetworkConfig;
|
||||
use slog::Logger;
|
||||
use slog::{o, Drain, Logger};
|
||||
use sloggers::{null::NullLoggerBuilder, Build};
|
||||
use slot_clock::{SlotClock, SystemTimeSlotClock};
|
||||
use std::sync::Arc;
|
||||
@@ -42,7 +42,7 @@ impl TestBeaconChain {
|
||||
|
||||
let keypairs = generate_deterministic_keypairs(1);
|
||||
|
||||
let log = get_logger();
|
||||
let log = get_logger(None);
|
||||
let store =
|
||||
HotColdDB::open_ephemeral(StoreConfig::default(), spec.clone(), log.clone()).unwrap();
|
||||
|
||||
@@ -93,16 +93,32 @@ pub fn recent_genesis_time() -> u64 {
|
||||
.as_secs()
|
||||
}
|
||||
|
||||
fn get_logger() -> Logger {
|
||||
NullLoggerBuilder.build().expect("logger should build")
|
||||
fn get_logger(log_level: Option<slog::Level>) -> Logger {
|
||||
if let Some(level) = log_level {
|
||||
let drain = {
|
||||
let decorator = slog_term::TermDecorator::new().build();
|
||||
let decorator =
|
||||
logging::AlignedTermDecorator::new(decorator, logging::MAX_MESSAGE_WIDTH);
|
||||
let drain = slog_term::FullFormat::new(decorator).build().fuse();
|
||||
let drain = slog_async::Async::new(drain).chan_size(2048).build();
|
||||
drain.filter_level(level)
|
||||
};
|
||||
|
||||
Logger::root(drain.fuse(), o!())
|
||||
} else {
|
||||
let builder = NullLoggerBuilder;
|
||||
builder.build().expect("should build logger")
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref CHAIN: TestBeaconChain = TestBeaconChain::new_with_system_clock();
|
||||
}
|
||||
|
||||
fn get_attestation_service() -> AttestationService<TestBeaconChainType> {
|
||||
let log = get_logger();
|
||||
fn get_attestation_service(
|
||||
log_level: Option<slog::Level>,
|
||||
) -> AttestationService<TestBeaconChainType> {
|
||||
let log = get_logger(log_level);
|
||||
let config = NetworkConfig::default();
|
||||
|
||||
let beacon_chain = CHAIN.chain.clone();
|
||||
@@ -111,7 +127,7 @@ fn get_attestation_service() -> AttestationService<TestBeaconChainType> {
|
||||
}
|
||||
|
||||
fn get_sync_committee_service() -> SyncCommitteeService<TestBeaconChainType> {
|
||||
let log = get_logger();
|
||||
let log = get_logger(None);
|
||||
let config = NetworkConfig::default();
|
||||
|
||||
let beacon_chain = CHAIN.chain.clone();
|
||||
@@ -128,28 +144,34 @@ async fn get_events<S: Stream<Item = SubnetServiceMessage> + Unpin>(
|
||||
) -> Vec<SubnetServiceMessage> {
|
||||
let mut events = Vec::new();
|
||||
|
||||
let collect_stream_fut = async {
|
||||
loop {
|
||||
if let Some(result) = stream.next().await {
|
||||
events.push(result);
|
||||
let timeout =
|
||||
tokio::time::sleep(Duration::from_millis(SLOT_DURATION_MILLIS) * num_slots_before_timeout);
|
||||
futures::pin_mut!(timeout);
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(event) = stream.next() => {
|
||||
events.push(event);
|
||||
if let Some(num) = num_events {
|
||||
if events.len() == num {
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
_ = timeout.as_mut() => {
|
||||
break;
|
||||
}
|
||||
|
||||
tokio::select! {
|
||||
_ = collect_stream_fut => events,
|
||||
_ = tokio::time::sleep(
|
||||
Duration::from_millis(SLOT_DURATION_MILLIS) * num_slots_before_timeout,
|
||||
) => events
|
||||
}
|
||||
}
|
||||
|
||||
events
|
||||
}
|
||||
|
||||
mod attestation_service {
|
||||
|
||||
use crate::subnet_service::attestation_subnets::MIN_PEER_DISCOVERY_SLOT_LOOK_AHEAD;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn get_subscription(
|
||||
@@ -195,7 +217,7 @@ mod attestation_service {
|
||||
let committee_count = 1;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
let mut attestation_service = get_attestation_service(None);
|
||||
let current_slot = attestation_service
|
||||
.beacon_chain
|
||||
.slot_clock
|
||||
@@ -237,15 +259,18 @@ mod attestation_service {
|
||||
matches::assert_matches!(
|
||||
events[..3],
|
||||
[
|
||||
SubnetServiceMessage::DiscoverPeers(_),
|
||||
SubnetServiceMessage::Subscribe(_any1),
|
||||
SubnetServiceMessage::EnrAdd(_any3)
|
||||
SubnetServiceMessage::EnrAdd(_any3),
|
||||
SubnetServiceMessage::DiscoverPeers(_),
|
||||
]
|
||||
);
|
||||
|
||||
// If the long lived and short lived subnets are the same, there should be no more events
|
||||
// as we don't resubscribe already subscribed subnets.
|
||||
if !attestation_service.random_subnets.contains(&subnet_id) {
|
||||
if !attestation_service
|
||||
.subscriptions(attestation_subnets::SubscriptionKind::LongLived)
|
||||
.contains_key(&subnet_id)
|
||||
{
|
||||
assert_eq!(expected[..], events[3..]);
|
||||
}
|
||||
// Should be subscribed to only 1 long lived subnet after unsubscription.
|
||||
@@ -267,7 +292,7 @@ mod attestation_service {
|
||||
let com2 = 0;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
let mut attestation_service = get_attestation_service(None);
|
||||
let current_slot = attestation_service
|
||||
.beacon_chain
|
||||
.slot_clock
|
||||
@@ -319,16 +344,19 @@ mod attestation_service {
|
||||
matches::assert_matches!(
|
||||
events[..3],
|
||||
[
|
||||
SubnetServiceMessage::DiscoverPeers(_),
|
||||
SubnetServiceMessage::Subscribe(_any1),
|
||||
SubnetServiceMessage::EnrAdd(_any3)
|
||||
SubnetServiceMessage::EnrAdd(_any3),
|
||||
SubnetServiceMessage::DiscoverPeers(_),
|
||||
]
|
||||
);
|
||||
|
||||
let expected = SubnetServiceMessage::Subscribe(Subnet::Attestation(subnet_id1));
|
||||
|
||||
// Should be still subscribed to 1 long lived and 1 short lived subnet if both are different.
|
||||
if !attestation_service.random_subnets.contains(&subnet_id1) {
|
||||
if !attestation_service
|
||||
.subscriptions(attestation_subnets::SubscriptionKind::LongLived)
|
||||
.contains_key(&subnet_id1)
|
||||
{
|
||||
assert_eq!(expected, events[3]);
|
||||
assert_eq!(attestation_service.subscription_count(), 2);
|
||||
} else {
|
||||
@@ -339,7 +367,10 @@ mod attestation_service {
|
||||
let unsubscribe_event = get_events(&mut attestation_service, None, 1).await;
|
||||
|
||||
// If the long lived and short lived subnets are different, we should get an unsubscription event.
|
||||
if !attestation_service.random_subnets.contains(&subnet_id1) {
|
||||
if !attestation_service
|
||||
.subscriptions(attestation_subnets::SubscriptionKind::LongLived)
|
||||
.contains_key(&subnet_id1)
|
||||
{
|
||||
assert_eq!(
|
||||
[SubnetServiceMessage::Unsubscribe(Subnet::Attestation(
|
||||
subnet_id1
|
||||
@@ -360,7 +391,7 @@ mod attestation_service {
|
||||
let committee_count = 1;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
let mut attestation_service = get_attestation_service(None);
|
||||
let current_slot = attestation_service
|
||||
.beacon_chain
|
||||
.slot_clock
|
||||
@@ -418,7 +449,7 @@ mod attestation_service {
|
||||
let committee_count = 1;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service();
|
||||
let mut attestation_service = get_attestation_service(None);
|
||||
let current_slot = attestation_service
|
||||
.beacon_chain
|
||||
.slot_clock
|
||||
@@ -465,6 +496,122 @@ mod attestation_service {
|
||||
assert_eq!(enr_add_count, 64);
|
||||
assert_eq!(unexpected_msg_count, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_subscribe_same_subnet_several_slots_apart() {
|
||||
// subscription config
|
||||
let validator_index = 1;
|
||||
let committee_count = 1;
|
||||
|
||||
// Makes 2 validator subscriptions to the same subnet but at different slots.
|
||||
// There should be just 1 unsubscription event for the later slot subscription (subscription_slot2).
|
||||
let subscription_slot1 = 0;
|
||||
let subscription_slot2 = MIN_PEER_DISCOVERY_SLOT_LOOK_AHEAD + 4;
|
||||
let com1 = MIN_PEER_DISCOVERY_SLOT_LOOK_AHEAD + 4;
|
||||
let com2 = 0;
|
||||
|
||||
// create the attestation service and subscriptions
|
||||
let mut attestation_service = get_attestation_service(None);
|
||||
let current_slot = attestation_service
|
||||
.beacon_chain
|
||||
.slot_clock
|
||||
.now()
|
||||
.expect("Could not get current slot");
|
||||
|
||||
let sub1 = get_subscription(
|
||||
validator_index,
|
||||
com1,
|
||||
current_slot + Slot::new(subscription_slot1),
|
||||
committee_count,
|
||||
);
|
||||
|
||||
let sub2 = get_subscription(
|
||||
validator_index,
|
||||
com2,
|
||||
current_slot + Slot::new(subscription_slot2),
|
||||
committee_count,
|
||||
);
|
||||
|
||||
let subnet_id1 = SubnetId::compute_subnet::<MainnetEthSpec>(
|
||||
current_slot + Slot::new(subscription_slot1),
|
||||
com1,
|
||||
committee_count,
|
||||
&attestation_service.beacon_chain.spec,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let subnet_id2 = SubnetId::compute_subnet::<MainnetEthSpec>(
|
||||
current_slot + Slot::new(subscription_slot2),
|
||||
com2,
|
||||
committee_count,
|
||||
&attestation_service.beacon_chain.spec,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Assert that subscriptions are different but their subnet is the same
|
||||
assert_ne!(sub1, sub2);
|
||||
assert_eq!(subnet_id1, subnet_id2);
|
||||
|
||||
// submit the subscriptions
|
||||
attestation_service
|
||||
.validator_subscriptions(vec![sub1, sub2])
|
||||
.unwrap();
|
||||
|
||||
// Unsubscription event should happen at the end of the slot.
|
||||
let events = get_events(&mut attestation_service, None, 1).await;
|
||||
matches::assert_matches!(
|
||||
events[..3],
|
||||
[
|
||||
SubnetServiceMessage::Subscribe(_any1),
|
||||
SubnetServiceMessage::EnrAdd(_any3),
|
||||
SubnetServiceMessage::DiscoverPeers(_),
|
||||
]
|
||||
);
|
||||
|
||||
let expected_subscription =
|
||||
SubnetServiceMessage::Subscribe(Subnet::Attestation(subnet_id1));
|
||||
let expected_unsubscription =
|
||||
SubnetServiceMessage::Unsubscribe(Subnet::Attestation(subnet_id1));
|
||||
|
||||
if !attestation_service
|
||||
.subscriptions(attestation_subnets::SubscriptionKind::LongLived)
|
||||
.contains_key(&subnet_id1)
|
||||
{
|
||||
assert_eq!(expected_subscription, events[3]);
|
||||
// fourth is a discovery event
|
||||
assert_eq!(expected_unsubscription, events[5]);
|
||||
}
|
||||
assert_eq!(attestation_service.subscription_count(), 1);
|
||||
|
||||
println!("{events:?}");
|
||||
let subscription_slot = current_slot + subscription_slot2 - 1; // one less do to the
|
||||
// advance subscription time
|
||||
let wait_slots = attestation_service
|
||||
.beacon_chain
|
||||
.slot_clock
|
||||
.duration_to_slot(subscription_slot)
|
||||
.unwrap()
|
||||
.as_millis() as u64
|
||||
/ SLOT_DURATION_MILLIS;
|
||||
|
||||
let no_events = dbg!(get_events(&mut attestation_service, None, wait_slots as u32).await);
|
||||
|
||||
assert_eq!(no_events, []);
|
||||
|
||||
let second_subscribe_event = get_events(&mut attestation_service, None, 2).await;
|
||||
// If the long lived and short lived subnets are different, we should get an unsubscription event.
|
||||
if !attestation_service
|
||||
.subscriptions(attestation_subnets::SubscriptionKind::LongLived)
|
||||
.contains_key(&subnet_id1)
|
||||
{
|
||||
assert_eq!(
|
||||
[SubnetServiceMessage::Subscribe(Subnet::Attestation(
|
||||
subnet_id1
|
||||
))],
|
||||
second_subscribe_event[..]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod sync_committee_service {
|
||||
|
||||
Reference in New Issue
Block a user