Update to libp2p 0.54

This is the same libp2p Substrate uses as of
https://github.com/paritytech/polkadot-sdk/pull/6248.
This commit is contained in:
Luke Parker
2025-01-17 04:50:15 -05:00
parent 2226dd59cc
commit 2a19e9da93
6 changed files with 292 additions and 347 deletions

524
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,7 @@ tributary-sdk = { path = "../../tributary-sdk" }
futures-util = { version = "0.3", default-features = false, features = ["std"] } futures-util = { version = "0.3", default-features = false, features = ["std"] }
tokio = { version = "1", default-features = false, features = ["sync"] } tokio = { version = "1", default-features = false, features = ["sync"] }
libp2p = { version = "0.52", default-features = false, features = ["tokio", "tcp", "noise", "yamux", "ping", "request-response", "gossipsub", "macros"] } libp2p = { version = "0.54", default-features = false, features = ["tokio", "tcp", "noise", "yamux", "ping", "request-response", "gossipsub", "macros"] }
log = { version = "0.4", default-features = false, features = ["std"] } log = { version = "0.4", default-features = false, features = ["std"] }
serai-task = { path = "../../../common/task", version = "0.1" } serai-task = { path = "../../../common/task", version = "0.1" }

View File

@@ -11,8 +11,7 @@ use serai_client::primitives::PublicKey as Public;
use futures_util::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use futures_util::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use libp2p::{ use libp2p::{
core::UpgradeInfo, core::upgrade::{UpgradeInfo, InboundConnectionUpgrade, OutboundConnectionUpgrade},
InboundUpgrade, OutboundUpgrade,
identity::{self, PeerId}, identity::{self, PeerId},
noise, noise,
}; };
@@ -119,12 +118,18 @@ impl UpgradeInfo for OnlyValidators {
} }
} }
impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> InboundUpgrade<S> for OnlyValidators { impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> InboundConnectionUpgrade<S>
for OnlyValidators
{
type Output = (PeerId, noise::Output<S>); type Output = (PeerId, noise::Output<S>);
type Error = io::Error; type Error = io::Error;
type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>; type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>;
fn upgrade_inbound(self, socket: S, info: Self::Info) -> Self::Future { fn upgrade_inbound(
self,
socket: S,
info: <Self as UpgradeInfo>::Info,
) -> <Self as InboundConnectionUpgrade<S>>::Future {
Box::pin(async move { Box::pin(async move {
let (dialer_noise_peer_id, mut socket) = noise::Config::new(&self.noise_keypair) let (dialer_noise_peer_id, mut socket) = noise::Config::new(&self.noise_keypair)
.unwrap() .unwrap()
@@ -147,12 +152,18 @@ impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> InboundUpgrade<S> for O
} }
} }
impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> OutboundUpgrade<S> for OnlyValidators { impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> OutboundConnectionUpgrade<S>
for OnlyValidators
{
type Output = (PeerId, noise::Output<S>); type Output = (PeerId, noise::Output<S>);
type Error = io::Error; type Error = io::Error;
type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>; type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>;
fn upgrade_outbound(self, socket: S, info: Self::Info) -> Self::Future { fn upgrade_outbound(
self,
socket: S,
info: <Self as UpgradeInfo>::Info,
) -> <Self as OutboundConnectionUpgrade<S>>::Future {
Box::pin(async move { Box::pin(async move {
let (listener_noise_peer_id, mut socket) = noise::Config::new(&self.noise_keypair) let (listener_noise_peer_id, mut socket) = noise::Config::new(&self.noise_keypair)
.unwrap() .unwrap()

View File

@@ -50,7 +50,7 @@ mod ping;
/// The request-response messages and behavior /// The request-response messages and behavior
mod reqres; mod reqres;
use reqres::{RequestId, Request, Response}; use reqres::{InboundRequestId, Request, Response};
/// The gossip messages and behavior /// The gossip messages and behavior
mod gossip; mod gossip;
@@ -66,14 +66,6 @@ use dial::DialTask;
const PORT: u16 = 30563; // 5132 ^ (('c' << 8) | 'o') const PORT: u16 = 30563; // 5132 ^ (('c' << 8) | 'o')
// usize::max, manually implemented, as max isn't a const fn
const MAX_LIBP2P_MESSAGE_SIZE: usize =
if gossip::MAX_LIBP2P_GOSSIP_MESSAGE_SIZE > reqres::MAX_LIBP2P_REQRES_MESSAGE_SIZE {
gossip::MAX_LIBP2P_GOSSIP_MESSAGE_SIZE
} else {
reqres::MAX_LIBP2P_REQRES_MESSAGE_SIZE
};
fn peer_id_from_public(public: PublicKey) -> PeerId { fn peer_id_from_public(public: PublicKey) -> PeerId {
// 0 represents the identity Multihash, that no hash was performed // 0 represents the identity Multihash, that no hash was performed
// It's an internal constant so we can't refer to the constant inside libp2p // It's an internal constant so we can't refer to the constant inside libp2p
@@ -143,9 +135,9 @@ struct Libp2pInner {
signed_cosigns: Mutex<mpsc::UnboundedReceiver<SignedCosign>>, signed_cosigns: Mutex<mpsc::UnboundedReceiver<SignedCosign>>,
signed_cosigns_send: mpsc::UnboundedSender<SignedCosign>, signed_cosigns_send: mpsc::UnboundedSender<SignedCosign>,
heartbeat_requests: Mutex<mpsc::UnboundedReceiver<(RequestId, ValidatorSet, [u8; 32])>>, heartbeat_requests: Mutex<mpsc::UnboundedReceiver<(InboundRequestId, ValidatorSet, [u8; 32])>>,
notable_cosign_requests: Mutex<mpsc::UnboundedReceiver<(RequestId, [u8; 32])>>, notable_cosign_requests: Mutex<mpsc::UnboundedReceiver<(InboundRequestId, [u8; 32])>>,
inbound_request_responses: mpsc::UnboundedSender<(RequestId, Response)>, inbound_request_responses: mpsc::UnboundedSender<(InboundRequestId, Response)>,
} }
/// The libp2p-backed P2P implementation. /// The libp2p-backed P2P implementation.
@@ -176,19 +168,9 @@ impl Libp2p {
Ok(OnlyValidators { serai_key: serai_key.clone(), noise_keypair: noise_keypair.clone() }) Ok(OnlyValidators { serai_key: serai_key.clone(), noise_keypair: noise_keypair.clone() })
}; };
let new_yamux = || {
let mut config = yamux::Config::default();
// 1 MiB default + max message size
config.set_max_buffer_size((1024 * 1024) + MAX_LIBP2P_MESSAGE_SIZE);
// 256 KiB default + max message size
config
.set_receive_window_size(((256 * 1024) + MAX_LIBP2P_MESSAGE_SIZE).try_into().unwrap());
config
};
let mut swarm = SwarmBuilder::with_existing_identity(identity::Keypair::generate_ed25519()) let mut swarm = SwarmBuilder::with_existing_identity(identity::Keypair::generate_ed25519())
.with_tokio() .with_tokio()
.with_tcp(TcpConfig::default().nodelay(true), new_only_validators, new_yamux) .with_tcp(TcpConfig::default().nodelay(true), new_only_validators, yamux::Config::default)
.unwrap() .unwrap()
.with_behaviour(|_| Behavior { .with_behaviour(|_| Behavior {
allow_list: allow_block_list::Behaviour::default(), allow_list: allow_block_list::Behaviour::default(),

View File

@@ -10,7 +10,7 @@ use futures_util::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use libp2p::request_response::{ use libp2p::request_response::{
self, Codec as CodecTrait, Event as GenericEvent, Config, Behaviour, ProtocolSupport, self, Codec as CodecTrait, Event as GenericEvent, Config, Behaviour, ProtocolSupport,
}; };
pub use request_response::{RequestId, Message}; pub use request_response::{InboundRequestId, Message};
use serai_cosign::SignedCosign; use serai_cosign::SignedCosign;
@@ -129,7 +129,6 @@ pub(crate) type Event = GenericEvent<Request, Response>;
pub(crate) type Behavior = Behaviour<Codec>; pub(crate) type Behavior = Behaviour<Codec>;
pub(crate) fn new_behavior() -> Behavior { pub(crate) fn new_behavior() -> Behavior {
let mut config = Config::default(); let config = Config::default().with_request_timeout(Duration::from_secs(5));
config.set_request_timeout(Duration::from_secs(5));
Behavior::new([(PROTOCOL, ProtocolSupport::Full)], config) Behavior::new([(PROTOCOL, ProtocolSupport::Full)], config)
} }

View File

@@ -17,7 +17,7 @@ use serai_cosign::SignedCosign;
use futures_util::StreamExt; use futures_util::StreamExt;
use libp2p::{ use libp2p::{
identity::PeerId, identity::PeerId,
request_response::{RequestId, ResponseChannel}, request_response::{InboundRequestId, OutboundRequestId, ResponseChannel},
swarm::{dial_opts::DialOpts, SwarmEvent, Swarm}, swarm::{dial_opts::DialOpts, SwarmEvent, Swarm},
}; };
@@ -65,12 +65,12 @@ pub(crate) struct SwarmTask {
tributary_gossip: mpsc::UnboundedSender<([u8; 32], Vec<u8>)>, tributary_gossip: mpsc::UnboundedSender<([u8; 32], Vec<u8>)>,
outbound_requests: mpsc::UnboundedReceiver<(PeerId, Request, oneshot::Sender<Response>)>, outbound_requests: mpsc::UnboundedReceiver<(PeerId, Request, oneshot::Sender<Response>)>,
outbound_request_responses: HashMap<RequestId, oneshot::Sender<Response>>, outbound_request_responses: HashMap<OutboundRequestId, oneshot::Sender<Response>>,
inbound_request_response_channels: HashMap<RequestId, ResponseChannel<Response>>, inbound_request_response_channels: HashMap<InboundRequestId, ResponseChannel<Response>>,
heartbeat_requests: mpsc::UnboundedSender<(RequestId, ValidatorSet, [u8; 32])>, heartbeat_requests: mpsc::UnboundedSender<(InboundRequestId, ValidatorSet, [u8; 32])>,
notable_cosign_requests: mpsc::UnboundedSender<(RequestId, [u8; 32])>, notable_cosign_requests: mpsc::UnboundedSender<(InboundRequestId, [u8; 32])>,
inbound_request_responses: mpsc::UnboundedReceiver<(RequestId, Response)>, inbound_request_responses: mpsc::UnboundedReceiver<(InboundRequestId, Response)>,
} }
impl SwarmTask { impl SwarmTask {
@@ -222,24 +222,20 @@ impl SwarmTask {
} }
} }
SwarmEvent::Behaviour( SwarmEvent::Behaviour(event) => {
BehaviorEvent::AllowList(event) | BehaviorEvent::ConnectionLimits(event) match event {
) => { BehaviorEvent::AllowList(event) | BehaviorEvent::ConnectionLimits(event) => {
// This *is* an exhaustive match as these events are empty enums // This *is* an exhaustive match as these events are empty enums
match event {} match event {}
} }
SwarmEvent::Behaviour( BehaviorEvent::Ping(ping::Event { peer: _, connection, result, }) => {
BehaviorEvent::Ping(ping::Event { peer: _, connection, result, })
) => {
if result.is_err() { if result.is_err() {
self.swarm.close_connection(connection); self.swarm.close_connection(connection);
} }
} }
SwarmEvent::Behaviour(BehaviorEvent::Reqres(event)) => { BehaviorEvent::Reqres(event) => self.handle_reqres(event),
self.handle_reqres(event) BehaviorEvent::Gossip(event) => self.handle_gossip(event),
} }
SwarmEvent::Behaviour(BehaviorEvent::Gossip(event)) => {
self.handle_gossip(event)
} }
// We don't handle any of these // We don't handle any of these
@@ -250,7 +246,14 @@ impl SwarmTask {
SwarmEvent::ExpiredListenAddr { .. } | SwarmEvent::ExpiredListenAddr { .. } |
SwarmEvent::ListenerClosed { .. } | SwarmEvent::ListenerClosed { .. } |
SwarmEvent::ListenerError { .. } | SwarmEvent::ListenerError { .. } |
SwarmEvent::Dialing { .. } => {} SwarmEvent::Dialing { .. } |
SwarmEvent::NewExternalAddrCandidate { .. } |
SwarmEvent::ExternalAddrConfirmed { .. } |
SwarmEvent::ExternalAddrExpired { .. } |
SwarmEvent::NewExternalAddrOfPeer { .. } => {}
// Requires as SwarmEvent is non-exhaustive
_ => log::warn!("unhandled SwarmEvent: {event:?}"),
} }
} }
@@ -321,9 +324,9 @@ impl SwarmTask {
outbound_requests: mpsc::UnboundedReceiver<(PeerId, Request, oneshot::Sender<Response>)>, outbound_requests: mpsc::UnboundedReceiver<(PeerId, Request, oneshot::Sender<Response>)>,
heartbeat_requests: mpsc::UnboundedSender<(RequestId, ValidatorSet, [u8; 32])>, heartbeat_requests: mpsc::UnboundedSender<(InboundRequestId, ValidatorSet, [u8; 32])>,
notable_cosign_requests: mpsc::UnboundedSender<(RequestId, [u8; 32])>, notable_cosign_requests: mpsc::UnboundedSender<(InboundRequestId, [u8; 32])>,
inbound_request_responses: mpsc::UnboundedReceiver<(RequestId, Response)>, inbound_request_responses: mpsc::UnboundedReceiver<(InboundRequestId, Response)>,
) { ) {
tokio::spawn( tokio::spawn(
SwarmTask { SwarmTask {