From b0a749548dad4ae9afc65760b7fdce877919cf06 Mon Sep 17 00:00:00 2001
From: Pierre Krieger <pierre.krieger1708@gmail.com>
Date: Tue, 11 Feb 2020 12:22:25 +0100
Subject: [PATCH] Pause Kademlia if too many connections (#4828)

* Pause Kademlia if too many connections

* Fix test

* Update client/network/src/discovery.rs

Co-Authored-By: Toralf Wittner <tw@dtex.org>

* Change the limit

Co-authored-by: Toralf Wittner <tw@dtex.org>
---
 substrate/client/network/src/behaviour.rs |  4 +++-
 substrate/client/network/src/discovery.rs | 26 ++++++++++++++++++-----
 substrate/client/network/src/service.rs   |  1 +
 3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/substrate/client/network/src/behaviour.rs b/substrate/client/network/src/behaviour.rs
index 8b903cec351..a1f54654b3e 100644
--- a/substrate/client/network/src/behaviour.rs
+++ b/substrate/client/network/src/behaviour.rs
@@ -65,6 +65,7 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Behaviour<B, S, H> {
 		known_addresses: Vec<(PeerId, Multiaddr)>,
 		enable_mdns: bool,
 		allow_private_ipv4: bool,
+		discovery_only_if_under_num: u64,
 	) -> Self {
 		Behaviour {
 			substrate,
@@ -73,7 +74,8 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Behaviour<B, S, H> {
 				local_public_key,
 				known_addresses,
 				enable_mdns,
-				allow_private_ipv4
+				allow_private_ipv4,
+				discovery_only_if_under_num,
 			).await,
 			events: Vec::new(),
 		}
diff --git a/substrate/client/network/src/discovery.rs b/substrate/client/network/src/discovery.rs
index de49913b265..2da69e18944 100644
--- a/substrate/client/network/src/discovery.rs
+++ b/substrate/client/network/src/discovery.rs
@@ -87,6 +87,8 @@ pub struct DiscoveryBehaviour<TSubstream> {
 	/// If false, `addresses_of_peer` won't return any private IPv4 address, except for the ones
 	/// stored in `user_defined`.
 	allow_private_ipv4: bool,
+	/// Number of active connections over which we interrupt the discovery process.
+	discovery_only_if_under_num: u64,
 }
 
 impl<TSubstream> DiscoveryBehaviour<TSubstream> {
@@ -98,6 +100,7 @@ impl<TSubstream> DiscoveryBehaviour<TSubstream> {
 		user_defined: Vec<(PeerId, Multiaddr)>,
 		enable_mdns: bool,
 		allow_private_ipv4: bool,
+		discovery_only_if_under_num: u64,
 	) -> Self {
 		if enable_mdns {
 			#[cfg(target_os = "unknown")]
@@ -120,6 +123,7 @@ impl<TSubstream> DiscoveryBehaviour<TSubstream> {
 			local_peer_id: local_public_key.into_peer_id(),
 			num_connections: 0,
 			allow_private_ipv4,
+			discovery_only_if_under_num,
 			#[cfg(not(target_os = "unknown"))]
 			mdns: if enable_mdns {
 				match Mdns::new() {
@@ -331,11 +335,19 @@ where
 
 		// Poll the stream that fires when we need to start a random Kademlia query.
 		while let Poll::Ready(_) = self.next_kad_random_query.poll_unpin(cx) {
-			let random_peer_id = PeerId::random();
-			debug!(target: "sub-libp2p", "Libp2p <= Starting random Kademlia request for \
-				{:?}", random_peer_id);
+			if self.num_connections < self.discovery_only_if_under_num {
+				let random_peer_id = PeerId::random();
+				debug!(target: "sub-libp2p", "Libp2p <= Starting random Kademlia request for \
+					{:?}", random_peer_id);
 
-			self.kademlia.get_closest_peers(random_peer_id);
+				self.kademlia.get_closest_peers(random_peer_id);
+			} else {
+				debug!(
+					target: "sub-libp2p",
+					"Kademlia paused due to high number of connections ({})",
+					self.num_connections
+				);
+			}
 
 			// Schedule the next random query with exponentially increasing delay,
 			// capped at 60 seconds.
@@ -435,6 +447,10 @@ where
 				NetworkBehaviourAction::GenerateEvent(event) => {
 					match event {
 						MdnsEvent::Discovered(list) => {
+							if self.num_connections >= self.discovery_only_if_under_num {
+								continue;
+							}
+
 							self.discoveries.extend(list.into_iter().map(|(peer_id, _)| peer_id));
 							if let Some(peer_id) = self.discoveries.pop_front() {
 								let ev = DiscoveryOut::Discovered(peer_id);
@@ -502,7 +518,7 @@ mod tests {
 				let user_defined = user_defined.clone();
 				let keypair_public = keypair.public();
 				async move {
-					DiscoveryBehaviour::new(keypair_public, user_defined, false, true).await
+					DiscoveryBehaviour::new(keypair_public, user_defined, false, true, 50).await
 				}
 			});
 			let mut swarm = Swarm::new(transport, behaviour, keypair.public().into_peer_id());
diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs
index e3eaf6c31d5..b4281112f61 100644
--- a/substrate/client/network/src/service.rs
+++ b/substrate/client/network/src/service.rs
@@ -232,6 +232,7 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>, H: ExHashT> NetworkWorker
 					TransportConfig::MemoryOnly => false,
 					TransportConfig::Normal { allow_private_ipv4, .. } => allow_private_ipv4,
 				},
+				u64::from(params.network_config.out_peers) + 15,
 			));
 			let (transport, bandwidth) = {
 				let (config_mem, config_wasm) = match params.network_config.transport {
-- 
GitLab