diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml
index 39598e2a88755..de4f484535e94 100644
--- a/client/network/Cargo.toml
+++ b/client/network/Cargo.toml
@@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
prost-build = "0.6.1"
[dependencies]
+async-std = { version = "1.6.2", features = ["unstable"] }
bitflags = "1.2.0"
bs58 = "0.3.1"
bytes = "0.5.0"
@@ -66,7 +67,6 @@ default-features = false
features = ["identify", "kad", "mdns", "mplex", "noise", "ping", "tcp-async-std", "websocket", "yamux"]
[dev-dependencies]
-async-std = "1.6.2"
assert_matches = "1.3"
env_logger = "0.7.0"
libp2p = { version = "0.23.0", default-features = false, features = ["secio"] }
diff --git a/client/network/src/gossip.rs b/client/network/src/gossip.rs
new file mode 100644
index 0000000000000..0650e7a2f818b
--- /dev/null
+++ b/client/network/src/gossip.rs
@@ -0,0 +1,245 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2017-2020 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+//! Helper for sending rate-limited gossip messages.
+//!
+//! # Context
+//!
+//! The [`NetworkService`] struct provides a way to send notifications to a certain peer through
+//! the [`NetworkService::notification_sender`] method. This method is quite low level and isn't
+//! expected to be used directly.
+//!
+//! The [`QueuedSender`] struct provided by this module is built on top of
+//! [`NetworkService::notification_sender`] and provides a cleaner way to send notifications.
+//!
+//! # Behaviour
+//!
+//! An instance of [`QueuedSender`] is specific to a certain combination of `PeerId` and
+//! protocol name. It maintains a buffer of messages waiting to be sent out. The user of this API
+//! is able to manipulate that queue, adding or removing obsolete messages.
+//!
+//! Creating a [`QueuedSender`] also returns a opaque `Future` whose responsibility it to
+//! drain that queue and actually send the messages. If the substream with the given combination
+//! of peer and protocol is closed, the queue is silently discarded. It is the role of the user
+//! to track which peers we are connected to.
+//!
+//! In normal situations, messages sent through a [`QueuedSender`] will arrive in the same
+//! order as they have been sent.
+//! It is possible, in the situation of disconnects and reconnects, that messages arrive in a
+//! different order. See also https://github.com/paritytech/substrate/issues/6756.
+//! However, if multiple instances of [`QueuedSender`] exist for the same peer and protocol, or
+//! if some other code uses the [`NetworkService`] to send notifications to this combination or
+//! peer and protocol, then the notifications will be interleaved in an unpredictable way.
+//!
+
+use crate::{ExHashT, NetworkService};
+
+use async_std::sync::{Condvar, Mutex, MutexGuard};
+use futures::prelude::*;
+use libp2p::PeerId;
+use sp_runtime::{traits::Block as BlockT, ConsensusEngineId};
+use std::{
+ collections::VecDeque,
+ fmt,
+ sync::{atomic, Arc},
+ time::Duration,
+};
+
+#[cfg(test)]
+mod tests;
+
+/// Notifications sender for a specific combination of network service, peer, and protocol.
+pub struct QueuedSender {
+ /// Shared between the front and the back task.
+ shared: Arc>,
+}
+
+impl QueuedSender {
+ /// Returns a new [`QueuedSender`] containing a queue of message for this specific
+ /// combination of peer and protocol.
+ ///
+ /// In addition to the [`QueuedSender`], also returns a `Future` whose role is to drive
+ /// the messages sending forward.
+ pub fn new(
+ service: Arc>,
+ peer_id: PeerId,
+ protocol: ConsensusEngineId,
+ queue_size_limit: usize,
+ messages_encode: F
+ ) -> (Self, impl Future