mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-10 20:22:02 +00:00
Updates all discovery searches to predicate searches (#975)
* Update global gossip topic handling * Adds ENR predicate searches to lighthouse * Correct log
This commit is contained in:
@@ -101,17 +101,12 @@ impl<TSubstream: AsyncRead + AsyncWrite, TSpec: EthSpec> Behaviour<TSubstream, T
|
||||
|
||||
/// Subscribes to a gossipsub topic.
|
||||
pub fn subscribe(&mut self, topic: GossipTopic) -> bool {
|
||||
if !self
|
||||
.network_globals
|
||||
// update the network globals
|
||||
self.network_globals
|
||||
.gossipsub_subscriptions
|
||||
.read()
|
||||
.contains(&topic)
|
||||
{
|
||||
self.network_globals
|
||||
.gossipsub_subscriptions
|
||||
.write()
|
||||
.push(topic.clone());
|
||||
}
|
||||
.write()
|
||||
.insert(topic.clone());
|
||||
// subscribe to the topic
|
||||
self.gossipsub.subscribe(topic.into())
|
||||
}
|
||||
|
||||
@@ -123,18 +118,12 @@ impl<TSubstream: AsyncRead + AsyncWrite, TSpec: EthSpec> Behaviour<TSubstream, T
|
||||
|
||||
/// Unsubscribe from a gossipsub topic.
|
||||
pub fn unsubscribe(&mut self, topic: GossipTopic) -> bool {
|
||||
let pos = self
|
||||
.network_globals
|
||||
// update the network globals
|
||||
self.network_globals
|
||||
.gossipsub_subscriptions
|
||||
.read()
|
||||
.iter()
|
||||
.position(|s| s == &topic);
|
||||
if let Some(pos) = pos {
|
||||
self.network_globals
|
||||
.gossipsub_subscriptions
|
||||
.write()
|
||||
.swap_remove(pos);
|
||||
}
|
||||
.write()
|
||||
.remove(&topic);
|
||||
// unsubscribe from the topic
|
||||
self.gossipsub.unsubscribe(topic.into())
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ use libp2p::discv5::enr::NodeId;
|
||||
use libp2p::discv5::{Discv5, Discv5Event};
|
||||
use libp2p::multiaddr::Protocol;
|
||||
use libp2p::swarm::{NetworkBehaviour, NetworkBehaviourAction, PollParameters, ProtocolsHandler};
|
||||
use slog::{debug, info, warn};
|
||||
use slog::{crit, debug, info, trace, warn};
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_types::BitVector;
|
||||
use std::collections::HashSet;
|
||||
@@ -263,24 +263,88 @@ impl<TSubstream, TSpec: EthSpec> Discovery<TSubstream, TSpec> {
|
||||
});
|
||||
|
||||
if peers_on_subnet < TARGET_SUBNET_PEERS {
|
||||
let target_peers = TARGET_SUBNET_PEERS - peers_on_subnet;
|
||||
debug!(self.log, "Searching for peers for subnet";
|
||||
"subnet_id" => *subnet_id,
|
||||
"connected_peers_on_subnet" => peers_on_subnet,
|
||||
"target_subnet_peers" => TARGET_SUBNET_PEERS
|
||||
"target_subnet_peers" => TARGET_SUBNET_PEERS,
|
||||
"target_peers" => target_peers
|
||||
);
|
||||
// TODO: Update to predicate search
|
||||
self.find_peers();
|
||||
|
||||
let log_clone = self.log.clone();
|
||||
|
||||
let subnet_predicate = move |enr: &Enr| {
|
||||
if let Some(bitfield_bytes) = enr.get(BITFIELD_ENR_KEY) {
|
||||
let bitfield = match BitVector::<TSpec::SubnetBitfieldLength>::from_ssz_bytes(
|
||||
bitfield_bytes,
|
||||
) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
warn!(log_clone, "Could not decode ENR bitfield for peer"; "peer_id" => format!("{}", enr.peer_id()), "error" => format!("{:?}", e));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
return bitfield.get(*subnet_id as usize).unwrap_or_else(|_| {
|
||||
debug!(log_clone, "Peer found but not on desired subnet"; "peer_id" => format!("{}", enr.peer_id()));
|
||||
false
|
||||
});
|
||||
}
|
||||
false
|
||||
};
|
||||
|
||||
// start the query
|
||||
self.start_query(subnet_predicate, target_peers as usize);
|
||||
}
|
||||
debug!(self.log, "Discovery ignored";
|
||||
"reason" => "Already connected to desired peers",
|
||||
"connected_peers_on_subnet" => peers_on_subnet,
|
||||
"target_subnet_peers" => TARGET_SUBNET_PEERS,
|
||||
);
|
||||
}
|
||||
|
||||
/* Internal Functions */
|
||||
|
||||
/// Search for new peers using the underlying discovery mechanism.
|
||||
/// Run a standard query to search for more peers.
|
||||
///
|
||||
/// This searches for the standard kademlia bucket size (16) peers.
|
||||
fn find_peers(&mut self) {
|
||||
debug!(self.log, "Searching for peers");
|
||||
self.start_query(|_| true, 16);
|
||||
}
|
||||
|
||||
/// Search for a specified number of new peers using the underlying discovery mechanism.
|
||||
///
|
||||
/// This can optionally search for peers for a given predicate. Regardless of the predicate
|
||||
/// given, this will only search for peers on the same enr_fork_id as specified in the local
|
||||
/// ENR.
|
||||
fn start_query<F>(&mut self, enr_predicate: F, num_nodes: usize)
|
||||
where
|
||||
F: Fn(&Enr) -> bool + Send + 'static + Clone,
|
||||
{
|
||||
// pick a random NodeId
|
||||
let random_node = NodeId::random();
|
||||
debug!(self.log, "Searching for peers");
|
||||
self.discovery.find_node(random_node);
|
||||
|
||||
let enr_fork_id = self.enr_fork_id().to_vec();
|
||||
// predicate for finding nodes with a matching fork
|
||||
let eth2_fork_predicate = move |enr: &Enr| enr.get(ETH2_ENR_KEY) == Some(&enr_fork_id);
|
||||
let predicate = move |enr: &Enr| eth2_fork_predicate(enr) && enr_predicate(enr);
|
||||
|
||||
// general predicate
|
||||
self.discovery
|
||||
.find_enr_predicate(random_node, predicate, num_nodes);
|
||||
}
|
||||
|
||||
/// Returns our current `eth2` field as SSZ bytes, associated with the local ENR. We only search for peers
|
||||
/// that have this field.
|
||||
fn enr_fork_id(&self) -> Vec<u8> {
|
||||
self.local_enr()
|
||||
.get(ETH2_ENR_KEY)
|
||||
.map(|bytes| bytes.clone())
|
||||
.unwrap_or_else(|| {
|
||||
crit!(self.log, "Local ENR has no eth2 field");
|
||||
Vec::new()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,9 +467,16 @@ where
|
||||
match self.discovery.poll(params) {
|
||||
Async::Ready(NetworkBehaviourAction::GenerateEvent(event)) => {
|
||||
match event {
|
||||
Discv5Event::Discovered(_enr) => {
|
||||
// not concerned about FINDNODE results, rather the result of an entire
|
||||
// query.
|
||||
Discv5Event::Discovered(enr) => {
|
||||
// peers that get discovered during a query but are not contactable or
|
||||
// don't match a predicate can end up here. For debugging purposes we
|
||||
// log these to see if we are unnecessarily dropping discovered peers
|
||||
if enr.get(ETH2_ENR_KEY) == Some(&self.enr_fork_id().to_vec()) {
|
||||
trace!(self.log, "Peer found in process of query"; "peer_id" => format!("{}", enr.peer_id()), "tcp_socket" => enr.tcp_socket());
|
||||
} else {
|
||||
// this is temporary warning for debugging the DHT
|
||||
warn!(self.log, "Found peer during discovery not on correct fork"; "peer_id" => format!("{}", enr.peer_id()), "tcp_socket" => enr.tcp_socket());
|
||||
}
|
||||
}
|
||||
Discv5Event::SocketUpdated(socket) => {
|
||||
info!(self.log, "Address updated"; "ip" => format!("{}",socket.ip()), "udp_port" => format!("{}", socket.port()));
|
||||
|
||||
@@ -153,7 +153,7 @@ impl<TSpec: EthSpec> Service<TSpec> {
|
||||
network_globals
|
||||
.gossipsub_subscriptions
|
||||
.write()
|
||||
.push(topic.clone());
|
||||
.insert(topic.clone());
|
||||
} else {
|
||||
warn!(log, "Could not subscribe to topic"; "topic" => format!("{}",topic_string));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! A collection of variables that are accessible outside of the network thread itself.
|
||||
use crate::{Enr, GossipTopic, Multiaddr, PeerId, PeerInfo};
|
||||
use parking_lot::RwLock;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::atomic::{AtomicU16, Ordering};
|
||||
use types::EthSpec;
|
||||
|
||||
@@ -19,7 +19,7 @@ pub struct NetworkGlobals<TSpec: EthSpec> {
|
||||
/// The collection of currently connected peers.
|
||||
pub connected_peer_set: RwLock<HashMap<PeerId, PeerInfo<TSpec>>>,
|
||||
/// The current gossipsub topic subscriptions.
|
||||
pub gossipsub_subscriptions: RwLock<Vec<GossipTopic>>,
|
||||
pub gossipsub_subscriptions: RwLock<HashSet<GossipTopic>>,
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
|
||||
@@ -31,7 +31,7 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
|
||||
listen_port_tcp: AtomicU16::new(tcp_port),
|
||||
listen_port_udp: AtomicU16::new(udp_port),
|
||||
connected_peer_set: RwLock::new(HashMap::new()),
|
||||
gossipsub_subscriptions: RwLock::new(Vec::new()),
|
||||
gossipsub_subscriptions: RwLock::new(HashSet::new()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ pub const ATTESTER_SLASHING_TOPIC: &str = "attester_slashing";
|
||||
|
||||
/// A gossipsub topic which encapsulates the type of messages that should be sent and received over
|
||||
/// the pubsub protocol and the way the messages should be encoded.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
pub struct GossipTopic {
|
||||
/// The encoding of the topic.
|
||||
encoding: GossipEncoding,
|
||||
@@ -28,7 +28,7 @@ pub struct GossipTopic {
|
||||
}
|
||||
|
||||
/// Enum that brings these topics into the rust type system.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
pub enum GossipKind {
|
||||
/// Topic for publishing beacon blocks.
|
||||
BeaconBlock,
|
||||
@@ -45,7 +45,7 @@ pub enum GossipKind {
|
||||
}
|
||||
|
||||
/// The known encoding types for gossipsub messages.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
pub enum GossipEncoding {
|
||||
/// Messages are encoded with SSZ.
|
||||
SSZ,
|
||||
|
||||
Reference in New Issue
Block a user