Skip to content

Commit bfbb46f

Browse files
Upgrade libp2p from 0.52.4 to 0.54.1 (#6248)
# Description Fixes #5996 https://github.com/libp2p/rust-libp2p/releases/tag/libp2p-v0.53.0 https://github.com/libp2p/rust-libp2p/blob/master/CHANGELOG.md ## Integration Nothing special is needed, just note that `yamux_window_size` is no longer applicable to libp2p (litep2p seems to still have it though). ## Review Notes There are a few simplifications and improvements done in libp2p 0.53 regarding swarm interface, I'll list a few key/applicable here. libp2p/rust-libp2p#4788 removed `write_length_prefixed` function, so I inlined its code instead. libp2p/rust-libp2p#4120 introduced new `libp2p::SwarmBuilder` instead of now deprecated `libp2p::swarm::SwarmBuilder`, the transition is straightforward and quite ergonomic (can be seen in tests). libp2p/rust-libp2p#4581 is the most annoying change I have seen that basically makes many enums `#[non_exhaustive]`. I mapped some, but those that couldn't be mapped I dealt with by printing log messages once they are hit (the best solution I could come up with, at least with stable Rust). libp2p/rust-libp2p#4306 makes connection close as soon as there are no handler using it, so I had to replace `KeepAlive::Until` with an explicit future that flips internal boolean after timeout, achieving the old behavior, though it should ideally be removed completely at some point. `yamux_window_size` is no longer used by libp2p thanks to libp2p/rust-libp2p#4970 and generally Yamux should have a higher performance now. I have resolved and cleaned up all deprecations related to libp2p except `BandwidthSinks`. Libp2p deprecated it (though it is still present in 0.54.1, which is why I didn't handle it just yet). Ideally Substrate would finally [switch to the official Prometheus client](paritytech/substrate#12699), in which case we'd get metrics for free. Otherwise a bit of code will need to be copy-pasted to maintain current behavior with `BandwidthSinks` gone, which I left a TODO about. The biggest change in 0.54.0 is libp2p/rust-libp2p#4568 that changed transport APIs and enabled unconditional potential port reuse, which can lead to very confusing errors if running two Substrate nodes on the same machine without changing listening port explicitly. Overall nothing scary here, but testing is always appreciated. # Checklist * [x] My PR includes a detailed description as outlined in the "Description" and its two subsections above. * [x] My PR follows the [labeling requirements]( https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CONTRIBUTING.md#Process ) of this project (at minimum one label for `T` required) * External contributors: ask maintainers to put the right label on your PR. --- Polkadot Address: 1vSxzbyz2cJREAuVWjhXUT1ds8vBzoxn2w4asNpusQKwjJd --------- Co-authored-by: Dmitry Markin <[email protected]>
1 parent c10e25a commit bfbb46f

File tree

20 files changed

+846
-1068
lines changed

20 files changed

+846
-1068
lines changed

Cargo.lock

Lines changed: 284 additions & 398 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ kvdb-shared-tests = { version = "0.11.0" }
841841
landlock = { version = "0.3.0" }
842842
libc = { version = "0.2.155" }
843843
libfuzzer-sys = { version = "0.4" }
844-
libp2p = { version = "0.52.4" }
844+
libp2p = { version = "0.54.1" }
845845
libp2p-identity = { version = "0.2.9" }
846846
libsecp256k1 = { version = "0.7.0", default-features = false }
847847
linked-hash-map = { version = "0.5.4" }

prdoc/pr_6248.prdoc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
title: Upgrade libp2p to 0.54.1
2+
3+
doc:
4+
- audience: [Node Dev, Node Operator]
5+
description: |
6+
Upgrade libp2p from 0.52.4 to 0.54.1
7+
8+
crates:
9+
- name: sc-network
10+
bump: major
11+
- name: sc-network-types
12+
bump: minor
13+
- name: sc-network-sync
14+
bump: patch
15+
- name: sc-telemetry
16+
bump: minor

substrate/client/network/src/behaviour.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub struct Behaviour<B: BlockT> {
6868
}
6969

7070
/// Event generated by `Behaviour`.
71+
#[derive(Debug)]
7172
pub enum BehaviourOut {
7273
/// Started a random iterative Kademlia discovery query.
7374
RandomKademliaStarted,

substrate/client/network/src/discovery.rs

Lines changed: 82 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ use futures::prelude::*;
5353
use futures_timer::Delay;
5454
use ip_network::IpNetwork;
5555
use libp2p::{
56-
core::{Endpoint, Multiaddr},
56+
core::{transport::PortUse, Endpoint, Multiaddr},
5757
kad::{
5858
self,
59-
record::store::{MemoryStore, RecordStore},
59+
store::{MemoryStore, RecordStore},
6060
Behaviour as Kademlia, BucketInserts, Config as KademliaConfig, Event as KademliaEvent,
61-
GetClosestPeersError, GetRecordOk, PeerRecord, QueryId, QueryResult, Quorum, Record,
61+
Event, GetClosestPeersError, GetRecordOk, PeerRecord, QueryId, QueryResult, Quorum, Record,
6262
RecordKey,
6363
},
6464
mdns::{self, tokio::Behaviour as TokioMdns},
@@ -68,8 +68,8 @@ use libp2p::{
6868
toggle::{Toggle, ToggleConnectionHandler},
6969
DialFailure, ExternalAddrConfirmed, FromSwarm,
7070
},
71-
ConnectionDenied, ConnectionId, DialError, NetworkBehaviour, PollParameters,
72-
StreamProtocol, THandler, THandlerInEvent, THandlerOutEvent, ToSwarm,
71+
ConnectionDenied, ConnectionId, DialError, NetworkBehaviour, StreamProtocol, THandler,
72+
THandlerInEvent, THandlerOutEvent, ToSwarm,
7373
},
7474
PeerId,
7575
};
@@ -214,23 +214,14 @@ impl DiscoveryConfig {
214214
enable_mdns,
215215
kademlia_disjoint_query_paths,
216216
kademlia_protocol,
217-
kademlia_legacy_protocol,
217+
kademlia_legacy_protocol: _,
218218
kademlia_replication_factor,
219219
} = self;
220220

221221
let kademlia = if let Some(ref kademlia_protocol) = kademlia_protocol {
222-
let mut config = KademliaConfig::default();
222+
let mut config = KademliaConfig::new(kademlia_protocol.clone());
223223

224224
config.set_replication_factor(kademlia_replication_factor);
225-
// Populate kad with both the legacy and the new protocol names.
226-
// Remove the legacy protocol:
227-
// https://github.com/paritytech/polkadot-sdk/issues/504
228-
let kademlia_protocols = if let Some(legacy_protocol) = kademlia_legacy_protocol {
229-
vec![kademlia_protocol.clone(), legacy_protocol]
230-
} else {
231-
vec![kademlia_protocol.clone()]
232-
};
233-
config.set_protocol_names(kademlia_protocols.into_iter().map(Into::into).collect());
234225

235226
config.set_record_filtering(libp2p::kad::StoreInserts::FilterBoth);
236227

@@ -613,12 +604,14 @@ impl NetworkBehaviour for DiscoveryBehaviour {
613604
peer: PeerId,
614605
addr: &Multiaddr,
615606
role_override: Endpoint,
607+
port_use: PortUse,
616608
) -> Result<THandler<Self>, ConnectionDenied> {
617609
self.kademlia.handle_established_outbound_connection(
618610
connection_id,
619611
peer,
620612
addr,
621613
role_override,
614+
port_use,
622615
)
623616
}
624617

@@ -690,7 +683,7 @@ impl NetworkBehaviour for DiscoveryBehaviour {
690683
Ok(list.into_iter().collect())
691684
}
692685

693-
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
686+
fn on_swarm_event(&mut self, event: FromSwarm) {
694687
match event {
695688
FromSwarm::ConnectionEstablished(e) => {
696689
self.num_connections += 1;
@@ -777,6 +770,10 @@ impl NetworkBehaviour for DiscoveryBehaviour {
777770

778771
self.kademlia.on_swarm_event(FromSwarm::ExternalAddrConfirmed(e));
779772
},
773+
event => {
774+
debug!(target: "sub-libp2p", "New unknown `FromSwarm` libp2p event: {event:?}");
775+
self.kademlia.on_swarm_event(event);
776+
},
780777
}
781778
}
782779

@@ -789,11 +786,7 @@ impl NetworkBehaviour for DiscoveryBehaviour {
789786
self.kademlia.on_connection_handler_event(peer_id, connection_id, event);
790787
}
791788

792-
fn poll(
793-
&mut self,
794-
cx: &mut Context,
795-
params: &mut impl PollParameters,
796-
) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
789+
fn poll(&mut self, cx: &mut Context) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
797790
// Immediately process the content of `discovered`.
798791
if let Some(ev) = self.pending_events.pop_front() {
799792
return Poll::Ready(ToSwarm::GenerateEvent(ev))
@@ -836,7 +829,7 @@ impl NetworkBehaviour for DiscoveryBehaviour {
836829
}
837830
}
838831

839-
while let Poll::Ready(ev) = self.kademlia.poll(cx, params) {
832+
while let Poll::Ready(ev) = self.kademlia.poll(cx) {
840833
match ev {
841834
ToSwarm::GenerateEvent(ev) => match ev {
842835
KademliaEvent::RoutingUpdated { peer, .. } => {
@@ -1019,30 +1012,38 @@ impl NetworkBehaviour for DiscoveryBehaviour {
10191012
e.key(), e,
10201013
),
10211014
},
1015+
KademliaEvent::OutboundQueryProgressed {
1016+
result: QueryResult::Bootstrap(res),
1017+
..
1018+
} => match res {
1019+
Ok(ok) => debug!(
1020+
target: "sub-libp2p",
1021+
"Libp2p => DHT bootstrap progressed: {ok:?}",
1022+
),
1023+
Err(e) => warn!(
1024+
target: "sub-libp2p",
1025+
"Libp2p => DHT bootstrap error: {e:?}",
1026+
),
1027+
},
10221028
// We never start any other type of query.
10231029
KademliaEvent::OutboundQueryProgressed { result: e, .. } => {
10241030
warn!(target: "sub-libp2p", "Libp2p => Unhandled Kademlia event: {:?}", e)
10251031
},
1032+
Event::ModeChanged { new_mode } => {
1033+
debug!(target: "sub-libp2p", "Libp2p => Kademlia mode changed: {new_mode}")
1034+
},
10261035
},
10271036
ToSwarm::Dial { opts } => return Poll::Ready(ToSwarm::Dial { opts }),
1028-
ToSwarm::NotifyHandler { peer_id, handler, event } =>
1029-
return Poll::Ready(ToSwarm::NotifyHandler { peer_id, handler, event }),
1030-
ToSwarm::CloseConnection { peer_id, connection } =>
1031-
return Poll::Ready(ToSwarm::CloseConnection { peer_id, connection }),
1032-
ToSwarm::NewExternalAddrCandidate(observed) =>
1033-
return Poll::Ready(ToSwarm::NewExternalAddrCandidate(observed)),
1034-
ToSwarm::ExternalAddrConfirmed(addr) =>
1035-
return Poll::Ready(ToSwarm::ExternalAddrConfirmed(addr)),
1036-
ToSwarm::ExternalAddrExpired(addr) =>
1037-
return Poll::Ready(ToSwarm::ExternalAddrExpired(addr)),
1038-
ToSwarm::ListenOn { opts } => return Poll::Ready(ToSwarm::ListenOn { opts }),
1039-
ToSwarm::RemoveListener { id } =>
1040-
return Poll::Ready(ToSwarm::RemoveListener { id }),
1037+
event => {
1038+
return Poll::Ready(event.map_out(|_| {
1039+
unreachable!("`GenerateEvent` is handled in a branch above; qed")
1040+
}));
1041+
},
10411042
}
10421043
}
10431044

10441045
// Poll mDNS.
1045-
while let Poll::Ready(ev) = self.mdns.poll(cx, params) {
1046+
while let Poll::Ready(ev) = self.mdns.poll(cx) {
10461047
match ev {
10471048
ToSwarm::GenerateEvent(event) => match event {
10481049
mdns::Event::Discovered(list) => {
@@ -1064,17 +1065,17 @@ impl NetworkBehaviour for DiscoveryBehaviour {
10641065
},
10651066
// `event` is an enum with no variant
10661067
ToSwarm::NotifyHandler { event, .. } => match event {},
1067-
ToSwarm::CloseConnection { peer_id, connection } =>
1068-
return Poll::Ready(ToSwarm::CloseConnection { peer_id, connection }),
1069-
ToSwarm::NewExternalAddrCandidate(observed) =>
1070-
return Poll::Ready(ToSwarm::NewExternalAddrCandidate(observed)),
1071-
ToSwarm::ExternalAddrConfirmed(addr) =>
1072-
return Poll::Ready(ToSwarm::ExternalAddrConfirmed(addr)),
1073-
ToSwarm::ExternalAddrExpired(addr) =>
1074-
return Poll::Ready(ToSwarm::ExternalAddrExpired(addr)),
1075-
ToSwarm::ListenOn { opts } => return Poll::Ready(ToSwarm::ListenOn { opts }),
1076-
ToSwarm::RemoveListener { id } =>
1077-
return Poll::Ready(ToSwarm::RemoveListener { id }),
1068+
event => {
1069+
return Poll::Ready(
1070+
event
1071+
.map_in(|_| {
1072+
unreachable!("`NotifyHandler` is handled in a branch above; qed")
1073+
})
1074+
.map_out(|_| {
1075+
unreachable!("`GenerateEvent` is handled in a branch above; qed")
1076+
}),
1077+
);
1078+
},
10781079
}
10791080
}
10801081

@@ -1117,21 +1118,14 @@ mod tests {
11171118
},
11181119
identity::Keypair,
11191120
noise,
1120-
swarm::{Executor, Swarm, SwarmEvent},
1121+
swarm::{Swarm, SwarmEvent},
11211122
yamux, Multiaddr,
11221123
};
11231124
use sp_core::hash::H256;
1124-
use std::{collections::HashSet, pin::Pin, task::Poll};
1125+
use std::{collections::HashSet, task::Poll, time::Duration};
11251126

1126-
struct TokioExecutor(tokio::runtime::Runtime);
1127-
impl Executor for TokioExecutor {
1128-
fn exec(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) {
1129-
let _ = self.0.spawn(f);
1130-
}
1131-
}
1132-
1133-
#[test]
1134-
fn discovery_working() {
1127+
#[tokio::test]
1128+
async fn discovery_working() {
11351129
let mut first_swarm_peer_id_and_addr = None;
11361130

11371131
let genesis_hash = H256::from_low_u64_be(1);
@@ -1142,42 +1136,40 @@ mod tests {
11421136
// the first swarm via `with_permanent_addresses`.
11431137
let mut swarms = (0..25)
11441138
.map(|i| {
1145-
let keypair = Keypair::generate_ed25519();
1146-
1147-
let transport = MemoryTransport::new()
1148-
.upgrade(upgrade::Version::V1)
1149-
.authenticate(noise::Config::new(&keypair).unwrap())
1150-
.multiplex(yamux::Config::default())
1151-
.boxed();
1152-
1153-
let behaviour = {
1154-
let mut config = DiscoveryConfig::new(keypair.public().to_peer_id());
1155-
config
1156-
.with_permanent_addresses(first_swarm_peer_id_and_addr.clone())
1157-
.allow_private_ip(true)
1158-
.allow_non_globals_in_dht(true)
1159-
.discovery_limit(50)
1160-
.with_kademlia(genesis_hash, fork_id, &protocol_id);
1161-
1162-
config.finish()
1163-
};
1164-
1165-
let runtime = tokio::runtime::Runtime::new().unwrap();
1166-
#[allow(deprecated)]
1167-
let mut swarm = libp2p::swarm::SwarmBuilder::with_executor(
1168-
transport,
1169-
behaviour,
1170-
keypair.public().to_peer_id(),
1171-
TokioExecutor(runtime),
1172-
)
1173-
.build();
1139+
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
1140+
.with_tokio()
1141+
.with_other_transport(|keypair| {
1142+
MemoryTransport::new()
1143+
.upgrade(upgrade::Version::V1)
1144+
.authenticate(noise::Config::new(&keypair).unwrap())
1145+
.multiplex(yamux::Config::default())
1146+
.boxed()
1147+
})
1148+
.unwrap()
1149+
.with_behaviour(|keypair| {
1150+
let mut config = DiscoveryConfig::new(keypair.public().to_peer_id());
1151+
config
1152+
.with_permanent_addresses(first_swarm_peer_id_and_addr.clone())
1153+
.allow_private_ip(true)
1154+
.allow_non_globals_in_dht(true)
1155+
.discovery_limit(50)
1156+
.with_kademlia(genesis_hash, fork_id, &protocol_id);
1157+
1158+
config.finish()
1159+
})
1160+
.unwrap()
1161+
.with_swarm_config(|config| {
1162+
// This is taken care of by notification protocols in non-test environment
1163+
config.with_idle_connection_timeout(Duration::from_secs(10))
1164+
})
1165+
.build();
11741166

11751167
let listen_addr: Multiaddr =
11761168
format!("/memory/{}", rand::random::<u64>()).parse().unwrap();
11771169

11781170
if i == 0 {
11791171
first_swarm_peer_id_and_addr =
1180-
Some((keypair.public().to_peer_id(), listen_addr.clone()))
1172+
Some((*swarm.local_peer_id(), listen_addr.clone()))
11811173
}
11821174

11831175
swarm.listen_on(listen_addr.clone()).unwrap();
@@ -1264,7 +1256,7 @@ mod tests {
12641256
}
12651257
});
12661258

1267-
futures::executor::block_on(fut);
1259+
fut.await
12681260
}
12691261

12701262
#[test]

substrate/client/network/src/network_state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ pub enum Endpoint {
106106
impl From<ConnectedPoint> for PeerEndpoint {
107107
fn from(endpoint: ConnectedPoint) -> Self {
108108
match endpoint {
109-
ConnectedPoint::Dialer { address, role_override } =>
109+
ConnectedPoint::Dialer { address, role_override, port_use: _ } =>
110110
Self::Dialing(address, role_override.into()),
111111
ConnectedPoint::Listener { local_addr, send_back_addr } =>
112112
Self::Listening { local_addr, send_back_addr },

0 commit comments

Comments
 (0)