Add a back-pressure-friendly alternative to NetworkService::write_notifications 🎉 (#6692)

* Add NetworkService::send_notifications

* Doc

* Doc

* API adjustment

* Address concerns

* Make it compile

* Start implementation

* Progress in the implementation

* Change implementation strategy again

* More work before weekend

* Finish changes

* Minor doc fix

* Revert some minor changes

* Apply suggestions from code review

* GroupError -> NotifsHandlerError

* Apply suggestions from code review

Co-authored-by: Roman Borschel <romanb@users.noreply.github.com>

* state_transition_waker -> close_waker

* Apply suggestions from code review

Co-authored-by: Roman Borschel <romanb@users.noreply.github.com>

* Finish renames in service.rs

* More renames

* More review suggestsions applied

* More review addressing

* Final change

* 512 -> 2048

Co-authored-by: Roman Borschel <romanb@users.noreply.github.com>
This commit is contained in:
Pierre Krieger
2020-07-29 13:23:19 +02:00
committed by GitHub
parent e674d64a72
commit 1ab7719314
12 changed files with 955 additions and 431 deletions
+42 -38
View File
@@ -47,8 +47,8 @@ use sp_runtime::traits::{
};
use sp_arithmetic::traits::SaturatedConversion;
use message::{BlockAnnounce, Message};
use message::generic::{Message as GenericMessage, ConsensusMessage, Roles};
use prometheus_endpoint::{Registry, Gauge, Counter, GaugeVec, HistogramVec, PrometheusError, Opts, register, U64};
use message::generic::{Message as GenericMessage, Roles};
use prometheus_endpoint::{Registry, Gauge, Counter, GaugeVec, PrometheusError, Opts, register, U64};
use sync::{ChainSync, SyncState};
use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque, hash_map::Entry};
@@ -67,7 +67,7 @@ pub mod message;
pub mod event;
pub mod sync;
pub use generic_proto::LegacyConnectionKillError;
pub use generic_proto::{NotificationsSink, Ready, NotifsHandlerError, LegacyConnectionKillError};
const REQUEST_TIMEOUT_SEC: u64 = 40;
/// Interval at which we perform time based maintenance
@@ -388,7 +388,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
block_announce_validator: Box<dyn BlockAnnounceValidator<B> + Send>,
metrics_registry: Option<&Registry>,
boot_node_ids: Arc<HashSet<PeerId>>,
queue_size_report: Option<HistogramVec>,
) -> error::Result<(Protocol<B, H>, sc_peerset::PeersetHandle)> {
let info = chain.info();
let sync = ChainSync::new(
@@ -417,7 +416,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
versions,
build_status_message(&config, &chain),
peerset,
queue_size_report,
);
let mut legacy_equiv_by_name = HashMap::new();
@@ -948,7 +946,12 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
}
/// Called on receipt of a status message via the legacy protocol on the first connection between two peers.
pub fn on_peer_connected(&mut self, who: PeerId, status: message::Status<B>) -> CustomMessageOutcome<B> {
pub fn on_peer_connected(
&mut self,
who: PeerId,
status: message::Status<B>,
notifications_sink: NotificationsSink,
) -> CustomMessageOutcome<B> {
trace!(target: "sync", "New peer {} {:?}", who, status);
let _protocol_version = {
if self.context_data.peers.contains_key(&who) {
@@ -1060,32 +1063,7 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
remote: who,
protocols: self.protocol_name_by_engine.keys().cloned().collect(),
roles: info.roles,
}
}
/// Send a notification to the given peer we're connected to.
///
/// Doesn't do anything if we don't have a notifications substream for that protocol with that
/// peer.
pub fn write_notification(
&mut self,
target: PeerId,
engine_id: ConsensusEngineId,
message: impl Into<Vec<u8>>,
) {
if let Some(protocol_name) = self.protocol_name_by_engine.get(&engine_id) {
let message = message.into();
let fallback = GenericMessage::<(), (), (), ()>::Consensus(ConsensusMessage {
engine_id,
data: message.clone(),
}).encode();
self.behaviour.write_notification(&target, protocol_name.clone(), message, fallback);
} else {
error!(
target: "sub-libp2p",
"Sending a notification with a protocol that wasn't registered: {:?}",
engine_id
);
notifications_sink,
}
}
@@ -1099,7 +1077,7 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
engine_id: ConsensusEngineId,
protocol_name: impl Into<Cow<'static, [u8]>>,
handshake_message: Vec<u8>,
) -> impl ExactSizeIterator<Item = (&'a PeerId, Roles)> + 'a {
) -> impl Iterator<Item = (&'a PeerId, Roles, &'a NotificationsSink)> + 'a {
let protocol_name = protocol_name.into();
if self.protocol_name_by_engine.insert(engine_id, protocol_name.clone()).is_some() {
error!(target: "sub-libp2p", "Notifications protocol already registered: {:?}", protocol_name);
@@ -1108,8 +1086,15 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
self.legacy_equiv_by_name.insert(protocol_name, Fallback::Consensus(engine_id));
}
self.context_data.peers.iter()
.map(|(peer_id, peer)| (peer_id, peer.info.roles))
let behaviour = &self.behaviour;
self.context_data.peers.iter().filter_map(move |(peer_id, peer)| {
if let Some(notifications_sink) = behaviour.notifications_sink(peer_id) {
Some((peer_id, peer.info.roles, notifications_sink))
} else {
log::error!("State mismatch: no notifications sink for opened peer {:?}", peer_id);
None
}
})
}
/// Called when peer sends us new transactions
@@ -1863,7 +1848,18 @@ pub enum CustomMessageOutcome<B: BlockT> {
JustificationImport(Origin, B::Hash, NumberFor<B>, Justification),
FinalityProofImport(Origin, B::Hash, NumberFor<B>, Vec<u8>),
/// Notification protocols have been opened with a remote.
NotificationStreamOpened { remote: PeerId, protocols: Vec<ConsensusEngineId>, roles: Roles },
NotificationStreamOpened {
remote: PeerId,
protocols: Vec<ConsensusEngineId>,
roles: Roles,
notifications_sink: NotificationsSink
},
/// The [`NotificationsSink`] of some notification protocols need an update.
NotificationStreamReplaced {
remote: PeerId,
protocols: Vec<ConsensusEngineId>,
notifications_sink: NotificationsSink,
},
/// Notification protocols have been closed with a remote.
NotificationStreamClosed { remote: PeerId, protocols: Vec<ConsensusEngineId> },
/// Messages have been received on one or more notifications protocols.
@@ -2028,9 +2024,10 @@ impl<B: BlockT, H: ExHashT> NetworkBehaviour for Protocol<B, H> {
};
let outcome = match event {
GenericProtoOut::CustomProtocolOpen { peer_id, received_handshake, .. } => {
GenericProtoOut::CustomProtocolOpen { peer_id, received_handshake, notifications_sink, .. } => {
match <Message<B> as Decode>::decode(&mut &received_handshake[..]) {
Ok(GenericMessage::Status(handshake)) => self.on_peer_connected(peer_id, handshake),
Ok(GenericMessage::Status(handshake)) =>
self.on_peer_connected(peer_id, handshake, notifications_sink),
Ok(msg) => {
debug!(
target: "sync",
@@ -2054,6 +2051,13 @@ impl<B: BlockT, H: ExHashT> NetworkBehaviour for Protocol<B, H> {
}
}
}
GenericProtoOut::CustomProtocolReplaced { peer_id, notifications_sink, .. } => {
CustomMessageOutcome::NotificationStreamReplaced {
remote: peer_id,
protocols: self.protocol_name_by_engine.keys().cloned().collect(),
notifications_sink,
}
},
GenericProtoOut::CustomProtocolClosed { peer_id, .. } => {
self.on_peer_disconnected(peer_id)
},