diff --git a/substrate/client/cli/src/params/network_params.rs b/substrate/client/cli/src/params/network_params.rs index 0b53616b9ed13f9cf049c50896fcce5a67cf7f31..4a926fdce8bbf6bd65e54288137c6cc94861d00d 100644 --- a/substrate/client/cli/src/params/network_params.rs +++ b/substrate/client/cli/src/params/network_params.rs @@ -36,10 +36,14 @@ pub struct NetworkParams { #[structopt(long = "reserved-nodes", value_name = "ADDR")] pub reserved_nodes: Vec<MultiaddrWithPeerId>, - /// Whether to only allow connections to/from reserved nodes. + /// Whether to only synchronize the chain with reserved nodes. /// - /// If you are a validator your node might still connect to other validator - /// nodes regardless of whether they are defined as reserved nodes. + /// Also disables automatic peer discovery. + /// + /// TCP connections might still be established with non-reserved nodes. + /// In particular, if you are a validator your node might still connect to other + /// validator nodes and collator nodes regardless of whether they are defined as + /// reserved nodes. #[structopt(long = "reserved-only")] pub reserved_only: bool, @@ -173,6 +177,7 @@ impl NetworkParams { wasm_external_transport: None, }, max_parallel_downloads: self.max_parallel_downloads, + enable_dht_random_walk: !self.reserved_only, allow_non_globals_in_dht, kademlia_disjoint_query_paths: self.kademlia_disjoint_query_paths, yamux_window_size: None, diff --git a/substrate/client/network/src/config.rs b/substrate/client/network/src/config.rs index 3eb53dabf045919fb19d1207a73a1a1fd77d824b..29a0128b87ea7161f729d2d2940df53841a513b5 100644 --- a/substrate/client/network/src/config.rs +++ b/substrate/client/network/src/config.rs @@ -408,10 +408,17 @@ pub struct NetworkConfiguration { pub transport: TransportConfig, /// Maximum number of peers to ask the same blocks in parallel. pub max_parallel_downloads: u32, + + /// True if Kademlia random discovery should be enabled. + /// + /// If true, the node will automatically randomly walk the DHT in order to find new peers. + pub enable_dht_random_walk: bool, + /// Should we insert non-global addresses into the DHT? pub allow_non_globals_in_dht: bool, - /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in the - /// presence of potentially adversarial nodes. + + /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in + /// the presence of potentially adversarial nodes. pub kademlia_disjoint_query_paths: bool, /// Size of Yamux receive window of all substreams. `None` for the default (256kiB). @@ -461,6 +468,7 @@ impl NetworkConfiguration { wasm_external_transport: None, }, max_parallel_downloads: 5, + enable_dht_random_walk: true, allow_non_globals_in_dht: false, kademlia_disjoint_query_paths: false, yamux_window_size: None, diff --git a/substrate/client/network/src/discovery.rs b/substrate/client/network/src/discovery.rs index d9d28569ad30b0aa949c00db3f9163611cd95e87..87b533ef77dc14c36662949f54919274149d7f12 100644 --- a/substrate/client/network/src/discovery.rs +++ b/substrate/client/network/src/discovery.rs @@ -80,6 +80,7 @@ const MAX_KNOWN_EXTERNAL_ADDRESSES: usize = 32; pub struct DiscoveryConfig { local_peer_id: PeerId, user_defined: Vec<(PeerId, Multiaddr)>, + dht_random_walk: bool, allow_private_ipv4: bool, allow_non_globals_in_dht: bool, discovery_only_if_under_num: u64, @@ -94,6 +95,7 @@ impl DiscoveryConfig { DiscoveryConfig { local_peer_id: local_public_key.into_peer_id(), user_defined: Vec::new(), + dht_random_walk: true, allow_private_ipv4: true, allow_non_globals_in_dht: false, discovery_only_if_under_num: std::u64::MAX, @@ -118,6 +120,13 @@ impl DiscoveryConfig { self } + /// Whether the discovery behaviour should periodically perform a random + /// walk on the DHT to discover peers. + pub fn with_dht_random_walk(&mut self, value: bool) -> &mut Self { + self.dht_random_walk = value; + self + } + /// Should private IPv4 addresses be reported? pub fn allow_private_ipv4(&mut self, value: bool) -> &mut Self { self.allow_private_ipv4 = value; @@ -163,6 +172,7 @@ impl DiscoveryConfig { let DiscoveryConfig { local_peer_id, user_defined, + dht_random_walk, allow_private_ipv4, allow_non_globals_in_dht, discovery_only_if_under_num, @@ -197,7 +207,11 @@ impl DiscoveryConfig { DiscoveryBehaviour { user_defined, kademlias, - next_kad_random_query: Delay::new(Duration::new(0, 0)), + next_kad_random_query: if dht_random_walk { + Some(Delay::new(Duration::new(0, 0))) + } else { + None + }, duration_to_next_kad: Duration::from_secs(1), pending_events: VecDeque::new(), local_peer_id, @@ -229,8 +243,9 @@ pub struct DiscoveryBehaviour { /// Discovers nodes on the local network. #[cfg(not(target_os = "unknown"))] mdns: MdnsWrapper, - /// Stream that fires when we need to perform the next random Kademlia query. - next_kad_random_query: Delay, + /// Stream that fires when we need to perform the next random Kademlia query. `None` if + /// random walking is disabled. + next_kad_random_query: Option<Delay>, /// After `next_kad_random_query` triggers, the next one triggers after this duration. duration_to_next_kad: Duration, /// Events to return in priority when polled. @@ -434,6 +449,8 @@ pub enum DiscoveryOut { ValuePutFailed(record::Key, Duration), /// Started a random Kademlia query for each DHT identified by the given `ProtocolId`s. + /// + /// Only happens if [`DiscoveryConfig::with_dht_random_walk`] has been configured to `true`. RandomKademliaStarted(Vec<ProtocolId>), } @@ -602,34 +619,36 @@ impl NetworkBehaviour for DiscoveryBehaviour { } // 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 actually_started = 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); - for k in self.kademlias.values_mut() { - k.get_closest_peers(random_peer_id.clone()); + if let Some(next_kad_random_query) = self.next_kad_random_query.as_mut() { + while let Poll::Ready(_) = next_kad_random_query.poll_unpin(cx) { + let actually_started = 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); + for k in self.kademlias.values_mut() { + k.get_closest_peers(random_peer_id.clone()); + } + true + } else { + debug!( + target: "sub-libp2p", + "Kademlia paused due to high number of connections ({})", + self.num_connections + ); + false + }; + + // Schedule the next random query with exponentially increasing delay, + // capped at 60 seconds. + *next_kad_random_query = Delay::new(self.duration_to_next_kad); + self.duration_to_next_kad = cmp::min(self.duration_to_next_kad * 2, + Duration::from_secs(60)); + + if actually_started { + let ev = DiscoveryOut::RandomKademliaStarted(self.kademlias.keys().cloned().collect()); + return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)); } - true - } else { - debug!( - target: "sub-libp2p", - "Kademlia paused due to high number of connections ({})", - self.num_connections - ); - false - }; - - // Schedule the next random query with exponentially increasing delay, - // capped at 60 seconds. - self.next_kad_random_query = Delay::new(self.duration_to_next_kad); - self.duration_to_next_kad = cmp::min(self.duration_to_next_kad * 2, - Duration::from_secs(60)); - - if actually_started { - let ev = DiscoveryOut::RandomKademliaStarted(self.kademlias.keys().cloned().collect()); - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)); } } diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index 58c623a8f5f1f6fa84f74789cbb9140d4c13655c..cb1cc4f3b77a65146c582c6865936617a815f643 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -268,6 +268,7 @@ impl<B: BlockT + 'static, H: ExHashT> NetworkWorker<B, H> { config.with_user_defined(known_addresses); config.discovery_limit(u64::from(params.network_config.default_peers_set.out_peers) + 15); config.add_protocol(params.protocol_id.clone()); + config.with_dht_random_walk(params.network_config.enable_dht_random_walk); config.allow_non_globals_in_dht(params.network_config.allow_non_globals_in_dht); config.use_kademlia_disjoint_query_paths(params.network_config.kademlia_disjoint_query_paths);