Embed the topology in the NetworkBehaviour (#889)

* Embed the topology in the NetworkBehaviour

* Put topologies inside of Floodsub and Kad

* Fix core tests

* Fix chat example

* More work

* Some cleanup

* Restore external addresses system
This commit is contained in:
Pierre Krieger
2019-01-26 23:57:53 +01:00
committed by GitHub
parent 30c082dfe5
commit df923526ca
21 changed files with 818 additions and 749 deletions

View File

@ -21,9 +21,10 @@
use crate::protocol::{FloodsubConfig, FloodsubMessage, FloodsubRpc, FloodsubSubscription, FloodsubSubscriptionAction};
use crate::topic::{Topic, TopicHash};
use cuckoofilter::CuckooFilter;
use fnv::FnvHashSet;
use futures::prelude::*;
use libp2p_core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction, PollParameters};
use libp2p_core::{protocols_handler::ProtocolsHandler, protocols_handler::OneShotHandler, PeerId};
use libp2p_core::{protocols_handler::ProtocolsHandler, protocols_handler::OneShotHandler, Multiaddr, PeerId};
use rand;
use smallvec::SmallVec;
use std::{collections::VecDeque, iter, marker::PhantomData};
@ -39,6 +40,9 @@ pub struct Floodsub<TSubstream> {
/// Peer id of the local node. Used for the source of the messages that we publish.
local_peer_id: PeerId,
/// List of peers to send messages to.
target_peers: FnvHashSet<PeerId>,
/// List of peers the network is connected to, and the topics that they're subscribed to.
// TODO: filter out peers that don't support floodsub, so that we avoid hammering them with
// opened substreams
@ -62,12 +66,43 @@ impl<TSubstream> Floodsub<TSubstream> {
Floodsub {
events: VecDeque::new(),
local_peer_id,
target_peers: FnvHashSet::default(),
connected_peers: HashMap::new(),
subscribed_topics: SmallVec::new(),
received: CuckooFilter::new(),
marker: PhantomData,
}
}
/// Add a node to the list of nodes to propagate messages to.
#[inline]
pub fn add_node_to_partial_view(&mut self, peer_id: PeerId) {
// Send our topics to this node if we're already connected to it.
if self.connected_peers.contains_key(&peer_id) {
for topic in self.subscribed_topics.iter() {
self.events.push_back(NetworkBehaviourAction::SendEvent {
peer_id: peer_id.clone(),
event: FloodsubRpc {
messages: Vec::new(),
subscriptions: vec![FloodsubSubscription {
topic: topic.hash().clone(),
action: FloodsubSubscriptionAction::Subscribe,
}],
},
});
}
}
if self.target_peers.insert(peer_id.clone()) {
self.events.push_back(NetworkBehaviourAction::DialPeer { peer_id });
}
}
/// Remove a node from the list of nodes to propagate messages to.
#[inline]
pub fn remove_node_from_partial_view(&mut self, peer_id: &PeerId) {
self.target_peers.remove(&peer_id);
}
}
impl<TSubstream> Floodsub<TSubstream> {
@ -171,7 +206,7 @@ impl<TSubstream> Floodsub<TSubstream> {
}
}
impl<TSubstream, TTopology> NetworkBehaviour<TTopology> for Floodsub<TSubstream>
impl<TSubstream> NetworkBehaviour for Floodsub<TSubstream>
where
TSubstream: AsyncRead + AsyncWrite,
{
@ -182,19 +217,25 @@ where
Default::default()
}
fn addresses_of_peer(&self, _: &PeerId) -> Vec<Multiaddr> {
Vec::new()
}
fn inject_connected(&mut self, id: PeerId, _: ConnectedPoint) {
// We need to send our subscriptions to the newly-connected node.
for topic in self.subscribed_topics.iter() {
self.events.push_back(NetworkBehaviourAction::SendEvent {
peer_id: id.clone(),
event: FloodsubRpc {
messages: Vec::new(),
subscriptions: vec![FloodsubSubscription {
topic: topic.hash().clone(),
action: FloodsubSubscriptionAction::Subscribe,
}],
},
});
if self.target_peers.contains(&id) {
for topic in self.subscribed_topics.iter() {
self.events.push_back(NetworkBehaviourAction::SendEvent {
peer_id: id.clone(),
event: FloodsubRpc {
messages: Vec::new(),
subscriptions: vec![FloodsubSubscription {
topic: topic.hash().clone(),
action: FloodsubSubscriptionAction::Subscribe,
}],
},
});
}
}
self.connected_peers.insert(id.clone(), SmallVec::new());
@ -203,6 +244,12 @@ where
fn inject_disconnected(&mut self, id: &PeerId, _: ConnectedPoint) {
let was_in = self.connected_peers.remove(id);
debug_assert!(was_in.is_some());
// We can be disconnected by the remote in case of inactivity for example, so we always
// try to reconnect.
if self.target_peers.contains(id) {
self.events.push_back(NetworkBehaviourAction::DialPeer { peer_id: id.clone() });
}
}
fn inject_node_event(
@ -290,7 +337,7 @@ where
fn poll(
&mut self,
_: &mut PollParameters<TTopology>,
_: &mut PollParameters,
) -> Async<
NetworkBehaviourAction<
<Self::ProtocolsHandler as ProtocolsHandler>::InEvent,