From 7c8a97739f836be7169118f5d231f09eca5c413b Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 14 Jul 2022 06:15:19 +0200 Subject: [PATCH 01/92] swarm/src/handler: Document responsibility limiting inbound streams (#2752) Document that the `ConnectionHandler` implementation has to enforce a limit on the number of inbound substreams. --- swarm/src/handler.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/swarm/src/handler.rs b/swarm/src/handler.rs index 2a301b70889..7060d33bc6a 100644 --- a/swarm/src/handler.rs +++ b/swarm/src/handler.rs @@ -116,6 +116,12 @@ pub trait ConnectionHandler: Send + 'static { fn listen_protocol(&self) -> SubstreamProtocol; /// Injects the output of a successful upgrade on a new inbound substream. + /// + /// Note that it is up to the [`ConnectionHandler`] implementation to manage the lifetime of the + /// negotiated inbound substreams. E.g. the implementation has to enforce a limit on the number + /// of simultaneously open negotiated inbound substreams. In other words it is up to the + /// [`ConnectionHandler`] implementation to stop a malicious remote node to open and keep alive + /// an excessive amount of inbound substreams. fn inject_fully_negotiated_inbound( &mut self, protocol: ::Output, From d4f8ec2d48bca3274296d92a1c74ccbfc9ce4276 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 15 Jul 2022 09:16:03 +0200 Subject: [PATCH 02/92] misc/metrics: Track # connected nodes supporting specific protocol (#2734) * misc/metrics: Explicitly delegate event recording to each recorder This allows delegating a single event to multiple `Recorder`s. That enables e.g. the `identify::Metrics` `Recorder` to act both on `IdentifyEvent` and `SwarmEvent`. The latter enables it to garbage collect per peer data on disconnects. * protocols/dcutr: Expose PROTOCOL_NAME * protocols/identify: Expose PROTOCOL_NAME and PUSH_PROTOCOL_NAME * protocols/ping: Expose PROTOCOL_NAME * protocols/relay: Expose HOP_PROTOCOL_NAME and STOP_PROTOCOL_NAME * misc/metrics: Track # connected nodes supporting specific protocol An example metric exposed with this patch: ``` libp2p_identify_protocols{protocol="/ipfs/ping/1.0.0"} 10 ``` This implies that 10 of the currently connected nodes support the ping protocol. --- misc/metrics/CHANGELOG.md | 4 + misc/metrics/src/dcutr.rs | 5 +- misc/metrics/src/gossipsub.rs | 4 +- misc/metrics/src/identify.rs | 145 +++++++++++++++++++++++++++-- misc/metrics/src/kad.rs | 40 +++----- misc/metrics/src/lib.rs | 52 +++++++++++ misc/metrics/src/ping.rs | 8 +- misc/metrics/src/relay.rs | 5 +- misc/metrics/src/swarm.rs | 30 +++--- protocols/dcutr/CHANGELOG.md | 4 + protocols/dcutr/src/lib.rs | 1 + protocols/dcutr/src/protocol.rs | 2 +- protocols/identify/CHANGELOG.md | 4 + protocols/identify/src/lib.rs | 2 +- protocols/identify/src/protocol.rs | 8 +- protocols/ping/CHANGELOG.md | 4 + protocols/ping/src/lib.rs | 4 +- protocols/ping/src/protocol.rs | 4 +- protocols/relay/CHANGELOG.md | 4 + protocols/relay/src/v2.rs | 3 +- protocols/relay/src/v2/protocol.rs | 4 +- 21 files changed, 259 insertions(+), 78 deletions(-) diff --git a/misc/metrics/CHANGELOG.md b/misc/metrics/CHANGELOG.md index 979617bdb29..1b3053eaae7 100644 --- a/misc/metrics/CHANGELOG.md +++ b/misc/metrics/CHANGELOG.md @@ -12,6 +12,10 @@ - Update to `libp2p-kad` `v0.39.0`. +- Track number of connected nodes supporting a specific protocol via the identify protocol. See [PR 2734]. + +[PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ + # 0.7.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/misc/metrics/src/dcutr.rs b/misc/metrics/src/dcutr.rs index 27dcbc08dc8..b90e784f9b7 100644 --- a/misc/metrics/src/dcutr.rs +++ b/misc/metrics/src/dcutr.rs @@ -77,10 +77,9 @@ impl From<&libp2p_dcutr::behaviour::Event> for EventType { } } -impl super::Recorder for super::Metrics { +impl super::Recorder for Metrics { fn record(&self, event: &libp2p_dcutr::behaviour::Event) { - self.dcutr - .events + self.events .get_or_create(&EventLabels { event: event.into(), }) diff --git a/misc/metrics/src/gossipsub.rs b/misc/metrics/src/gossipsub.rs index 0bb6af5f452..a82c1a72a24 100644 --- a/misc/metrics/src/gossipsub.rs +++ b/misc/metrics/src/gossipsub.rs @@ -40,10 +40,10 @@ impl Metrics { } } -impl super::Recorder for super::Metrics { +impl super::Recorder for Metrics { fn record(&self, event: &libp2p_gossipsub::GossipsubEvent) { if let libp2p_gossipsub::GossipsubEvent::Message { .. } = event { - self.gossipsub.messages.inc(); + self.messages.inc(); } } } diff --git a/misc/metrics/src/identify.rs b/misc/metrics/src/identify.rs index 7431eda5d25..b3ae5a75910 100644 --- a/misc/metrics/src/identify.rs +++ b/misc/metrics/src/identify.rs @@ -18,12 +18,18 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +use libp2p_core::PeerId; +use prometheus_client::encoding::text::{EncodeMetric, Encoder}; use prometheus_client::metrics::counter::Counter; use prometheus_client::metrics::histogram::{exponential_buckets, Histogram}; +use prometheus_client::metrics::MetricType; use prometheus_client::registry::Registry; +use std::collections::HashMap; use std::iter; +use std::sync::{Arc, Mutex}; pub struct Metrics { + protocols: Protocols, error: Counter, pushed: Counter, received: Counter, @@ -36,6 +42,15 @@ impl Metrics { pub fn new(registry: &mut Registry) -> Self { let sub_registry = registry.sub_registry_with_prefix("identify"); + let protocols = Protocols::default(); + sub_registry.register( + "protocols", + "Number of connected nodes supporting a specific protocol, with \ + \"unrecognized\" for each peer supporting one or more unrecognized \ + protocols", + Box::new(protocols.clone()), + ); + let error = Counter::default(); sub_registry.register( "errors", @@ -86,6 +101,7 @@ impl Metrics { ); Self { + protocols, error, pushed, received, @@ -96,27 +112,136 @@ impl Metrics { } } -impl super::Recorder for super::Metrics { +impl super::Recorder for Metrics { fn record(&self, event: &libp2p_identify::IdentifyEvent) { match event { libp2p_identify::IdentifyEvent::Error { .. } => { - self.identify.error.inc(); + self.error.inc(); } libp2p_identify::IdentifyEvent::Pushed { .. } => { - self.identify.pushed.inc(); + self.pushed.inc(); } - libp2p_identify::IdentifyEvent::Received { info, .. } => { - self.identify.received.inc(); - self.identify - .received_info_protocols + libp2p_identify::IdentifyEvent::Received { peer_id, info, .. } => { + { + let mut protocols: Vec = info + .protocols + .iter() + .filter(|p| { + let allowed_protocols: &[&[u8]] = &[ + #[cfg(feature = "dcutr")] + libp2p_dcutr::PROTOCOL_NAME, + // #[cfg(feature = "gossipsub")] + // #[cfg(not(target_os = "unknown"))] + // TODO: Add Gossipsub protocol name + libp2p_identify::PROTOCOL_NAME, + libp2p_identify::PUSH_PROTOCOL_NAME, + #[cfg(feature = "kad")] + libp2p_kad::protocol::DEFAULT_PROTO_NAME, + #[cfg(feature = "ping")] + libp2p_ping::PROTOCOL_NAME, + #[cfg(feature = "relay")] + libp2p_relay::v2::STOP_PROTOCOL_NAME, + #[cfg(feature = "relay")] + libp2p_relay::v2::HOP_PROTOCOL_NAME, + ]; + + allowed_protocols.contains(&p.as_bytes()) + }) + .cloned() + .collect(); + + // Signal via an additional label value that one or more + // protocols of the remote peer have not been recognized. + if protocols.len() < info.protocols.len() { + protocols.push("unrecognized".to_string()); + } + + protocols.sort_unstable(); + protocols.dedup(); + + self.protocols.add(*peer_id, protocols); + } + + self.received.inc(); + self.received_info_protocols .observe(info.protocols.len() as f64); - self.identify - .received_info_listen_addrs + self.received_info_listen_addrs .observe(info.listen_addrs.len() as f64); } libp2p_identify::IdentifyEvent::Sent { .. } => { - self.identify.sent.inc(); + self.sent.inc(); } } } } + +impl super::Recorder> for Metrics { + fn record(&self, event: &libp2p_swarm::SwarmEvent) { + if let libp2p_swarm::SwarmEvent::ConnectionClosed { + peer_id, + num_established, + .. + } = event + { + if *num_established == 0 { + self.protocols.remove(*peer_id) + } + } + } +} + +#[derive(Default, Clone)] +struct Protocols { + peers: Arc>>>, +} + +impl Protocols { + fn add(&self, peer: PeerId, protocols: Vec) { + self.peers + .lock() + .expect("Lock not to be poisoned") + .insert(peer, protocols); + } + + fn remove(&self, peer: PeerId) { + self.peers + .lock() + .expect("Lock not to be poisoned") + .remove(&peer); + } +} + +impl EncodeMetric for Protocols { + fn encode(&self, mut encoder: Encoder) -> Result<(), std::io::Error> { + let count_by_protocol = self + .peers + .lock() + .expect("Lock not to be poisoned") + .iter() + .fold( + HashMap::::default(), + |mut acc, (_, protocols)| { + for protocol in protocols { + let count = acc.entry(protocol.to_string()).or_default(); + *count = *count + 1; + } + acc + }, + ); + + for (protocol, count) in count_by_protocol { + encoder + .with_label_set(&("protocol", protocol)) + .no_suffix()? + .no_bucket()? + .encode_value(count)? + .no_exemplar()?; + } + + Ok(()) + } + + fn metric_type(&self) -> MetricType { + MetricType::Gauge + } +} diff --git a/misc/metrics/src/kad.rs b/misc/metrics/src/kad.rs index 8ab71befe91..5e5a1056060 100644 --- a/misc/metrics/src/kad.rs +++ b/misc/metrics/src/kad.rs @@ -159,25 +159,21 @@ impl Metrics { } } -impl super::Recorder for super::Metrics { +impl super::Recorder for Metrics { fn record(&self, event: &libp2p_kad::KademliaEvent) { match event { libp2p_kad::KademliaEvent::OutboundQueryCompleted { result, stats, .. } => { - self.kad - .query_result_num_requests + self.query_result_num_requests .get_or_create(&result.into()) .observe(stats.num_requests().into()); - self.kad - .query_result_num_success + self.query_result_num_success .get_or_create(&result.into()) .observe(stats.num_successes().into()); - self.kad - .query_result_num_failure + self.query_result_num_failure .get_or_create(&result.into()) .observe(stats.num_failures().into()); if let Some(duration) = stats.duration() { - self.kad - .query_result_duration + self.query_result_duration .get_or_create(&result.into()) .observe(duration.as_secs_f64()); } @@ -185,36 +181,30 @@ impl super::Recorder for super::Metrics { match result { libp2p_kad::QueryResult::GetRecord(result) => match result { Ok(ok) => self - .kad .query_result_get_record_ok .observe(ok.records.len() as f64), Err(error) => { - self.kad - .query_result_get_record_error + self.query_result_get_record_error .get_or_create(&error.into()) .inc(); } }, libp2p_kad::QueryResult::GetClosestPeers(result) => match result { Ok(ok) => self - .kad .query_result_get_closest_peers_ok .observe(ok.peers.len() as f64), Err(error) => { - self.kad - .query_result_get_closest_peers_error + self.query_result_get_closest_peers_error .get_or_create(&error.into()) .inc(); } }, libp2p_kad::QueryResult::GetProviders(result) => match result { Ok(ok) => self - .kad .query_result_get_providers_ok .observe(ok.providers.len() as f64), Err(error) => { - self.kad - .query_result_get_providers_error + self.query_result_get_providers_error .get_or_create(&error.into()) .inc(); } @@ -230,16 +220,14 @@ impl super::Recorder for super::Metrics { } => { let bucket = low.ilog2().unwrap_or(0); if *is_new_peer { - self.kad - .routing_updated + self.routing_updated .get_or_create(&RoutingUpdated { action: RoutingAction::Added, bucket, }) .inc(); } else { - self.kad - .routing_updated + self.routing_updated .get_or_create(&RoutingUpdated { action: RoutingAction::Updated, bucket, @@ -248,8 +236,7 @@ impl super::Recorder for super::Metrics { } if old_peer.is_some() { - self.kad - .routing_updated + self.routing_updated .get_or_create(&RoutingUpdated { action: RoutingAction::Evicted, bucket, @@ -259,10 +246,7 @@ impl super::Recorder for super::Metrics { } libp2p_kad::KademliaEvent::InboundRequest { request } => { - self.kad - .inbound_requests - .get_or_create(&request.into()) - .inc(); + self.inbound_requests.get_or_create(&request.into()).inc(); } _ => {} } diff --git a/misc/metrics/src/lib.rs b/misc/metrics/src/lib.rs index 634d13590df..d9fa3c40ffe 100644 --- a/misc/metrics/src/lib.rs +++ b/misc/metrics/src/lib.rs @@ -95,3 +95,55 @@ pub trait Recorder { /// Record the given event. fn record(&self, event: &Event); } + +#[cfg(feature = "dcutr")] +impl Recorder for Metrics { + fn record(&self, event: &libp2p_dcutr::behaviour::Event) { + self.dcutr.record(event) + } +} + +#[cfg(feature = "gossipsub")] +#[cfg(not(target_os = "unknown"))] +impl Recorder for Metrics { + fn record(&self, event: &libp2p_gossipsub::GossipsubEvent) { + self.gossipsub.record(event) + } +} + +#[cfg(feature = "identify")] +impl Recorder for Metrics { + fn record(&self, event: &libp2p_identify::IdentifyEvent) { + self.identify.record(event) + } +} + +#[cfg(feature = "kad")] +impl Recorder for Metrics { + fn record(&self, event: &libp2p_kad::KademliaEvent) { + self.kad.record(event) + } +} + +#[cfg(feature = "ping")] +impl Recorder for Metrics { + fn record(&self, event: &libp2p_ping::PingEvent) { + self.ping.record(event) + } +} + +#[cfg(feature = "relay")] +impl Recorder for Metrics { + fn record(&self, event: &libp2p_relay::v2::relay::Event) { + self.relay.record(event) + } +} + +impl Recorder> for Metrics { + fn record(&self, event: &libp2p_swarm::SwarmEvent) { + self.swarm.record(event); + + #[cfg(feature = "identify")] + self.identify.record(event) + } +} diff --git a/misc/metrics/src/ping.rs b/misc/metrics/src/ping.rs index 76d50b54d17..b7c3ef60f9b 100644 --- a/misc/metrics/src/ping.rs +++ b/misc/metrics/src/ping.rs @@ -92,17 +92,17 @@ impl Metrics { } } -impl super::Recorder for super::Metrics { +impl super::Recorder for Metrics { fn record(&self, event: &libp2p_ping::PingEvent) { match &event.result { Ok(libp2p_ping::PingSuccess::Pong) => { - self.ping.pong_received.inc(); + self.pong_received.inc(); } Ok(libp2p_ping::PingSuccess::Ping { rtt }) => { - self.ping.rtt.observe(rtt.as_secs_f64()); + self.rtt.observe(rtt.as_secs_f64()); } Err(failure) => { - self.ping.failure.get_or_create(&failure.into()).inc(); + self.failure.get_or_create(&failure.into()).inc(); } } } diff --git a/misc/metrics/src/relay.rs b/misc/metrics/src/relay.rs index 479dcaab724..9267a975b08 100644 --- a/misc/metrics/src/relay.rs +++ b/misc/metrics/src/relay.rs @@ -102,10 +102,9 @@ impl From<&libp2p_relay::v2::relay::Event> for EventType { } } -impl super::Recorder for super::Metrics { +impl super::Recorder for Metrics { fn record(&self, event: &libp2p_relay::v2::relay::Event) { - self.relay - .events + self.events .get_or_create(&EventLabels { event: event.into(), }) diff --git a/misc/metrics/src/swarm.rs b/misc/metrics/src/swarm.rs index d0fb0c664f2..e9c5a0493ce 100644 --- a/misc/metrics/src/swarm.rs +++ b/misc/metrics/src/swarm.rs @@ -138,34 +138,29 @@ impl Metrics { } } -impl super::Recorder> - for super::Metrics -{ +impl super::Recorder> for Metrics { fn record(&self, event: &libp2p_swarm::SwarmEvent) { match event { libp2p_swarm::SwarmEvent::Behaviour(_) => {} libp2p_swarm::SwarmEvent::ConnectionEstablished { endpoint, .. } => { - self.swarm - .connections_established + self.connections_established .get_or_create(&ConnectionEstablishedLabels { role: endpoint.into(), }) .inc(); } libp2p_swarm::SwarmEvent::ConnectionClosed { endpoint, .. } => { - self.swarm - .connections_closed + self.connections_closed .get_or_create(&ConnectionClosedLabels { role: endpoint.into(), }) .inc(); } libp2p_swarm::SwarmEvent::IncomingConnection { .. } => { - self.swarm.connections_incoming.inc(); + self.connections_incoming.inc(); } libp2p_swarm::SwarmEvent::IncomingConnectionError { error, .. } => { - self.swarm - .connections_incoming_error + self.connections_incoming_error .get_or_create(&IncomingConnectionErrorLabels { error: error.into(), }) @@ -178,8 +173,7 @@ impl super::Recorder super::Recorder { - self.swarm.connected_to_banned_peer.inc(); + self.connected_to_banned_peer.inc(); } libp2p_swarm::SwarmEvent::NewListenAddr { .. } => { - self.swarm.new_listen_addr.inc(); + self.new_listen_addr.inc(); } libp2p_swarm::SwarmEvent::ExpiredListenAddr { .. } => { - self.swarm.expired_listen_addr.inc(); + self.expired_listen_addr.inc(); } libp2p_swarm::SwarmEvent::ListenerClosed { .. } => { - self.swarm.listener_closed.inc(); + self.listener_closed.inc(); } libp2p_swarm::SwarmEvent::ListenerError { .. } => { - self.swarm.listener_error.inc(); + self.listener_error.inc(); } libp2p_swarm::SwarmEvent::Dialing(_) => { - self.swarm.dial_attempt.inc(); + self.dial_attempt.inc(); } } } diff --git a/protocols/dcutr/CHANGELOG.md b/protocols/dcutr/CHANGELOG.md index 7d144a20772..0416de5e9cb 100644 --- a/protocols/dcutr/CHANGELOG.md +++ b/protocols/dcutr/CHANGELOG.md @@ -2,6 +2,10 @@ - Update to `libp2p-swarm` `v0.38.0`. +- Expose `PROTOCOL_NAME`. See [PR 2734]. + +[PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ + # 0.4.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/dcutr/src/lib.rs b/protocols/dcutr/src/lib.rs index 20ca846d99b..c55f22427f8 100644 --- a/protocols/dcutr/src/lib.rs +++ b/protocols/dcutr/src/lib.rs @@ -27,6 +27,7 @@ mod protocol; pub use protocol::{ inbound::UpgradeError as InboundUpgradeError, outbound::UpgradeError as OutboundUpgradeError, + PROTOCOL_NAME, }; mod message_proto { diff --git a/protocols/dcutr/src/protocol.rs b/protocols/dcutr/src/protocol.rs index d2b8b39a6d0..67f9af69f70 100644 --- a/protocols/dcutr/src/protocol.rs +++ b/protocols/dcutr/src/protocol.rs @@ -21,6 +21,6 @@ pub mod inbound; pub mod outbound; -const PROTOCOL_NAME: &[u8; 13] = b"/libp2p/dcutr"; +pub const PROTOCOL_NAME: &[u8; 13] = b"/libp2p/dcutr"; const MAX_MESSAGE_SIZE_BYTES: usize = 4096; diff --git a/protocols/identify/CHANGELOG.md b/protocols/identify/CHANGELOG.md index 60c77cd032a..499af6e3a13 100644 --- a/protocols/identify/CHANGELOG.md +++ b/protocols/identify/CHANGELOG.md @@ -2,6 +2,10 @@ - Update to `libp2p-swarm` `v0.38.0`. +- Expose `PROTOCOL_NAME` and `PUSH_PROTOCOL_NAME`. See [PR 2734]. + +[PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ + # 0.37.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/identify/src/lib.rs b/protocols/identify/src/lib.rs index f5de8f7a6ac..17925fb6eed 100644 --- a/protocols/identify/src/lib.rs +++ b/protocols/identify/src/lib.rs @@ -45,7 +45,7 @@ //! [`IdentifyInfo`]: self::IdentifyInfo pub use self::identify::{Identify, IdentifyConfig, IdentifyEvent}; -pub use self::protocol::{IdentifyInfo, UpgradeError}; +pub use self::protocol::{IdentifyInfo, UpgradeError, PROTOCOL_NAME, PUSH_PROTOCOL_NAME}; mod handler; mod identify; diff --git a/protocols/identify/src/protocol.rs b/protocols/identify/src/protocol.rs index 735fbcb342b..163ac0aa396 100644 --- a/protocols/identify/src/protocol.rs +++ b/protocols/identify/src/protocol.rs @@ -34,6 +34,10 @@ use void::Void; const MAX_MESSAGE_SIZE_BYTES: usize = 4096; +pub const PROTOCOL_NAME: &[u8; 14] = b"/ipfs/id/1.0.0"; + +pub const PUSH_PROTOCOL_NAME: &[u8; 19] = b"/ipfs/id/push/1.0.0"; + /// Substream upgrade protocol for `/ipfs/id/1.0.0`. #[derive(Debug, Clone)] pub struct IdentifyProtocol; @@ -104,7 +108,7 @@ impl UpgradeInfo for IdentifyProtocol { type InfoIter = iter::Once; fn protocol_info(&self) -> Self::InfoIter { - iter::once(b"/ipfs/id/1.0.0") + iter::once(PROTOCOL_NAME) } } @@ -136,7 +140,7 @@ impl UpgradeInfo for IdentifyPushProtocol { type InfoIter = iter::Once; fn protocol_info(&self) -> Self::InfoIter { - iter::once(b"/ipfs/id/push/1.0.0") + iter::once(PUSH_PROTOCOL_NAME) } } diff --git a/protocols/ping/CHANGELOG.md b/protocols/ping/CHANGELOG.md index a31b17d02f5..af9bb0a9690 100644 --- a/protocols/ping/CHANGELOG.md +++ b/protocols/ping/CHANGELOG.md @@ -2,6 +2,10 @@ - Update to `libp2p-swarm` `v0.38.0`. +- Expose `PROTOCOL_NAME`. See [PR 2734]. + +[PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ + # 0.37.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/ping/src/lib.rs b/protocols/ping/src/lib.rs index 81133b86d74..2a01025ee6d 100644 --- a/protocols/ping/src/lib.rs +++ b/protocols/ping/src/lib.rs @@ -57,8 +57,8 @@ use std::{ note = "Use re-exports that omit `Ping` prefix, i.e. `libp2p::ping::Config` etc" )] pub use self::{ - Config as PingConfig, Event as PingEvent, Failure as PingFailure, Result as PingResult, - Success as PingSuccess, + protocol::PROTOCOL_NAME, Config as PingConfig, Event as PingEvent, Failure as PingFailure, + Result as PingResult, Success as PingSuccess, }; #[deprecated(since = "0.30.0", note = "Use libp2p::ping::Behaviour instead.")] pub use Behaviour as Ping; diff --git a/protocols/ping/src/protocol.rs b/protocols/ping/src/protocol.rs index 499c5ad4a0f..659040e2d7f 100644 --- a/protocols/ping/src/protocol.rs +++ b/protocols/ping/src/protocol.rs @@ -26,6 +26,8 @@ use rand::{distributions, prelude::*}; use std::{io, iter, time::Duration}; use void::Void; +pub const PROTOCOL_NAME: &[u8; 16] = b"/ipfs/ping/1.0.0"; + /// The `Ping` protocol upgrade. /// /// The ping protocol sends 32 bytes of random data in configurable @@ -55,7 +57,7 @@ impl UpgradeInfo for Ping { type InfoIter = iter::Once; fn protocol_info(&self) -> Self::InfoIter { - iter::once(b"/ipfs/ping/1.0.0") + iter::once(PROTOCOL_NAME) } } diff --git a/protocols/relay/CHANGELOG.md b/protocols/relay/CHANGELOG.md index cd615778196..f03817080ea 100644 --- a/protocols/relay/CHANGELOG.md +++ b/protocols/relay/CHANGELOG.md @@ -2,6 +2,10 @@ - Update to `libp2p-swarm` `v0.38.0`. +- Expose `HOP_PROTOCOL_NAME` and `STOP_PROTOCOL_NAME`. See [PR 2734]. + +[PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ + # 0.10.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/relay/src/v2.rs b/protocols/relay/src/v2.rs index 7219ab3d69c..c610c1a3b2c 100644 --- a/protocols/relay/src/v2.rs +++ b/protocols/relay/src/v2.rs @@ -34,7 +34,8 @@ pub use protocol::{ inbound_hop::FatalUpgradeError as InboundHopFatalUpgradeError, inbound_stop::FatalUpgradeError as InboundStopFatalUpgradeError, outbound_hop::FatalUpgradeError as OutboundHopFatalUpgradeError, - outbound_stop::FatalUpgradeError as OutboundStopFatalUpgradeError, + outbound_stop::FatalUpgradeError as OutboundStopFatalUpgradeError, HOP_PROTOCOL_NAME, + STOP_PROTOCOL_NAME, }; /// The ID of an outgoing / incoming, relay / destination request. diff --git a/protocols/relay/src/v2/protocol.rs b/protocols/relay/src/v2/protocol.rs index ab2dc487b6f..27f69994957 100644 --- a/protocols/relay/src/v2/protocol.rs +++ b/protocols/relay/src/v2/protocol.rs @@ -26,8 +26,8 @@ pub mod inbound_stop; pub mod outbound_hop; pub mod outbound_stop; -const HOP_PROTOCOL_NAME: &[u8; 31] = b"/libp2p/circuit/relay/0.2.0/hop"; -const STOP_PROTOCOL_NAME: &[u8; 32] = b"/libp2p/circuit/relay/0.2.0/stop"; +pub const HOP_PROTOCOL_NAME: &[u8; 31] = b"/libp2p/circuit/relay/0.2.0/hop"; +pub const STOP_PROTOCOL_NAME: &[u8; 32] = b"/libp2p/circuit/relay/0.2.0/stop"; const MAX_MESSAGE_SIZE: usize = 4096; From 1a553db59686fef5bdc780c0bfe7c583a2f8e6c5 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 18 Jul 2022 04:20:11 +0100 Subject: [PATCH 03/92] core/muxing: Flatten `StreamMuxer` interface to `poll_{inbound,outbound,address_change,close}` (#2724) Instead of having a mix of `poll_event`, `poll_outbound` and `poll_close`, we flatten the entire interface of `StreamMuxer` into 4 individual functions: - `poll_inbound` - `poll_outbound` - `poll_address_change` - `poll_close` This design is closer to the design of other async traits like `AsyncRead` and `AsyncWrite`. It also allows us to delete the `StreamMuxerEvent`. --- Cargo.toml | 20 +- core/CHANGELOG.md | 8 +- core/Cargo.toml | 2 +- core/src/either.rs | 65 ++---- core/src/muxing.rs | 90 +-------- core/src/muxing/boxed.rs | 104 +++------- core/src/muxing/singleton.rs | 55 ++---- core/src/transport/upgrade.rs | 1 - misc/keygen/Cargo.toml | 2 +- misc/metrics/CHANGELOG.md | 2 + misc/metrics/Cargo.toml | 2 +- muxers/mplex/CHANGELOG.md | 4 + muxers/mplex/Cargo.toml | 4 +- muxers/mplex/benches/split_send_size.rs | 11 +- muxers/mplex/src/lib.rs | 42 ++-- muxers/mplex/tests/async_write.rs | 15 +- muxers/mplex/tests/two_peers.rs | 35 +--- muxers/yamux/CHANGELOG.md | 4 + muxers/yamux/Cargo.toml | 4 +- muxers/yamux/src/lib.rs | 48 ++--- protocols/autonat/CHANGELOG.md | 2 + protocols/autonat/Cargo.toml | 2 +- protocols/dcutr/CHANGELOG.md | 2 + protocols/dcutr/Cargo.toml | 2 +- protocols/floodsub/CHANGELOG.md | 2 + protocols/floodsub/Cargo.toml | 2 +- protocols/gossipsub/CHANGELOG.md | 2 + protocols/gossipsub/Cargo.toml | 2 +- protocols/identify/CHANGELOG.md | 2 + protocols/identify/Cargo.toml | 2 +- protocols/kad/CHANGELOG.md | 2 + protocols/kad/Cargo.toml | 2 +- protocols/mdns/CHANGELOG.md | 2 + protocols/mdns/Cargo.toml | 2 +- protocols/ping/CHANGELOG.md | 2 + protocols/ping/Cargo.toml | 2 +- protocols/relay/CHANGELOG.md | 2 + protocols/relay/Cargo.toml | 2 +- protocols/rendezvous/CHANGELOG.md | 2 + protocols/rendezvous/Cargo.toml | 2 +- protocols/request-response/CHANGELOG.md | 2 + protocols/request-response/Cargo.toml | 2 +- swarm/CHANGELOG.md | 2 + swarm/Cargo.toml | 2 +- swarm/src/connection.rs | 73 ++++--- swarm/src/connection/substream.rs | 252 ------------------------ transports/deflate/CHANGELOG.md | 4 + transports/deflate/Cargo.toml | 4 +- transports/dns/CHANGELOG.md | 4 + transports/dns/Cargo.toml | 4 +- transports/noise/CHANGELOG.md | 4 + transports/noise/Cargo.toml | 4 +- transports/plaintext/CHANGELOG.md | 4 + transports/plaintext/Cargo.toml | 4 +- transports/tcp/Cargo.toml | 2 +- transports/uds/CHANGELOG.md | 4 + transports/uds/Cargo.toml | 4 +- transports/wasm-ext/CHANGELOG.md | 4 + transports/wasm-ext/Cargo.toml | 4 +- transports/websocket/CHANGELOG.md | 4 + transports/websocket/Cargo.toml | 4 +- 61 files changed, 267 insertions(+), 682 deletions(-) delete mode 100644 swarm/src/connection/substream.rs diff --git a/Cargo.toml b/Cargo.toml index c12144717c2..9e6d6ea4786 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,25 +78,25 @@ instant = "0.1.11" # Explicit dependency to be used in `wasm-bindgen` feature lazy_static = "1.2" libp2p-autonat = { version = "0.6.0", path = "protocols/autonat", optional = true } -libp2p-core = { version = "0.34.0", path = "core", default-features = false } +libp2p-core = { version = "0.35.0", path = "core", default-features = false } libp2p-dcutr = { version = "0.5.0", path = "protocols/dcutr", optional = true } libp2p-floodsub = { version = "0.38.0", path = "protocols/floodsub", optional = true } libp2p-identify = { version = "0.38.0", path = "protocols/identify", optional = true } libp2p-kad = { version = "0.39.0", path = "protocols/kad", optional = true } libp2p-metrics = { version = "0.8.0", path = "misc/metrics", optional = true } -libp2p-mplex = { version = "0.34.0", path = "muxers/mplex", optional = true } -libp2p-noise = { version = "0.37.0", path = "transports/noise", optional = true } +libp2p-mplex = { version = "0.35.0", path = "muxers/mplex", optional = true } +libp2p-noise = { version = "0.38.0", path = "transports/noise", optional = true } libp2p-ping = { version = "0.38.0", path = "protocols/ping", optional = true } -libp2p-plaintext = { version = "0.34.0", path = "transports/plaintext", optional = true } +libp2p-plaintext = { version = "0.35.0", path = "transports/plaintext", optional = true } libp2p-pnet = { version = "0.22.0", path = "transports/pnet", optional = true } libp2p-relay = { version = "0.11.0", path = "protocols/relay", optional = true } libp2p-rendezvous = { version = "0.8.0", path = "protocols/rendezvous", optional = true } libp2p-request-response = { version = "0.20.0", path = "protocols/request-response", optional = true } libp2p-swarm = { version = "0.38.0", path = "swarm" } libp2p-swarm-derive = { version = "0.28.0", path = "swarm-derive" } -libp2p-uds = { version = "0.33.0", path = "transports/uds", optional = true } -libp2p-wasm-ext = { version = "0.34.0", path = "transports/wasm-ext", default-features = false, optional = true } -libp2p-yamux = { version = "0.38.0", path = "muxers/yamux", optional = true } +libp2p-uds = { version = "0.34.0", path = "transports/uds", optional = true } +libp2p-wasm-ext = { version = "0.35.0", path = "transports/wasm-ext", default-features = false, optional = true } +libp2p-yamux = { version = "0.39.0", path = "muxers/yamux", optional = true } multiaddr = { version = "0.14.0" } parking_lot = "0.12.0" pin-project = "1.0.0" @@ -104,11 +104,11 @@ rand = "0.7.3" # Explicit dependency to be used in `wasm-bindgen` feature smallvec = "1.6.1" [target.'cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))'.dependencies] -libp2p-deflate = { version = "0.34.0", path = "transports/deflate", optional = true } -libp2p-dns = { version = "0.34.0", path = "transports/dns", optional = true, default-features = false } +libp2p-deflate = { version = "0.35.0", path = "transports/deflate", optional = true } +libp2p-dns = { version = "0.35.0", path = "transports/dns", optional = true, default-features = false } libp2p-mdns = { version = "0.39.0", path = "protocols/mdns", optional = true } libp2p-tcp = { version = "0.34.0", path = "transports/tcp", default-features = false, optional = true } -libp2p-websocket = { version = "0.36.0", path = "transports/websocket", optional = true } +libp2p-websocket = { version = "0.37.0", path = "transports/websocket", optional = true } [target.'cfg(not(target_os = "unknown"))'.dependencies] libp2p-gossipsub = { version = "0.40.0", path = "protocols/gossipsub", optional = true } diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 442499f118a..0102096d780 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,6 +1,12 @@ +# 0.35.0 [unreleased] + +- Remove `StreamMuxer::poll_event` in favor of individual functions: `poll_inbound`, `poll_outbound` + and `poll_address_change`. Consequently, `StreamMuxerEvent` is also removed. See [PR 2724]. + +[PR 2724]: https://github.com/libp2p/rust-libp2p/pull/2724 + # 0.34.0 -- Introduce `StreamMuxerEvent::map_inbound_stream`. See [PR 2691]. - Remove `{read,write,flush,shutdown,destroy}_substream` functions from `StreamMuxer` trait in favor of forcing `StreamMuxer::Substream` to implement `AsyncRead + AsyncWrite`. See [PR 2707]. - Replace `Into` bound on `StreamMuxer::Error` with `std::error::Error`. See [PR 2710]. diff --git a/core/Cargo.toml b/core/Cargo.toml index deb6479e433..386dff09669 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-core" edition = "2021" rust-version = "1.56.1" description = "Core traits and structs of libp2p" -version = "0.34.0" +version = "0.35.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" diff --git a/core/src/either.rs b/core/src/either.rs index bce6e05aadf..4b5c20b2929 100644 --- a/core/src/either.rs +++ b/core/src/either.rs @@ -19,7 +19,7 @@ // DEALINGS IN THE SOFTWARE. use crate::{ - muxing::{StreamMuxer, StreamMuxerEvent}, + muxing::StreamMuxer, transport::{ListenerId, Transport, TransportError, TransportEvent}, Multiaddr, ProtocolName, }; @@ -202,60 +202,38 @@ where B: StreamMuxer, { type Substream = EitherOutput; - type OutboundSubstream = EitherOutbound; type Error = EitherError; - fn poll_event( - &self, - cx: &mut Context<'_>, - ) -> Poll, Self::Error>> { + fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll> { match self { EitherOutput::First(inner) => inner - .poll_event(cx) - .map_err(EitherError::A) - .map_ok(|event| event.map_inbound_stream(EitherOutput::First)), + .poll_inbound(cx) + .map_ok(EitherOutput::First) + .map_err(EitherError::A), EitherOutput::Second(inner) => inner - .poll_event(cx) - .map_err(EitherError::B) - .map_ok(|event| event.map_inbound_stream(EitherOutput::Second)), + .poll_inbound(cx) + .map_ok(EitherOutput::Second) + .map_err(EitherError::B), } } - fn open_outbound(&self) -> Self::OutboundSubstream { + fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll> { match self { - EitherOutput::First(inner) => EitherOutbound::A(inner.open_outbound()), - EitherOutput::Second(inner) => EitherOutbound::B(inner.open_outbound()), - } - } - - fn poll_outbound( - &self, - cx: &mut Context<'_>, - substream: &mut Self::OutboundSubstream, - ) -> Poll> { - match (self, substream) { - (EitherOutput::First(ref inner), EitherOutbound::A(ref mut substream)) => inner - .poll_outbound(cx, substream) - .map(|p| p.map(EitherOutput::First)) + EitherOutput::First(inner) => inner + .poll_outbound(cx) + .map_ok(EitherOutput::First) .map_err(EitherError::A), - (EitherOutput::Second(ref inner), EitherOutbound::B(ref mut substream)) => inner - .poll_outbound(cx, substream) - .map(|p| p.map(EitherOutput::Second)) + EitherOutput::Second(inner) => inner + .poll_outbound(cx) + .map_ok(EitherOutput::Second) .map_err(EitherError::B), - _ => panic!("Wrong API usage"), } } - fn destroy_outbound(&self, substream: Self::OutboundSubstream) { + fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll> { match self { - EitherOutput::First(inner) => match substream { - EitherOutbound::A(substream) => inner.destroy_outbound(substream), - _ => panic!("Wrong API usage"), - }, - EitherOutput::Second(inner) => match substream { - EitherOutbound::B(substream) => inner.destroy_outbound(substream), - _ => panic!("Wrong API usage"), - }, + EitherOutput::First(inner) => inner.poll_address_change(cx).map_err(EitherError::A), + EitherOutput::Second(inner) => inner.poll_address_change(cx).map_err(EitherError::B), } } @@ -267,13 +245,6 @@ where } } -#[derive(Debug, Copy, Clone)] -#[must_use = "futures do nothing unless polled"] -pub enum EitherOutbound { - A(A::OutboundSubstream), - B(B::OutboundSubstream), -} - /// Implements `Future` and dispatches all method calls to either `First` or `Second`. #[pin_project(project = EitherFutureProj)] #[derive(Debug, Copy, Clone)] diff --git a/core/src/muxing.rs b/core/src/muxing.rs index 050d8d1bd35..a2bdfa80b37 100644 --- a/core/src/muxing.rs +++ b/core/src/muxing.rs @@ -63,62 +63,25 @@ mod singleton; /// Provides multiplexing for a connection by allowing users to open substreams. /// /// A substream created by a [`StreamMuxer`] is a type that implements [`AsyncRead`] and [`AsyncWrite`]. -/// -/// Inbound substreams are reported via [`StreamMuxer::poll_event`]. -/// Outbound substreams can be opened via [`StreamMuxer::open_outbound`] and subsequent polling via -/// [`StreamMuxer::poll_outbound`]. +/// The [`StreamMuxer`] itself is modelled closely after [`AsyncWrite`]. It features `poll`-style +/// functions that allow the implementation to make progress on various tasks. pub trait StreamMuxer { /// Type of the object that represents the raw substream where data can be read and written. type Substream: AsyncRead + AsyncWrite; - /// Future that will be resolved when the outgoing substream is open. - type OutboundSubstream; - /// Error type of the muxer type Error: std::error::Error; - /// Polls for a connection-wide event. - /// - /// This function behaves the same as a `Stream`. - /// - /// If `Pending` is returned, then the current task will be notified once the muxer - /// is ready to be polled, similar to the API of `Stream::poll()`. - /// Only the latest task that was used to call this method may be notified. - /// - /// It is permissible and common to use this method to perform background - /// work, such as processing incoming packets and polling timers. - /// - /// An error can be generated if the connection has been closed. - fn poll_event( - &self, - cx: &mut Context<'_>, - ) -> Poll, Self::Error>>; + /// Poll for new inbound substreams. + fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll>; - /// Opens a new outgoing substream, and produces the equivalent to a future that will be - /// resolved when it becomes available. - /// - /// The API of `OutboundSubstream` is totally opaque, and the object can only be interfaced - /// through the methods on the `StreamMuxer` trait. - fn open_outbound(&self) -> Self::OutboundSubstream; + /// Poll for a new, outbound substream. + fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll>; - /// Polls the outbound substream. - /// - /// If `Pending` is returned, then the current task will be notified once the substream - /// is ready to be polled, similar to the API of `Future::poll()`. - /// However, for each individual outbound substream, only the latest task that was used to - /// call this method may be notified. + /// Poll for an address change of the underlying connection. /// - /// May panic or produce an undefined result if an earlier polling of the same substream - /// returned `Ready` or `Err`. - fn poll_outbound( - &self, - cx: &mut Context<'_>, - s: &mut Self::OutboundSubstream, - ) -> Poll>; - - /// Destroys an outbound substream future. Use this after the outbound substream has finished, - /// or if you want to interrupt it. - fn destroy_outbound(&self, s: Self::OutboundSubstream); + /// Not all implementations may support this feature. + fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll>; /// Closes this `StreamMuxer`. /// @@ -132,38 +95,3 @@ pub trait StreamMuxer { /// > immediately dropping the muxer. fn poll_close(&self, cx: &mut Context<'_>) -> Poll>; } - -/// Event about a connection, reported by an implementation of [`StreamMuxer`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum StreamMuxerEvent { - /// Remote has opened a new substream. Contains the substream in question. - InboundSubstream(T), - - /// Address to the remote has changed. The previous one is now obsolete. - /// - /// > **Note**: This can for example happen when using the QUIC protocol, where the two nodes - /// > can change their IP address while retaining the same QUIC connection. - AddressChange(Multiaddr), -} - -impl StreamMuxerEvent { - /// If `self` is a [`StreamMuxerEvent::InboundSubstream`], returns the content. Otherwise - /// returns `None`. - pub fn into_inbound_substream(self) -> Option { - if let StreamMuxerEvent::InboundSubstream(s) = self { - Some(s) - } else { - None - } - } - - /// Map the stream within [`StreamMuxerEvent::InboundSubstream`] to a new type. - pub fn map_inbound_stream(self, map: impl FnOnce(T) -> O) -> StreamMuxerEvent { - match self { - StreamMuxerEvent::InboundSubstream(stream) => { - StreamMuxerEvent::InboundSubstream(map(stream)) - } - StreamMuxerEvent::AddressChange(addr) => StreamMuxerEvent::AddressChange(addr), - } - } -} diff --git a/core/src/muxing/boxed.rs b/core/src/muxing/boxed.rs index ad39ef0532d..80753813dcb 100644 --- a/core/src/muxing/boxed.rs +++ b/core/src/muxing/boxed.rs @@ -1,23 +1,16 @@ -use crate::muxing::StreamMuxerEvent; use crate::StreamMuxer; -use fnv::FnvHashMap; -use futures::{ready, AsyncRead, AsyncWrite}; -use parking_lot::Mutex; +use futures::{AsyncRead, AsyncWrite}; +use multiaddr::Multiaddr; use std::error::Error; use std::fmt; use std::io; use std::io::{IoSlice, IoSliceMut}; use std::pin::Pin; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::task::{Context, Poll}; /// Abstract `StreamMuxer`. pub struct StreamMuxerBox { - inner: Box< - dyn StreamMuxer - + Send - + Sync, - >, + inner: Box + Send + Sync>, } /// Abstract type for asynchronous reading and writing. @@ -31,8 +24,6 @@ where T: StreamMuxer, { inner: T, - outbound: Mutex>, - next_outbound: AtomicUsize, } impl StreamMuxer for Wrap @@ -42,53 +33,29 @@ where T::Error: Send + Sync + 'static, { type Substream = SubstreamBox; - type OutboundSubstream = usize; // TODO: use a newtype type Error = io::Error; #[inline] - fn poll_event( - &self, - cx: &mut Context<'_>, - ) -> Poll, Self::Error>> { - let event = ready!(self.inner.poll_event(cx).map_err(into_io_error)?) - .map_inbound_stream(SubstreamBox::new); - - Poll::Ready(Ok(event)) - } - - #[inline] - fn open_outbound(&self) -> Self::OutboundSubstream { - let outbound = self.inner.open_outbound(); - let id = self.next_outbound.fetch_add(1, Ordering::Relaxed); - self.outbound.lock().insert(id, outbound); - id + fn poll_close(&self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_close(cx).map_err(into_io_error) } - #[inline] - fn poll_outbound( - &self, - cx: &mut Context<'_>, - substream: &mut Self::OutboundSubstream, - ) -> Poll> { - let mut list = self.outbound.lock(); - let stream = ready!(self - .inner - .poll_outbound(cx, list.get_mut(substream).unwrap()) - .map_err(into_io_error)?); - - Poll::Ready(Ok(SubstreamBox::new(stream))) + fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll> { + self.inner + .poll_inbound(cx) + .map_ok(SubstreamBox::new) + .map_err(into_io_error) } - #[inline] - fn destroy_outbound(&self, substream: Self::OutboundSubstream) { - let mut list = self.outbound.lock(); + fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll> { self.inner - .destroy_outbound(list.remove(&substream).unwrap()) + .poll_outbound(cx) + .map_ok(SubstreamBox::new) + .map_err(into_io_error) } - #[inline] - fn poll_close(&self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_close(cx).map_err(into_io_error) + fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_address_change(cx).map_err(into_io_error) } } @@ -104,15 +71,10 @@ impl StreamMuxerBox { pub fn new(muxer: T) -> StreamMuxerBox where T: StreamMuxer + Send + Sync + 'static, - T::OutboundSubstream: Send, T::Substream: Send + Unpin + 'static, T::Error: Send + Sync + 'static, { - let wrap = Wrap { - inner: muxer, - outbound: Mutex::new(Default::default()), - next_outbound: AtomicUsize::new(0), - }; + let wrap = Wrap { inner: muxer }; StreamMuxerBox { inner: Box::new(wrap), @@ -122,39 +84,23 @@ impl StreamMuxerBox { impl StreamMuxer for StreamMuxerBox { type Substream = SubstreamBox; - type OutboundSubstream = usize; // TODO: use a newtype type Error = io::Error; #[inline] - fn poll_event( - &self, - cx: &mut Context<'_>, - ) -> Poll, Self::Error>> { - self.inner.poll_event(cx) + fn poll_close(&self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_close(cx) } - #[inline] - fn open_outbound(&self) -> Self::OutboundSubstream { - self.inner.open_outbound() + fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_inbound(cx) } - #[inline] - fn poll_outbound( - &self, - cx: &mut Context<'_>, - s: &mut Self::OutboundSubstream, - ) -> Poll> { - self.inner.poll_outbound(cx, s) + fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_outbound(cx) } - #[inline] - fn destroy_outbound(&self, substream: Self::OutboundSubstream) { - self.inner.destroy_outbound(substream) - } - - #[inline] - fn poll_close(&self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_close(cx) + fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_address_change(cx) } } diff --git a/core/src/muxing/singleton.rs b/core/src/muxing/singleton.rs index c461ed00fc3..d67cb5e9825 100644 --- a/core/src/muxing/singleton.rs +++ b/core/src/muxing/singleton.rs @@ -18,12 +18,10 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::{ - connection::Endpoint, - muxing::{StreamMuxer, StreamMuxerEvent}, -}; +use crate::{connection::Endpoint, muxing::StreamMuxer}; use futures::prelude::*; +use multiaddr::Multiaddr; use std::cell::Cell; use std::{io, task::Context, task::Poll}; @@ -52,55 +50,36 @@ impl SingletonMuxer { } } -/// Outbound substream attempt of the `SingletonMuxer`. -pub struct OutboundSubstream {} - impl StreamMuxer for SingletonMuxer where TSocket: AsyncRead + AsyncWrite + Unpin, { type Substream = TSocket; - type OutboundSubstream = OutboundSubstream; type Error = io::Error; - fn poll_event( - &self, - _: &mut Context<'_>, - ) -> Poll, io::Error>> { + fn poll_inbound(&self, _: &mut Context<'_>) -> Poll> { match self.endpoint { - Endpoint::Dialer => return Poll::Pending, - Endpoint::Listener => {} - } - - if let Some(stream) = self.inner.replace(None) { - Poll::Ready(Ok(StreamMuxerEvent::InboundSubstream(stream))) - } else { - Poll::Pending + Endpoint::Dialer => Poll::Pending, + Endpoint::Listener => match self.inner.replace(None) { + None => Poll::Pending, + Some(stream) => Poll::Ready(Ok(stream)), + }, } } - fn open_outbound(&self) -> Self::OutboundSubstream { - OutboundSubstream {} - } - - fn poll_outbound( - &self, - _: &mut Context<'_>, - _: &mut Self::OutboundSubstream, - ) -> Poll> { + fn poll_outbound(&self, _: &mut Context<'_>) -> Poll> { match self.endpoint { - Endpoint::Listener => return Poll::Pending, - Endpoint::Dialer => {} - } - - if let Some(stream) = self.inner.replace(None) { - Poll::Ready(Ok(stream)) - } else { - Poll::Pending + Endpoint::Listener => Poll::Pending, + Endpoint::Dialer => match self.inner.replace(None) { + None => Poll::Pending, + Some(stream) => Poll::Ready(Ok(stream)), + }, } } - fn destroy_outbound(&self, _: Self::OutboundSubstream) {} + fn poll_address_change(&self, _: &mut Context<'_>) -> Poll> { + Poll::Pending + } fn poll_close(&self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) diff --git a/core/src/transport/upgrade.rs b/core/src/transport/upgrade.rs index c872ec955e4..da87fb9dd6a 100644 --- a/core/src/transport/upgrade.rs +++ b/core/src/transport/upgrade.rs @@ -301,7 +301,6 @@ impl Multiplexed { T::Error: Send + Sync, M: StreamMuxer + Send + Sync + 'static, M::Substream: Send + Unpin + 'static, - M::OutboundSubstream: Send + 'static, M::Error: Send + Sync + 'static, { boxed(self.map(|(i, m), _| (i, StreamMuxerBox::new(m)))) diff --git a/misc/keygen/Cargo.toml b/misc/keygen/Cargo.toml index 614aa2e6bf2..4be54014f0a 100644 --- a/misc/keygen/Cargo.toml +++ b/misc/keygen/Cargo.toml @@ -13,5 +13,5 @@ clap = {version = "3.1.6", features = ["derive"]} zeroize = "1" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" -libp2p-core = { path = "../../core", default-features = false, version = "0.34.0"} +libp2p-core = { path = "../../core", default-features = false, version = "0.35.0"} base64 = "0.13.0" diff --git a/misc/metrics/CHANGELOG.md b/misc/metrics/CHANGELOG.md index 1b3053eaae7..c9cc21a06f1 100644 --- a/misc/metrics/CHANGELOG.md +++ b/misc/metrics/CHANGELOG.md @@ -14,6 +14,8 @@ - Track number of connected nodes supporting a specific protocol via the identify protocol. See [PR 2734]. +- Update to `libp2p-core` `v0.35.0`. + [PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ # 0.7.0 diff --git a/misc/metrics/Cargo.toml b/misc/metrics/Cargo.toml index f38e192947f..7fdfec733e0 100644 --- a/misc/metrics/Cargo.toml +++ b/misc/metrics/Cargo.toml @@ -19,7 +19,7 @@ relay = ["libp2p-relay"] dcutr = ["libp2p-dcutr"] [dependencies] -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-dcutr = { version = "0.5.0", path = "../../protocols/dcutr", optional = true } libp2p-identify = { version = "0.38.0", path = "../../protocols/identify", optional = true } libp2p-kad = { version = "0.39.0", path = "../../protocols/kad", optional = true } diff --git a/muxers/mplex/CHANGELOG.md b/muxers/mplex/CHANGELOG.md index add3d1ace0d..6b374e1b66c 100644 --- a/muxers/mplex/CHANGELOG.md +++ b/muxers/mplex/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.35.0 [unreleased] + +- Update to `libp2p-core` `v0.35.0` + # 0.34.0 - `Substream` now implements `AsyncRead` and `AsyncWrite`. See [PR 2706]. diff --git a/muxers/mplex/Cargo.toml b/muxers/mplex/Cargo.toml index 3b5a82cd959..ac053a5020f 100644 --- a/muxers/mplex/Cargo.toml +++ b/muxers/mplex/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-mplex" edition = "2021" rust-version = "1.56.1" description = "Mplex multiplexing protocol for libp2p" -version = "0.34.0" +version = "0.35.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] bytes = "1" futures = "0.3.1" asynchronous-codec = "0.6" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } log = "0.4" nohash-hasher = "0.2" parking_lot = "0.12" diff --git a/muxers/mplex/benches/split_send_size.rs b/muxers/mplex/benches/split_send_size.rs index f5bf771d1ab..d536edf4c8a 100644 --- a/muxers/mplex/benches/split_send_size.rs +++ b/muxers/mplex/benches/split_send_size.rs @@ -114,11 +114,9 @@ fn run( } transport::TransportEvent::Incoming { upgrade, .. } => { let (_peer, conn) = upgrade.await.unwrap(); - let mut s = poll_fn(|cx| conn.poll_event(cx)) + let mut s = poll_fn(|cx| conn.poll_inbound(cx)) .await - .expect("unexpected error") - .into_inbound_substream() - .expect("Unexpected muxer event"); + .expect("unexpected error"); let mut buf = vec![0u8; payload_len]; let mut off = 0; @@ -143,10 +141,7 @@ fn run( let sender = async move { let addr = addr_receiver.await.unwrap(); let (_peer, conn) = sender_trans.dial(addr).unwrap().await.unwrap(); - let mut handle = conn.open_outbound(); - let mut stream = poll_fn(|cx| conn.poll_outbound(cx, &mut handle)) - .await - .unwrap(); + let mut stream = poll_fn(|cx| conn.poll_outbound(cx)).await.unwrap(); let mut off = 0; loop { let n = poll_fn(|cx| Pin::new(&mut stream).poll_write(cx, &payload[off..])) diff --git a/muxers/mplex/src/lib.rs b/muxers/mplex/src/lib.rs index 80b1db16481..59b38db1156 100644 --- a/muxers/mplex/src/lib.rs +++ b/muxers/mplex/src/lib.rs @@ -28,9 +28,8 @@ use bytes::Bytes; use codec::LocalStreamId; use futures::{future, prelude::*, ready}; use libp2p_core::{ - muxing::StreamMuxerEvent, upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}, - StreamMuxer, + Multiaddr, StreamMuxer, }; use parking_lot::Mutex; use std::{cmp, iter, pin::Pin, sync::Arc, task::Context, task::Poll}; @@ -75,9 +74,6 @@ where } /// Multiplexer. Implements the `StreamMuxer` trait. -/// -/// This implementation isn't capable of detecting when the underlying socket changes its address, -/// and no [`StreamMuxerEvent::AddressChange`] event is ever emitted. pub struct Multiplex { io: Arc>>, } @@ -87,33 +83,24 @@ where C: AsyncRead + AsyncWrite + Unpin, { type Substream = Substream; - type OutboundSubstream = OutboundSubstream; type Error = io::Error; - fn poll_event( - &self, - cx: &mut Context<'_>, - ) -> Poll>> { - let stream_id = ready!(self.io.lock().poll_next_stream(cx))?; - let stream = Substream::new(stream_id, self.io.clone()); - Poll::Ready(Ok(StreamMuxerEvent::InboundSubstream(stream))) + fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll> { + self.io + .lock() + .poll_next_stream(cx) + .map_ok(|stream_id| Substream::new(stream_id, self.io.clone())) } - fn open_outbound(&self) -> Self::OutboundSubstream { - OutboundSubstream {} + fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll> { + self.io + .lock() + .poll_open_stream(cx) + .map_ok(|stream_id| Substream::new(stream_id, self.io.clone())) } - fn poll_outbound( - &self, - cx: &mut Context<'_>, - _: &mut Self::OutboundSubstream, - ) -> Poll> { - let stream_id = ready!(self.io.lock().poll_open_stream(cx))?; - Poll::Ready(Ok(Substream::new(stream_id, self.io.clone()))) - } - - fn destroy_outbound(&self, _substream: Self::OutboundSubstream) { - // Nothing to do, since `open_outbound` creates no new local state. + fn poll_address_change(&self, _: &mut Context<'_>) -> Poll> { + Poll::Pending } fn poll_close(&self, cx: &mut Context<'_>) -> Poll> { @@ -121,9 +108,6 @@ where } } -/// Active attempt to open an outbound substream. -pub struct OutboundSubstream {} - impl AsyncRead for Substream where C: AsyncRead + AsyncWrite + Unpin, diff --git a/muxers/mplex/tests/async_write.rs b/muxers/mplex/tests/async_write.rs index 9dbda1a198d..94d69cd7ff1 100644 --- a/muxers/mplex/tests/async_write.rs +++ b/muxers/mplex/tests/async_write.rs @@ -60,10 +60,7 @@ fn async_write() { .await .unwrap(); - let mut outbound_token = client.open_outbound(); - let mut outbound = poll_fn(|cx| client.poll_outbound(cx, &mut outbound_token)) - .await - .unwrap(); + let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap(); let mut buf = Vec::new(); outbound.read_to_end(&mut buf).await.unwrap(); @@ -76,15 +73,7 @@ fn async_write() { .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); let client = Arc::new(transport.dial(rx.await.unwrap()).unwrap().await.unwrap()); - let mut inbound = loop { - if let Some(s) = poll_fn(|cx| client.poll_event(cx)) - .await - .unwrap() - .into_inbound_substream() - { - break s; - } - }; + let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap(); inbound.write_all(b"hello world").await.unwrap(); // The test consists in making sure that this flushes the substream. diff --git a/muxers/mplex/tests/two_peers.rs b/muxers/mplex/tests/two_peers.rs index 4283452fe07..20812fde55c 100644 --- a/muxers/mplex/tests/two_peers.rs +++ b/muxers/mplex/tests/two_peers.rs @@ -60,10 +60,7 @@ fn client_to_server_outbound() { .await .unwrap(); - let mut outbound_token = client.open_outbound(); - let mut outbound = poll_fn(|cx| client.poll_outbound(cx, &mut outbound_token)) - .await - .unwrap(); + let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap(); let mut buf = Vec::new(); outbound.read_to_end(&mut buf).await.unwrap(); @@ -77,15 +74,7 @@ fn client_to_server_outbound() { .boxed(); let client = Arc::new(transport.dial(rx.await.unwrap()).unwrap().await.unwrap()); - let mut inbound = loop { - if let Some(s) = poll_fn(|cx| client.poll_event(cx)) - .await - .unwrap() - .into_inbound_substream() - { - break s; - } - }; + let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap(); inbound.write_all(b"hello world").await.unwrap(); inbound.close().await.unwrap(); @@ -131,15 +120,7 @@ fn client_to_server_inbound() { .unwrap(), ); - let mut inbound = loop { - if let Some(s) = poll_fn(|cx| client.poll_event(cx)) - .await - .unwrap() - .into_inbound_substream() - { - break s; - } - }; + let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap(); let mut buf = Vec::new(); inbound.read_to_end(&mut buf).await.unwrap(); @@ -154,10 +135,7 @@ fn client_to_server_inbound() { let client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); - let mut outbound_token = client.open_outbound(); - let mut outbound = poll_fn(|cx| client.poll_outbound(cx, &mut outbound_token)) - .await - .unwrap(); + let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap(); outbound.write_all(b"hello world").await.unwrap(); outbound.close().await.unwrap(); @@ -199,10 +177,7 @@ fn protocol_not_match() { .await .unwrap(); - let mut outbound_token = client.open_outbound(); - let mut outbound = poll_fn(|cx| client.poll_outbound(cx, &mut outbound_token)) - .await - .unwrap(); + let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap(); let mut buf = Vec::new(); outbound.read_to_end(&mut buf).await.unwrap(); diff --git a/muxers/yamux/CHANGELOG.md b/muxers/yamux/CHANGELOG.md index 95d01fbbfcd..e8eded11836 100644 --- a/muxers/yamux/CHANGELOG.md +++ b/muxers/yamux/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.39.0 [unreleased] + +- Update to `libp2p-core` `v0.35.0` + # 0.38.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/muxers/yamux/Cargo.toml b/muxers/yamux/Cargo.toml index a7c55f08949..02dfb832d8d 100644 --- a/muxers/yamux/Cargo.toml +++ b/muxers/yamux/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-yamux" edition = "2021" rust-version = "1.56.1" description = "Yamux multiplexing protocol for libp2p" -version = "0.38.0" +version = "0.39.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"] [dependencies] futures = "0.3.1" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } parking_lot = "0.12" thiserror = "1.0" yamux = "0.10.0" diff --git a/muxers/yamux/src/lib.rs b/muxers/yamux/src/lib.rs index 8eb6fb3e895..a06e7934cf0 100644 --- a/muxers/yamux/src/lib.rs +++ b/muxers/yamux/src/lib.rs @@ -24,11 +24,11 @@ use futures::{ future, prelude::*, - ready, stream::{BoxStream, LocalBoxStream}, }; -use libp2p_core::muxing::{StreamMuxer, StreamMuxerEvent}; +use libp2p_core::muxing::StreamMuxer; use libp2p_core::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}; +use libp2p_core::Multiaddr; use parking_lot::Mutex; use std::{ fmt, io, iter, mem, @@ -36,6 +36,7 @@ use std::{ task::{Context, Poll}, }; use thiserror::Error; +use yamux::ConnectionError; /// A Yamux connection. pub struct Yamux(Mutex>); @@ -97,44 +98,35 @@ where pub type YamuxResult = Result; -/// > **Note**: This implementation never emits [`StreamMuxerEvent::AddressChange`] events. impl StreamMuxer for Yamux where S: Stream> + Unpin, { type Substream = yamux::Stream; - type OutboundSubstream = OpenSubstreamToken; type Error = YamuxError; - fn poll_event( - &self, - c: &mut Context<'_>, - ) -> Poll>> { - let mut inner = self.0.lock(); - match ready!(inner.incoming.poll_next_unpin(c)) { - Some(Ok(s)) => Poll::Ready(Ok(StreamMuxerEvent::InboundSubstream(s))), - Some(Err(e)) => Poll::Ready(Err(e)), - None => Poll::Ready(Err(yamux::ConnectionError::Closed.into())), - } - } - - fn open_outbound(&self) -> Self::OutboundSubstream { - OpenSubstreamToken(()) + fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll> { + self.0 + .lock() + .incoming + .poll_next_unpin(cx) + .map(|maybe_stream| { + let stream = maybe_stream + .transpose()? + .ok_or(YamuxError(ConnectionError::Closed))?; + + Ok(stream) + }) } - fn poll_outbound( - &self, - c: &mut Context<'_>, - _: &mut OpenSubstreamToken, - ) -> Poll> { - let mut inner = self.0.lock(); - Pin::new(&mut inner.control) - .poll_open_stream(c) + fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.0.lock().control) + .poll_open_stream(cx) .map_err(YamuxError) } - fn destroy_outbound(&self, _: Self::OutboundSubstream) { - self.0.lock().control.abort_open_stream() + fn poll_address_change(&self, _: &mut Context<'_>) -> Poll> { + Poll::Pending } fn poll_close(&self, c: &mut Context<'_>) -> Poll> { diff --git a/protocols/autonat/CHANGELOG.md b/protocols/autonat/CHANGELOG.md index eafaecff2a5..0c48b41951b 100644 --- a/protocols/autonat/CHANGELOG.md +++ b/protocols/autonat/CHANGELOG.md @@ -4,6 +4,8 @@ - Update to `libp2p-request-response` `v0.20.0`. +- Update to `libp2p-core` `v0.35.0`. + # 0.5.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/autonat/Cargo.toml b/protocols/autonat/Cargo.toml index 9e0d272785d..44f3c2b894d 100644 --- a/protocols/autonat/Cargo.toml +++ b/protocols/autonat/Cargo.toml @@ -18,7 +18,7 @@ async-trait = "0.1" futures = "0.3" futures-timer = "3.0" instant = "0.1" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } libp2p-request-response = { version = "0.20.0", path = "../request-response" } log = "0.4" diff --git a/protocols/dcutr/CHANGELOG.md b/protocols/dcutr/CHANGELOG.md index 0416de5e9cb..f740b188455 100644 --- a/protocols/dcutr/CHANGELOG.md +++ b/protocols/dcutr/CHANGELOG.md @@ -4,6 +4,8 @@ - Expose `PROTOCOL_NAME`. See [PR 2734]. +- Update to `libp2p-core` `v0.35.0`. + [PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ # 0.4.0 diff --git a/protocols/dcutr/Cargo.toml b/protocols/dcutr/Cargo.toml index 1786412cadf..6f8c4c284fd 100644 --- a/protocols/dcutr/Cargo.toml +++ b/protocols/dcutr/Cargo.toml @@ -17,7 +17,7 @@ either = "1.6.0" futures = "0.3.1" futures-timer = "3.0" instant = "0.1.11" -libp2p-core = { version = "0.34.0", path = "../../core" } +libp2p-core = { version = "0.35.0", path = "../../core" } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4" prost-codec = { version = "0.1", path = "../../misc/prost-codec" } diff --git a/protocols/floodsub/CHANGELOG.md b/protocols/floodsub/CHANGELOG.md index 491c87b99b5..89d4dd22b16 100644 --- a/protocols/floodsub/CHANGELOG.md +++ b/protocols/floodsub/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.38.0`. +- Update to `libp2p-core` `v0.35.0`. + # 0.37.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/floodsub/Cargo.toml b/protocols/floodsub/Cargo.toml index 2556384f00a..d240ef66d07 100644 --- a/protocols/floodsub/Cargo.toml +++ b/protocols/floodsub/Cargo.toml @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] cuckoofilter = "0.5.0" fnv = "1.0" futures = "0.3.1" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4" prost = "0.10" diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index 0d0a5fa333f..f6b0902d306 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.38.0`. +- Update to `libp2p-core` `v0.35.0`. + # 0.39.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/gossipsub/Cargo.toml b/protocols/gossipsub/Cargo.toml index 5e787076647..e992fb3b9ef 100644 --- a/protocols/gossipsub/Cargo.toml +++ b/protocols/gossipsub/Cargo.toml @@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"] [dependencies] libp2p-swarm = { version = "0.38.0", path = "../../swarm" } -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } bytes = "1.0" byteorder = "1.3.4" fnv = "1.0.7" diff --git a/protocols/identify/CHANGELOG.md b/protocols/identify/CHANGELOG.md index 499af6e3a13..38acfad9b64 100644 --- a/protocols/identify/CHANGELOG.md +++ b/protocols/identify/CHANGELOG.md @@ -4,6 +4,8 @@ - Expose `PROTOCOL_NAME` and `PUSH_PROTOCOL_NAME`. See [PR 2734]. +- Update to `libp2p-core` `v0.35.0`. + [PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ # 0.37.0 diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml index 2fc604d1c25..1b3341df3f8 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] asynchronous-codec = "0.6" futures = "0.3.1" futures-timer = "3.0.2" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4.1" lru = "0.7.2" diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 66730eecde5..6b78a6fcbce 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.38.0`. +- Update to `libp2p-core` `v0.35.0`. + # 0.38.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index 6686664f9b2..f33697f2e32 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -18,7 +18,7 @@ fnv = "1.0" asynchronous-codec = "0.6" futures = "0.3.1" log = "0.4" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } prost = "0.10" rand = "0.7.2" diff --git a/protocols/mdns/CHANGELOG.md b/protocols/mdns/CHANGELOG.md index 320f8b13a2e..1bf4be8f6ae 100644 --- a/protocols/mdns/CHANGELOG.md +++ b/protocols/mdns/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.38.0`. +- Update to `libp2p-core` `v0.35.0`. + # 0.38.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/mdns/Cargo.toml b/protocols/mdns/Cargo.toml index f97c185030a..eb32b7e9426 100644 --- a/protocols/mdns/Cargo.toml +++ b/protocols/mdns/Cargo.toml @@ -17,7 +17,7 @@ dns-parser = "0.8.0" futures = "0.3.13" if-watch = "1.0.0" lazy_static = "1.4.0" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4.14" rand = "0.8.3" diff --git a/protocols/ping/CHANGELOG.md b/protocols/ping/CHANGELOG.md index af9bb0a9690..e14934fe7a2 100644 --- a/protocols/ping/CHANGELOG.md +++ b/protocols/ping/CHANGELOG.md @@ -4,6 +4,8 @@ - Expose `PROTOCOL_NAME`. See [PR 2734]. +- Update to `libp2p-core` `v0.35.0`. + [PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ # 0.37.0 diff --git a/protocols/ping/Cargo.toml b/protocols/ping/Cargo.toml index 741cbf05fbc..14984332db7 100644 --- a/protocols/ping/Cargo.toml +++ b/protocols/ping/Cargo.toml @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] futures = "0.3.1" futures-timer = "3.0.2" instant = "0.1.11" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4.1" rand = "0.7.2" diff --git a/protocols/relay/CHANGELOG.md b/protocols/relay/CHANGELOG.md index f03817080ea..85e066668bc 100644 --- a/protocols/relay/CHANGELOG.md +++ b/protocols/relay/CHANGELOG.md @@ -4,6 +4,8 @@ - Expose `HOP_PROTOCOL_NAME` and `STOP_PROTOCOL_NAME`. See [PR 2734]. +- Update to `libp2p-core` `v0.35.0`. + [PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ # 0.10.0 diff --git a/protocols/relay/Cargo.toml b/protocols/relay/Cargo.toml index 97d29ebdfd0..817025842f8 100644 --- a/protocols/relay/Cargo.toml +++ b/protocols/relay/Cargo.toml @@ -17,7 +17,7 @@ either = "1.6.0" futures = "0.3.1" futures-timer = "3" instant = "0.1.11" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4" pin-project = "1" diff --git a/protocols/rendezvous/CHANGELOG.md b/protocols/rendezvous/CHANGELOG.md index 11120e0be1b..c087f77b393 100644 --- a/protocols/rendezvous/CHANGELOG.md +++ b/protocols/rendezvous/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.38.0`. +- Update to `libp2p-core` `v0.35.0`. + # 0.7.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/rendezvous/Cargo.toml b/protocols/rendezvous/Cargo.toml index b8d81a87e20..745285b91bd 100644 --- a/protocols/rendezvous/Cargo.toml +++ b/protocols/rendezvous/Cargo.toml @@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"] [dependencies] asynchronous-codec = "0.6" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } prost = "0.10" void = "1" diff --git a/protocols/request-response/CHANGELOG.md b/protocols/request-response/CHANGELOG.md index 8acc422ee40..bf556496fc1 100644 --- a/protocols/request-response/CHANGELOG.md +++ b/protocols/request-response/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.38.0`. +- Update to `libp2p-core` `v0.35.0`. + # 0.19.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/request-response/Cargo.toml b/protocols/request-response/Cargo.toml index 010647fe6b3..91f95484f73 100644 --- a/protocols/request-response/Cargo.toml +++ b/protocols/request-response/Cargo.toml @@ -15,7 +15,7 @@ async-trait = "0.1" bytes = "1" futures = "0.3.1" instant = "0.1.11" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4.11" rand = "0.7" diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index 174924889b0..02edf9beef4 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -2,6 +2,8 @@ - Update dial address concurrency factor to `8`, thus dialing up to 8 addresses concurrently for a single connection attempt. See `Swarm::dial_concurrency_factor` and [PR 2741]. +- Update to `libp2p-core` `v0.35.0`. + [PR 2741]: https://github.com/libp2p/rust-libp2p/pull/2741/ # 0.37.0 diff --git a/swarm/Cargo.toml b/swarm/Cargo.toml index 2953c984368..e2829f80093 100644 --- a/swarm/Cargo.toml +++ b/swarm/Cargo.toml @@ -16,7 +16,7 @@ fnv = "1.0" futures = "0.3.1" futures-timer = "3.0.2" instant = "0.1.11" -libp2p-core = { version = "0.34.0", path = "../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../core", default-features = false } log = "0.4" pin-project = "1.0.0" rand = "0.7" diff --git a/swarm/src/connection.rs b/swarm/src/connection.rs index 733016dceb0..8d29ca53793 100644 --- a/swarm/src/connection.rs +++ b/swarm/src/connection.rs @@ -20,7 +20,6 @@ mod error; mod handler_wrapper; -mod substream; pub(crate) mod pool; @@ -30,18 +29,19 @@ pub use error::{ }; pub use pool::{ConnectionCounters, ConnectionLimits}; pub use pool::{EstablishedConnection, PendingConnection}; -pub use substream::{Close, SubstreamEndpoint}; use crate::handler::ConnectionHandler; use crate::IntoConnectionHandler; +use futures::future::poll_fn; use handler_wrapper::HandlerWrapper; use libp2p_core::connection::ConnectedPoint; use libp2p_core::multiaddr::Multiaddr; use libp2p_core::muxing::StreamMuxerBox; -use libp2p_core::upgrade; use libp2p_core::PeerId; -use std::{error::Error, fmt, pin::Pin, task::Context, task::Poll}; -use substream::{Muxing, SubstreamEvent}; +use libp2p_core::{upgrade, StreamMuxer}; +use std::collections::VecDeque; +use std::future::Future; +use std::{error::Error, fmt, io, pin::Pin, task::Context, task::Poll}; /// Information about a successfully established connection. #[derive(Debug, Clone, PartialEq, Eq)] @@ -52,6 +52,13 @@ pub struct Connected { pub peer_id: PeerId, } +/// Endpoint for a received substream. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum SubstreamEndpoint { + Dialer(TDialInfo), + Listener, +} + /// Event generated by a [`Connection`]. #[derive(Debug, Clone)] pub enum Event { @@ -67,19 +74,22 @@ where THandler: ConnectionHandler, { /// Node that handles the muxing. - muxing: substream::Muxing>, + muxing: StreamMuxerBox, /// Handler that processes substreams. handler: HandlerWrapper, + /// List of "open_info" that is waiting for new outbound substreams. + open_info: VecDeque>, } impl fmt::Debug for Connection where THandler: ConnectionHandler + fmt::Debug, + THandler::OutboundOpenInfo: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Connection") - .field("muxing", &self.muxing) .field("handler", &self.handler) + .field("open_info", &self.open_info) .finish() } } @@ -108,8 +118,9 @@ where max_negotiating_inbound_streams, ); Connection { - muxing: Muxing::new(muxer), + muxing: muxer, handler: wrapped_handler, + open_info: VecDeque::with_capacity(8), } } @@ -120,10 +131,10 @@ where /// Begins an orderly shutdown of the connection, returning the connection /// handler and a `Future` that resolves when connection shutdown is complete. - pub fn close(self) -> (THandler, Close) { + pub fn close(self) -> (THandler, impl Future>) { ( self.handler.into_connection_handler(), - self.muxing.close().0, + poll_fn(move |cx| self.muxing.poll_close(cx)), ) } @@ -138,38 +149,38 @@ where match self.handler.poll(cx)? { Poll::Pending => {} Poll::Ready(handler_wrapper::Event::OutboundSubstreamRequest(user_data)) => { - self.muxing.open_substream(user_data); - continue; + self.open_info.push_back(user_data); + continue; // Poll handler until exhausted. } Poll::Ready(handler_wrapper::Event::Custom(event)) => { return Poll::Ready(Ok(Event::Handler(event))); } } - // Perform I/O on the connection through the muxer, informing the handler - // of new substreams. - match self.muxing.poll(cx)? { - Poll::Pending => {} - Poll::Ready(SubstreamEvent::InboundSubstream { substream }) => { - self.handler - .inject_substream(substream, SubstreamEndpoint::Listener); - continue; - } - Poll::Ready(SubstreamEvent::OutboundSubstream { - user_data, - substream, - }) => { + if !self.open_info.is_empty() { + if let Poll::Ready(substream) = self.muxing.poll_outbound(cx)? { + let user_data = self + .open_info + .pop_front() + .expect("`open_info` is not empty"); let endpoint = SubstreamEndpoint::Dialer(user_data); self.handler.inject_substream(substream, endpoint); - continue; - } - Poll::Ready(SubstreamEvent::AddressChange(address)) => { - self.handler.inject_address_change(&address); - return Poll::Ready(Ok(Event::AddressChange(address))); + continue; // Go back to the top, handler can potentially make progress again. } } - return Poll::Pending; + if let Poll::Ready(substream) = self.muxing.poll_inbound(cx)? { + self.handler + .inject_substream(substream, SubstreamEndpoint::Listener); + continue; // Go back to the top, handler can potentially make progress again. + } + + if let Poll::Ready(address) = self.muxing.poll_address_change(cx)? { + self.handler.inject_address_change(&address); + return Poll::Ready(Ok(Event::AddressChange(address))); + } + + return Poll::Pending; // Nothing can make progress, return `Pending`. } } } diff --git a/swarm/src/connection/substream.rs b/swarm/src/connection/substream.rs deleted file mode 100644 index 47d5d315b20..00000000000 --- a/swarm/src/connection/substream.rs +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -use futures::prelude::*; -use libp2p_core::multiaddr::Multiaddr; -use libp2p_core::muxing::{StreamMuxer, StreamMuxerEvent}; -use smallvec::SmallVec; -use std::sync::Arc; -use std::{fmt, pin::Pin, task::Context, task::Poll}; - -/// Endpoint for a received substream. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum SubstreamEndpoint { - Dialer(TDialInfo), - Listener, -} - -/// Implementation of `Stream` that handles substream multiplexing. -/// -/// The stream will receive substreams and can be used to open new outgoing substreams. Destroying -/// the `Muxing` will **not** close the existing substreams. -/// -/// The stream will close once both the inbound and outbound channels are closed, and no more -/// outbound substream attempt is pending. -pub struct Muxing -where - TMuxer: StreamMuxer, -{ - /// The muxer used to manage substreams. - inner: Arc, - /// List of substreams we are currently opening. - outbound_substreams: SmallVec<[(TUserData, TMuxer::OutboundSubstream); 8]>, -} - -/// Future that signals the remote that we have closed the connection. -pub struct Close { - /// Muxer to close. - muxer: Arc, -} - -/// Event that can happen on the `Muxing`. -pub enum SubstreamEvent -where - TMuxer: StreamMuxer, -{ - /// A new inbound substream arrived. - InboundSubstream { - /// The newly-opened substream. Will return EOF of an error if the `Muxing` is - /// destroyed or `close_graceful` is called. - substream: TMuxer::Substream, - }, - - /// An outbound substream has successfully been opened. - OutboundSubstream { - /// User data that has been passed to the `open_substream` method. - user_data: TUserData, - /// The newly-opened substream. Will return EOF of an error if the `Muxing` is - /// destroyed or `close_graceful` is called. - substream: TMuxer::Substream, - }, - - /// Address to the remote has changed. The previous one is now obsolete. - /// - /// > **Note**: This can for example happen when using the QUIC protocol, where the two nodes - /// > can change their IP address while retaining the same QUIC connection. - AddressChange(Multiaddr), -} - -/// Identifier for a substream being opened. -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct OutboundSubstreamId(usize); - -impl Muxing -where - TMuxer: StreamMuxer, -{ - /// Creates a new node events stream. - pub fn new(muxer: TMuxer) -> Self { - Muxing { - inner: Arc::new(muxer), - outbound_substreams: SmallVec::new(), - } - } - - /// Starts the process of opening a new outbound substream. - /// - /// After calling this method, polling the stream should eventually produce either an - /// `OutboundSubstream` event or an `OutboundClosed` event containing the user data that has - /// been passed to this method. - pub fn open_substream(&mut self, user_data: TUserData) { - let raw = self.inner.open_outbound(); - self.outbound_substreams.push((user_data, raw)); - } - - /// Destroys the node stream and returns all the pending outbound substreams, plus an object - /// that signals the remote that we shut down the connection. - #[must_use] - pub fn close(mut self) -> (Close, Vec) { - let substreams = self.cancel_outgoing(); - let close = Close { - muxer: self.inner.clone(), - }; - (close, substreams) - } - - /// Destroys all outbound streams and returns the corresponding user data. - pub fn cancel_outgoing(&mut self) -> Vec { - let mut out = Vec::with_capacity(self.outbound_substreams.len()); - for (user_data, outbound) in self.outbound_substreams.drain(..) { - out.push(user_data); - self.inner.destroy_outbound(outbound); - } - out - } - - /// Provides an API similar to `Future`. - pub fn poll( - &mut self, - cx: &mut Context<'_>, - ) -> Poll, TMuxer::Error>> { - // Polling inbound substream. - match self.inner.poll_event(cx) { - Poll::Ready(Ok(StreamMuxerEvent::InboundSubstream(substream))) => { - return Poll::Ready(Ok(SubstreamEvent::InboundSubstream { substream })); - } - Poll::Ready(Ok(StreamMuxerEvent::AddressChange(addr))) => { - return Poll::Ready(Ok(SubstreamEvent::AddressChange(addr))) - } - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - Poll::Pending => {} - } - - // Polling outbound substreams. - // We remove each element from `outbound_substreams` one by one and add them back. - for n in (0..self.outbound_substreams.len()).rev() { - let (user_data, mut outbound) = self.outbound_substreams.swap_remove(n); - match self.inner.poll_outbound(cx, &mut outbound) { - Poll::Ready(Ok(substream)) => { - self.inner.destroy_outbound(outbound); - return Poll::Ready(Ok(SubstreamEvent::OutboundSubstream { - user_data, - substream, - })); - } - Poll::Pending => { - self.outbound_substreams.push((user_data, outbound)); - } - Poll::Ready(Err(err)) => { - self.inner.destroy_outbound(outbound); - return Poll::Ready(Err(err)); - } - } - } - - // Nothing happened. Register our task to be notified and return. - Poll::Pending - } -} - -impl fmt::Debug for Muxing -where - TMuxer: StreamMuxer, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.debug_struct("Muxing") - .field("outbound_substreams", &self.outbound_substreams.len()) - .finish() - } -} - -impl Drop for Muxing -where - TMuxer: StreamMuxer, -{ - fn drop(&mut self) { - // The substreams that were produced will continue to work, as the muxer is held in an Arc. - // However we will no longer process any further inbound or outbound substream, and we - // therefore close everything. - for (_, outbound) in self.outbound_substreams.drain(..) { - self.inner.destroy_outbound(outbound); - } - } -} - -impl Future for Close -where - TMuxer: StreamMuxer, -{ - type Output = Result<(), TMuxer::Error>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match self.muxer.poll_close(cx) { - Poll::Pending => Poll::Pending, - Poll::Ready(Ok(())) => Poll::Ready(Ok(())), - Poll::Ready(Err(err)) => Poll::Ready(Err(err)), - } - } -} - -impl fmt::Debug for Close -where - TMuxer: StreamMuxer, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.debug_struct("Close").finish() - } -} - -impl fmt::Debug for SubstreamEvent -where - TMuxer: StreamMuxer, - TMuxer::Substream: fmt::Debug, - TUserData: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SubstreamEvent::InboundSubstream { substream } => f - .debug_struct("SubstreamEvent::OutboundClosed") - .field("substream", substream) - .finish(), - SubstreamEvent::OutboundSubstream { - user_data, - substream, - } => f - .debug_struct("SubstreamEvent::OutboundSubstream") - .field("user_data", user_data) - .field("substream", substream) - .finish(), - SubstreamEvent::AddressChange(address) => f - .debug_struct("SubstreamEvent::AddressChange") - .field("address", address) - .finish(), - } - } -} diff --git a/transports/deflate/CHANGELOG.md b/transports/deflate/CHANGELOG.md index ebc2d811375..317a9ab78d3 100644 --- a/transports/deflate/CHANGELOG.md +++ b/transports/deflate/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.35.0 [unreleased] + +- Update to `libp2p-core` `v0.35.0`. + # 0.34.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/transports/deflate/Cargo.toml b/transports/deflate/Cargo.toml index 82536d8acc3..4ac8661d0a3 100644 --- a/transports/deflate/Cargo.toml +++ b/transports/deflate/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-deflate" edition = "2021" rust-version = "1.56.1" description = "Deflate encryption protocol for libp2p" -version = "0.34.0" +version = "0.35.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"] [dependencies] futures = "0.3.1" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } flate2 = "1.0" [dev-dependencies] diff --git a/transports/dns/CHANGELOG.md b/transports/dns/CHANGELOG.md index a32d5a95eb5..c9b9083cb3a 100644 --- a/transports/dns/CHANGELOG.md +++ b/transports/dns/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.35.0 [unreleased] + +- Update to `libp2p-core` `v0.35.0`. + # 0.34.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/transports/dns/Cargo.toml b/transports/dns/Cargo.toml index 1aaa7a15302..46ca3aca1af 100644 --- a/transports/dns/Cargo.toml +++ b/transports/dns/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-dns" edition = "2021" rust-version = "1.56.1" description = "DNS transport implementation for libp2p" -version = "0.34.0" +version = "0.35.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -11,7 +11,7 @@ keywords = ["peer-to-peer", "libp2p", "networking"] categories = ["network-programming", "asynchronous"] [dependencies] -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } log = "0.4.1" futures = "0.3.1" async-std-resolver = { version = "0.21", optional = true } diff --git a/transports/noise/CHANGELOG.md b/transports/noise/CHANGELOG.md index ca830796b59..6b323eabd27 100644 --- a/transports/noise/CHANGELOG.md +++ b/transports/noise/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.38.0 [unreleased] + +- Update to `libp2p-core` `v0.35.0`. + # 0.37.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/transports/noise/Cargo.toml b/transports/noise/Cargo.toml index f0b8ef8996e..171a89a4715 100644 --- a/transports/noise/Cargo.toml +++ b/transports/noise/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-noise" edition = "2021" rust-version = "1.56.1" description = "Cryptographic handshake protocol using the noise framework." -version = "0.37.0" +version = "0.38.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -13,7 +13,7 @@ bytes = "1" curve25519-dalek = "3.0.0" futures = "0.3.1" lazy_static = "1.2" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } log = "0.4" prost = "0.10" rand = "0.8.3" diff --git a/transports/plaintext/CHANGELOG.md b/transports/plaintext/CHANGELOG.md index 560075bc0a2..7c5c389a0cd 100644 --- a/transports/plaintext/CHANGELOG.md +++ b/transports/plaintext/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.35.0 [unreleased] + +- Update to `libp2p-core` `v0.35.0`. + # 0.34.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/transports/plaintext/Cargo.toml b/transports/plaintext/Cargo.toml index e5534f93c1e..c8cd9395da0 100644 --- a/transports/plaintext/Cargo.toml +++ b/transports/plaintext/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-plaintext" edition = "2021" rust-version = "1.56.1" description = "Plaintext encryption dummy protocol for libp2p" -version = "0.34.0" +version = "0.35.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] bytes = "1" futures = "0.3.1" asynchronous-codec = "0.6" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } log = "0.4.8" prost = "0.10" unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] } diff --git a/transports/tcp/Cargo.toml b/transports/tcp/Cargo.toml index e72f3eaee56..0b86689fa32 100644 --- a/transports/tcp/Cargo.toml +++ b/transports/tcp/Cargo.toml @@ -18,7 +18,7 @@ if-watch = { version = "1.0.0", optional = true } if-addrs = { version = "0.7.0", optional = true } ipnet = "2.0.0" libc = "0.2.80" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } log = "0.4.11" socket2 = { version = "0.4.0", features = ["all"] } tokio-crate = { package = "tokio", version = "1.19.0", default-features = false, features = ["net"], optional = true } diff --git a/transports/uds/CHANGELOG.md b/transports/uds/CHANGELOG.md index 65c5da0559a..c27c12b8c3e 100644 --- a/transports/uds/CHANGELOG.md +++ b/transports/uds/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.34.0 [unreleased] + +- Update to `libp2p-core` `v0.35.0`. + # 0.33.0 - Update dependencies. diff --git a/transports/uds/Cargo.toml b/transports/uds/Cargo.toml index 30d01c4f490..e00e6ae09f3 100644 --- a/transports/uds/Cargo.toml +++ b/transports/uds/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-uds" edition = "2021" rust-version = "1.56.1" description = "Unix domain sockets transport for libp2p" -version = "0.33.0" +version = "0.34.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"] [target.'cfg(all(unix, not(target_os = "emscripten")))'.dependencies] async-std = { version = "1.6.2", optional = true } -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } log = "0.4.1" futures = "0.3.1" tokio = { version = "1.15", default-features = false, features = ["net"], optional = true } diff --git a/transports/wasm-ext/CHANGELOG.md b/transports/wasm-ext/CHANGELOG.md index 65ff72d10bf..c3438b68b20 100644 --- a/transports/wasm-ext/CHANGELOG.md +++ b/transports/wasm-ext/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.35.0 [unreleased] + +- Update to `libp2p-core` `v0.35.0`. + # 0.34.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/transports/wasm-ext/Cargo.toml b/transports/wasm-ext/Cargo.toml index a0f67226513..34926d04b52 100644 --- a/transports/wasm-ext/Cargo.toml +++ b/transports/wasm-ext/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-wasm-ext" edition = "2021" rust-version = "1.56.1" description = "Allows passing in an external transport in a WASM environment" -version = "0.34.0" +version = "0.35.0" authors = ["Pierre Krieger "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -13,7 +13,7 @@ categories = ["network-programming", "asynchronous"] [dependencies] futures = "0.3.1" js-sys = "0.3.50" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } parity-send-wrapper = "0.1.0" wasm-bindgen = "0.2.42" wasm-bindgen-futures = "0.4.4" diff --git a/transports/websocket/CHANGELOG.md b/transports/websocket/CHANGELOG.md index 3783fef6c44..1a46978cd3b 100644 --- a/transports/websocket/CHANGELOG.md +++ b/transports/websocket/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.37.0 [unreleased] + +- Update to `libp2p-core` `v0.35.0`. + # 0.36.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/transports/websocket/Cargo.toml b/transports/websocket/Cargo.toml index 624fc0cbe4f..49121c4f22b 100644 --- a/transports/websocket/Cargo.toml +++ b/transports/websocket/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-websocket" edition = "2021" rust-version = "1.56.1" description = "WebSocket transport for libp2p" -version = "0.36.0" +version = "0.37.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] futures-rustls = "0.22" either = "1.5.3" futures = "0.3.1" -libp2p-core = { version = "0.34.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } log = "0.4.8" parking_lot = "0.12.0" quicksink = "0.1" From e95232cfaa8473b243e08080102f83fe69d7d0fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Jul 2022 04:04:26 +0200 Subject: [PATCH 04/92] build(deps): Bump Swatinem/rust-cache from 1.4.0 to 2.0.0 (#2759) * build(deps): Bump Swatinem/rust-cache from 1.4.0 to 2.0.0 Bumps [Swatinem/rust-cache](https://github.com/Swatinem/rust-cache) from 1.4.0 to 2.0.0. - [Release notes](https://github.com/Swatinem/rust-cache/releases) - [Changelog](https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md) - [Commits](https://github.com/Swatinem/rust-cache/compare/cb2cf0cc7c5198d3364b9630e2c3d457f160790c...6720f05bc48b77f96918929a9019fb2203ff71f8) --- updated-dependencies: - dependency-name: Swatinem/rust-cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5cda587983c..3e97069e3a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@cb2cf0cc7c5198d3364b9630e2c3d457f160790c # v1.4.0 + - uses: Swatinem/rust-cache@6720f05bc48b77f96918929a9019fb2203ff71f8 # v2.0.0 with: key: ${{ matrix.args }} @@ -72,7 +72,7 @@ jobs: - name: Install CMake run: sudo apt-get install -y cmake - - uses: Swatinem/rust-cache@cb2cf0cc7c5198d3364b9630e2c3d457f160790c # v1.4.0 + - uses: Swatinem/rust-cache@6720f05bc48b77f96918929a9019fb2203ff71f8 # v2.0.0 with: key: ${{ matrix.toolchain }} @@ -99,7 +99,7 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@cb2cf0cc7c5198d3364b9630e2c3d457f160790c # v1.4.0 + - uses: Swatinem/rust-cache@6720f05bc48b77f96918929a9019fb2203ff71f8 # v2.0.0 - name: Check rustdoc links run: RUSTDOCFLAGS="--deny broken_intra_doc_links" cargo doc --verbose --workspace --no-deps --document-private-items --all-features @@ -122,7 +122,7 @@ jobs: override: true components: clippy - - uses: Swatinem/rust-cache@cb2cf0cc7c5198d3364b9630e2c3d457f160790c # v1.4.0 + - uses: Swatinem/rust-cache@6720f05bc48b77f96918929a9019fb2203ff71f8 # v2.0.0 - name: Run cargo clippy uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1.0.3 @@ -147,7 +147,7 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@cb2cf0cc7c5198d3364b9630e2c3d457f160790c # v1.4.0 + - uses: Swatinem/rust-cache@6720f05bc48b77f96918929a9019fb2203ff71f8 # v2.0.0 - name: Run ipfs-kad example run: RUST_LOG=libp2p_swarm=debug,libp2p_kad=trace,libp2p_tcp=debug cargo run --example ipfs-kad From 66c2319230f77a8f3d5b1efa7ccfadfcc5d5df0c Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 19 Jul 2022 08:57:50 +0200 Subject: [PATCH 05/92] transports/tcp: Bump to v0.35.0 (#2760) Follow up on https://github.com/libp2p/rust-libp2p/pull/2724/. Given that libp2p-core is bumped to v0.35.0, libp2p-tcp needs to be bumped as well. --- Cargo.toml | 2 +- transports/tcp/CHANGELOG.md | 4 ++++ transports/tcp/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9e6d6ea4786..f716d822552 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,7 +107,7 @@ smallvec = "1.6.1" libp2p-deflate = { version = "0.35.0", path = "transports/deflate", optional = true } libp2p-dns = { version = "0.35.0", path = "transports/dns", optional = true, default-features = false } libp2p-mdns = { version = "0.39.0", path = "protocols/mdns", optional = true } -libp2p-tcp = { version = "0.34.0", path = "transports/tcp", default-features = false, optional = true } +libp2p-tcp = { version = "0.35.0", path = "transports/tcp", default-features = false, optional = true } libp2p-websocket = { version = "0.37.0", path = "transports/websocket", optional = true } [target.'cfg(not(target_os = "unknown"))'.dependencies] diff --git a/transports/tcp/CHANGELOG.md b/transports/tcp/CHANGELOG.md index 4a9d0245b2b..5d860270be9 100644 --- a/transports/tcp/CHANGELOG.md +++ b/transports/tcp/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.35.0 [unreleased] + +- Update to `libp2p-core` `v0.35.0`. + # 0.34.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/transports/tcp/Cargo.toml b/transports/tcp/Cargo.toml index 0b86689fa32..22969c060ff 100644 --- a/transports/tcp/Cargo.toml +++ b/transports/tcp/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-tcp" edition = "2021" rust-version = "1.56.1" description = "TCP/IP transport protocol for libp2p" -version = "0.34.0" +version = "0.35.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" From c8066df232e16f1d0908c6dfda91a366d7d21028 Mon Sep 17 00:00:00 2001 From: tgmichel Date: Tue, 19 Jul 2022 09:14:00 +0200 Subject: [PATCH 06/92] *: Update to `if-watch` `1.1.1` (#2754) --- protocols/mdns/CHANGELOG.md | 1 + protocols/mdns/Cargo.toml | 2 +- transports/tcp/CHANGELOG.md | 2 ++ transports/tcp/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/protocols/mdns/CHANGELOG.md b/protocols/mdns/CHANGELOG.md index 1bf4be8f6ae..e3b37be4c60 100644 --- a/protocols/mdns/CHANGELOG.md +++ b/protocols/mdns/CHANGELOG.md @@ -1,6 +1,7 @@ # 0.39.0 [unreleased] - Update to `libp2p-swarm` `v0.38.0`. +- Update to `if-watch` `v1.1.1`. - Update to `libp2p-core` `v0.35.0`. diff --git a/protocols/mdns/Cargo.toml b/protocols/mdns/Cargo.toml index eb32b7e9426..bb060c9ed1f 100644 --- a/protocols/mdns/Cargo.toml +++ b/protocols/mdns/Cargo.toml @@ -15,7 +15,7 @@ async-io = "1.3.1" data-encoding = "2.3.2" dns-parser = "0.8.0" futures = "0.3.13" -if-watch = "1.0.0" +if-watch = "1.1.1" lazy_static = "1.4.0" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } diff --git a/transports/tcp/CHANGELOG.md b/transports/tcp/CHANGELOG.md index 5d860270be9..bf7a5e0daba 100644 --- a/transports/tcp/CHANGELOG.md +++ b/transports/tcp/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-core` `v0.35.0`. +- Update to `if-watch` `v1.1.1`. + # 0.34.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/transports/tcp/Cargo.toml b/transports/tcp/Cargo.toml index 22969c060ff..7273db58c51 100644 --- a/transports/tcp/Cargo.toml +++ b/transports/tcp/Cargo.toml @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] async-io-crate = { package = "async-io", version = "1.2.0", optional = true } futures = "0.3.8" futures-timer = "3.0" -if-watch = { version = "1.0.0", optional = true } +if-watch = { version = "1.1.1", optional = true } if-addrs = { version = "0.7.0", optional = true } ipnet = "2.0.0" libc = "0.2.80" From 163c5c17520926f829cf3dfdb17d5c2d79b0f7df Mon Sep 17 00:00:00 2001 From: Hubert Date: Thu, 21 Jul 2022 22:58:41 +0200 Subject: [PATCH 07/92] README.md: Add crates.io and docs.rs badges (#2766) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fb45ac38c10..6e668184a8b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ [![dependency status](https://deps.rs/repo/github/libp2p/rust-libp2p/status.svg?style=flat-square)](https://deps.rs/repo/github/libp2p/rust-libp2p) +[![Crates.io](https://img.shields.io/crates/v/libp2p.svg)](https://crates.io/crates/libp2p) +[![docs.rs](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/libp2p) This repository is the central place for Rust development of the [libp2p](https://libp2p.io) spec. From 51a847128cb641202241b641066a1ea1fdfcd078 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Jul 2022 11:20:39 +0200 Subject: [PATCH 08/92] build(deps): Update prometheus-client requirement from 0.16.0 to 0.17.0 (#2761) * build(deps): Update prometheus-client requirement from 0.16.0 to 0.17.0 Updates the requirements on [prometheus-client](https://github.com/prometheus/client_rust) to permit the latest version. - [Release notes](https://github.com/prometheus/client_rust/releases) - [Changelog](https://github.com/prometheus/client_rust/blob/master/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_rust/compare/v0.16.0...v0.17.0) --- updated-dependencies: - dependency-name: prometheus-client dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- misc/metrics/CHANGELOG.md | 4 ++++ misc/metrics/Cargo.toml | 2 +- protocols/gossipsub/CHANGELOG.md | 4 ++++ protocols/gossipsub/Cargo.toml | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/misc/metrics/CHANGELOG.md b/misc/metrics/CHANGELOG.md index c9cc21a06f1..06e2163597e 100644 --- a/misc/metrics/CHANGELOG.md +++ b/misc/metrics/CHANGELOG.md @@ -16,6 +16,10 @@ - Update to `libp2p-core` `v0.35.0`. +- Update to `prometheus-client` `v0.17.0`. See [PR 2761]. + +[PR 2761]: https://github.com/libp2p/rust-libp2p/pull/2761/ + [PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ # 0.7.0 diff --git a/misc/metrics/Cargo.toml b/misc/metrics/Cargo.toml index 7fdfec733e0..7ccd259e535 100644 --- a/misc/metrics/Cargo.toml +++ b/misc/metrics/Cargo.toml @@ -26,7 +26,7 @@ libp2p-kad = { version = "0.39.0", path = "../../protocols/kad", optional = true libp2p-ping = { version = "0.38.0", path = "../../protocols/ping", optional = true } libp2p-relay = { version = "0.11.0", path = "../../protocols/relay", optional = true } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } -prometheus-client = "0.16.0" +prometheus-client = "0.17.0" [target.'cfg(not(target_os = "unknown"))'.dependencies] libp2p-gossipsub = { version = "0.40.0", path = "../../protocols/gossipsub", optional = true } diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index f6b0902d306..233d3873e98 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -4,6 +4,10 @@ - Update to `libp2p-core` `v0.35.0`. +- Update to `prometheus-client` `v0.17.0`. See [PR 2761]. + +[PR 2761]: https://github.com/libp2p/rust-libp2p/pull/2761/ + # 0.39.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/gossipsub/Cargo.toml b/protocols/gossipsub/Cargo.toml index e992fb3b9ef..da97500808d 100644 --- a/protocols/gossipsub/Cargo.toml +++ b/protocols/gossipsub/Cargo.toml @@ -31,7 +31,7 @@ serde = { version = "1", optional = true, features = ["derive"] } wasm-timer = "0.2.5" instant = "0.1.11" # Metrics dependencies -prometheus-client = "0.16.0" +prometheus-client = "0.17.0" [dev-dependencies] async-std = "1.6.3" From f15a3dc4e018c706b9b900dc01bdeafe82c62402 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 22 Jul 2022 10:40:27 +0100 Subject: [PATCH 09/92] core/muxing: Drop `Unpin` requirement from `SubstreamBox` (#2762) We are already boxing the given object so we might as well pin to to avoid the `Unpin` trait bound. --- core/CHANGELOG.md | 2 ++ core/src/muxing/boxed.rs | 34 +++++++++++++++++----------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 0102096d780..2ee23a194be 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -2,8 +2,10 @@ - Remove `StreamMuxer::poll_event` in favor of individual functions: `poll_inbound`, `poll_outbound` and `poll_address_change`. Consequently, `StreamMuxerEvent` is also removed. See [PR 2724]. +- Drop `Unpin` requirement from `SubstreamBox`. See [PR XXXX. [PR 2724]: https://github.com/libp2p/rust-libp2p/pull/2724 +[PR XXXX]: https://github.com/libp2p/rust-libp2p/pull/XXXX # 0.34.0 diff --git a/core/src/muxing/boxed.rs b/core/src/muxing/boxed.rs index 80753813dcb..259dfd01219 100644 --- a/core/src/muxing/boxed.rs +++ b/core/src/muxing/boxed.rs @@ -17,7 +17,7 @@ pub struct StreamMuxerBox { /// /// A [`SubstreamBox`] erases the concrete type it is given and only retains its `AsyncRead` /// and `AsyncWrite` capabilities. -pub struct SubstreamBox(Box); +pub struct SubstreamBox(Pin>); struct Wrap where @@ -106,8 +106,8 @@ impl StreamMuxer for StreamMuxerBox { impl SubstreamBox { /// Construct a new [`SubstreamBox`] from something that implements [`AsyncRead`] and [`AsyncWrite`]. - pub fn new(stream: S) -> Self { - Self(Box::new(stream)) + pub fn new(stream: S) -> Self { + Self(Box::pin(stream)) } } @@ -118,7 +118,7 @@ impl fmt::Debug for SubstreamBox { } /// Workaround because Rust does not allow `Box`. -trait AsyncReadWrite: AsyncRead + AsyncWrite + Unpin { +trait AsyncReadWrite: AsyncRead + AsyncWrite { /// Helper function to capture the erased inner type. /// /// Used to make the [`Debug`] implementation of [`SubstreamBox`] more useful. @@ -127,7 +127,7 @@ trait AsyncReadWrite: AsyncRead + AsyncWrite + Unpin { impl AsyncReadWrite for S where - S: AsyncRead + AsyncWrite + Unpin, + S: AsyncRead + AsyncWrite, { fn type_name(&self) -> &'static str { std::any::type_name::() @@ -136,44 +136,44 @@ where impl AsyncRead for SubstreamBox { fn poll_read( - self: Pin<&mut Self>, + mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { - Pin::new(&mut self.get_mut().0).poll_read(cx, buf) + self.0.as_mut().poll_read(cx, buf) } fn poll_read_vectored( - self: Pin<&mut Self>, + mut self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>], ) -> Poll> { - Pin::new(&mut self.get_mut().0).poll_read_vectored(cx, bufs) + self.0.as_mut().poll_read_vectored(cx, bufs) } } impl AsyncWrite for SubstreamBox { fn poll_write( - self: Pin<&mut Self>, + mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - Pin::new(&mut self.get_mut().0).poll_write(cx, buf) + self.0.as_mut().poll_write(cx, buf) } fn poll_write_vectored( - self: Pin<&mut Self>, + mut self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>], ) -> Poll> { - Pin::new(&mut self.get_mut().0).poll_write_vectored(cx, bufs) + self.0.as_mut().poll_write_vectored(cx, bufs) } - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.get_mut().0).poll_flush(cx) + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.0.as_mut().poll_flush(cx) } - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.get_mut().0).poll_close(cx) + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.0.as_mut().poll_close(cx) } } From 2e2c117dab52ec46c94310bbc71a4d8398988554 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 22 Jul 2022 10:59:55 +0100 Subject: [PATCH 10/92] core/tests: Remove unnecessary `Arc` (#2763) --- muxers/mplex/tests/async_write.rs | 3 +-- muxers/mplex/tests/two_peers.rs | 23 ++++++++++------------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/muxers/mplex/tests/async_write.rs b/muxers/mplex/tests/async_write.rs index 94d69cd7ff1..2c4a2d10f0d 100644 --- a/muxers/mplex/tests/async_write.rs +++ b/muxers/mplex/tests/async_write.rs @@ -22,7 +22,6 @@ use futures::future::poll_fn; use futures::{channel::oneshot, prelude::*}; use libp2p_core::{upgrade, StreamMuxer, Transport}; use libp2p_tcp::TcpTransport; -use std::sync::Arc; #[test] fn async_write() { @@ -72,7 +71,7 @@ fn async_write() { let mut transport = TcpTransport::default() .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); - let client = Arc::new(transport.dial(rx.await.unwrap()).unwrap().await.unwrap()); + let client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap(); inbound.write_all(b"hello world").await.unwrap(); diff --git a/muxers/mplex/tests/two_peers.rs b/muxers/mplex/tests/two_peers.rs index 20812fde55c..2b976c12fea 100644 --- a/muxers/mplex/tests/two_peers.rs +++ b/muxers/mplex/tests/two_peers.rs @@ -22,7 +22,6 @@ use futures::future::poll_fn; use futures::{channel::oneshot, prelude::*}; use libp2p_core::{upgrade, StreamMuxer, Transport}; use libp2p_tcp::TcpTransport; -use std::sync::Arc; #[test] fn client_to_server_outbound() { @@ -73,7 +72,7 @@ fn client_to_server_outbound() { .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)) .boxed(); - let client = Arc::new(transport.dial(rx.await.unwrap()).unwrap().await.unwrap()); + let client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap(); inbound.write_all(b"hello world").await.unwrap(); inbound.close().await.unwrap(); @@ -108,17 +107,15 @@ fn client_to_server_inbound() { tx.send(addr).unwrap(); - let client = Arc::new( - transport - .next() - .await - .expect("some event") - .into_incoming() - .unwrap() - .0 - .await - .unwrap(), - ); + let client = transport + .next() + .await + .expect("some event") + .into_incoming() + .unwrap() + .0 + .await + .unwrap(); let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap(); From 95713ab91c4dcd8494daa190a45d4a9444ff91b0 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Sat, 23 Jul 2022 20:48:52 +0200 Subject: [PATCH 11/92] core: fix PR number in changelog entry (#2769) --- core/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 2ee23a194be..5098d45dd11 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -2,10 +2,10 @@ - Remove `StreamMuxer::poll_event` in favor of individual functions: `poll_inbound`, `poll_outbound` and `poll_address_change`. Consequently, `StreamMuxerEvent` is also removed. See [PR 2724]. -- Drop `Unpin` requirement from `SubstreamBox`. See [PR XXXX. +- Drop `Unpin` requirement from `SubstreamBox`. See [PR 2762]. [PR 2724]: https://github.com/libp2p/rust-libp2p/pull/2724 -[PR XXXX]: https://github.com/libp2p/rust-libp2p/pull/XXXX +[PR 2762]: https://github.com/libp2p/rust-libp2p/pull/2762 # 0.34.0 From f85a9909aca659f10f6b024fa0ed581199dddf90 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 25 Jul 2022 08:34:05 +0100 Subject: [PATCH 12/92] core/tests: Remove unnecessary util module (#2764) --- core/tests/transport_upgrade.rs | 12 --------- core/tests/util.rs | 47 --------------------------------- 2 files changed, 59 deletions(-) delete mode 100644 core/tests/util.rs diff --git a/core/tests/transport_upgrade.rs b/core/tests/transport_upgrade.rs index ecba64dfb2f..723a04b0780 100644 --- a/core/tests/transport_upgrade.rs +++ b/core/tests/transport_upgrade.rs @@ -18,8 +18,6 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -mod util; - use futures::prelude::*; use libp2p_core::identity; use libp2p_core::transport::{MemoryTransport, Transport}; @@ -91,11 +89,6 @@ fn upgrade_pipeline() { .apply(HelloUpgrade {}) .apply(HelloUpgrade {}) .multiplex(MplexConfig::default()) - .and_then(|(peer, mplex), _| { - // Gracefully close the connection to allow protocol - // negotiation to complete. - util::CloseMuxer::new(mplex).map_ok(move |mplex| (peer, mplex)) - }) .boxed(); let dialer_keys = identity::Keypair::generate_ed25519(); @@ -110,11 +103,6 @@ fn upgrade_pipeline() { .apply(HelloUpgrade {}) .apply(HelloUpgrade {}) .multiplex(MplexConfig::default()) - .and_then(|(peer, mplex), _| { - // Gracefully close the connection to allow protocol - // negotiation to complete. - util::CloseMuxer::new(mplex).map_ok(move |mplex| (peer, mplex)) - }) .boxed(); let listen_addr1 = Multiaddr::from(Protocol::Memory(random::())); diff --git a/core/tests/util.rs b/core/tests/util.rs deleted file mode 100644 index 7ca52188a52..00000000000 --- a/core/tests/util.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![allow(dead_code)] - -use futures::prelude::*; -use libp2p_core::muxing::StreamMuxer; -use std::{pin::Pin, task::Context, task::Poll}; - -pub struct CloseMuxer { - state: CloseMuxerState, -} - -impl CloseMuxer { - pub fn new(m: M) -> CloseMuxer { - CloseMuxer { - state: CloseMuxerState::Close(m), - } - } -} - -pub enum CloseMuxerState { - Close(M), - Done, -} - -impl Future for CloseMuxer -where - M: StreamMuxer, - M::Error: From, -{ - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - loop { - match std::mem::replace(&mut self.state, CloseMuxerState::Done) { - CloseMuxerState::Close(muxer) => { - if !muxer.poll_close(cx)?.is_ready() { - self.state = CloseMuxerState::Close(muxer); - return Poll::Pending; - } - return Poll::Ready(Ok(muxer)); - } - CloseMuxerState::Done => panic!(), - } - } - } -} - -impl Unpin for CloseMuxer {} From c19a211dfd489b1b1412050c5adccf896d78ac50 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Mon, 25 Jul 2022 10:45:43 +0200 Subject: [PATCH 13/92] misc/metrics: fix clippy::assign-op-pattern (#2773) --- misc/metrics/src/identify.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/metrics/src/identify.rs b/misc/metrics/src/identify.rs index b3ae5a75910..730528167a8 100644 --- a/misc/metrics/src/identify.rs +++ b/misc/metrics/src/identify.rs @@ -223,7 +223,7 @@ impl EncodeMetric for Protocols { |mut acc, (_, protocols)| { for protocol in protocols { let count = acc.entry(protocol.to_string()).or_default(); - *count = *count + 1; + *count += 1; } acc }, From 0ec3bbccb2eb8dc4c1db62db184e1358777942ae Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 25 Jul 2022 15:49:22 +0100 Subject: [PATCH 14/92] core/muxing: Remove `Unpin` requirement from `StreamMuxer::Substream` (#2776) --- core/CHANGELOG.md | 3 ++- core/src/muxing/boxed.rs | 4 ++-- core/src/transport/upgrade.rs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 5098d45dd11..0fb742af96a 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -2,10 +2,11 @@ - Remove `StreamMuxer::poll_event` in favor of individual functions: `poll_inbound`, `poll_outbound` and `poll_address_change`. Consequently, `StreamMuxerEvent` is also removed. See [PR 2724]. -- Drop `Unpin` requirement from `SubstreamBox`. See [PR 2762]. +- Drop `Unpin` requirement from `SubstreamBox`. See [PR 2762] and [PR 2776]. [PR 2724]: https://github.com/libp2p/rust-libp2p/pull/2724 [PR 2762]: https://github.com/libp2p/rust-libp2p/pull/2762 +[PR 2776]: https://github.com/libp2p/rust-libp2p/pull/2776 # 0.34.0 diff --git a/core/src/muxing/boxed.rs b/core/src/muxing/boxed.rs index 259dfd01219..5dc98835866 100644 --- a/core/src/muxing/boxed.rs +++ b/core/src/muxing/boxed.rs @@ -29,7 +29,7 @@ where impl StreamMuxer for Wrap where T: StreamMuxer, - T::Substream: Send + Unpin + 'static, + T::Substream: Send + 'static, T::Error: Send + Sync + 'static, { type Substream = SubstreamBox; @@ -71,7 +71,7 @@ impl StreamMuxerBox { pub fn new(muxer: T) -> StreamMuxerBox where T: StreamMuxer + Send + Sync + 'static, - T::Substream: Send + Unpin + 'static, + T::Substream: Send + 'static, T::Error: Send + Sync + 'static, { let wrap = Wrap { inner: muxer }; diff --git a/core/src/transport/upgrade.rs b/core/src/transport/upgrade.rs index da87fb9dd6a..eb7b310c0a9 100644 --- a/core/src/transport/upgrade.rs +++ b/core/src/transport/upgrade.rs @@ -300,7 +300,7 @@ impl Multiplexed { T::ListenerUpgrade: Send + 'static, T::Error: Send + Sync, M: StreamMuxer + Send + Sync + 'static, - M::Substream: Send + Unpin + 'static, + M::Substream: Send + 'static, M::Error: Send + Sync + 'static, { boxed(self.map(|(i, m), _| (i, StreamMuxerBox::new(m)))) From 74f01e47c9104678a211fec36918f1bd854c1c79 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Mon, 25 Jul 2022 17:33:31 +0200 Subject: [PATCH 15/92] transports/tcp: fix clippy::from-over-into (#2774) --- transports/tcp/src/provider/tokio.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/transports/tcp/src/provider/tokio.rs b/transports/tcp/src/provider/tokio.rs index fa9ebe3b3ff..564eebfa48b 100644 --- a/transports/tcp/src/provider/tokio.rs +++ b/transports/tcp/src/provider/tokio.rs @@ -155,9 +155,9 @@ impl Provider for Tcp { #[derive(Debug)] pub struct TcpStream(pub tokio_crate::net::TcpStream); -impl Into for TcpStream { - fn into(self: TcpStream) -> tokio_crate::net::TcpStream { - self.0 +impl From for tokio_crate::net::TcpStream { + fn from(t: TcpStream) -> tokio_crate::net::TcpStream { + t.0 } } From ce963dfcaa0a99e4b9bef27cdfe29e48946d823a Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Mon, 25 Jul 2022 17:57:50 +0200 Subject: [PATCH 16/92] core: fix clippy::op-ref, clippy::needless-borrow (#2770) --- core/src/identity/ecdsa.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/identity/ecdsa.rs b/core/src/identity/ecdsa.rs index b883243b13b..81dfec4b4e0 100644 --- a/core/src/identity/ecdsa.rs +++ b/core/src/identity/ecdsa.rs @@ -157,7 +157,7 @@ impl PublicKey { let buf = Self::del_asn1_header(k).ok_or_else(|| { DecodingError::new("failed to parse asn.1 encoded ecdsa p256 public key") })?; - Self::from_bytes(&buf) + Self::from_bytes(buf) } // ecPublicKey (ANSI X9.62 public key type) OID: 1.2.840.10045.2.1 @@ -198,8 +198,8 @@ impl PublicKey { if asn1_head[0] != 0x30 || asn1_head[2] != 0x30 || asn1_head[3] as usize != oids_len - || &oids_buf[..Self::EC_PUBLIC_KEY_OID.len()] != &Self::EC_PUBLIC_KEY_OID - || &oids_buf[Self::EC_PUBLIC_KEY_OID.len()..] != &Self::SECP_256_R1_OID + || oids_buf[..Self::EC_PUBLIC_KEY_OID.len()] != Self::EC_PUBLIC_KEY_OID + || oids_buf[Self::EC_PUBLIC_KEY_OID.len()..] != Self::SECP_256_R1_OID || bitstr_head[0] != 0x03 || bitstr_head[2] != 0x00 { From 56c492cf41191ed7e299b8de29a2dc064b410e57 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 27 Jul 2022 08:23:07 +0200 Subject: [PATCH 17/92] core/muxing: Drop `Sync` requirement for `StreamMuxer` on `StreamMuxerBox` (#2775) `StreamMuxerBox` is never shared across threads but owned by a single connection. Restricting it to be `Sync` unnecessarily limits the design space around the `StreamMuxer` trait and its implementations. --- core/CHANGELOG.md | 2 ++ core/src/muxing/boxed.rs | 4 ++-- core/src/transport/upgrade.rs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 0fb742af96a..047a7ac40e2 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -3,9 +3,11 @@ - Remove `StreamMuxer::poll_event` in favor of individual functions: `poll_inbound`, `poll_outbound` and `poll_address_change`. Consequently, `StreamMuxerEvent` is also removed. See [PR 2724]. - Drop `Unpin` requirement from `SubstreamBox`. See [PR 2762] and [PR 2776]. +- Drop `Sync` requirement on `StreamMuxer` for constructing `StreamMuxerBox`. See [PR 2775]. [PR 2724]: https://github.com/libp2p/rust-libp2p/pull/2724 [PR 2762]: https://github.com/libp2p/rust-libp2p/pull/2762 +[PR 2775]: https://github.com/libp2p/rust-libp2p/pull/2775 [PR 2776]: https://github.com/libp2p/rust-libp2p/pull/2776 # 0.34.0 diff --git a/core/src/muxing/boxed.rs b/core/src/muxing/boxed.rs index 5dc98835866..8c6467dd7ad 100644 --- a/core/src/muxing/boxed.rs +++ b/core/src/muxing/boxed.rs @@ -10,7 +10,7 @@ use std::task::{Context, Poll}; /// Abstract `StreamMuxer`. pub struct StreamMuxerBox { - inner: Box + Send + Sync>, + inner: Box + Send>, } /// Abstract type for asynchronous reading and writing. @@ -70,7 +70,7 @@ impl StreamMuxerBox { /// Turns a stream muxer into a `StreamMuxerBox`. pub fn new(muxer: T) -> StreamMuxerBox where - T: StreamMuxer + Send + Sync + 'static, + T: StreamMuxer + Send + 'static, T::Substream: Send + 'static, T::Error: Send + Sync + 'static, { diff --git a/core/src/transport/upgrade.rs b/core/src/transport/upgrade.rs index eb7b310c0a9..8fc0454794f 100644 --- a/core/src/transport/upgrade.rs +++ b/core/src/transport/upgrade.rs @@ -299,7 +299,7 @@ impl Multiplexed { T::Dial: Send + 'static, T::ListenerUpgrade: Send + 'static, T::Error: Send + Sync, - M: StreamMuxer + Send + Sync + 'static, + M: StreamMuxer + Send + 'static, M::Substream: Send + 'static, M::Error: Send + Sync + 'static, { From 09c690862e6989b1d098e93d5fc23decc1d58ebc Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Thu, 28 Jul 2022 03:04:36 +0200 Subject: [PATCH 18/92] protocols/dcutr: Fix clippy lints (#2772) --- protocols/dcutr/src/behaviour.rs | 61 ++++++++++++-------------- protocols/dcutr/src/handler/relayed.rs | 12 ++--- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/protocols/dcutr/src/behaviour.rs b/protocols/dcutr/src/behaviour.rs index 893148890b7..5d93d90b339 100644 --- a/protocols/dcutr/src/behaviour.rs +++ b/protocols/dcutr/src/behaviour.rs @@ -65,6 +65,7 @@ pub enum UpgradeError { Handler(ConnectionHandlerUpgrErr), } +#[derive(Default)] pub struct Behaviour { /// Queue of actions to return when polled. queued_actions: VecDeque, @@ -145,40 +146,35 @@ impl NetworkBehaviour for Behaviour { handler: Self::ConnectionHandler, _error: &DialError, ) { - match handler { - handler::Prototype::DirectConnection { - relayed_connection_id, - role: handler::Role::Initiator { attempt }, - } => { - let peer_id = - peer_id.expect("Peer of `Prototype::DirectConnection` is always known."); - if attempt < MAX_NUMBER_OF_UPGRADE_ATTEMPTS { - self.queued_actions.push_back(ActionBuilder::Connect { + if let handler::Prototype::DirectConnection { + relayed_connection_id, + role: handler::Role::Initiator { attempt }, + } = handler + { + let peer_id = peer_id.expect("Peer of `Prototype::DirectConnection` is always known."); + if attempt < MAX_NUMBER_OF_UPGRADE_ATTEMPTS { + self.queued_actions.push_back(ActionBuilder::Connect { + peer_id, + handler: NotifyHandler::One(relayed_connection_id), + attempt: attempt + 1, + }); + } else { + self.queued_actions.extend([ + NetworkBehaviourAction::NotifyHandler { peer_id, handler: NotifyHandler::One(relayed_connection_id), - attempt: attempt + 1, - }); - } else { - self.queued_actions.extend([ - NetworkBehaviourAction::NotifyHandler { - peer_id, - handler: NotifyHandler::One(relayed_connection_id), - event: Either::Left( - handler::relayed::Command::UpgradeFinishedDontKeepAlive, - ), - } - .into(), - NetworkBehaviourAction::GenerateEvent( - Event::DirectConnectionUpgradeFailed { - remote_peer_id: peer_id, - error: UpgradeError::Dial, - }, - ) - .into(), - ]); - } + event: Either::Left( + handler::relayed::Command::UpgradeFinishedDontKeepAlive, + ), + } + .into(), + NetworkBehaviourAction::GenerateEvent(Event::DirectConnectionUpgradeFailed { + remote_peer_id: peer_id, + error: UpgradeError::Dial, + }) + .into(), + ]); } - _ => {} } } @@ -324,7 +320,6 @@ impl NetworkBehaviour for Behaviour { /// A [`NetworkBehaviourAction`], either complete, or still requiring data from [`PollParameters`] /// before being returned in [`Behaviour::poll`]. -#[allow(clippy::large_enum_variant)] enum ActionBuilder { Done(NetworkBehaviourAction), Connect { @@ -333,7 +328,7 @@ enum ActionBuilder { peer_id: PeerId, }, AcceptInboundConnect { - inbound_connect: protocol::inbound::PendingConnect, + inbound_connect: Box, handler: NotifyHandler, peer_id: PeerId, }, diff --git a/protocols/dcutr/src/handler/relayed.rs b/protocols/dcutr/src/handler/relayed.rs index 9f9e2e01c13..e172b8f6993 100644 --- a/protocols/dcutr/src/handler/relayed.rs +++ b/protocols/dcutr/src/handler/relayed.rs @@ -44,7 +44,7 @@ pub enum Command { }, AcceptInboundConnect { obs_addrs: Vec, - inbound_connect: protocol::inbound::PendingConnect, + inbound_connect: Box, }, /// Upgrading the relayed connection to a direct connection either failed for good or succeeded. /// There is no need to keep the relayed connection alive for the sake of upgrading to a direct @@ -76,7 +76,7 @@ impl fmt::Debug for Command { pub enum Event { InboundConnectRequest { - inbound_connect: protocol::inbound::PendingConnect, + inbound_connect: Box, remote_addr: Multiaddr, }, InboundNegotiationFailed { @@ -201,7 +201,7 @@ impl ConnectionHandler for Handler { }; self.queued_events.push_back(ConnectionHandlerEvent::Custom( Event::InboundConnectRequest { - inbound_connect, + inbound_connect: Box::new(inbound_connect), remote_addr, }, )); @@ -245,9 +245,10 @@ impl ConnectionHandler for Handler { inbound_connect, obs_addrs, } => { - if let Some(_) = self + if self .inbound_connect .replace(inbound_connect.accept(obs_addrs).boxed()) + .is_some() { log::warn!( "New inbound connect stream while still upgrading previous one. \ @@ -337,8 +338,7 @@ impl ConnectionHandler for Handler { _ => { // Anything else is considered a fatal error or misbehaviour of // the remote peer and results in closing the connection. - self.pending_error = - Some(error.map_upgrade_err(|e| e.map_err(|e| EitherError::B(e)))); + self.pending_error = Some(error.map_upgrade_err(|e| e.map_err(EitherError::B))); } } } From eaf3f3a7fb4aba228ebd15366ab79b64cf37832c Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Thu, 28 Jul 2022 03:35:35 +0200 Subject: [PATCH 19/92] .cargo: Check all features in custom-clippy (#2771) --- .cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 95976aaa800..9d5619d2c4e 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,3 @@ [alias] # Temporary solution to have clippy config in a single place until https://github.com/rust-lang/rust-clippy/blob/master/doc/roadmap-2021.md#lintstoml-configuration is shipped. -custom-clippy = "clippy -- -A clippy::type_complexity -A clippy::pedantic -D warnings" +custom-clippy = "clippy --all-features -- -A clippy::type_complexity -A clippy::pedantic -D warnings" From 2b9e21268284a6a9a5de6887592ca6aad5af896c Mon Sep 17 00:00:00 2001 From: Luke Hinds <7058938+lukehinds@users.noreply.github.com> Date: Tue, 2 Aug 2022 07:46:50 +0100 Subject: [PATCH 20/92] examples/README.md: Fix tutorial link (#2790) --- examples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index 225425e0ff7..6c16d77cf66 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,7 +7,7 @@ A set of examples showcasing how to use rust-libp2p. - [Ping](ping.rs) Small `ping` clone, sending a ping to a peer, expecting a pong as a response. See - [tutorial](../src/tutorial.rs) for a step-by-step guide building the example. + [tutorial](../src/tutorials/ping.rs) for a step-by-step guide building the example. ## Individual libp2p protocols From 028decec6913f33b49bffb8cbfa7202629b2c22f Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 3 Aug 2022 15:12:11 +0200 Subject: [PATCH 21/92] core/muxing: Have functions on `StreamMuxer` take `Pin<&mut Self>` (#2765) Co-authored-by: Elena Frank Co-authored-by: Max Inden --- core/CHANGELOG.md | 2 + core/src/either.rs | 43 +++++---- core/src/muxing.rs | 119 +++++++++++++++++++++++- core/src/muxing/boxed.rs | 68 ++++++++++---- core/src/muxing/singleton.rs | 30 ++++-- muxers/mplex/benches/split_send_size.rs | 14 ++- muxers/mplex/src/lib.rs | 17 +++- muxers/mplex/tests/async_write.rs | 13 +-- muxers/mplex/tests/two_peers.rs | 24 ++--- muxers/yamux/src/lib.rs | 70 +++++++------- swarm/src/connection.rs | 16 ++-- swarm/src/connection/pool.rs | 6 +- 12 files changed, 298 insertions(+), 124 deletions(-) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 047a7ac40e2..dc4fd0829c0 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -4,11 +4,13 @@ and `poll_address_change`. Consequently, `StreamMuxerEvent` is also removed. See [PR 2724]. - Drop `Unpin` requirement from `SubstreamBox`. See [PR 2762] and [PR 2776]. - Drop `Sync` requirement on `StreamMuxer` for constructing `StreamMuxerBox`. See [PR 2775]. +- Use `Pin<&mut Self>` as the receiver type for all `StreamMuxer` poll functions. See [PR 2765]. [PR 2724]: https://github.com/libp2p/rust-libp2p/pull/2724 [PR 2762]: https://github.com/libp2p/rust-libp2p/pull/2762 [PR 2775]: https://github.com/libp2p/rust-libp2p/pull/2775 [PR 2776]: https://github.com/libp2p/rust-libp2p/pull/2776 +[PR 2765]: https://github.com/libp2p/rust-libp2p/pull/2765 # 0.34.0 diff --git a/core/src/either.rs b/core/src/either.rs index 4b5c20b2929..42984519488 100644 --- a/core/src/either.rs +++ b/core/src/either.rs @@ -204,43 +204,54 @@ where type Substream = EitherOutput; type Error = EitherError; - fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll> { - match self { - EitherOutput::First(inner) => inner + fn poll_inbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + match self.project() { + EitherOutputProj::First(inner) => inner .poll_inbound(cx) .map_ok(EitherOutput::First) .map_err(EitherError::A), - EitherOutput::Second(inner) => inner + EitherOutputProj::Second(inner) => inner .poll_inbound(cx) .map_ok(EitherOutput::Second) .map_err(EitherError::B), } } - fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll> { - match self { - EitherOutput::First(inner) => inner + fn poll_outbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + match self.project() { + EitherOutputProj::First(inner) => inner .poll_outbound(cx) .map_ok(EitherOutput::First) .map_err(EitherError::A), - EitherOutput::Second(inner) => inner + EitherOutputProj::Second(inner) => inner .poll_outbound(cx) .map_ok(EitherOutput::Second) .map_err(EitherError::B), } } - fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll> { - match self { - EitherOutput::First(inner) => inner.poll_address_change(cx).map_err(EitherError::A), - EitherOutput::Second(inner) => inner.poll_address_change(cx).map_err(EitherError::B), + fn poll_address_change( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + match self.project() { + EitherOutputProj::First(inner) => inner.poll_address_change(cx).map_err(EitherError::A), + EitherOutputProj::Second(inner) => { + inner.poll_address_change(cx).map_err(EitherError::B) + } } } - fn poll_close(&self, cx: &mut Context<'_>) -> Poll> { - match self { - EitherOutput::First(inner) => inner.poll_close(cx).map_err(EitherError::A), - EitherOutput::Second(inner) => inner.poll_close(cx).map_err(EitherError::B), + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.project() { + EitherOutputProj::First(inner) => inner.poll_close(cx).map_err(EitherError::A), + EitherOutputProj::Second(inner) => inner.poll_close(cx).map_err(EitherError::B), } } } diff --git a/core/src/muxing.rs b/core/src/muxing.rs index a2bdfa80b37..2d1e1068044 100644 --- a/core/src/muxing.rs +++ b/core/src/muxing.rs @@ -52,6 +52,8 @@ use futures::{task::Context, task::Poll, AsyncRead, AsyncWrite}; use multiaddr::Multiaddr; +use std::future::Future; +use std::pin::Pin; pub use self::boxed::StreamMuxerBox; pub use self::boxed::SubstreamBox; @@ -73,15 +75,24 @@ pub trait StreamMuxer { type Error: std::error::Error; /// Poll for new inbound substreams. - fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll>; + fn poll_inbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>; /// Poll for a new, outbound substream. - fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll>; + fn poll_outbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>; /// Poll for an address change of the underlying connection. /// /// Not all implementations may support this feature. - fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll>; + fn poll_address_change( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>; /// Closes this `StreamMuxer`. /// @@ -93,5 +104,105 @@ pub trait StreamMuxer { /// > that the remote is properly informed of the shutdown. However, apart from /// > properly informing the remote, there is no difference between this and /// > immediately dropping the muxer. - fn poll_close(&self, cx: &mut Context<'_>) -> Poll>; + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; +} + +/// Extension trait for [`StreamMuxer`]. +pub trait StreamMuxerExt: StreamMuxer + Sized { + /// Convenience function for calling [`StreamMuxer::poll_inbound`] for [`StreamMuxer`]s that are `Unpin`. + fn poll_inbound_unpin( + &mut self, + cx: &mut Context<'_>, + ) -> Poll> + where + Self: Unpin, + { + Pin::new(self).poll_inbound(cx) + } + + /// Convenience function for calling [`StreamMuxer::poll_outbound`] for [`StreamMuxer`]s that are `Unpin`. + fn poll_outbound_unpin( + &mut self, + cx: &mut Context<'_>, + ) -> Poll> + where + Self: Unpin, + { + Pin::new(self).poll_outbound(cx) + } + + /// Convenience function for calling [`StreamMuxer::poll_address_change`] for [`StreamMuxer`]s that are `Unpin`. + fn poll_address_change_unpin( + &mut self, + cx: &mut Context<'_>, + ) -> Poll> + where + Self: Unpin, + { + Pin::new(self).poll_address_change(cx) + } + + /// Convenience function for calling [`StreamMuxer::poll_close`] for [`StreamMuxer`]s that are `Unpin`. + fn poll_close_unpin(&mut self, cx: &mut Context<'_>) -> Poll> + where + Self: Unpin, + { + Pin::new(self).poll_close(cx) + } + + /// Returns a future that resolves to the next inbound `Substream` opened by the remote. + fn next_inbound(&mut self) -> NextInbound<'_, Self> { + NextInbound(self) + } + + /// Returns a future that opens a new outbound `Substream` with the remote. + fn next_outbound(&mut self) -> NextOutbound<'_, Self> { + NextOutbound(self) + } + + /// Returns a future for closing this [`StreamMuxer`]. + fn close(self) -> Close { + Close(self) + } +} + +impl StreamMuxerExt for S where S: StreamMuxer {} + +pub struct NextInbound<'a, S>(&'a mut S); + +pub struct NextOutbound<'a, S>(&'a mut S); + +pub struct Close(S); + +impl<'a, S> Future for NextInbound<'a, S> +where + S: StreamMuxer + Unpin, +{ + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.0.poll_inbound_unpin(cx) + } +} + +impl<'a, S> Future for NextOutbound<'a, S> +where + S: StreamMuxer + Unpin, +{ + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.0.poll_outbound_unpin(cx) + } +} + +impl Future for Close +where + S: StreamMuxer + Unpin, +{ + type Output = Result<(), S::Error>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.0.poll_close_unpin(cx) + } } diff --git a/core/src/muxing/boxed.rs b/core/src/muxing/boxed.rs index 8c6467dd7ad..0f5b6e5822e 100644 --- a/core/src/muxing/boxed.rs +++ b/core/src/muxing/boxed.rs @@ -1,6 +1,7 @@ use crate::StreamMuxer; use futures::{AsyncRead, AsyncWrite}; use multiaddr::Multiaddr; +use pin_project::pin_project; use std::error::Error; use std::fmt; use std::io; @@ -10,7 +11,7 @@ use std::task::{Context, Poll}; /// Abstract `StreamMuxer`. pub struct StreamMuxerBox { - inner: Box + Send>, + inner: Pin + Send>>, } /// Abstract type for asynchronous reading and writing. @@ -19,10 +20,12 @@ pub struct StreamMuxerBox { /// and `AsyncWrite` capabilities. pub struct SubstreamBox(Pin>); +#[pin_project] struct Wrap where T: StreamMuxer, { + #[pin] inner: T, } @@ -36,26 +39,40 @@ where type Error = io::Error; #[inline] - fn poll_close(&self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_close(cx).map_err(into_io_error) + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().inner.poll_close(cx).map_err(into_io_error) } - fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll> { - self.inner + fn poll_inbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.project() + .inner .poll_inbound(cx) .map_ok(SubstreamBox::new) .map_err(into_io_error) } - fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll> { - self.inner + fn poll_outbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.project() + .inner .poll_outbound(cx) .map_ok(SubstreamBox::new) .map_err(into_io_error) } - fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_address_change(cx).map_err(into_io_error) + fn poll_address_change( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.project() + .inner + .poll_address_change(cx) + .map_err(into_io_error) } } @@ -77,9 +94,15 @@ impl StreamMuxerBox { let wrap = Wrap { inner: muxer }; StreamMuxerBox { - inner: Box::new(wrap), + inner: Box::pin(wrap), } } + + fn project( + self: Pin<&mut Self>, + ) -> Pin<&mut (dyn StreamMuxer + Send)> { + self.get_mut().inner.as_mut() + } } impl StreamMuxer for StreamMuxerBox { @@ -87,20 +110,29 @@ impl StreamMuxer for StreamMuxerBox { type Error = io::Error; #[inline] - fn poll_close(&self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_close(cx) + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().poll_close(cx) } - fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_inbound(cx) + fn poll_inbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.project().poll_inbound(cx) } - fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_outbound(cx) + fn poll_outbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.project().poll_outbound(cx) } - fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_address_change(cx) + fn poll_address_change( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.project().poll_address_change(cx) } } diff --git a/core/src/muxing/singleton.rs b/core/src/muxing/singleton.rs index d67cb5e9825..193cfb6303f 100644 --- a/core/src/muxing/singleton.rs +++ b/core/src/muxing/singleton.rs @@ -23,6 +23,7 @@ use crate::{connection::Endpoint, muxing::StreamMuxer}; use futures::prelude::*; use multiaddr::Multiaddr; use std::cell::Cell; +use std::pin::Pin; use std::{io, task::Context, task::Poll}; /// Implementation of `StreamMuxer` that allows only one substream on top of a connection, @@ -57,31 +58,44 @@ where type Substream = TSocket; type Error = io::Error; - fn poll_inbound(&self, _: &mut Context<'_>) -> Poll> { - match self.endpoint { + fn poll_inbound( + self: Pin<&mut Self>, + _: &mut Context<'_>, + ) -> Poll> { + let this = self.get_mut(); + + match this.endpoint { Endpoint::Dialer => Poll::Pending, - Endpoint::Listener => match self.inner.replace(None) { + Endpoint::Listener => match this.inner.replace(None) { None => Poll::Pending, Some(stream) => Poll::Ready(Ok(stream)), }, } } - fn poll_outbound(&self, _: &mut Context<'_>) -> Poll> { - match self.endpoint { + fn poll_outbound( + self: Pin<&mut Self>, + _: &mut Context<'_>, + ) -> Poll> { + let this = self.get_mut(); + + match this.endpoint { Endpoint::Listener => Poll::Pending, - Endpoint::Dialer => match self.inner.replace(None) { + Endpoint::Dialer => match this.inner.replace(None) { None => Poll::Pending, Some(stream) => Poll::Ready(Ok(stream)), }, } } - fn poll_address_change(&self, _: &mut Context<'_>) -> Poll> { + fn poll_address_change( + self: Pin<&mut Self>, + _: &mut Context<'_>, + ) -> Poll> { Poll::Pending } - fn poll_close(&self, _cx: &mut Context<'_>) -> Poll> { + fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } } diff --git a/muxers/mplex/benches/split_send_size.rs b/muxers/mplex/benches/split_send_size.rs index d536edf4c8a..f74bcd1046f 100644 --- a/muxers/mplex/benches/split_send_size.rs +++ b/muxers/mplex/benches/split_send_size.rs @@ -26,9 +26,9 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughpu use futures::future::poll_fn; use futures::prelude::*; use futures::{channel::oneshot, future::join}; +use libp2p_core::muxing::StreamMuxerExt; use libp2p_core::{ - identity, multiaddr::multiaddr, muxing, transport, upgrade, Multiaddr, PeerId, StreamMuxer, - Transport, + identity, multiaddr::multiaddr, muxing, transport, upgrade, Multiaddr, PeerId, Transport, }; use libp2p_mplex as mplex; use libp2p_plaintext::PlainText2Config; @@ -113,10 +113,8 @@ fn run( addr_sender.take().unwrap().send(listen_addr).unwrap(); } transport::TransportEvent::Incoming { upgrade, .. } => { - let (_peer, conn) = upgrade.await.unwrap(); - let mut s = poll_fn(|cx| conn.poll_inbound(cx)) - .await - .expect("unexpected error"); + let (_peer, mut conn) = upgrade.await.unwrap(); + let mut s = conn.next_inbound().await.expect("unexpected error"); let mut buf = vec![0u8; payload_len]; let mut off = 0; @@ -140,8 +138,8 @@ fn run( // Spawn and block on the sender, i.e. until all data is sent. let sender = async move { let addr = addr_receiver.await.unwrap(); - let (_peer, conn) = sender_trans.dial(addr).unwrap().await.unwrap(); - let mut stream = poll_fn(|cx| conn.poll_outbound(cx)).await.unwrap(); + let (_peer, mut conn) = sender_trans.dial(addr).unwrap().await.unwrap(); + let mut stream = conn.next_outbound().await.unwrap(); let mut off = 0; loop { let n = poll_fn(|cx| Pin::new(&mut stream).poll_write(cx, &payload[off..])) diff --git a/muxers/mplex/src/lib.rs b/muxers/mplex/src/lib.rs index 59b38db1156..14f9cda65d9 100644 --- a/muxers/mplex/src/lib.rs +++ b/muxers/mplex/src/lib.rs @@ -85,25 +85,34 @@ where type Substream = Substream; type Error = io::Error; - fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll> { + fn poll_inbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { self.io .lock() .poll_next_stream(cx) .map_ok(|stream_id| Substream::new(stream_id, self.io.clone())) } - fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll> { + fn poll_outbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { self.io .lock() .poll_open_stream(cx) .map_ok(|stream_id| Substream::new(stream_id, self.io.clone())) } - fn poll_address_change(&self, _: &mut Context<'_>) -> Poll> { + fn poll_address_change( + self: Pin<&mut Self>, + _: &mut Context<'_>, + ) -> Poll> { Poll::Pending } - fn poll_close(&self, cx: &mut Context<'_>) -> Poll> { + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.io.lock().poll_close(cx) } } diff --git a/muxers/mplex/tests/async_write.rs b/muxers/mplex/tests/async_write.rs index 2c4a2d10f0d..bfbabf0f776 100644 --- a/muxers/mplex/tests/async_write.rs +++ b/muxers/mplex/tests/async_write.rs @@ -18,9 +18,9 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use futures::future::poll_fn; use futures::{channel::oneshot, prelude::*}; -use libp2p_core::{upgrade, StreamMuxer, Transport}; +use libp2p_core::muxing::StreamMuxerExt; +use libp2p_core::{upgrade, Transport}; use libp2p_tcp::TcpTransport; #[test] @@ -49,7 +49,7 @@ fn async_write() { tx.send(addr).unwrap(); - let client = transport + let mut client = transport .next() .await .expect("some event") @@ -59,7 +59,7 @@ fn async_write() { .await .unwrap(); - let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap(); + let mut outbound = client.next_outbound().await.unwrap(); let mut buf = Vec::new(); outbound.read_to_end(&mut buf).await.unwrap(); @@ -71,8 +71,9 @@ fn async_write() { let mut transport = TcpTransport::default() .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); - let client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); - let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap(); + let mut client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); + + let mut inbound = client.next_inbound().await.unwrap(); inbound.write_all(b"hello world").await.unwrap(); // The test consists in making sure that this flushes the substream. diff --git a/muxers/mplex/tests/two_peers.rs b/muxers/mplex/tests/two_peers.rs index 2b976c12fea..d30fcc1063d 100644 --- a/muxers/mplex/tests/two_peers.rs +++ b/muxers/mplex/tests/two_peers.rs @@ -18,9 +18,9 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use futures::future::poll_fn; use futures::{channel::oneshot, prelude::*}; -use libp2p_core::{upgrade, StreamMuxer, Transport}; +use libp2p_core::muxing::StreamMuxerExt; +use libp2p_core::{upgrade, Transport}; use libp2p_tcp::TcpTransport; #[test] @@ -49,7 +49,7 @@ fn client_to_server_outbound() { tx.send(addr).unwrap(); - let client = transport + let mut client = transport .next() .await .expect("some event") @@ -59,7 +59,7 @@ fn client_to_server_outbound() { .await .unwrap(); - let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap(); + let mut outbound = client.next_outbound().await.unwrap(); let mut buf = Vec::new(); outbound.read_to_end(&mut buf).await.unwrap(); @@ -72,8 +72,8 @@ fn client_to_server_outbound() { .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)) .boxed(); - let client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); - let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap(); + let mut client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); + let mut inbound = client.next_inbound().await.unwrap(); inbound.write_all(b"hello world").await.unwrap(); inbound.close().await.unwrap(); @@ -107,7 +107,7 @@ fn client_to_server_inbound() { tx.send(addr).unwrap(); - let client = transport + let mut client = transport .next() .await .expect("some event") @@ -117,7 +117,7 @@ fn client_to_server_inbound() { .await .unwrap(); - let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap(); + let mut inbound = client.next_inbound().await.unwrap(); let mut buf = Vec::new(); inbound.read_to_end(&mut buf).await.unwrap(); @@ -130,9 +130,9 @@ fn client_to_server_inbound() { .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)) .boxed(); - let client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); + let mut client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); - let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap(); + let mut outbound = client.next_outbound().await.unwrap(); outbound.write_all(b"hello world").await.unwrap(); outbound.close().await.unwrap(); @@ -164,7 +164,7 @@ fn protocol_not_match() { tx.send(addr).unwrap(); - let client = transport + let mut client = transport .next() .await .expect("some event") @@ -174,7 +174,7 @@ fn protocol_not_match() { .await .unwrap(); - let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap(); + let mut outbound = client.next_outbound().await.unwrap(); let mut buf = Vec::new(); outbound.read_to_end(&mut buf).await.unwrap(); diff --git a/muxers/yamux/src/lib.rs b/muxers/yamux/src/lib.rs index a06e7934cf0..07327e203b3 100644 --- a/muxers/yamux/src/lib.rs +++ b/muxers/yamux/src/lib.rs @@ -29,7 +29,6 @@ use futures::{ use libp2p_core::muxing::StreamMuxer; use libp2p_core::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use libp2p_core::Multiaddr; -use parking_lot::Mutex; use std::{ fmt, io, iter, mem, pin::Pin, @@ -39,7 +38,12 @@ use thiserror::Error; use yamux::ConnectionError; /// A Yamux connection. -pub struct Yamux(Mutex>); +pub struct Yamux { + /// The [`futures::stream::Stream`] of incoming substreams. + incoming: S, + /// Handle to control the connection. + control: yamux::Control, +} impl fmt::Debug for Yamux { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -47,13 +51,6 @@ impl fmt::Debug for Yamux { } } -struct Inner { - /// The [`futures::stream::Stream`] of incoming substreams. - incoming: S, - /// Handle to control the connection. - control: yamux::Control, -} - /// A token to poll for an outbound substream. #[derive(Debug)] pub struct OpenSubstreamToken(()); @@ -66,14 +63,14 @@ where fn new(io: C, cfg: yamux::Config, mode: yamux::Mode) -> Self { let conn = yamux::Connection::new(io, cfg, mode); let ctrl = conn.control(); - let inner = Inner { + + Yamux { incoming: Incoming { stream: yamux::into_stream(conn).err_into().boxed(), _marker: std::marker::PhantomData, }, control: ctrl, - }; - Yamux(Mutex::new(inner)) + } } } @@ -85,14 +82,14 @@ where fn local(io: C, cfg: yamux::Config, mode: yamux::Mode) -> Self { let conn = yamux::Connection::new(io, cfg, mode); let ctrl = conn.control(); - let inner = Inner { + + Yamux { incoming: LocalIncoming { stream: yamux::into_stream(conn).err_into().boxed_local(), _marker: std::marker::PhantomData, }, control: ctrl, - }; - Yamux(Mutex::new(inner)) + } } } @@ -105,41 +102,44 @@ where type Substream = yamux::Stream; type Error = YamuxError; - fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll> { - self.0 - .lock() - .incoming - .poll_next_unpin(cx) - .map(|maybe_stream| { - let stream = maybe_stream - .transpose()? - .ok_or(YamuxError(ConnectionError::Closed))?; - - Ok(stream) - }) + fn poll_inbound( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.incoming.poll_next_unpin(cx).map(|maybe_stream| { + let stream = maybe_stream + .transpose()? + .ok_or(YamuxError(ConnectionError::Closed))?; + + Ok(stream) + }) } - fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.0.lock().control) + fn poll_outbound( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + Pin::new(&mut self.control) .poll_open_stream(cx) .map_err(YamuxError) } - fn poll_address_change(&self, _: &mut Context<'_>) -> Poll> { + fn poll_address_change( + self: Pin<&mut Self>, + _: &mut Context<'_>, + ) -> Poll> { Poll::Pending } - fn poll_close(&self, c: &mut Context<'_>) -> Poll> { - let mut inner = self.0.lock(); - - if let Poll::Ready(()) = Pin::new(&mut inner.control) + fn poll_close(mut self: Pin<&mut Self>, c: &mut Context<'_>) -> Poll> { + if let Poll::Ready(()) = Pin::new(&mut self.control) .poll_close(c) .map_err(YamuxError)? { return Poll::Ready(Ok(())); } - while let Poll::Ready(maybe_inbound_stream) = inner.incoming.poll_next_unpin(c)? { + while let Poll::Ready(maybe_inbound_stream) = self.incoming.poll_next_unpin(c)? { match maybe_inbound_stream { Some(inbound_stream) => mem::drop(inbound_stream), None => return Poll::Ready(Ok(())), diff --git a/swarm/src/connection.rs b/swarm/src/connection.rs index 8d29ca53793..f92186618ae 100644 --- a/swarm/src/connection.rs +++ b/swarm/src/connection.rs @@ -32,13 +32,12 @@ pub use pool::{EstablishedConnection, PendingConnection}; use crate::handler::ConnectionHandler; use crate::IntoConnectionHandler; -use futures::future::poll_fn; use handler_wrapper::HandlerWrapper; use libp2p_core::connection::ConnectedPoint; use libp2p_core::multiaddr::Multiaddr; -use libp2p_core::muxing::StreamMuxerBox; +use libp2p_core::muxing::{StreamMuxerBox, StreamMuxerExt}; +use libp2p_core::upgrade; use libp2p_core::PeerId; -use libp2p_core::{upgrade, StreamMuxer}; use std::collections::VecDeque; use std::future::Future; use std::{error::Error, fmt, io, pin::Pin, task::Context, task::Poll}; @@ -132,10 +131,7 @@ where /// Begins an orderly shutdown of the connection, returning the connection /// handler and a `Future` that resolves when connection shutdown is complete. pub fn close(self) -> (THandler, impl Future>) { - ( - self.handler.into_connection_handler(), - poll_fn(move |cx| self.muxing.poll_close(cx)), - ) + (self.handler.into_connection_handler(), self.muxing.close()) } /// Polls the handler and the substream, forwarding events from the former to the latter and @@ -158,7 +154,7 @@ where } if !self.open_info.is_empty() { - if let Poll::Ready(substream) = self.muxing.poll_outbound(cx)? { + if let Poll::Ready(substream) = self.muxing.poll_outbound_unpin(cx)? { let user_data = self .open_info .pop_front() @@ -169,13 +165,13 @@ where } } - if let Poll::Ready(substream) = self.muxing.poll_inbound(cx)? { + if let Poll::Ready(substream) = self.muxing.poll_inbound_unpin(cx)? { self.handler .inject_substream(substream, SubstreamEndpoint::Listener); continue; // Go back to the top, handler can potentially make progress again. } - if let Poll::Ready(address) = self.muxing.poll_address_change(cx)? { + if let Poll::Ready(address) = self.muxing.poll_address_change_unpin(cx)? { self.handler.inject_address_change(&address); return Poll::Ready(Ok(Event::AddressChange(address))); } diff --git a/swarm/src/connection/pool.rs b/swarm/src/connection/pool.rs index 4bbdf9c4162..62e931e9510 100644 --- a/swarm/src/connection/pool.rs +++ b/swarm/src/connection/pool.rs @@ -38,7 +38,7 @@ use futures::{ stream::FuturesUnordered, }; use libp2p_core::connection::{ConnectionId, Endpoint, PendingPoint}; -use libp2p_core::muxing::{StreamMuxer, StreamMuxerBox}; +use libp2p_core::muxing::{StreamMuxerBox, StreamMuxerExt}; use std::{ collections::{hash_map, HashMap}, convert::TryFrom as _, @@ -604,7 +604,7 @@ where match event { task::PendingConnectionEvent::ConnectionEstablished { id, - output: (obtained_peer_id, muxer), + output: (obtained_peer_id, mut muxer), outgoing, } => { let PendingConnectionInfo { @@ -692,7 +692,7 @@ where if let Err(error) = error { self.spawn( poll_fn(move |cx| { - if let Err(e) = ready!(muxer.poll_close(cx)) { + if let Err(e) = ready!(muxer.poll_close_unpin(cx)) { log::debug!( "Failed to close connection {:?} to peer {}: {:?}", id, From 57840a31cd4a72bfa29d62c0b12b6d6f18ab715f Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Thu, 4 Aug 2022 00:54:05 +0200 Subject: [PATCH 22/92] transports/quic: adapt QuicMuxer to libp2p#2724 Discussed in libp2p#2722. --- transports/quic/src/muxer.rs | 303 ++++++++++++++++------------------- 1 file changed, 142 insertions(+), 161 deletions(-) diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index 9fe6e7e4cd9..aaa0a7edcbe 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -22,7 +22,7 @@ use crate::connection::{Connection, ConnectionEvent}; use crate::error::Error; use futures::{AsyncRead, AsyncWrite}; -use libp2p_core::muxing::{StreamMuxer, StreamMuxerEvent}; +use libp2p_core::muxing::StreamMuxer; use parking_lot::Mutex; use std::{ collections::{HashMap, VecDeque}, @@ -54,6 +54,60 @@ struct QuicMuxerInner { poll_event_waker: Option, } +impl QuicMuxerInner { + fn poll_connection(&mut self, cx: &mut Context<'_>) { + while let Poll::Ready(event) = self.connection.poll_event(cx) { + match event { + ConnectionEvent::Connected => { + tracing::error!("Unexpected Connected event on established QUIC connection"); + } + ConnectionEvent::ConnectionLost(_) => { + if let Some(waker) = self.poll_close_waker.take() { + waker.wake(); + } + self.connection.close(); + } + + ConnectionEvent::StreamOpened => { + if let Some(waker) = self.pending_substreams.pop_front() { + waker.wake(); + } + } + ConnectionEvent::StreamReadable(substream) => { + if let Some(substream) = self.substreams.get_mut(&substream) { + if let Some(waker) = substream.read_waker.take() { + waker.wake(); + } + } + } + ConnectionEvent::StreamWritable(substream) => { + if let Some(substream) = self.substreams.get_mut(&substream) { + if let Some(waker) = substream.write_waker.take() { + waker.wake(); + } + } + } + ConnectionEvent::StreamFinished(substream) => { + if let Some(substream) = self.substreams.get_mut(&substream) { + substream.finished = true; + if let Some(waker) = substream.finished_waker.take() { + waker.wake(); + } + } + } + ConnectionEvent::StreamStopped(substream) => { + if let Some(substream) = self.substreams.get_mut(&substream) { + substream.stopped = true; + } + } + ConnectionEvent::StreamAvailable => { + // Handled below. + } + } + } + } +} + /// State of a single substream. #[derive(Default, Clone)] struct SubstreamState { @@ -89,6 +143,93 @@ impl QuicMuxer { } } } +impl StreamMuxer for QuicMuxer { + type Substream = Substream; + type Error = Error; + + fn poll_address_change( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.inner.lock().poll_connection(cx); + // TODO + Poll::Pending + } + + fn poll_inbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + let mut inner = self.inner.lock(); + inner.poll_connection(cx); + if let Some(substream_id) = inner.connection.pop_incoming_substream() { + inner.substreams.insert(substream_id, Default::default()); + let substream = Substream::new(substream_id, self.inner.clone()); + Poll::Ready(Ok(substream)) + } else { + inner.poll_event_waker = Some(cx.waker().clone()); + Poll::Pending + } + } + + fn poll_outbound( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + let mut inner = self.inner.lock(); + inner.poll_connection(cx); + if let Some(substream_id) = inner.connection.pop_outgoing_substream() { + inner.substreams.insert(substream_id, Default::default()); + let substream = Substream::new(substream_id, self.inner.clone()); + Poll::Ready(Ok(substream)) + } else { + inner.pending_substreams.push_back(cx.waker().clone()); + Poll::Pending + } + } + + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let mut inner = self.inner.lock(); + inner.poll_connection(cx); + + if inner.connection.connection.is_drained() { + return Poll::Ready(Ok(())); + } + + if inner.substreams.is_empty() { + let connection = &mut inner.connection; + if !connection.connection.is_closed() { + connection.close(); + if let Some(waker) = inner.poll_event_waker.take() { + waker.wake(); + } + } else { + } + while let Poll::Ready(event) = inner.connection.poll_event(cx) { + if let ConnectionEvent::ConnectionLost(_) = event { + return Poll::Ready(Ok(())); + } + } + } else { + for substream in inner.substreams.clone().keys() { + if let Err(e) = inner.connection.shutdown_substream(*substream) { + tracing::error!("substream finish error on muxer close: {}", e); + } + } + } + + // Register `cx.waker()` as being woken up if the connection closes. + inner.poll_close_waker = Some(cx.waker().clone()); + + Poll::Pending + } +} + +impl fmt::Debug for QuicMuxer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("QuicMuxer").finish() + } +} pub struct Substream { id: quinn_proto::StreamId, @@ -270,163 +411,3 @@ impl AsyncWrite for Substream { } } } - -impl StreamMuxer for QuicMuxer { - type OutboundSubstream = (); - type Substream = Substream; - type Error = Error; - - /// Polls for a connection-wide event. - /// - /// This function behaves the same as a `Stream`. - /// - /// If `Pending` is returned, then the current task will be notified once the muxer - /// is ready to be polled, similar to the API of `Stream::poll()`. - /// Only the latest task that was used to call this method may be notified. - /// - /// It is permissible and common to use this method to perform background - /// work, such as processing incoming packets and polling timers. - /// - /// An error can be generated if the connection has been closed. - fn poll_event( - &self, - cx: &mut Context<'_>, - ) -> Poll, Self::Error>> { - // We use `poll_event` to perform the background processing of the entire connection. - let mut inner = self.inner.lock(); - - while let Poll::Ready(event) = inner.connection.poll_event(cx) { - match event { - ConnectionEvent::Connected => { - tracing::error!("Unexpected Connected event on established QUIC connection"); - } - ConnectionEvent::ConnectionLost(_) => { - if let Some(waker) = inner.poll_close_waker.take() { - waker.wake(); - } - inner.connection.close(); - } - - ConnectionEvent::StreamOpened => { - if let Some(waker) = inner.pending_substreams.pop_front() { - waker.wake(); - } - } - ConnectionEvent::StreamReadable(substream) => { - if let Some(substream) = inner.substreams.get_mut(&substream) { - if let Some(waker) = substream.read_waker.take() { - waker.wake(); - } - } - } - ConnectionEvent::StreamWritable(substream) => { - if let Some(substream) = inner.substreams.get_mut(&substream) { - if let Some(waker) = substream.write_waker.take() { - waker.wake(); - } - } - } - ConnectionEvent::StreamFinished(substream) => { - if let Some(substream) = inner.substreams.get_mut(&substream) { - substream.finished = true; - if let Some(waker) = substream.finished_waker.take() { - waker.wake(); - } - } - } - ConnectionEvent::StreamStopped(substream) => { - if let Some(substream) = inner.substreams.get_mut(&substream) { - substream.stopped = true; - } - } - ConnectionEvent::StreamAvailable => { - // Handled below. - } - } - } - - if let Some(substream_id) = inner.connection.pop_incoming_substream() { - inner.substreams.insert(substream_id, Default::default()); - let substream = Substream::new(substream_id, self.inner.clone()); - Poll::Ready(Ok(StreamMuxerEvent::InboundSubstream(substream))) - } else { - inner.poll_event_waker = Some(cx.waker().clone()); - Poll::Pending - } - } - - /// Opens a new outgoing substream, and produces the equivalent to a future that will be - /// resolved when it becomes available. - /// - /// We provide the same handler to poll it by multiple tasks, which is done as a FIFO - /// queue via `poll_outbound`. - fn open_outbound(&self) -> Self::OutboundSubstream {} - - /// Polls the outbound substream. - /// - /// If `Pending` is returned, then the current task will be notified once the substream - /// is ready to be polled, similar to the API of `Future::poll()`. - fn poll_outbound( - &self, - cx: &mut Context<'_>, - _: &mut Self::OutboundSubstream, - ) -> Poll> { - let mut inner = self.inner.lock(); - if let Some(substream_id) = inner.connection.pop_outgoing_substream() { - inner.substreams.insert(substream_id, Default::default()); - let substream = Substream::new(substream_id, self.inner.clone()); - Poll::Ready(Ok(substream)) - } else { - inner.pending_substreams.push_back(cx.waker().clone()); - Poll::Pending - } - } - - /// Destroys an outbound substream future. Use this after the outbound substream has finished, - /// or if you want to interrupt it. - fn destroy_outbound(&self, _: Self::OutboundSubstream) { - // Do nothing because we don't know which waker should be destroyed. - // TODO `Self::OutboundSubstream` -> autoincrement id. - } - - fn poll_close(&self, cx: &mut Context<'_>) -> Poll> { - let mut inner = self.inner.lock(); - - if inner.connection.connection.is_drained() { - return Poll::Ready(Ok(())); - } - - if inner.substreams.is_empty() { - let connection = &mut inner.connection; - if !connection.connection.is_closed() { - connection.close(); - if let Some(waker) = inner.poll_event_waker.take() { - waker.wake(); - } - } else { - } - while let Poll::Ready(event) = inner.connection.poll_event(cx) { - if let ConnectionEvent::ConnectionLost(_) = event { - return Poll::Ready(Ok(())); - } - } - } else { - for substream in inner.substreams.clone().keys() { - if let Err(e) = inner.connection.shutdown_substream(*substream) { - tracing::error!("substream finish error on muxer close: {}", e); - } - } - } - - // Register `cx.waker()` as being woken up if the connection closes. - inner.poll_close_waker = Some(cx.waker().clone()); - - Poll::Pending - } -} - -impl fmt::Debug for QuicMuxer { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("QuicMuxer").finish() - } -} From 579b1be5d52416faac20655b461ed8ae2347bab9 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 8 Aug 2022 07:18:32 +0200 Subject: [PATCH 23/92] swarm-derive/: Generate OutEvent if not provided (#2792) Generate `NetworkBehaviour::OutEvent` if not provided through `#[behaviour(out_event = "MyOutEvent")]` and event processing is disabled (default). --- CHANGELOG.md | 2 + Cargo.toml | 2 +- swarm-derive/CHANGELOG.md | 5 + swarm-derive/Cargo.toml | 5 +- swarm-derive/src/lib.rs | 146 ++++++++++++++++----- swarm-derive/tests/test.rs | 262 +++++++++++++++++++++---------------- swarm/CHANGELOG.md | 9 ++ swarm/src/behaviour.rs | 23 +--- 8 files changed, 281 insertions(+), 173 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4496d987a0..ca42a4e26eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ - Update to [`libp2p-dcutr` `v0.5.0`](protocols/dcutr/CHANGELOG.md#050). +- Update to [`libp2p-derive` `v0.29.0`](swarm-derive/CHANGELOG.md#0290). + - Update to [`libp2p-rendezvous` `v0.8.0`](protocols/rendezvous/CHANGELOG.md#080). - Update to [`libp2p-ping` `v0.38.0`](protocols/ping/CHANGELOG.md#0380). diff --git a/Cargo.toml b/Cargo.toml index f716d822552..75867ddbf4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,7 +93,7 @@ libp2p-relay = { version = "0.11.0", path = "protocols/relay", optional = true } libp2p-rendezvous = { version = "0.8.0", path = "protocols/rendezvous", optional = true } libp2p-request-response = { version = "0.20.0", path = "protocols/request-response", optional = true } libp2p-swarm = { version = "0.38.0", path = "swarm" } -libp2p-swarm-derive = { version = "0.28.0", path = "swarm-derive" } +libp2p-swarm-derive = { version = "0.29.0", path = "swarm-derive" } libp2p-uds = { version = "0.34.0", path = "transports/uds", optional = true } libp2p-wasm-ext = { version = "0.35.0", path = "transports/wasm-ext", default-features = false, optional = true } libp2p-yamux = { version = "0.39.0", path = "muxers/yamux", optional = true } diff --git a/swarm-derive/CHANGELOG.md b/swarm-derive/CHANGELOG.md index 4d467c5e76a..b8b1e4530e0 100644 --- a/swarm-derive/CHANGELOG.md +++ b/swarm-derive/CHANGELOG.md @@ -1,3 +1,8 @@ +# 0.29.0 - [unreleased] + +- Generate `NetworkBehaviour::OutEvent` if not provided through `#[behaviour(out_event = + "MyOutEvent")]` and event processing is disabled (default). + # 0.28.0 - Import `ListenerId` from `libp2p::core::transport`. See [PR 2652]. diff --git a/swarm-derive/Cargo.toml b/swarm-derive/Cargo.toml index 97a205674d9..05ed063257d 100644 --- a/swarm-derive/Cargo.toml +++ b/swarm-derive/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-swarm-derive" edition = "2021" rust-version = "1.56.1" description = "Procedural macros of libp2p-core" -version = "0.28.0" +version = "0.29.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -14,8 +14,9 @@ categories = ["network-programming", "asynchronous"] proc-macro = true [dependencies] -syn = { version = "1.0.8", default-features = false, features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"] } +heck = "0.4" quote = "1.0" +syn = { version = "1.0.8", default-features = false, features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"] } [dev-dependencies] libp2p = { path = "../", default-features = false, features = ["ping", "identify", "kad"] } diff --git a/swarm-derive/src/lib.rs b/swarm-derive/src/lib.rs index 1216add96c0..8a42220246a 100644 --- a/swarm-derive/src/lib.rs +++ b/swarm-derive/src/lib.rs @@ -20,6 +20,7 @@ #![recursion_limit = "256"] +use heck::ToUpperCamelCase; use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Ident}; @@ -99,49 +100,106 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { .filter(|f| !is_ignored(f)) .collect::>(); - // The final out event. - // If we find a `#[behaviour(out_event = "Foo")]` attribute on the struct, we set `Foo` as - // the out event. Otherwise we use `()`. - let out_event = { - let mut out = quote! {()}; - for meta_items in ast.attrs.iter().filter_map(get_meta_items) { - for meta_item in meta_items { - match meta_item { - syn::NestedMeta::Meta(syn::Meta::NameValue(ref m)) - if m.path.is_ident("out_event") => - { + let (out_event_name, out_event_definition, out_event_from_clauses) = { + // If we find a `#[behaviour(out_event = "Foo")]` attribute on the + // struct, we set `Foo` as the out event. If not, the `OutEvent` is + // generated. + let user_provided_out_event_name: Option = ast + .attrs + .iter() + .filter_map(get_meta_items) + .flatten() + .filter_map(|meta_item| { + if let syn::NestedMeta::Meta(syn::Meta::NameValue(ref m)) = meta_item { + if m.path.is_ident("out_event") { if let syn::Lit::Str(ref s) = m.lit { - let ident: syn::Type = syn::parse_str(&s.value()).unwrap(); - out = quote! {#ident}; + return Some(syn::parse_str(&s.value()).unwrap()); } } - _ => (), } + None + }) + .next(); + + match (user_provided_out_event_name, event_process) { + // User provided `OutEvent`. + (Some(name), false) => { + let definition = None; + let from_clauses = data_struct_fields + .iter() + .map(|field| { + let ty = &field.ty; + quote! {#name #ty_generics: From< <#ty as #trait_to_impl>::OutEvent >} + }) + .collect::>(); + (name, definition, from_clauses) + } + // User did not provide `OutEvent`. Generate it. + (None, false) => { + let name: syn::Type = syn::parse_str(&(ast.ident.to_string() + "Event")).unwrap(); + let definition = { + let fields = data_struct_fields + .iter() + .map(|field| { + let variant: syn::Variant = syn::parse_str( + &field + .ident + .clone() + .expect( + "Fields of NetworkBehaviour implementation to be named.", + ) + .to_string() + .to_upper_camel_case(), + ) + .unwrap(); + let ty = &field.ty; + quote! {#variant(<#ty as NetworkBehaviour>::OutEvent)} + }) + .collect::>(); + let visibility = &ast.vis; + + Some(quote! { + #visibility enum #name #impl_generics { + #(#fields),* + } + }) + }; + let from_clauses = vec![]; + (name, definition, from_clauses) + } + // User uses `NetworkBehaviourEventProcess`. + (name, true) => { + let definition = None; + let from_clauses = data_struct_fields + .iter() + .map(|field| { + let ty = &field.ty; + quote! {Self: #net_behv_event_proc<<#ty as #trait_to_impl>::OutEvent>} + }) + .collect::>(); + ( + name.unwrap_or_else(|| syn::parse_str("()").unwrap()), + definition, + from_clauses, + ) } } - out }; // Build the `where ...` clause of the trait implementation. let where_clause = { let additional = data_struct_fields .iter() - .flat_map(|field| { + .map(|field| { let ty = &field.ty; - vec![ - quote! {#ty: #trait_to_impl}, - if event_process { - quote! {Self: #net_behv_event_proc<<#ty as #trait_to_impl>::OutEvent>} - } else { - quote! {#out_event: From< <#ty as #trait_to_impl>::OutEvent >} - }, - ] + quote! {#ty: #trait_to_impl} }) + .chain(out_event_from_clauses) .collect::>(); if let Some(where_clause) = where_clause { if where_clause.predicates.trailing_punct() { - Some(quote! {#where_clause #(#additional),*}) + Some(quote! {#where_clause #(#additional),* }) } else { Some(quote! {#where_clause, #(#additional),*}) } @@ -437,18 +495,18 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // List of statements to put in `poll()`. // // We poll each child one by one and wrap around the output. - let poll_stmts = data_struct_fields.iter().enumerate().enumerate().map(|(enum_n, (field_n, field))| { - let field_name = match field.ident { - Some(ref i) => quote!{ self.#i }, - None => quote!{ self.#field_n }, - }; + let poll_stmts = data_struct_fields.iter().enumerate().map(|(field_n, field)| { + let field = field + .ident + .clone() + .expect("Fields of NetworkBehaviour implementation to be named."); - let mut wrapped_event = if enum_n != 0 { + let mut wrapped_event = if field_n != 0 { quote!{ #either_ident::Second(event) } } else { quote!{ event } }; - for _ in 0 .. data_struct_fields.len() - 1 - enum_n { + for _ in 0 .. data_struct_fields.len() - 1 - field_n { wrapped_event = quote!{ #either_ident::First(#wrapped_event) }; } @@ -460,7 +518,6 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { let mut out_handler = None; for (f_n, f) in data_struct_fields.iter().enumerate() { - let f_name = match f.ident { Some(ref i) => quote! { self.#i }, None => quote! { self.#f_n }, @@ -492,16 +549,31 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { } } } else { + // If the `NetworkBehaviour`'s `OutEvent` is generated by the derive macro, wrap the sub + // `NetworkBehaviour` `OutEvent` in the variant of the generated `OutEvent`. If the + // `NetworkBehaviour`'s `OutEvent` is provided by the user, use the corresponding `From` + // implementation. + let into_out_event = if out_event_definition.is_some() { + let event_variant: syn::Variant = syn::parse_str( + &field + .to_string() + .to_upper_camel_case() + ).unwrap(); + quote! { #out_event_name::#event_variant(event) } + } else { + quote! { event.into() } + }; + quote! { std::task::Poll::Ready(#network_behaviour_action::GenerateEvent(event)) => { - return std::task::Poll::Ready(#network_behaviour_action::GenerateEvent(event.into())) + return std::task::Poll::Ready(#network_behaviour_action::GenerateEvent(#into_out_event)) } } }; Some(quote!{ loop { - match #trait_to_impl::poll(&mut #field_name, cx, poll_params) { + match #trait_to_impl::poll(&mut self.#field, cx, poll_params) { #generate_event_match_arm std::task::Poll::Ready(#network_behaviour_action::Dial { opts, handler: provided_handler }) => { return std::task::Poll::Ready(#network_behaviour_action::Dial { opts, handler: #provided_handler_and_new_handlers }); @@ -527,11 +599,13 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Now the magic happens. let final_quote = quote! { + #out_event_definition + impl #impl_generics #trait_to_impl for #name #ty_generics #where_clause { type ConnectionHandler = #connection_handler_ty; - type OutEvent = #out_event; + type OutEvent = #out_event_name #ty_generics; fn new_handler(&mut self) -> Self::ConnectionHandler { use #into_connection_handler; diff --git a/swarm-derive/tests/test.rs b/swarm-derive/tests/test.rs index 4961806d357..09048e5e801 100644 --- a/swarm-derive/tests/test.rs +++ b/swarm-derive/tests/test.rs @@ -38,18 +38,17 @@ fn empty() { fn one_field() { #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] struct Foo { ping: libp2p::ping::Ping, } - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} - } - #[allow(dead_code)] + #[allow(unreachable_code)] fn foo() { - require_net_behaviour::(); + let _out_event: ::OutEvent = unimplemented!(); + match _out_event { + FooEvent::Ping(libp2p::ping::Event { .. }) => {} + } } } @@ -57,23 +56,21 @@ fn one_field() { fn two_fields() { #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] struct Foo { ping: libp2p::ping::Ping, identify: libp2p::identify::Identify, } - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {} - } - - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} - } - #[allow(dead_code)] + #[allow(unreachable_code)] fn foo() { - require_net_behaviour::(); + let _out_event: ::OutEvent = unimplemented!(); + match _out_event { + FooEvent::Ping(libp2p::ping::Event { .. }) => {} + FooEvent::Identify(event) => { + let _: libp2p::identify::IdentifyEvent = event; + } + } } } @@ -81,7 +78,6 @@ fn two_fields() { fn three_fields() { #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] struct Foo { ping: libp2p::ping::Ping, identify: libp2p::identify::Identify, @@ -90,21 +86,19 @@ fn three_fields() { foo: String, } - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} - } - - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {} - } - - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::kad::KademliaEvent) {} - } - #[allow(dead_code)] + #[allow(unreachable_code)] fn foo() { - require_net_behaviour::(); + let _out_event: ::OutEvent = unimplemented!(); + match _out_event { + FooEvent::Ping(libp2p::ping::Event { .. }) => {} + FooEvent::Identify(event) => { + let _: libp2p::identify::IdentifyEvent = event; + } + FooEvent::Kad(event) => { + let _: libp2p::kad::KademliaEvent = event; + } + } } } @@ -112,7 +106,6 @@ fn three_fields() { fn three_fields_non_last_ignored() { #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] struct Foo { ping: libp2p::ping::Ping, #[behaviour(ignore)] @@ -120,17 +113,16 @@ fn three_fields_non_last_ignored() { kad: libp2p::kad::Kademlia, } - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} - } - - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::kad::KademliaEvent) {} - } - #[allow(dead_code)] + #[allow(unreachable_code)] fn foo() { - require_net_behaviour::(); + let _out_event: ::OutEvent = unimplemented!(); + match _out_event { + FooEvent::Ping(libp2p::ping::Event { .. }) => {} + FooEvent::Kad(event) => { + let _: libp2p::kad::KademliaEvent = event; + } + } } } @@ -138,20 +130,12 @@ fn three_fields_non_last_ignored() { fn custom_polling() { #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(poll_method = "foo", event_process = true)] + #[behaviour(poll_method = "foo")] struct Foo { ping: libp2p::ping::Ping, identify: libp2p::identify::Identify, } - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} - } - - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {} - } - impl Foo { fn foo( &mut self, @@ -177,18 +161,27 @@ fn custom_polling() { fn custom_event_no_polling() { #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(out_event = "Vec", event_process = true)] + #[behaviour(out_event = "MyEvent")] struct Foo { ping: libp2p::ping::Ping, identify: libp2p::identify::Identify, } - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} + enum MyEvent { + Ping(libp2p::ping::PingEvent), + Identify(libp2p::identify::IdentifyEvent), } - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {} + impl From for MyEvent { + fn from(event: libp2p::ping::PingEvent) -> Self { + MyEvent::Ping(event) + } + } + + impl From for MyEvent { + fn from(event: libp2p::identify::IdentifyEvent) -> Self { + MyEvent::Identify(event) + } } #[allow(dead_code)] @@ -201,18 +194,27 @@ fn custom_event_no_polling() { fn custom_event_and_polling() { #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(poll_method = "foo", out_event = "String", event_process = true)] + #[behaviour(poll_method = "foo", out_event = "MyEvent")] struct Foo { ping: libp2p::ping::Ping, identify: libp2p::identify::Identify, } - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} + enum MyEvent { + Ping(libp2p::ping::PingEvent), + Identify(libp2p::identify::IdentifyEvent), } - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {} + impl From for MyEvent { + fn from(event: libp2p::ping::PingEvent) -> Self { + MyEvent::Ping(event) + } + } + + impl From for MyEvent { + fn from(event: libp2p::identify::IdentifyEvent) -> Self { + MyEvent::Identify(event) + } } impl Foo { @@ -236,12 +238,44 @@ fn custom_event_and_polling() { } } +#[test] +fn custom_event_mismatching_field_names() { + #[allow(dead_code)] + #[derive(NetworkBehaviour)] + #[behaviour(out_event = "MyEvent")] + struct Foo { + a: libp2p::ping::Ping, + b: libp2p::identify::Identify, + } + + enum MyEvent { + Ping(libp2p::ping::PingEvent), + Identify(libp2p::identify::IdentifyEvent), + } + + impl From for MyEvent { + fn from(event: libp2p::ping::PingEvent) -> Self { + MyEvent::Ping(event) + } + } + + impl From for MyEvent { + fn from(event: libp2p::identify::IdentifyEvent) -> Self { + MyEvent::Identify(event) + } + } + + #[allow(dead_code)] + fn foo() { + require_net_behaviour::(); + } +} + #[test] fn where_clause() { #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] - struct Foo { + struct Foo { ping: libp2p::ping::Ping, bar: T, } @@ -249,38 +283,30 @@ fn where_clause() { #[test] fn nested_derives_with_import() { - use libp2p::swarm::NetworkBehaviourEventProcess; - #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] struct Foo { ping: libp2p::ping::Ping, } #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] struct Bar { foo: Foo, } - impl NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} - } - - impl NetworkBehaviourEventProcess<()> for Bar { - fn inject_event(&mut self, _: ()) {} - } - #[allow(dead_code)] - fn bar() { - require_net_behaviour::(); + #[allow(unreachable_code)] + fn foo() { + let _out_event: ::OutEvent = unimplemented!(); + match _out_event { + BarEvent::Foo(FooEvent::Ping(libp2p::ping::Event { .. })) => {} + } } } #[test] -fn event_process_false() { +fn custom_event_emit_event_through_poll() { enum BehaviourOutEvent { Ping(libp2p::ping::PingEvent), Identify(libp2p::identify::IdentifyEvent), @@ -331,20 +357,11 @@ fn with_toggle() { #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] struct Foo { identify: libp2p::identify::Identify, ping: Toggle, } - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {} - } - - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} - } - #[allow(dead_code)] fn foo() { require_net_behaviour::(); @@ -357,28 +374,11 @@ fn with_either() { #[allow(dead_code)] #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] struct Foo { kad: libp2p::kad::Kademlia, ping_or_identify: Either, } - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::kad::KademliaEvent) {} - } - - impl - libp2p::swarm::NetworkBehaviourEventProcess< - Either, - > for Foo - { - fn inject_event( - &mut self, - _: Either, - ) { - } - } - #[allow(dead_code)] fn foo() { require_net_behaviour::(); @@ -386,7 +386,7 @@ fn with_either() { } #[test] -fn no_event_with_either() { +fn custom_event_with_either() { use either::Either; enum BehaviourOutEvent { @@ -394,14 +394,6 @@ fn no_event_with_either() { PingOrIdentify(Either), } - #[allow(dead_code)] - #[derive(NetworkBehaviour)] - #[behaviour(out_event = "BehaviourOutEvent", event_process = false)] - struct Foo { - kad: libp2p::kad::Kademlia, - ping_or_identify: Either, - } - impl From for BehaviourOutEvent { fn from(event: libp2p::kad::KademliaEvent) -> Self { BehaviourOutEvent::Kad(event) @@ -414,6 +406,14 @@ fn no_event_with_either() { } } + #[allow(dead_code)] + #[derive(NetworkBehaviour)] + #[behaviour(out_event = "BehaviourOutEvent")] + struct Foo { + kad: libp2p::kad::Kademlia, + ping_or_identify: Either, + } + #[allow(dead_code)] fn foo() { require_net_behaviour::(); @@ -425,7 +425,6 @@ fn mixed_field_order() { struct Foo {} #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] pub struct Behaviour { #[behaviour(ignore)] _foo: Foo, @@ -437,12 +436,43 @@ fn mixed_field_order() { _foo3: Foo, } - impl libp2p::swarm::NetworkBehaviourEventProcess for Behaviour { - fn inject_event(&mut self, _evt: T) {} - } - #[allow(dead_code)] fn behaviour() { require_net_behaviour::(); } } + +#[test] +fn event_process() { + #[allow(dead_code)] + #[derive(NetworkBehaviour)] + #[behaviour(event_process = true)] + struct Foo { + ping: libp2p::ping::Ping, + identify: libp2p::identify::Identify, + } + + impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { + fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {} + } + + impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { + fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} + } + + #[allow(dead_code, unreachable_code)] + fn bar() { + require_net_behaviour::(); + + let mut _swarm: libp2p::Swarm = unimplemented!(); + + let _ = async { + loop { + match _swarm.select_next_some().await { + SwarmEvent::Behaviour(()) => break, + _ => {} + } + } + }; + } +} diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index 02edf9beef4..62de6afa063 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -4,6 +4,15 @@ - Update to `libp2p-core` `v0.35.0`. +- When deriving `NetworkBehaviour` on a custom `struct` where the user does not specify their own + `OutEvent` via `#[behaviour(out_event = "MyBehaviourEvent")]` and where the user does not enable + `#[behaviour(event_process = true)]`, then the derive macro generates an `OutEvent` definition for + the user. + + See [`NetworkBehaviour` + documentation](https://docs.rs/libp2p/latest/libp2p/swarm/trait.NetworkBehaviour.html) for + details. + [PR 2741]: https://github.com/libp2p/rust-libp2p/pull/2741/ # 0.37.0 diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index 3dd6ddf9588..7ab54c73c05 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -79,16 +79,11 @@ pub(crate) type THandlerOutEvent = /// it will delegate to each `struct` member and return a concatenated array of all addresses /// returned by the struct members. /// -/// When creating a custom [`NetworkBehaviour`], you must choose one of two methods to respond to -/// incoming events: -/// * One option is setting a custom `out_event` with `#[behaviour(out_event = "AnotherType")]`. -/// In this case, events generated by the custom [`NetworkBehaviour`] struct members will be -/// converted to your custom `out_event` for you to handle after polling the swarm. -/// * Alternatively, users that need access to the root [`NetworkBehaviour`] implementation while -/// processing emitted events, can specify `#[behaviour(event_process = true)]` (default is false). -/// Events generated by the behaviour's struct members are delegated to [`NetworkBehaviourEventProcess`] -/// trait implementations. Those must be provided by the user on the type that [`NetworkBehaviour`] -/// is derived on. +/// Events ([`NetworkBehaviour::OutEvent`]) returned by each `struct` member are wrapped in a new +/// `enum` event, with an `enum` variant for each `struct` member. Users can define this event +/// `enum` themselves and provide the name to the derive macro via `#[behaviour(out_event = +/// "MyCustomOutEvent")]`. If the user does not specify an `out_event`, the derive macro generates +/// the event definition itself, naming it `Event`. /// /// When setting a custom `out_event`, the aforementioned conversion of each of the event types /// generated by the struct members to the custom `out_event` is handled by [`From`] @@ -123,14 +118,6 @@ pub(crate) type THandlerOutEvent = /// } /// ``` /// -/// When using `event_process = true` the [`NetworkBehaviourEventProcess`] trait implementations -/// are granted exclusive access to the [`NetworkBehaviour`], therefore -/// [blocking code](https://ryhl.io/blog/async-what-is-blocking/) in these implementations will -/// block the entire [`Swarm`](crate::Swarm) from processing new events, since the swarm cannot progress -/// without also having exclusive access to the [`NetworkBehaviour`]. A better alternative is to execute -/// blocking or asynchronous logic on a separate task, perhaps with the help of a bounded channel to -/// maintain backpressure. The sender for the channel could be included in the NetworkBehaviours constructor. -/// /// Optionally one can provide a custom `poll` function through the `#[behaviour(poll_method = /// "poll")]` attribute. This function must have the same signature as the [`NetworkBehaviour#poll`] /// function and will be called last within the generated [`NetworkBehaviour`] implementation. From e2b83b7c8fb7fb349d2cad3c20f05285d0fd6530 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 8 Aug 2022 08:14:46 +0200 Subject: [PATCH 24/92] SECURITY.md: Document supported releases and security mail addr (#2800) --- SECURITY.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..4db2a630818 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,9 @@ +# Security Policy + +## Supported Versions + +By default we provide security patches for the latest released version only. On request we patch older versions. + +## Reporting a Vulnerability + +Please reach out to security@libp2p.io. Please do not file a public issue on GitHub. From 3da8b423c282383b7c55b2eda7050bd991a2813b Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 8 Aug 2022 10:57:11 +0200 Subject: [PATCH 25/92] README: Point to security@libp2p.io (#2799) --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index cb81ca42c79..d13ee922496 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -5,7 +5,7 @@ about: Create a bug report for rust-libp2p. - + ## Summary diff --git a/README.md b/README.md index 6e668184a8b..b2e5a7d9bac 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This repository is the central place for Rust development of the [libp2p](https: - The **[examples](examples)** folder contains small binaries showcasing the many protocols in this repository. -- For **security related issues** please reach out to security@ipfs.io. Please +- For **security related issues** please reach out to security@libp2p.io. Please do not file a public issue on GitHub. - To **report bugs, suggest improvements or request new features** please open a From 1012579d776268ec18f1a3f1cbea30fcbf0921dc Mon Sep 17 00:00:00 2001 From: Kourosh Date: Wed, 10 Aug 2022 12:20:24 +0430 Subject: [PATCH 26/92] protocols/: Remove passing default variant to `WithPeerId::condition` (#2802) --- protocols/floodsub/src/layer.rs | 12 ++++-------- protocols/gossipsub/src/behaviour.rs | 12 ++++-------- protocols/identify/src/identify.rs | 10 ++++------ protocols/kad/src/behaviour.rs | 9 ++------- protocols/request-response/src/lib.rs | 9 +++------ 5 files changed, 17 insertions(+), 35 deletions(-) diff --git a/protocols/floodsub/src/layer.rs b/protocols/floodsub/src/layer.rs index 059ff505080..4256e39b7dc 100644 --- a/protocols/floodsub/src/layer.rs +++ b/protocols/floodsub/src/layer.rs @@ -29,8 +29,8 @@ use fnv::FnvHashSet; use libp2p_core::{connection::ConnectionId, PeerId}; use libp2p_core::{ConnectedPoint, Multiaddr}; use libp2p_swarm::{ - dial_opts::{self, DialOpts}, - NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, OneShotHandler, PollParameters, + dial_opts::DialOpts, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, OneShotHandler, + PollParameters, }; use log::warn; use smallvec::SmallVec; @@ -109,9 +109,7 @@ impl Floodsub { if self.target_peers.insert(peer_id) { let handler = self.new_handler(); self.events.push_back(NetworkBehaviourAction::Dial { - opts: DialOpts::peer_id(peer_id) - .condition(dial_opts::PeerCondition::Disconnected) - .build(), + opts: DialOpts::peer_id(peer_id).build(), handler, }); } @@ -343,9 +341,7 @@ impl NetworkBehaviour for Floodsub { if self.target_peers.contains(id) { let handler = self.new_handler(); self.events.push_back(NetworkBehaviourAction::Dial { - opts: DialOpts::peer_id(*id) - .condition(dial_opts::PeerCondition::Disconnected) - .build(), + opts: DialOpts::peer_id(*id).build(), handler, }); } diff --git a/protocols/gossipsub/src/behaviour.rs b/protocols/gossipsub/src/behaviour.rs index 3ec0b117d58..82dc3469e73 100644 --- a/protocols/gossipsub/src/behaviour.rs +++ b/protocols/gossipsub/src/behaviour.rs @@ -41,8 +41,8 @@ use libp2p_core::{ multiaddr::Protocol::Ip6, ConnectedPoint, Multiaddr, PeerId, }; use libp2p_swarm::{ - dial_opts::{self, DialOpts}, - IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, + dial_opts::DialOpts, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, + NotifyHandler, PollParameters, }; use wasm_timer::Instant; @@ -1143,9 +1143,7 @@ where debug!("Connecting to explicit peer {:?}", peer_id); let handler = self.new_handler(); self.events.push_back(NetworkBehaviourAction::Dial { - opts: DialOpts::peer_id(*peer_id) - .condition(dial_opts::PeerCondition::Disconnected) - .build(), + opts: DialOpts::peer_id(*peer_id).build(), handler, }); } @@ -1644,9 +1642,7 @@ where // dial peer let handler = self.new_handler(); self.events.push_back(NetworkBehaviourAction::Dial { - opts: DialOpts::peer_id(peer_id) - .condition(dial_opts::PeerCondition::Disconnected) - .build(), + opts: DialOpts::peer_id(peer_id).build(), handler, }); } diff --git a/protocols/identify/src/identify.rs b/protocols/identify/src/identify.rs index 9ed56b3265e..d30e98e1400 100644 --- a/protocols/identify/src/identify.rs +++ b/protocols/identify/src/identify.rs @@ -26,9 +26,9 @@ use libp2p_core::{ Multiaddr, PeerId, PublicKey, }; use libp2p_swarm::{ - dial_opts::{self, DialOpts}, - AddressScore, ConnectionHandler, ConnectionHandlerUpgrErr, DialError, IntoConnectionHandler, - NegotiatedSubstream, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, + dial_opts::DialOpts, AddressScore, ConnectionHandler, ConnectionHandlerUpgrErr, DialError, + IntoConnectionHandler, NegotiatedSubstream, NetworkBehaviour, NetworkBehaviourAction, + NotifyHandler, PollParameters, }; use lru::LruCache; use std::{ @@ -196,9 +196,7 @@ impl Identify { if self.pending_push.insert(p) && !self.connected.contains_key(&p) { let handler = self.new_handler(); self.events.push_back(NetworkBehaviourAction::Dial { - opts: DialOpts::peer_id(p) - .condition(dial_opts::PeerCondition::Disconnected) - .build(), + opts: DialOpts::peer_id(p).build(), handler, }); } diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index 59d63b36e9d..f40932ad0d3 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -565,9 +565,7 @@ where kbucket::InsertResult::Pending { disconnected } => { let handler = self.new_handler(); self.queued_events.push_back(NetworkBehaviourAction::Dial { - opts: DialOpts::peer_id(disconnected.into_preimage()) - .condition(dial_opts::PeerCondition::Disconnected) - .build(), + opts: DialOpts::peer_id(disconnected.into_preimage()).build(), handler, }); RoutingUpdate::Pending @@ -1162,7 +1160,6 @@ where let handler = self.new_handler(); self.queued_events.push_back(NetworkBehaviourAction::Dial { opts: DialOpts::peer_id(disconnected.into_preimage()) - .condition(dial_opts::PeerCondition::Disconnected) .build(), handler, }) @@ -2342,9 +2339,7 @@ where query.inner.pending_rpcs.push((peer_id, event)); let handler = self.new_handler(); self.queued_events.push_back(NetworkBehaviourAction::Dial { - opts: DialOpts::peer_id(peer_id) - .condition(dial_opts::PeerCondition::Disconnected) - .build(), + opts: DialOpts::peer_id(peer_id).build(), handler, }); } diff --git a/protocols/request-response/src/lib.rs b/protocols/request-response/src/lib.rs index f8a4e2eb3a9..ea334292494 100644 --- a/protocols/request-response/src/lib.rs +++ b/protocols/request-response/src/lib.rs @@ -66,9 +66,8 @@ use futures::channel::oneshot; use handler::{RequestProtocol, RequestResponseHandler, RequestResponseHandlerEvent}; use libp2p_core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId}; use libp2p_swarm::{ - dial_opts::{self, DialOpts}, - DialError, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, - PollParameters, + dial_opts::DialOpts, DialError, IntoConnectionHandler, NetworkBehaviour, + NetworkBehaviourAction, NotifyHandler, PollParameters, }; use smallvec::SmallVec; use std::{ @@ -385,9 +384,7 @@ where if let Some(request) = self.try_send_request(peer, request) { let handler = self.new_handler(); self.pending_events.push_back(NetworkBehaviourAction::Dial { - opts: DialOpts::peer_id(*peer) - .condition(dial_opts::PeerCondition::Disconnected) - .build(), + opts: DialOpts::peer_id(*peer).build(), handler, }); self.pending_outbound_requests From a4110a2b6939d5b460f11df6dd158308f517becf Mon Sep 17 00:00:00 2001 From: Kourosh Date: Wed, 10 Aug 2022 12:50:31 +0430 Subject: [PATCH 27/92] *: Remove `inject_connected` / `inject_disconnected` from docs (#2805) --- protocols/gossipsub/src/behaviour.rs | 2 +- swarm/src/behaviour.rs | 7 +++---- swarm/src/lib.rs | 18 +++++++----------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/protocols/gossipsub/src/behaviour.rs b/protocols/gossipsub/src/behaviour.rs index 82dc3469e73..900e1b43be4 100644 --- a/protocols/gossipsub/src/behaviour.rs +++ b/protocols/gossipsub/src/behaviour.rs @@ -3335,7 +3335,7 @@ where )); } else if let Some(conn) = self.connected_peers.get_mut(&propagation_source) { // Only change the value if the old value is Floodsub (the default set in - // inject_connected). All other PeerKind changes are ignored. + // inject_connection_established). All other PeerKind changes are ignored. debug!( "New peer type found: {} for peer: {}", kind, propagation_source diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index 7ab54c73c05..d6802c086a8 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -205,8 +205,7 @@ pub trait NetworkBehaviour: 'static { /// Informs the behaviour about a closed connection to a peer. /// /// A call to this method is always paired with an earlier call to - /// `inject_connection_established` with the same peer ID, connection ID and - /// endpoint. + /// [`NetworkBehaviour::inject_connection_established`] with the same peer ID, connection ID and endpoint. fn inject_connection_closed( &mut self, _: &PeerId, @@ -230,8 +229,8 @@ pub trait NetworkBehaviour: 'static { /// Informs the behaviour about an event generated by the handler dedicated to the peer identified by `peer_id`. /// for the behaviour. /// - /// The `peer_id` is guaranteed to be in a connected state. In other words, `inject_connected` - /// has previously been called with this `PeerId`. + /// The `peer_id` is guaranteed to be in a connected state. In other words, + /// [`NetworkBehaviour::inject_connection_established`] has previously been called with this `PeerId`. fn inject_event( &mut self, peer_id: PeerId, diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index f32c2df56bf..74de015a858 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -1701,13 +1701,12 @@ mod tests { /// after which one peer bans the other. /// /// The test expects both behaviours to be notified via pairs of - /// inject_connected / inject_disconnected as well as - /// inject_connection_established / inject_connection_closed calls - /// while unbanned. + /// [`NetworkBehaviour::inject_connection_established`] / [`NetworkBehaviour::inject_connection_closed`] + /// calls while unbanned. /// /// While the ban is in effect, further dials occur. For these connections no - /// `inject_connected`, `inject_connection_established`, `inject_disconnected`, - /// `inject_connection_closed` calls should be registered. + /// [`NetworkBehaviour::inject_connection_established`], [`NetworkBehaviour::inject_connection_closed`] + /// calls should be registered. #[test] fn test_connect_disconnect_ban() { // Since the test does not try to open any substreams, we can @@ -1827,8 +1826,7 @@ mod tests { /// after which one peer disconnects the other using [`Swarm::disconnect_peer_id`]. /// /// The test expects both behaviours to be notified via pairs of - /// inject_connected / inject_disconnected as well as - /// inject_connection_established / inject_connection_closed calls. + /// [`NetworkBehaviour::inject_connection_established`] / [`NetworkBehaviour::inject_connection_closed`] calls. #[test] fn test_swarm_disconnect() { // Since the test does not try to open any substreams, we can @@ -1896,8 +1894,7 @@ mod tests { /// using [`NetworkBehaviourAction::CloseConnection`] returned by a [`NetworkBehaviour`]. /// /// The test expects both behaviours to be notified via pairs of - /// inject_connected / inject_disconnected as well as - /// inject_connection_established / inject_connection_closed calls. + /// [`NetworkBehaviour::inject_connection_established`] / [`NetworkBehaviour::inject_connection_closed`] calls. #[test] fn test_behaviour_disconnect_all() { // Since the test does not try to open any substreams, we can @@ -1967,8 +1964,7 @@ mod tests { /// using [`NetworkBehaviourAction::CloseConnection`] returned by a [`NetworkBehaviour`]. /// /// The test expects both behaviours to be notified via pairs of - /// inject_connected / inject_disconnected as well as - /// inject_connection_established / inject_connection_closed calls. + /// [`NetworkBehaviour::inject_connection_established`] / [`NetworkBehaviour::inject_connection_closed`] calls. #[test] fn test_behaviour_disconnect_one() { // Since the test does not try to open any substreams, we can From 0a01c81c7b5e2d8e47df66c3381ac4b19196ad26 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Sat, 13 Aug 2022 12:46:45 +0200 Subject: [PATCH 28/92] misc/multistream-select: Replace msg.get(0) with msg.first() (#2816) --- misc/multistream-select/src/protocol.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/multistream-select/src/protocol.rs b/misc/multistream-select/src/protocol.rs index 1cfdcc4b588..d1374ef7495 100644 --- a/misc/multistream-select/src/protocol.rs +++ b/misc/multistream-select/src/protocol.rs @@ -179,7 +179,7 @@ impl Message { // If it starts with a `/`, ends with a line feed without any // other line feeds in-between, it must be a protocol name. - if msg.get(0) == Some(&b'/') + if msg.first() == Some(&b'/') && msg.last() == Some(&b'\n') && !msg[..msg.len() - 1].contains(&b'\n') { From 3ce0ef9de7f012af4416e7f1556db613f8c974b1 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sat, 13 Aug 2022 16:33:50 +0200 Subject: [PATCH 29/92] transports/quic: apply suggestions from review --- transports/quic/src/muxer.rs | 48 +++++++++++++++++------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index aaa0a7edcbe..ba4a771c328 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -25,14 +25,15 @@ use futures::{AsyncRead, AsyncWrite}; use libp2p_core::muxing::StreamMuxer; use parking_lot::Mutex; use std::{ - collections::{HashMap, VecDeque}, - fmt, io, + collections::HashMap, + io, pin::Pin, sync::{Arc, Weak}, task::{Context, Poll, Waker}, }; /// State for a single opened QUIC connection. +#[derive(Debug)] pub struct QuicMuxer { // Note: This could theoretically be an asynchronous future, in order to yield the current // task if a task running in parallel is already holding the lock. However, using asynchronous @@ -41,17 +42,18 @@ pub struct QuicMuxer { } /// Mutex-protected fields of [`QuicMuxer`]. +#[derive(Debug)] struct QuicMuxerInner { /// Inner connection object that yields events. connection: Connection, // /// State of all the substreams that the muxer reports as open. substreams: HashMap, - /// A FIFO of wakers to wake if a new outgoing substream is opened. - pending_substreams: VecDeque, + /// Waker to wake if a new outbound substream is opened. + poll_outbound_waker: Option, + /// Waker to wake if a new inbound substream was happened. + poll_inbound_waker: Option, /// Waker to wake if the connection is closed. poll_close_waker: Option, - /// Waker to wake if any event is happened. - poll_event_waker: Option, } impl QuicMuxerInner { @@ -59,7 +61,7 @@ impl QuicMuxerInner { while let Poll::Ready(event) = self.connection.poll_event(cx) { match event { ConnectionEvent::Connected => { - tracing::error!("Unexpected Connected event on established QUIC connection"); + tracing::warn!("Unexpected Connected event on established QUIC connection"); } ConnectionEvent::ConnectionLost(_) => { if let Some(waker) = self.poll_close_waker.take() { @@ -69,7 +71,7 @@ impl QuicMuxerInner { } ConnectionEvent::StreamOpened => { - if let Some(waker) = self.pending_substreams.pop_front() { + if let Some(waker) = self.poll_outbound_waker.take() { waker.wake(); } } @@ -101,7 +103,9 @@ impl QuicMuxerInner { } } ConnectionEvent::StreamAvailable => { - // Handled below. + if let Some(waker) = self.poll_inbound_waker.take() { + waker.wake(); + } } } } @@ -109,7 +113,7 @@ impl QuicMuxerInner { } /// State of a single substream. -#[derive(Default, Clone)] +#[derive(Debug, Default, Clone)] struct SubstreamState { /// Waker to wake if the substream becomes readable or stopped. read_waker: Option, @@ -136,9 +140,9 @@ impl QuicMuxer { inner: Arc::new(Mutex::new(QuicMuxerInner { connection, substreams: Default::default(), - pending_substreams: Default::default(), + poll_outbound_waker: None, poll_close_waker: None, - poll_event_waker: None, + poll_inbound_waker: None, })), } } @@ -167,7 +171,7 @@ impl StreamMuxer for QuicMuxer { let substream = Substream::new(substream_id, self.inner.clone()); Poll::Ready(Ok(substream)) } else { - inner.poll_event_waker = Some(cx.waker().clone()); + inner.poll_inbound_waker = Some(cx.waker().clone()); Poll::Pending } } @@ -183,7 +187,7 @@ impl StreamMuxer for QuicMuxer { let substream = Substream::new(substream_id, self.inner.clone()); Poll::Ready(Ok(substream)) } else { - inner.pending_substreams.push_back(cx.waker().clone()); + inner.poll_outbound_waker = Some(cx.waker().clone()); Poll::Pending } } @@ -200,7 +204,7 @@ impl StreamMuxer for QuicMuxer { let connection = &mut inner.connection; if !connection.connection.is_closed() { connection.close(); - if let Some(waker) = inner.poll_event_waker.take() { + if let Some(waker) = inner.poll_inbound_waker.take() { waker.wake(); } } else { @@ -211,9 +215,9 @@ impl StreamMuxer for QuicMuxer { } } } else { - for substream in inner.substreams.clone().keys() { - if let Err(e) = inner.connection.shutdown_substream(*substream) { - tracing::error!("substream finish error on muxer close: {}", e); + for substream in inner.substreams.keys().cloned().collect::>() { + if let Err(e) = inner.connection.shutdown_substream(substream) { + tracing::warn!("substream finish error on muxer close: {}", e); } } } @@ -225,12 +229,6 @@ impl StreamMuxer for QuicMuxer { } } -impl fmt::Debug for QuicMuxer { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("QuicMuxer").finish() - } -} - pub struct Substream { id: quinn_proto::StreamId, muxer: Weak>, @@ -319,7 +317,7 @@ impl AsyncRead for Substream { } } if chunks.finalize().should_transmit() { - if let Some(waker) = muxer.poll_event_waker.take() { + if let Some(waker) = muxer.poll_inbound_waker.take() { waker.wake(); } } From 3060d122a1f5751e252f7a7479f2ddb48b02847d Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sat, 13 Aug 2022 16:38:58 +0200 Subject: [PATCH 30/92] transports/quic: rename QuicMuxerInner -> Inner --- transports/quic/src/muxer.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index ba4a771c328..06d8c783376 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -38,12 +38,12 @@ pub struct QuicMuxer { // Note: This could theoretically be an asynchronous future, in order to yield the current // task if a task running in parallel is already holding the lock. However, using asynchronous // mutexes without async/await is extremely tedious and maybe not worth the effort. - inner: Arc>, + inner: Arc>, } /// Mutex-protected fields of [`QuicMuxer`]. #[derive(Debug)] -struct QuicMuxerInner { +struct Inner { /// Inner connection object that yields events. connection: Connection, // /// State of all the substreams that the muxer reports as open. @@ -56,7 +56,7 @@ struct QuicMuxerInner { poll_close_waker: Option, } -impl QuicMuxerInner { +impl Inner { fn poll_connection(&mut self, cx: &mut Context<'_>) { while let Poll::Ready(event) = self.connection.poll_event(cx) { match event { @@ -137,7 +137,7 @@ impl QuicMuxer { assert!(!connection.is_handshaking()); QuicMuxer { - inner: Arc::new(Mutex::new(QuicMuxerInner { + inner: Arc::new(Mutex::new(Inner { connection, substreams: Default::default(), poll_outbound_waker: None, @@ -231,11 +231,11 @@ impl StreamMuxer for QuicMuxer { pub struct Substream { id: quinn_proto::StreamId, - muxer: Weak>, + muxer: Weak>, } impl Substream { - fn new(id: quinn_proto::StreamId, muxer: Arc>) -> Self { + fn new(id: quinn_proto::StreamId, muxer: Arc>) -> Self { Self { id, muxer: Arc::downgrade(&muxer), From 63c6edc0697c6a0e388d32e97bc73cc3488ca5e0 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sat, 13 Aug 2022 17:07:52 +0200 Subject: [PATCH 31/92] transports/quic: improve poll_{inbound, outbound} --- transports/quic/src/muxer.rs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index 06d8c783376..96c6cddf4b6 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -166,14 +166,16 @@ impl StreamMuxer for QuicMuxer { ) -> Poll> { let mut inner = self.inner.lock(); inner.poll_connection(cx); - if let Some(substream_id) = inner.connection.pop_incoming_substream() { - inner.substreams.insert(substream_id, Default::default()); - let substream = Substream::new(substream_id, self.inner.clone()); - Poll::Ready(Ok(substream)) - } else { - inner.poll_inbound_waker = Some(cx.waker().clone()); - Poll::Pending - } + let substream_id = match inner.connection.pop_incoming_substream() { + Some(id) => id, + None => { + inner.poll_inbound_waker = Some(cx.waker().clone()); + return Poll::Pending; + } + }; + inner.substreams.insert(substream_id, Default::default()); + let substream = Substream::new(substream_id, self.inner.clone()); + Poll::Ready(Ok(substream)) } fn poll_outbound( @@ -182,14 +184,16 @@ impl StreamMuxer for QuicMuxer { ) -> Poll> { let mut inner = self.inner.lock(); inner.poll_connection(cx); - if let Some(substream_id) = inner.connection.pop_outgoing_substream() { - inner.substreams.insert(substream_id, Default::default()); - let substream = Substream::new(substream_id, self.inner.clone()); - Poll::Ready(Ok(substream)) - } else { - inner.poll_outbound_waker = Some(cx.waker().clone()); - Poll::Pending - } + let substream_id = match inner.connection.pop_outgoing_substream() { + Some(id) => id, + None => { + inner.poll_outbound_waker = Some(cx.waker().clone()); + return Poll::Pending; + } + }; + inner.substreams.insert(substream_id, Default::default()); + let substream = Substream::new(substream_id, self.inner.clone()); + Poll::Ready(Ok(substream)) } fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { From 06aaea67f38c90c4eae70014438e069e1a042882 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Sun, 14 Aug 2022 04:03:04 +0200 Subject: [PATCH 32/92] *: Fix `clippy::derive-partial-eq-without-eq` (#2818) --- core/src/lib.rs | 2 ++ core/src/peer_record.rs | 2 +- core/src/signed_envelope.rs | 2 +- protocols/autonat/src/behaviour.rs | 2 +- protocols/autonat/src/behaviour/as_client.rs | 4 ++-- protocols/autonat/src/behaviour/as_server.rs | 4 ++-- protocols/autonat/src/lib.rs | 1 + protocols/dcutr/src/lib.rs | 1 + protocols/floodsub/src/lib.rs | 1 + protocols/gossipsub/src/config.rs | 2 +- protocols/gossipsub/src/rpc_proto.rs | 1 + protocols/gossipsub/src/types.rs | 2 +- protocols/identify/src/lib.rs | 1 + protocols/kad/src/lib.rs | 1 + protocols/relay/src/v2.rs | 1 + protocols/relay/src/v2/protocol.rs | 2 +- protocols/rendezvous/src/codec.rs | 3 ++- protocols/request-response/src/lib.rs | 4 ++-- transports/noise/src/io/handshake.rs | 1 + transports/plaintext/src/lib.rs | 1 + 20 files changed, 25 insertions(+), 13 deletions(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index 315e20bc8cd..fc5b6c2426e 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -38,6 +38,7 @@ #[cfg(feature = "serde")] extern crate _serde as serde; +#[allow(clippy::derive_partial_eq_without_eq)] mod keys_proto { include!(concat!(env!("OUT_DIR"), "/keys_proto.rs")); } @@ -46,6 +47,7 @@ mod envelope_proto { include!(concat!(env!("OUT_DIR"), "/envelope_proto.rs")); } +#[allow(clippy::derive_partial_eq_without_eq)] mod peer_record_proto { include!(concat!(env!("OUT_DIR"), "/peer_record_proto.rs")); } diff --git a/core/src/peer_record.rs b/core/src/peer_record.rs index f86df68f957..d0d8e21a4b5 100644 --- a/core/src/peer_record.rs +++ b/core/src/peer_record.rs @@ -13,7 +13,7 @@ const DOMAIN_SEP: &str = "libp2p-routing-state"; /// /// Peer records are designed to be distributable and carry a signature by being wrapped in a signed envelope. /// For more information see RFC0003 of the libp2p specifications: -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct PeerRecord { peer_id: PeerId, seq: u64, diff --git a/core/src/signed_envelope.rs b/core/src/signed_envelope.rs index 94e94316473..33bfdf2d4f4 100644 --- a/core/src/signed_envelope.rs +++ b/core/src/signed_envelope.rs @@ -8,7 +8,7 @@ use unsigned_varint::encode::usize_buffer; /// A signed envelope contains an arbitrary byte string payload, a signature of the payload, and the public key that can be used to verify the signature. /// /// For more details see libp2p RFC0002: -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct SignedEnvelope { key: PublicKey, payload_type: Vec, diff --git a/protocols/autonat/src/behaviour.rs b/protocols/autonat/src/behaviour.rs index f98bf5af532..b39a7b141b4 100644 --- a/protocols/autonat/src/behaviour.rs +++ b/protocols/autonat/src/behaviour.rs @@ -130,7 +130,7 @@ impl ProbeId { } /// Event produced by [`Behaviour`]. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Event { /// Event on an inbound probe. InboundProbe(InboundProbeEvent), diff --git a/protocols/autonat/src/behaviour/as_client.rs b/protocols/autonat/src/behaviour/as_client.rs index 8d0097deab8..5a5e18b6531 100644 --- a/protocols/autonat/src/behaviour/as_client.rs +++ b/protocols/autonat/src/behaviour/as_client.rs @@ -40,7 +40,7 @@ use std::{ }; /// Outbound probe failed or was aborted. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum OutboundProbeError { /// Probe was aborted because no server is known, or all servers /// are throttled through [`Config::throttle_server_period`]. @@ -54,7 +54,7 @@ pub enum OutboundProbeError { Response(ResponseError), } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum OutboundProbeEvent { /// A dial-back request was sent to a remote peer. Request { diff --git a/protocols/autonat/src/behaviour/as_server.rs b/protocols/autonat/src/behaviour/as_server.rs index 9b045c02b4c..681076b92cb 100644 --- a/protocols/autonat/src/behaviour/as_server.rs +++ b/protocols/autonat/src/behaviour/as_server.rs @@ -38,7 +38,7 @@ use std::{ }; /// Inbound probe failed. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum InboundProbeError { /// Receiving the dial-back request or sending a response failed. InboundRequest(InboundFailure), @@ -46,7 +46,7 @@ pub enum InboundProbeError { Response(ResponseError), } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum InboundProbeEvent { /// A dial-back request was received from a remote peer. Request { diff --git a/protocols/autonat/src/lib.rs b/protocols/autonat/src/lib.rs index 3a1bf63cc8e..b21c73dd0d0 100644 --- a/protocols/autonat/src/lib.rs +++ b/protocols/autonat/src/lib.rs @@ -31,6 +31,7 @@ pub use self::{ }; pub use libp2p_request_response::{InboundFailure, OutboundFailure}; +#[allow(clippy::derive_partial_eq_without_eq)] mod structs_proto { include!(concat!(env!("OUT_DIR"), "/structs.rs")); } diff --git a/protocols/dcutr/src/lib.rs b/protocols/dcutr/src/lib.rs index c55f22427f8..4a843bac2b7 100644 --- a/protocols/dcutr/src/lib.rs +++ b/protocols/dcutr/src/lib.rs @@ -30,6 +30,7 @@ pub use protocol::{ PROTOCOL_NAME, }; +#[allow(clippy::derive_partial_eq_without_eq)] mod message_proto { include!(concat!(env!("OUT_DIR"), "/holepunch.pb.rs")); } diff --git a/protocols/floodsub/src/lib.rs b/protocols/floodsub/src/lib.rs index 16f0df610a9..109d0db8795 100644 --- a/protocols/floodsub/src/lib.rs +++ b/protocols/floodsub/src/lib.rs @@ -28,6 +28,7 @@ pub mod protocol; mod layer; mod topic; +#[allow(clippy::derive_partial_eq_without_eq)] mod rpc_proto { include!(concat!(env!("OUT_DIR"), "/floodsub.pb.rs")); } diff --git a/protocols/gossipsub/src/config.rs b/protocols/gossipsub/src/config.rs index 93939757c63..a0a8d5e46a1 100644 --- a/protocols/gossipsub/src/config.rs +++ b/protocols/gossipsub/src/config.rs @@ -50,7 +50,7 @@ pub enum ValidationMode { } /// Selector for custom Protocol Id -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum GossipsubVersion { V1_0, V1_1, diff --git a/protocols/gossipsub/src/rpc_proto.rs b/protocols/gossipsub/src/rpc_proto.rs index b9fa8106c6a..3903318fbfb 100644 --- a/protocols/gossipsub/src/rpc_proto.rs +++ b/protocols/gossipsub/src/rpc_proto.rs @@ -17,6 +17,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +#![allow(clippy::derive_partial_eq_without_eq)] include!(concat!(env!("OUT_DIR"), "/gossipsub.pb.rs")); diff --git a/protocols/gossipsub/src/types.rs b/protocols/gossipsub/src/types.rs index 6ffde514e37..29c72d1f044 100644 --- a/protocols/gossipsub/src/types.rs +++ b/protocols/gossipsub/src/types.rs @@ -86,7 +86,7 @@ declare_message_id_type!(MessageId, "MessageId"); // filter duplicates quickly without performing the overhead of decompression. declare_message_id_type!(FastMessageId, "FastMessageId"); -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct PeerConnections { /// The kind of protocol the peer supports. pub kind: PeerKind, diff --git a/protocols/identify/src/lib.rs b/protocols/identify/src/lib.rs index 17925fb6eed..2f73a5a0cad 100644 --- a/protocols/identify/src/lib.rs +++ b/protocols/identify/src/lib.rs @@ -51,6 +51,7 @@ mod handler; mod identify; mod protocol; +#[allow(clippy::derive_partial_eq_without_eq)] mod structs_proto { include!(concat!(env!("OUT_DIR"), "/structs.rs")); } diff --git a/protocols/kad/src/lib.rs b/protocols/kad/src/lib.rs index e46e2b16b54..8c000a00bd2 100644 --- a/protocols/kad/src/lib.rs +++ b/protocols/kad/src/lib.rs @@ -52,6 +52,7 @@ mod behaviour; mod jobs; mod query; +#[allow(clippy::derive_partial_eq_without_eq)] mod dht_proto { include!(concat!(env!("OUT_DIR"), "/dht.pb.rs")); } diff --git a/protocols/relay/src/v2.rs b/protocols/relay/src/v2.rs index c610c1a3b2c..dcfcdf609fb 100644 --- a/protocols/relay/src/v2.rs +++ b/protocols/relay/src/v2.rs @@ -21,6 +21,7 @@ //! Implementation of the [libp2p circuit relay v2 //! specification](https://github.com/libp2p/specs/issues/314). +#[allow(clippy::derive_partial_eq_without_eq)] mod message_proto { include!(concat!(env!("OUT_DIR"), "/message_v2.pb.rs")); } diff --git a/protocols/relay/src/v2/protocol.rs b/protocols/relay/src/v2/protocol.rs index 27f69994957..6e9ccc14277 100644 --- a/protocols/relay/src/v2/protocol.rs +++ b/protocols/relay/src/v2/protocol.rs @@ -31,7 +31,7 @@ pub const STOP_PROTOCOL_NAME: &[u8; 32] = b"/libp2p/circuit/relay/0.2.0/stop"; const MAX_MESSAGE_SIZE: usize = 4096; -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Limit { duration: Option, data_in_bytes: Option, diff --git a/protocols/rendezvous/src/codec.rs b/protocols/rendezvous/src/codec.rs index 3798cea70a8..375ebd6c228 100644 --- a/protocols/rendezvous/src/codec.rs +++ b/protocols/rendezvous/src/codec.rs @@ -182,7 +182,7 @@ impl NewRegistration { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Registration { pub namespace: Namespace, pub record: PeerRecord, @@ -594,6 +594,7 @@ impl From for ConversionError { #[error("The response code ({0:?}) cannot be mapped to our ErrorCode enum")] pub struct UnmappableStatusCode(wire::message::ResponseStatus); +#[allow(clippy::derive_partial_eq_without_eq)] mod wire { include!(concat!(env!("OUT_DIR"), "/rendezvous.pb.rs")); } diff --git a/protocols/request-response/src/lib.rs b/protocols/request-response/src/lib.rs index ea334292494..c4e18d894fb 100644 --- a/protocols/request-response/src/lib.rs +++ b/protocols/request-response/src/lib.rs @@ -147,7 +147,7 @@ pub enum RequestResponseEvent /// Possible failures occurring in the context of sending /// an outbound request and receiving the response. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum OutboundFailure { /// The request could not be sent because a dialing attempt failed. DialFailure, @@ -184,7 +184,7 @@ impl std::error::Error for OutboundFailure {} /// Possible failures occurring in the context of receiving an /// inbound request and sending a response. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum InboundFailure { /// The inbound request timed out, either while reading the /// incoming request or before a response is sent, e.g. if diff --git a/transports/noise/src/io/handshake.rs b/transports/noise/src/io/handshake.rs index fa97798fb23..35099ea84dc 100644 --- a/transports/noise/src/io/handshake.rs +++ b/transports/noise/src/io/handshake.rs @@ -20,6 +20,7 @@ //! Noise protocol handshake I/O. +#[allow(clippy::derive_partial_eq_without_eq)] mod payload_proto { include!(concat!(env!("OUT_DIR"), "/payload.proto.rs")); } diff --git a/transports/plaintext/src/lib.rs b/transports/plaintext/src/lib.rs index 1e9cfecf66f..9855a3297b3 100644 --- a/transports/plaintext/src/lib.rs +++ b/transports/plaintext/src/lib.rs @@ -35,6 +35,7 @@ use void::Void; mod error; mod handshake; +#[allow(clippy::derive_partial_eq_without_eq)] mod structs_proto { include!(concat!(env!("OUT_DIR"), "/structs.rs")); } From cef505685c418a1d8a6a11af91f2eb2414700211 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 16 Aug 2022 04:50:17 +0200 Subject: [PATCH 33/92] core/muxing: Generalise `StreamMuxer::poll_address_change` to `poll` (#2797) This is to allow general-purpose background work to be performed by implementations. --- core/CHANGELOG.md | 6 +++-- core/src/either.rs | 21 ++++++++--------- core/src/muxing.rs | 45 +++++++++++++++++++++--------------- core/src/muxing/boxed.rs | 38 ++++++++++++++---------------- core/src/muxing/singleton.rs | 16 ++++++------- muxers/mplex/src/lib.rs | 10 ++++---- muxers/yamux/src/lib.rs | 7 +++--- swarm/src/connection.rs | 43 ++++++++++++++++++++-------------- 8 files changed, 99 insertions(+), 87 deletions(-) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index dc4fd0829c0..c377d042106 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,16 +1,18 @@ # 0.35.0 [unreleased] -- Remove `StreamMuxer::poll_event` in favor of individual functions: `poll_inbound`, `poll_outbound` - and `poll_address_change`. Consequently, `StreamMuxerEvent` is also removed. See [PR 2724]. - Drop `Unpin` requirement from `SubstreamBox`. See [PR 2762] and [PR 2776]. - Drop `Sync` requirement on `StreamMuxer` for constructing `StreamMuxerBox`. See [PR 2775]. - Use `Pin<&mut Self>` as the receiver type for all `StreamMuxer` poll functions. See [PR 2765]. +- Change `StreamMuxer` interface to be entirely poll-based. All functions on `StreamMuxer` now + require a `Context` and return `Poll`. This gives callers fine-grained control over what they + would like to make progress on. See [PR 2724] and [PR 2797]. [PR 2724]: https://github.com/libp2p/rust-libp2p/pull/2724 [PR 2762]: https://github.com/libp2p/rust-libp2p/pull/2762 [PR 2775]: https://github.com/libp2p/rust-libp2p/pull/2775 [PR 2776]: https://github.com/libp2p/rust-libp2p/pull/2776 [PR 2765]: https://github.com/libp2p/rust-libp2p/pull/2765 +[PR 2797]: https://github.com/libp2p/rust-libp2p/pull/2797 # 0.34.0 diff --git a/core/src/either.rs b/core/src/either.rs index 42984519488..a34552bf28f 100644 --- a/core/src/either.rs +++ b/core/src/either.rs @@ -18,6 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +use crate::muxing::StreamMuxerEvent; use crate::{ muxing::StreamMuxer, transport::{ListenerId, Transport, TransportError, TransportEvent}, @@ -236,22 +237,20 @@ where } } - fn poll_address_change( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { match self.project() { - EitherOutputProj::First(inner) => inner.poll_address_change(cx).map_err(EitherError::A), - EitherOutputProj::Second(inner) => { - inner.poll_address_change(cx).map_err(EitherError::B) - } + EitherOutputProj::First(inner) => inner.poll_close(cx).map_err(EitherError::A), + EitherOutputProj::Second(inner) => inner.poll_close(cx).map_err(EitherError::B), } } - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { match self.project() { - EitherOutputProj::First(inner) => inner.poll_close(cx).map_err(EitherError::A), - EitherOutputProj::Second(inner) => inner.poll_close(cx).map_err(EitherError::B), + EitherOutputProj::First(inner) => inner.poll(cx).map_err(EitherError::A), + EitherOutputProj::Second(inner) => inner.poll(cx).map_err(EitherError::B), } } } diff --git a/core/src/muxing.rs b/core/src/muxing.rs index 2d1e1068044..9763436e94a 100644 --- a/core/src/muxing.rs +++ b/core/src/muxing.rs @@ -75,6 +75,10 @@ pub trait StreamMuxer { type Error: std::error::Error; /// Poll for new inbound substreams. + /// + /// This function should be called whenever callers are ready to accept more inbound streams. In + /// other words, callers may exercise back-pressure on incoming streams by not calling this + /// function if a certain limit is hit. fn poll_inbound( self: Pin<&mut Self>, cx: &mut Context<'_>, @@ -86,25 +90,33 @@ pub trait StreamMuxer { cx: &mut Context<'_>, ) -> Poll>; - /// Poll for an address change of the underlying connection. + /// Poll to close this [`StreamMuxer`]. /// - /// Not all implementations may support this feature. - fn poll_address_change( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll>; - - /// Closes this `StreamMuxer`. - /// - /// After this has returned `Poll::Ready(Ok(()))`, the muxer has become useless. All - /// subsequent reads must return either `EOF` or an error. All subsequent writes, shutdowns, - /// or polls must generate an error or be ignored. + /// After this has returned `Poll::Ready(Ok(()))`, the muxer has become useless and may be safely + /// dropped. /// /// > **Note**: You are encouraged to call this method and wait for it to return `Ready`, so /// > that the remote is properly informed of the shutdown. However, apart from /// > properly informing the remote, there is no difference between this and /// > immediately dropping the muxer. fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; + + /// Poll to allow the underlying connection to make progress. + /// + /// In contrast to all other `poll`-functions on [`StreamMuxer`], this function MUST be called + /// unconditionally. Because it will be called regardless, this function can be used by + /// implementations to return events about the underlying connection that the caller MUST deal + /// with. + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>; +} + +/// An event produced by a [`StreamMuxer`]. +pub enum StreamMuxerEvent { + /// The address of the remote has changed. + AddressChange(Multiaddr), } /// Extension trait for [`StreamMuxer`]. @@ -131,15 +143,12 @@ pub trait StreamMuxerExt: StreamMuxer + Sized { Pin::new(self).poll_outbound(cx) } - /// Convenience function for calling [`StreamMuxer::poll_address_change`] for [`StreamMuxer`]s that are `Unpin`. - fn poll_address_change_unpin( - &mut self, - cx: &mut Context<'_>, - ) -> Poll> + /// Convenience function for calling [`StreamMuxer::poll`] for [`StreamMuxer`]s that are `Unpin`. + fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll> where Self: Unpin, { - Pin::new(self).poll_address_change(cx) + Pin::new(self).poll(cx) } /// Convenience function for calling [`StreamMuxer::poll_close`] for [`StreamMuxer`]s that are `Unpin`. diff --git a/core/src/muxing/boxed.rs b/core/src/muxing/boxed.rs index 0f5b6e5822e..99f7a87c6a5 100644 --- a/core/src/muxing/boxed.rs +++ b/core/src/muxing/boxed.rs @@ -1,6 +1,5 @@ -use crate::StreamMuxer; +use crate::muxing::{StreamMuxer, StreamMuxerEvent}; use futures::{AsyncRead, AsyncWrite}; -use multiaddr::Multiaddr; use pin_project::pin_project; use std::error::Error; use std::fmt; @@ -38,11 +37,6 @@ where type Substream = SubstreamBox; type Error = io::Error; - #[inline] - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().inner.poll_close(cx).map_err(into_io_error) - } - fn poll_inbound( self: Pin<&mut Self>, cx: &mut Context<'_>, @@ -65,14 +59,16 @@ where .map_err(into_io_error) } - fn poll_address_change( + #[inline] + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().inner.poll_close(cx).map_err(into_io_error) + } + + fn poll( self: Pin<&mut Self>, cx: &mut Context<'_>, - ) -> Poll> { - self.project() - .inner - .poll_address_change(cx) - .map_err(into_io_error) + ) -> Poll> { + self.project().inner.poll(cx).map_err(into_io_error) } } @@ -109,11 +105,6 @@ impl StreamMuxer for StreamMuxerBox { type Substream = SubstreamBox; type Error = io::Error; - #[inline] - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().poll_close(cx) - } - fn poll_inbound( self: Pin<&mut Self>, cx: &mut Context<'_>, @@ -128,11 +119,16 @@ impl StreamMuxer for StreamMuxerBox { self.project().poll_outbound(cx) } - fn poll_address_change( + #[inline] + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().poll_close(cx) + } + + fn poll( self: Pin<&mut Self>, cx: &mut Context<'_>, - ) -> Poll> { - self.project().poll_address_change(cx) + ) -> Poll> { + self.project().poll(cx) } } diff --git a/core/src/muxing/singleton.rs b/core/src/muxing/singleton.rs index 193cfb6303f..3ba2c1cb366 100644 --- a/core/src/muxing/singleton.rs +++ b/core/src/muxing/singleton.rs @@ -18,10 +18,10 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::{connection::Endpoint, muxing::StreamMuxer}; +use crate::connection::Endpoint; +use crate::muxing::{StreamMuxer, StreamMuxerEvent}; use futures::prelude::*; -use multiaddr::Multiaddr; use std::cell::Cell; use std::pin::Pin; use std::{io, task::Context, task::Poll}; @@ -88,14 +88,14 @@ where } } - fn poll_address_change( + fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll( self: Pin<&mut Self>, _: &mut Context<'_>, - ) -> Poll> { + ) -> Poll> { Poll::Pending } - - fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } } diff --git a/muxers/mplex/src/lib.rs b/muxers/mplex/src/lib.rs index 14f9cda65d9..501c4dd6735 100644 --- a/muxers/mplex/src/lib.rs +++ b/muxers/mplex/src/lib.rs @@ -27,10 +27,8 @@ pub use config::{MaxBufferBehaviour, MplexConfig}; use bytes::Bytes; use codec::LocalStreamId; use futures::{future, prelude::*, ready}; -use libp2p_core::{ - upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}, - Multiaddr, StreamMuxer, -}; +use libp2p_core::muxing::{StreamMuxer, StreamMuxerEvent}; +use libp2p_core::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use parking_lot::Mutex; use std::{cmp, iter, pin::Pin, sync::Arc, task::Context, task::Poll}; @@ -105,10 +103,10 @@ where .map_ok(|stream_id| Substream::new(stream_id, self.io.clone())) } - fn poll_address_change( + fn poll( self: Pin<&mut Self>, _: &mut Context<'_>, - ) -> Poll> { + ) -> Poll> { Poll::Pending } diff --git a/muxers/yamux/src/lib.rs b/muxers/yamux/src/lib.rs index 07327e203b3..5b109f2b3b0 100644 --- a/muxers/yamux/src/lib.rs +++ b/muxers/yamux/src/lib.rs @@ -26,9 +26,8 @@ use futures::{ prelude::*, stream::{BoxStream, LocalBoxStream}, }; -use libp2p_core::muxing::StreamMuxer; +use libp2p_core::muxing::{StreamMuxer, StreamMuxerEvent}; use libp2p_core::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}; -use libp2p_core::Multiaddr; use std::{ fmt, io, iter, mem, pin::Pin, @@ -124,10 +123,10 @@ where .map_err(YamuxError) } - fn poll_address_change( + fn poll( self: Pin<&mut Self>, _: &mut Context<'_>, - ) -> Poll> { + ) -> Poll> { Poll::Pending } diff --git a/swarm/src/connection.rs b/swarm/src/connection.rs index f92186618ae..24e54aba525 100644 --- a/swarm/src/connection.rs +++ b/swarm/src/connection.rs @@ -35,7 +35,7 @@ use crate::IntoConnectionHandler; use handler_wrapper::HandlerWrapper; use libp2p_core::connection::ConnectedPoint; use libp2p_core::multiaddr::Multiaddr; -use libp2p_core::muxing::{StreamMuxerBox, StreamMuxerExt}; +use libp2p_core::muxing::{StreamMuxerBox, StreamMuxerEvent, StreamMuxerExt}; use libp2p_core::upgrade; use libp2p_core::PeerId; use std::collections::VecDeque; @@ -153,27 +153,36 @@ where } } - if !self.open_info.is_empty() { - if let Poll::Ready(substream) = self.muxing.poll_outbound_unpin(cx)? { - let user_data = self - .open_info - .pop_front() - .expect("`open_info` is not empty"); - let endpoint = SubstreamEndpoint::Dialer(user_data); - self.handler.inject_substream(substream, endpoint); - continue; // Go back to the top, handler can potentially make progress again. + match self.muxing.poll_unpin(cx)? { + Poll::Pending => {} + Poll::Ready(StreamMuxerEvent::AddressChange(address)) => { + self.handler.inject_address_change(&address); + return Poll::Ready(Ok(Event::AddressChange(address))); } } - if let Poll::Ready(substream) = self.muxing.poll_inbound_unpin(cx)? { - self.handler - .inject_substream(substream, SubstreamEndpoint::Listener); - continue; // Go back to the top, handler can potentially make progress again. + if !self.open_info.is_empty() { + match self.muxing.poll_outbound_unpin(cx)? { + Poll::Pending => {} + Poll::Ready(substream) => { + let user_data = self + .open_info + .pop_front() + .expect("`open_info` is not empty"); + let endpoint = SubstreamEndpoint::Dialer(user_data); + self.handler.inject_substream(substream, endpoint); + continue; // Go back to the top, handler can potentially make progress again. + } + } } - if let Poll::Ready(address) = self.muxing.poll_address_change_unpin(cx)? { - self.handler.inject_address_change(&address); - return Poll::Ready(Ok(Event::AddressChange(address))); + match self.muxing.poll_inbound_unpin(cx)? { + Poll::Pending => {} + Poll::Ready(substream) => { + self.handler + .inject_substream(substream, SubstreamEndpoint::Listener); + continue; // Go back to the top, handler can potentially make progress again. + } } return Poll::Pending; // Nothing can make progress, return `Pending`. From 0e5a25dea8b8e9b8c7ffaaf9549d3d03fe498c13 Mon Sep 17 00:00:00 2001 From: qidu Date: Tue, 16 Aug 2022 11:12:28 +0800 Subject: [PATCH 34/92] examples/file-sharing: Support binary files (#2786) --- examples/file-sharing.rs | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/examples/file-sharing.rs b/examples/file-sharing.rs index 492eee11eeb..b90246e0b4f 100644 --- a/examples/file-sharing.rs +++ b/examples/file-sharing.rs @@ -84,6 +84,7 @@ use futures::prelude::*; use libp2p::core::{Multiaddr, PeerId}; use libp2p::multiaddr::Protocol; use std::error::Error; +use std::io::Write; use std::path::PathBuf; #[async_std::main] @@ -134,8 +135,9 @@ async fn main() -> Result<(), Box> { // Reply with the content of the file on incoming requests. Some(network::Event::InboundRequest { request, channel }) => { if request == name { - let file_content = std::fs::read_to_string(&path)?; - network_client.respond_file(file_content, channel).await; + network_client + .respond_file(std::fs::read(&path)?, channel) + .await; } } e => todo!("{:?}", e), @@ -158,12 +160,12 @@ async fn main() -> Result<(), Box> { }); // Await the requests, ignore the remaining once a single one succeeds. - let file = futures::future::select_ok(requests) + let file_content = futures::future::select_ok(requests) .await .map_err(|_| "None of the providers returned file.")? .0; - println!("Content of file {}: {}", name, file); + std::io::stdout().write_all(&file_content)?; } } @@ -337,7 +339,7 @@ mod network { &mut self, peer: PeerId, file_name: String, - ) -> Result> { + ) -> Result, Box> { let (sender, receiver) = oneshot::channel(); self.sender .send(Command::RequestFile { @@ -351,9 +353,16 @@ mod network { } /// Respond with the provided file content to the given request. - pub async fn respond_file(&mut self, file: String, channel: ResponseChannel) { + pub async fn respond_file( + &mut self, + file: Vec, + channel: ResponseChannel, + ) { self.sender - .send(Command::RespondFile { file, channel }) + .send(Command::RespondFile { + file: file, + channel, + }) .await .expect("Command receiver not to be dropped."); } @@ -367,7 +376,7 @@ mod network { pending_start_providing: HashMap>, pending_get_providers: HashMap>>, pending_request_file: - HashMap>>>, + HashMap, Box>>>, } impl EventLoop { @@ -476,7 +485,7 @@ mod network { )) => {} SwarmEvent::NewListenAddr { address, .. } => { let local_peer_id = *self.swarm.local_peer_id(); - println!( + eprintln!( "Local node is listening on {:?}", address.with(Protocol::P2p(local_peer_id.into())) ); @@ -500,7 +509,7 @@ mod network { } } SwarmEvent::IncomingConnectionError { .. } => {} - SwarmEvent::Dialing(peer_id) => println!("Dialing {}", peer_id), + SwarmEvent::Dialing(peer_id) => eprintln!("Dialing {}", peer_id), e => panic!("{:?}", e), } } @@ -625,10 +634,10 @@ mod network { RequestFile { file_name: String, peer: PeerId, - sender: oneshot::Sender>>, + sender: oneshot::Sender, Box>>, }, RespondFile { - file: String, + file: Vec, channel: ResponseChannel, }, } @@ -650,7 +659,7 @@ mod network { #[derive(Debug, Clone, PartialEq, Eq)] struct FileRequest(String); #[derive(Debug, Clone, PartialEq, Eq)] - pub struct FileResponse(String); + pub struct FileResponse(Vec); impl ProtocolName for FileExchangeProtocol { fn protocol_name(&self) -> &[u8] { @@ -689,13 +698,13 @@ mod network { where T: AsyncRead + Unpin + Send, { - let vec = read_length_prefixed(io, 1_000_000).await?; + let vec = read_length_prefixed(io, 500_000_000).await?; // update transfer maximum if vec.is_empty() { return Err(io::ErrorKind::UnexpectedEof.into()); } - Ok(FileResponse(String::from_utf8(vec).unwrap())) + Ok(FileResponse(vec)) } async fn write_request( From 878c49fa14d8176cbcebe86c99fce271f0e676fa Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 16 Aug 2022 06:58:17 +0200 Subject: [PATCH 35/92] swarm/src/behaviour: Deprecate NetworkBehaviourEventProcess (#2784) In preparation for https://github.com/libp2p/rust-libp2p/pull/2751. --- examples/chat-tokio.rs | 80 ++++++++------ examples/chat.rs | 4 +- examples/distributed-key-value-store.rs | 94 ++++++++-------- examples/ipfs-private.rs | 141 +++++++++++++----------- swarm/CHANGELOG.md | 78 ++++++++++++- swarm/src/behaviour.rs | 13 ++- swarm/src/behaviour/either.rs | 8 +- swarm/src/behaviour/toggle.rs | 8 +- swarm/src/lib.rs | 5 +- 9 files changed, 267 insertions(+), 164 deletions(-) diff --git a/examples/chat-tokio.rs b/examples/chat-tokio.rs index 66c25205246..a082f3ef113 100644 --- a/examples/chat-tokio.rs +++ b/examples/chat-tokio.rs @@ -44,7 +44,7 @@ use libp2p::{ mdns::{Mdns, MdnsEvent}, mplex, noise, - swarm::{dial_opts::DialOpts, NetworkBehaviourEventProcess, SwarmBuilder, SwarmEvent}, + swarm::{SwarmBuilder, SwarmEvent}, // `TokioTcpTransport` is available through the `tcp-tokio` feature. tcp::TokioTcpTransport, Multiaddr, @@ -82,47 +82,29 @@ async fn main() -> Result<(), Box> { // Create a Floodsub topic let floodsub_topic = floodsub::Topic::new("chat"); - // We create a custom network behaviour that combines floodsub and mDNS. - // The derive generates a delegating `NetworkBehaviour` impl which in turn - // requires the implementations of `NetworkBehaviourEventProcess` for - // the events of each behaviour. + // We create a custom behaviour that combines floodsub and mDNS. + // The derive generates a delegating `NetworkBehaviour` impl. #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] + #[behaviour(out_event = "MyBehaviourEvent")] struct MyBehaviour { floodsub: Floodsub, mdns: Mdns, } - impl NetworkBehaviourEventProcess for MyBehaviour { - // Called when `floodsub` produces an event. - fn inject_event(&mut self, message: FloodsubEvent) { - if let FloodsubEvent::Message(message) = message { - println!( - "Received: '{:?}' from {:?}", - String::from_utf8_lossy(&message.data), - message.source - ); - } + enum MyBehaviourEvent { + Floodsub(FloodsubEvent), + Mdns(MdnsEvent), + } + + impl From for MyBehaviourEvent { + fn from(event: FloodsubEvent) -> Self { + MyBehaviourEvent::Floodsub(event) } } - impl NetworkBehaviourEventProcess for MyBehaviour { - // Called when `mdns` produces an event. - fn inject_event(&mut self, event: MdnsEvent) { - match event { - MdnsEvent::Discovered(list) => { - for (peer, _) in list { - self.floodsub.add_node_to_partial_view(peer); - } - } - MdnsEvent::Expired(list) => { - for (peer, _) in list { - if !self.mdns.has_node(&peer) { - self.floodsub.remove_node_from_partial_view(&peer); - } - } - } - } + impl From for MyBehaviourEvent { + fn from(event: MdnsEvent) -> Self { + MyBehaviourEvent::Mdns(event) } } @@ -166,8 +148,36 @@ async fn main() -> Result<(), Box> { swarm.behaviour_mut().floodsub.publish(floodsub_topic.clone(), line.as_bytes()); } event = swarm.select_next_some() => { - if let SwarmEvent::NewListenAddr { address, .. } = event { - println!("Listening on {:?}", address); + match event { + SwarmEvent::NewListenAddr { address, .. } => { + println!("Listening on {:?}", address); + } + SwarmEvent::Behaviour(MyBehaviourEvent::Floodsub(event)) => { + if let FloodsubEvent::Message(message) = event { + println!( + "Received: '{:?}' from {:?}", + String::from_utf8_lossy(&message.data), + message.source + ); + } + } + SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(event)) => { + match event { + MdnsEvent::Discovered(list) => { + for (peer, _) in list { + swarm.behaviour_mut().floodsub.add_node_to_partial_view(peer); + } + } + MdnsEvent::Expired(list) => { + for (peer, _) in list { + if !swarm.behaviour().mdns.has_node(&peer) { + swarm.behaviour_mut().floodsub.remove_node_from_partial_view(&peer); + } + } + } + } + } + _ => {} } } } diff --git a/examples/chat.rs b/examples/chat.rs index d03c0a6f3e5..b9569142a41 100644 --- a/examples/chat.rs +++ b/examples/chat.rs @@ -79,9 +79,7 @@ async fn main() -> Result<(), Box> { let floodsub_topic = floodsub::Topic::new("chat"); // We create a custom network behaviour that combines floodsub and mDNS. - // In the future, we want to improve libp2p to make this easier to do. - // Use the derive to generate delegating NetworkBehaviour impl and require the - // NetworkBehaviourEventProcess implementations below. + // Use the derive to generate delegating NetworkBehaviour impl. #[derive(NetworkBehaviour)] #[behaviour(out_event = "OutEvent")] struct MyBehaviour { diff --git a/examples/distributed-key-value-store.rs b/examples/distributed-key-value-store.rs index 6bf28bf0ff9..7fef717cf78 100644 --- a/examples/distributed-key-value-store.rs +++ b/examples/distributed-key-value-store.rs @@ -50,7 +50,7 @@ use libp2p::kad::{ use libp2p::{ development_transport, identity, mdns::{Mdns, MdnsConfig, MdnsEvent}, - swarm::{NetworkBehaviourEventProcess, SwarmEvent}, + swarm::SwarmEvent, NetworkBehaviour, PeerId, Swarm, }; use std::error::Error; @@ -68,28 +68,60 @@ async fn main() -> Result<(), Box> { // We create a custom network behaviour that combines Kademlia and mDNS. #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] + #[behaviour(out_event = "MyBehaviourEvent")] struct MyBehaviour { kademlia: Kademlia, mdns: Mdns, } - impl NetworkBehaviourEventProcess for MyBehaviour { - // Called when `mdns` produces an event. - fn inject_event(&mut self, event: MdnsEvent) { - if let MdnsEvent::Discovered(list) = event { - for (peer_id, multiaddr) in list { - self.kademlia.add_address(&peer_id, multiaddr); - } - } + enum MyBehaviourEvent { + Kademlia(KademliaEvent), + Mdns(MdnsEvent), + } + + impl From for MyBehaviourEvent { + fn from(event: KademliaEvent) -> Self { + MyBehaviourEvent::Kademlia(event) + } + } + + impl From for MyBehaviourEvent { + fn from(event: MdnsEvent) -> Self { + MyBehaviourEvent::Mdns(event) } } - impl NetworkBehaviourEventProcess for MyBehaviour { - // Called when `kademlia` produces an event. - fn inject_event(&mut self, message: KademliaEvent) { - match message { - KademliaEvent::OutboundQueryCompleted { result, .. } => match result { + // Create a swarm to manage peers and events. + let mut swarm = { + // Create a Kademlia behaviour. + let store = MemoryStore::new(local_peer_id); + let kademlia = Kademlia::new(local_peer_id, store); + let mdns = task::block_on(Mdns::new(MdnsConfig::default()))?; + let behaviour = MyBehaviour { kademlia, mdns }; + Swarm::new(transport, behaviour, local_peer_id) + }; + + // Read full lines from stdin + let mut stdin = io::BufReader::new(io::stdin()).lines().fuse(); + + // Listen on all interfaces and whatever port the OS assigns. + swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; + + // Kick it off. + loop { + select! { + line = stdin.select_next_some() => handle_input_line(&mut swarm.behaviour_mut().kademlia, line.expect("Stdin not to close")), + event = swarm.select_next_some() => match event { + SwarmEvent::NewListenAddr { address, .. } => { + println!("Listening in {:?}", address); + }, + SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(MdnsEvent::Discovered(list))) => { + for (peer_id, multiaddr) in list { + swarm.behaviour_mut().kademlia.add_address(&peer_id, multiaddr); + } + } + SwarmEvent::Behaviour(MyBehaviourEvent::Kademlia(KademliaEvent::OutboundQueryCompleted { result, ..})) => { + match result { QueryResult::GetProviders(Ok(ok)) => { for peer in ok.providers { println!( @@ -137,38 +169,10 @@ async fn main() -> Result<(), Box> { eprintln!("Failed to put provider record: {:?}", err); } _ => {} - }, - _ => {} + } } + _ => {} } - } - - // Create a swarm to manage peers and events. - let mut swarm = { - // Create a Kademlia behaviour. - let store = MemoryStore::new(local_peer_id); - let kademlia = Kademlia::new(local_peer_id, store); - let mdns = task::block_on(Mdns::new(MdnsConfig::default()))?; - let behaviour = MyBehaviour { kademlia, mdns }; - Swarm::new(transport, behaviour, local_peer_id) - }; - - // Read full lines from stdin - let mut stdin = io::BufReader::new(io::stdin()).lines().fuse(); - - // Listen on all interfaces and whatever port the OS assigns. - swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; - - // Kick it off. - loop { - select! { - line = stdin.select_next_some() => handle_input_line(&mut swarm.behaviour_mut().kademlia, line.expect("Stdin not to close")), - event = swarm.select_next_some() => match event { - SwarmEvent::NewListenAddr { address, .. } => { - println!("Listening in {:?}", address); - }, - _ => {} - } } } } diff --git a/examples/ipfs-private.rs b/examples/ipfs-private.rs index 113bdf988f2..00b529bf6f2 100644 --- a/examples/ipfs-private.rs +++ b/examples/ipfs-private.rs @@ -41,9 +41,10 @@ use libp2p::{ identify::{Identify, IdentifyConfig, IdentifyEvent}, identity, multiaddr::Protocol, - noise, ping, + noise, + ping::{self, PingEvent}, pnet::{PnetConfig, PreSharedKey}, - swarm::{NetworkBehaviourEventProcess, SwarmEvent}, + swarm::SwarmEvent, tcp::TcpTransport, yamux::YamuxConfig, Multiaddr, NetworkBehaviour, PeerId, Swarm, Transport, @@ -157,78 +158,34 @@ async fn main() -> Result<(), Box> { // We create a custom network behaviour that combines gossipsub, ping and identify. #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] + #[behaviour(out_event = "MyBehaviourEvent")] struct MyBehaviour { gossipsub: Gossipsub, identify: Identify, ping: ping::Behaviour, } - impl NetworkBehaviourEventProcess for MyBehaviour { - // Called when `identify` produces an event. - fn inject_event(&mut self, event: IdentifyEvent) { - println!("identify: {:?}", event); + enum MyBehaviourEvent { + Gossipsub(GossipsubEvent), + Identify(IdentifyEvent), + Ping(PingEvent), + } + + impl From for MyBehaviourEvent { + fn from(event: GossipsubEvent) -> Self { + MyBehaviourEvent::Gossipsub(event) } } - impl NetworkBehaviourEventProcess for MyBehaviour { - // Called when `gossipsub` produces an event. - fn inject_event(&mut self, event: GossipsubEvent) { - match event { - GossipsubEvent::Message { - propagation_source: peer_id, - message_id: id, - message, - } => println!( - "Got message: {} with id: {} from peer: {:?}", - String::from_utf8_lossy(&message.data), - id, - peer_id - ), - _ => {} - } + impl From for MyBehaviourEvent { + fn from(event: IdentifyEvent) -> Self { + MyBehaviourEvent::Identify(event) } } - impl NetworkBehaviourEventProcess for MyBehaviour { - // Called when `ping` produces an event. - fn inject_event(&mut self, event: ping::Event) { - match event { - ping::Event { - peer, - result: Result::Ok(ping::Success::Ping { rtt }), - } => { - println!( - "ping: rtt to {} is {} ms", - peer.to_base58(), - rtt.as_millis() - ); - } - ping::Event { - peer, - result: Result::Ok(ping::Success::Pong), - } => { - println!("ping: pong from {}", peer.to_base58()); - } - ping::Event { - peer, - result: Result::Err(ping::Failure::Timeout), - } => { - println!("ping: timeout to {}", peer.to_base58()); - } - ping::Event { - peer, - result: Result::Err(ping::Failure::Unsupported), - } => { - println!("ping: {} does not support ping protocol", peer.to_base58()); - } - ping::Event { - peer, - result: Result::Err(ping::Failure::Other { error }), - } => { - println!("ping: ping::Failure with {}: {}", peer.to_base58(), error); - } - } + impl From for MyBehaviourEvent { + fn from(event: PingEvent) -> Self { + MyBehaviourEvent::Ping(event) } } @@ -282,8 +239,64 @@ async fn main() -> Result<(), Box> { } }, event = swarm.select_next_some() => { - if let SwarmEvent::NewListenAddr { address, .. } = event { - println!("Listening on {:?}", address); + match event { + SwarmEvent::NewListenAddr { address, .. } => { + println!("Listening on {:?}", address); + } + SwarmEvent::Behaviour(MyBehaviourEvent::Identify(event)) => { + println!("identify: {:?}", event); + } + SwarmEvent::Behaviour(MyBehaviourEvent::Gossipsub(GossipsubEvent::Message { + propagation_source: peer_id, + message_id: id, + message, + })) => { + println!( + "Got message: {} with id: {} from peer: {:?}", + String::from_utf8_lossy(&message.data), + id, + peer_id + ) + } + SwarmEvent::Behaviour(MyBehaviourEvent::Ping(event)) => { + match event { + ping::Event { + peer, + result: Result::Ok(ping::Success::Ping { rtt }), + } => { + println!( + "ping: rtt to {} is {} ms", + peer.to_base58(), + rtt.as_millis() + ); + } + ping::Event { + peer, + result: Result::Ok(ping::Success::Pong), + } => { + println!("ping: pong from {}", peer.to_base58()); + } + ping::Event { + peer, + result: Result::Err(ping::Failure::Timeout), + } => { + println!("ping: timeout to {}", peer.to_base58()); + } + ping::Event { + peer, + result: Result::Err(ping::Failure::Unsupported), + } => { + println!("ping: {} does not support ping protocol", peer.to_base58()); + } + ping::Event { + peer, + result: Result::Err(ping::Failure::Other { error }), + } => { + println!("ping: ping::Failure with {}: {}", peer.to_base58(), error); + } + } + } + _ => {} } } } diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index 62de6afa063..a235c0ae2bc 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -1,8 +1,72 @@ # 0.38.0 [unreleased] -- Update dial address concurrency factor to `8`, thus dialing up to 8 addresses concurrently for a single connection attempt. See `Swarm::dial_concurrency_factor` and [PR 2741]. +- Deprecate `NetworkBehaviourEventProcess`. When deriving `NetworkBehaviour` on a custom `struct` users + should either bring their own `OutEvent` via `#[behaviour(out_event = "MyBehaviourEvent")]` or, + when not specified, have the derive macro generate one for the user. -- Update to `libp2p-core` `v0.35.0`. + See [`NetworkBehaviour` + documentation](https://docs.rs/libp2p/latest/libp2p/swarm/trait.NetworkBehaviour.html) and [PR + 2784] for details. + + Previously + + ``` rust + #[derive(NetworkBehaviour)] + #[behaviour(event_process = true)] + struct MyBehaviour { + gossipsub: Gossipsub, + mdns: Mdns, + } + + impl NetworkBehaviourEventProcess for MyBehaviour { + fn inject_event(&mut self, message: GossipsubEvent) { + todo!("Handle event") + } + } + + impl NetworkBehaviourEventProcess for MyBehaviour { + fn inject_event(&mut self, message: MdnsEvent) { + todo!("Handle event") + } + } + ``` + + Now + + ``` rust + #[derive(NetworkBehaviour)] + #[behaviour(out_event = "MyBehaviourEvent")] + struct MyBehaviour { + gossipsub: Gossipsub, + mdns: Mdns, + } + + enum MyBehaviourEvent { + Gossipsub(GossipsubEvent), + Mdns(MdnsEvent), + } + + impl From for MyBehaviourEvent { + fn from(event: GossipsubEvent) -> Self { + MyBehaviourEvent::Gossipsub(event) + } + } + + impl From for MyBehaviourEvent { + fn from(event: MdnsEvent) -> Self { + MyBehaviourEvent::Mdns(event) + } + } + + match swarm.next().await.unwrap() { + SwarmEvent::Behaviour(MyBehaviourEvent::Gossipsub(event)) => { + todo!("Handle event") + } + SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(event)) => { + todo!("Handle event") + } + } + ``` - When deriving `NetworkBehaviour` on a custom `struct` where the user does not specify their own `OutEvent` via `#[behaviour(out_event = "MyBehaviourEvent")]` and where the user does not enable @@ -10,10 +74,16 @@ the user. See [`NetworkBehaviour` - documentation](https://docs.rs/libp2p/latest/libp2p/swarm/trait.NetworkBehaviour.html) for - details. + documentation](https://docs.rs/libp2p/latest/libp2p/swarm/trait.NetworkBehaviour.html) and [PR + 2792] for details. + +- Update dial address concurrency factor to `8`, thus dialing up to 8 addresses concurrently for a single connection attempt. See `Swarm::dial_concurrency_factor` and [PR 2741]. + +- Update to `libp2p-core` `v0.35.0`. [PR 2741]: https://github.com/libp2p/rust-libp2p/pull/2741/ +[PR 2784]: https://github.com/libp2p/rust-libp2p/pull/2784 +[PR 2792]: https://github.com/libp2p/rust-libp2p/pull/2792 # 0.37.0 diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index d6802c086a8..c0ac597680c 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -85,9 +85,9 @@ pub(crate) type THandlerOutEvent = /// "MyCustomOutEvent")]`. If the user does not specify an `out_event`, the derive macro generates /// the event definition itself, naming it `Event`. /// -/// When setting a custom `out_event`, the aforementioned conversion of each of the event types -/// generated by the struct members to the custom `out_event` is handled by [`From`] -/// implementations the user needs to provide. +/// The aforementioned conversion of each of the event types generated by the struct members to the +/// custom `out_event` is handled by [`From`] implementations which the user needs to define in +/// addition to the event `enum` itself. /// /// ``` rust /// # use libp2p::identify::{Identify, IdentifyEvent}; @@ -326,6 +326,13 @@ pub trait PollParameters { /// /// You can opt out of this behaviour through `#[behaviour(event_process = false)]`. See the /// documentation of [`NetworkBehaviour`] for details. +#[deprecated( + since = "0.38.0", + note = "Use `#[behaviour(out_event = \"MyBehaviourEvent\")]` instead. See \ + https://github.com/libp2p/rust-libp2p/blob/master/swarm/CHANGELOG.md#0380 \ + for instructions on how to migrate. Will be removed with \ + https://github.com/libp2p/rust-libp2p/pull/2751." +)] pub trait NetworkBehaviourEventProcess { /// Called when one of the fields of the type you're deriving `NetworkBehaviour` on generates /// an event. diff --git a/swarm/src/behaviour/either.rs b/swarm/src/behaviour/either.rs index 54e60e77b3a..fc4c50e63ef 100644 --- a/swarm/src/behaviour/either.rs +++ b/swarm/src/behaviour/either.rs @@ -19,10 +19,9 @@ // DEALINGS IN THE SOFTWARE. use crate::handler::{either::IntoEitherHandler, ConnectionHandler, IntoConnectionHandler}; -use crate::{ - DialError, NetworkBehaviour, NetworkBehaviourAction, NetworkBehaviourEventProcess, - PollParameters, -}; +#[allow(deprecated)] +pub use crate::NetworkBehaviourEventProcess; +use crate::{DialError, NetworkBehaviour, NetworkBehaviourAction, PollParameters}; use either::Either; use libp2p_core::{ connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId, @@ -237,6 +236,7 @@ where } } +#[allow(deprecated)] impl NetworkBehaviourEventProcess for Either where diff --git a/swarm/src/behaviour/toggle.rs b/swarm/src/behaviour/toggle.rs index 50ea6487770..64ebdf779e5 100644 --- a/swarm/src/behaviour/toggle.rs +++ b/swarm/src/behaviour/toggle.rs @@ -23,10 +23,9 @@ use crate::handler::{ KeepAlive, SubstreamProtocol, }; use crate::upgrade::{InboundUpgradeSend, OutboundUpgradeSend, SendWrapper}; -use crate::{ - DialError, NetworkBehaviour, NetworkBehaviourAction, NetworkBehaviourEventProcess, - PollParameters, -}; +#[allow(deprecated)] +pub use crate::NetworkBehaviourEventProcess; +use crate::{DialError, NetworkBehaviour, NetworkBehaviourAction, PollParameters}; use either::Either; use libp2p_core::{ connection::ConnectionId, @@ -233,6 +232,7 @@ where } } +#[allow(deprecated)] impl NetworkBehaviourEventProcess for Toggle where TBehaviour: NetworkBehaviourEventProcess, diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 74de015a858..38df855cff5 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -63,9 +63,10 @@ pub mod behaviour; pub mod dial_opts; pub mod handler; +#[allow(deprecated)] +pub use behaviour::NetworkBehaviourEventProcess; pub use behaviour::{ - CloseConnection, NetworkBehaviour, NetworkBehaviourAction, NetworkBehaviourEventProcess, - NotifyHandler, PollParameters, + CloseConnection, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, }; pub use connection::{ ConnectionCounters, ConnectionError, ConnectionLimit, ConnectionLimits, PendingConnectionError, From 6a9fa3d93008d67ef62eff5b56d5aac3f340fd09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 08:49:09 +0200 Subject: [PATCH 36/92] build(deps): Update prost requirement from 0.10 to 0.11 (#2788) * build(deps): Update prost-build requirement from 0.10 to 0.11 Updates the requirements on [prost-build](https://github.com/tokio-rs/prost) to permit the latest version. - [Release notes](https://github.com/tokio-rs/prost/releases) - [Commits](https://github.com/tokio-rs/prost/compare/v0.10.0...v0.11.0) --- updated-dependencies: - dependency-name: prost-build dependency-type: direct:production ... Signed-off-by: dependabot[bot] * build(deps): Update prost requirement from 0.10 to 0.11 Updates the requirements on [prost](https://github.com/tokio-rs/prost) to permit the latest version. - [Release notes](https://github.com/tokio-rs/prost/releases) - [Commits](https://github.com/tokio-rs/prost/compare/v0.10.0...v0.11.0) --- updated-dependencies: - dependency-name: prost dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 15 +++++++++++++++ core/Cargo.toml | 4 ++-- misc/prost-codec/CHANGELOG.md | 5 +++++ misc/prost-codec/Cargo.toml | 6 +++--- protocols/autonat/Cargo.toml | 4 ++-- protocols/dcutr/Cargo.toml | 6 +++--- protocols/floodsub/Cargo.toml | 4 ++-- protocols/gossipsub/Cargo.toml | 4 ++-- protocols/identify/Cargo.toml | 6 +++--- protocols/kad/Cargo.toml | 4 ++-- protocols/relay/Cargo.toml | 6 +++--- protocols/rendezvous/Cargo.toml | 4 ++-- transports/noise/Cargo.toml | 4 ++-- transports/plaintext/Cargo.toml | 4 ++-- 14 files changed, 48 insertions(+), 28 deletions(-) create mode 100644 misc/prost-codec/CHANGELOG.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e97069e3a9..c1509406f8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,6 +24,9 @@ jobs: with: access_token: ${{ github.token }} + - name: Install Protoc + uses: arduino/setup-protoc@v1 + - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@6720f05bc48b77f96918929a9019fb2203ff71f8 # v2.0.0 @@ -56,6 +59,9 @@ jobs: with: access_token: ${{ github.token }} + - name: Install Protoc + uses: arduino/setup-protoc@v1 + - uses: actions/checkout@v3 - name: Install Rust ${{ matrix.toolchain }} @@ -91,6 +97,9 @@ jobs: with: access_token: ${{ github.token }} + - name: Install Protoc + uses: arduino/setup-protoc@v1 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 @@ -113,6 +122,9 @@ jobs: with: access_token: ${{ github.token }} + - name: Install Protoc + uses: arduino/setup-protoc@v1 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 @@ -139,6 +151,9 @@ jobs: with: access_token: ${{ github.token }} + - name: Install Protoc + uses: arduino/setup-protoc@v1 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 diff --git a/core/Cargo.toml b/core/Cargo.toml index 386dff09669..f0197b675d0 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -28,7 +28,7 @@ multistream-select = { version = "0.11", path = "../misc/multistream-select" } p256 = { version = "0.10.0", default-features = false, features = ["ecdsa"], optional = true } parking_lot = "0.12.0" pin-project = "1.0.0" -prost = "0.10" +prost = "0.11" rand = "0.8" rw-stream-sink = { version = "0.3.0", path = "../misc/rw-stream-sink" } sha2 = "0.10.0" @@ -56,7 +56,7 @@ rmp-serde = "1.0" serde_json = "1.0" [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [features] default = [ "secp256k1", "ecdsa" ] diff --git a/misc/prost-codec/CHANGELOG.md b/misc/prost-codec/CHANGELOG.md new file mode 100644 index 00000000000..af426fb1955 --- /dev/null +++ b/misc/prost-codec/CHANGELOG.md @@ -0,0 +1,5 @@ +# 0.2.0 [unreleased] + +- Update to prost(-build) `v0.11`. See [PR 2788]. + +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788/ \ No newline at end of file diff --git a/misc/prost-codec/Cargo.toml b/misc/prost-codec/Cargo.toml index 02969651acc..f4d1e90f844 100644 --- a/misc/prost-codec/Cargo.toml +++ b/misc/prost-codec/Cargo.toml @@ -3,7 +3,7 @@ name = "prost-codec" edition = "2021" rust-version = "1.56.1" description = "Asynchronous de-/encoding of Protobuf structs using asynchronous-codec, unsigned-varint and prost." -version = "0.1.0" +version = "0.2.0" authors = ["Max Inden "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -13,9 +13,9 @@ categories = ["asynchronous"] [dependencies] asynchronous-codec = { version = "0.6" } bytes = { version = "1" } -prost = "0.10" +prost = "0.11" thiserror = "1.0" unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] } [dev-dependencies] -prost-build = "0.10" +prost-build = "0.11" diff --git a/protocols/autonat/Cargo.toml b/protocols/autonat/Cargo.toml index 44f3c2b894d..6ec668e4fdc 100644 --- a/protocols/autonat/Cargo.toml +++ b/protocols/autonat/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["peer-to-peer", "libp2p", "networking"] categories = ["network-programming", "asynchronous"] [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [dependencies] async-trait = "0.1" @@ -23,7 +23,7 @@ libp2p-swarm = { version = "0.38.0", path = "../../swarm" } libp2p-request-response = { version = "0.20.0", path = "../request-response" } log = "0.4" rand = "0.8" -prost = "0.10" +prost = "0.11" [dev-dependencies] async-std = { version = "1.10", features = ["attributes"] } diff --git a/protocols/dcutr/Cargo.toml b/protocols/dcutr/Cargo.toml index 6f8c4c284fd..3193df1bbe0 100644 --- a/protocols/dcutr/Cargo.toml +++ b/protocols/dcutr/Cargo.toml @@ -20,13 +20,13 @@ instant = "0.1.11" libp2p-core = { version = "0.35.0", path = "../../core" } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4" -prost-codec = { version = "0.1", path = "../../misc/prost-codec" } -prost = "0.10" +prost-codec = { version = "0.2", path = "../../misc/prost-codec" } +prost = "0.11" thiserror = "1.0" void = "1" [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [dev-dependencies] env_logger = "0.8.3" diff --git a/protocols/floodsub/Cargo.toml b/protocols/floodsub/Cargo.toml index d240ef66d07..8c2631e5ce8 100644 --- a/protocols/floodsub/Cargo.toml +++ b/protocols/floodsub/Cargo.toml @@ -17,9 +17,9 @@ futures = "0.3.1" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4" -prost = "0.10" +prost = "0.11" rand = "0.7" smallvec = "1.6.1" [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" diff --git a/protocols/gossipsub/Cargo.toml b/protocols/gossipsub/Cargo.toml index da97500808d..5c7f2a16e8f 100644 --- a/protocols/gossipsub/Cargo.toml +++ b/protocols/gossipsub/Cargo.toml @@ -24,7 +24,7 @@ log = "0.4.11" sha2 = "0.10.0" base64 = "0.13.0" smallvec = "1.6.1" -prost = "0.10" +prost = "0.11" hex_fmt = "0.3.0" regex = "1.5.5" serde = { version = "1", optional = true, features = ["derive"] } @@ -45,4 +45,4 @@ hex = "0.4.2" derive_builder = "0.11.1" [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml index 1b3341df3f8..9db09cd1bf2 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -18,8 +18,8 @@ libp2p-core = { version = "0.35.0", path = "../../core", default-features = fals libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4.1" lru = "0.7.2" -prost-codec = { version = "0.1", path = "../../misc/prost-codec" } -prost = "0.10" +prost-codec = { version = "0.2", path = "../../misc/prost-codec" } +prost = "0.11" smallvec = "1.6.1" thiserror = "1.0" void = "1.0" @@ -37,4 +37,4 @@ libp2p = { path = "../..", default-features = false, features = [ ]} [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index f33697f2e32..d1910dccbbb 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3.1" log = "0.4" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } -prost = "0.10" +prost = "0.11" rand = "0.7.2" sha2 = "0.10.0" smallvec = "1.6.1" @@ -40,7 +40,7 @@ libp2p-yamux = { path = "../../muxers/yamux" } quickcheck = "0.9.0" [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [features] serde = ["_serde", "bytes/serde"] diff --git a/protocols/relay/Cargo.toml b/protocols/relay/Cargo.toml index 817025842f8..4a7396f938b 100644 --- a/protocols/relay/Cargo.toml +++ b/protocols/relay/Cargo.toml @@ -21,8 +21,8 @@ libp2p-core = { version = "0.35.0", path = "../../core", default-features = fals libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4" pin-project = "1" -prost-codec = { version = "0.1", path = "../../misc/prost-codec" } -prost = "0.10" +prost-codec = { version = "0.2", path = "../../misc/prost-codec" } +prost = "0.11" rand = "0.8.4" smallvec = "1.6.1" static_assertions = "1" @@ -30,7 +30,7 @@ thiserror = "1.0" void = "1" [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [dev-dependencies] env_logger = "0.9.0" diff --git a/protocols/rendezvous/Cargo.toml b/protocols/rendezvous/Cargo.toml index 745285b91bd..833fee1f19d 100644 --- a/protocols/rendezvous/Cargo.toml +++ b/protocols/rendezvous/Cargo.toml @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] asynchronous-codec = "0.6" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } -prost = "0.10" +prost = "0.11" void = "1" log = "0.4" futures = { version = "0.3", default-features = false, features = ["std"] } @@ -34,4 +34,4 @@ rand = "0.8" tokio = { version = "1.15", features = [ "rt-multi-thread", "time", "macros", "sync", "process", "fs", "net" ] } [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" diff --git a/transports/noise/Cargo.toml b/transports/noise/Cargo.toml index 171a89a4715..708b3eb286e 100644 --- a/transports/noise/Cargo.toml +++ b/transports/noise/Cargo.toml @@ -15,7 +15,7 @@ futures = "0.3.1" lazy_static = "1.2" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } log = "0.4" -prost = "0.10" +prost = "0.11" rand = "0.8.3" sha2 = "0.10.0" static_assertions = "1" @@ -36,4 +36,4 @@ quickcheck = "0.9.0" sodiumoxide = "0.2.5" [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" diff --git a/transports/plaintext/Cargo.toml b/transports/plaintext/Cargo.toml index c8cd9395da0..354782d9253 100644 --- a/transports/plaintext/Cargo.toml +++ b/transports/plaintext/Cargo.toml @@ -16,7 +16,7 @@ futures = "0.3.1" asynchronous-codec = "0.6" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } log = "0.4.8" -prost = "0.10" +prost = "0.11" unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] } void = "1.0.2" @@ -26,4 +26,4 @@ quickcheck = "0.9.0" rand = "0.7" [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" From 8dc0188a1d6f62c59b1ea07088d6e1c651419006 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 16 Aug 2022 10:15:31 +0200 Subject: [PATCH 37/92] swarm/src/connection: Test max_negotiating_inbound_streams (#2785) Test that `HandlerWrapper` upholds the provided `max_negotiating_inbound_streams` limit. --- core/src/upgrade.rs | 2 + core/src/upgrade/pending.rs | 76 +++++++++++++++ swarm/src/connection/handler_wrapper.rs | 79 ++++++++++++++++ swarm/src/handler.rs | 2 + swarm/src/handler/pending.rs | 120 ++++++++++++++++++++++++ 5 files changed, 279 insertions(+) create mode 100644 core/src/upgrade/pending.rs create mode 100644 swarm/src/handler/pending.rs diff --git a/core/src/upgrade.rs b/core/src/upgrade.rs index 2cb3c060b90..34a27cdf77a 100644 --- a/core/src/upgrade.rs +++ b/core/src/upgrade.rs @@ -64,6 +64,7 @@ mod error; mod from_fn; mod map; mod optional; +mod pending; mod select; mod transfer; @@ -77,6 +78,7 @@ pub use self::{ from_fn::{from_fn, FromFnUpgrade}, map::{MapInboundUpgrade, MapInboundUpgradeErr, MapOutboundUpgrade, MapOutboundUpgradeErr}, optional::OptionalUpgrade, + pending::PendingUpgrade, select::SelectUpgrade, transfer::{read_length_prefixed, read_varint, write_length_prefixed, write_varint}, }; diff --git a/core/src/upgrade/pending.rs b/core/src/upgrade/pending.rs new file mode 100644 index 00000000000..15d3c31df48 --- /dev/null +++ b/core/src/upgrade/pending.rs @@ -0,0 +1,76 @@ +// Copyright 2022 Protocol Labs. +// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +use crate::upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeInfo}; +use futures::future; +use std::iter; +use void::Void; + +/// Implementation of [`UpgradeInfo`], [`InboundUpgrade`] and [`OutboundUpgrade`] that always +/// returns a pending upgrade. +#[derive(Debug, Copy, Clone)] +pub struct PendingUpgrade

{ + protocol_name: P, +} + +impl

PendingUpgrade

{ + pub fn new(protocol_name: P) -> Self { + Self { protocol_name } + } +} + +impl

UpgradeInfo for PendingUpgrade

+where + P: ProtocolName + Clone, +{ + type Info = P; + type InfoIter = iter::Once

; + + fn protocol_info(&self) -> Self::InfoIter { + iter::once(self.protocol_name.clone()) + } +} + +impl InboundUpgrade for PendingUpgrade

+where + P: ProtocolName + Clone, +{ + type Output = Void; + type Error = Void; + type Future = future::Pending>; + + fn upgrade_inbound(self, _: C, _: Self::Info) -> Self::Future { + future::pending() + } +} + +impl OutboundUpgrade for PendingUpgrade

+where + P: ProtocolName + Clone, +{ + type Output = Void; + type Error = Void; + type Future = future::Pending>; + + fn upgrade_outbound(self, _: C, _: Self::Info) -> Self::Future { + future::pending() + } +} diff --git a/swarm/src/connection/handler_wrapper.rs b/swarm/src/connection/handler_wrapper.rs index 77eb1d79bbf..03d09b3fbc1 100644 --- a/swarm/src/connection/handler_wrapper.rs +++ b/swarm/src/connection/handler_wrapper.rs @@ -440,3 +440,82 @@ pub enum Event { /// Other event. Custom(TCustom), } + +#[cfg(test)] +mod tests { + use super::*; + use crate::handler::PendingConnectionHandler; + use quickcheck::*; + use std::sync::Arc; + + #[test] + fn max_negotiating_inbound_streams() { + fn prop(max_negotiating_inbound_streams: u8) { + let max_negotiating_inbound_streams: usize = max_negotiating_inbound_streams.into(); + let mut wrapper = HandlerWrapper::new( + PeerId::random(), + ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }, + PendingConnectionHandler::new("test".to_string()), + None, + max_negotiating_inbound_streams, + ); + let alive_substreams_counter = Arc::new(()); + + for _ in 0..max_negotiating_inbound_streams { + let substream = + SubstreamBox::new(PendingSubstream(alive_substreams_counter.clone())); + wrapper.inject_substream(substream, SubstreamEndpoint::Listener); + } + + assert_eq!( + Arc::strong_count(&alive_substreams_counter), + max_negotiating_inbound_streams + 1, + "Expect none of the substreams up to the limit to be dropped." + ); + + let substream = SubstreamBox::new(PendingSubstream(alive_substreams_counter.clone())); + wrapper.inject_substream(substream, SubstreamEndpoint::Listener); + + assert_eq!( + Arc::strong_count(&alive_substreams_counter), + max_negotiating_inbound_streams + 1, + "Expect substream exceeding the limit to be dropped." + ); + } + + QuickCheck::new().quickcheck(prop as fn(_)); + } + + struct PendingSubstream(Arc<()>); + + impl AsyncRead for PendingSubstream { + fn poll_read( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + _buf: &mut [u8], + ) -> Poll> { + Poll::Pending + } + } + + impl AsyncWrite for PendingSubstream { + fn poll_write( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + _buf: &[u8], + ) -> Poll> { + Poll::Pending + } + + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Pending + } + + fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Pending + } + } +} diff --git a/swarm/src/handler.rs b/swarm/src/handler.rs index 7060d33bc6a..c6125f277b1 100644 --- a/swarm/src/handler.rs +++ b/swarm/src/handler.rs @@ -44,6 +44,7 @@ mod map_in; mod map_out; pub mod multi; mod one_shot; +mod pending; mod select; pub use crate::upgrade::{InboundUpgradeSend, OutboundUpgradeSend, SendWrapper, UpgradeInfoSend}; @@ -56,6 +57,7 @@ pub use dummy::DummyConnectionHandler; pub use map_in::MapInEvent; pub use map_out::MapOutEvent; pub use one_shot::{OneShotHandler, OneShotHandlerConfig}; +pub use pending::PendingConnectionHandler; pub use select::{ConnectionHandlerSelect, IntoConnectionHandlerSelect}; /// A handler for a set of protocols used on a connection with a remote. diff --git a/swarm/src/handler/pending.rs b/swarm/src/handler/pending.rs new file mode 100644 index 00000000000..04c1696515c --- /dev/null +++ b/swarm/src/handler/pending.rs @@ -0,0 +1,120 @@ +// Copyright 2022 Protocol Labs. +// Copyright 2018 Parity Technologies (UK) Ltd. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +use crate::handler::{ + ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, KeepAlive, + SubstreamProtocol, +}; +use crate::NegotiatedSubstream; +use libp2p_core::{ + upgrade::{InboundUpgrade, OutboundUpgrade, PendingUpgrade}, + Multiaddr, +}; +use std::task::{Context, Poll}; +use void::Void; + +/// Implementation of [`ConnectionHandler`] that returns a pending upgrade. +#[derive(Clone, Debug)] +pub struct PendingConnectionHandler { + protocol_name: String, +} + +impl PendingConnectionHandler { + pub fn new(protocol_name: String) -> Self { + PendingConnectionHandler { protocol_name } + } +} + +impl ConnectionHandler for PendingConnectionHandler { + type InEvent = Void; + type OutEvent = Void; + type Error = Void; + type InboundProtocol = PendingUpgrade; + type OutboundProtocol = PendingUpgrade; + type OutboundOpenInfo = Void; + type InboundOpenInfo = (); + + fn listen_protocol(&self) -> SubstreamProtocol { + SubstreamProtocol::new(PendingUpgrade::new(self.protocol_name.clone()), ()) + } + + fn inject_fully_negotiated_inbound( + &mut self, + protocol: >::Output, + _: Self::InboundOpenInfo, + ) { + void::unreachable(protocol) + } + + fn inject_fully_negotiated_outbound( + &mut self, + protocol: >::Output, + _info: Self::OutboundOpenInfo, + ) { + void::unreachable(protocol); + #[allow(unreachable_code)] + { + void::unreachable(_info); + } + } + + fn inject_event(&mut self, v: Self::InEvent) { + void::unreachable(v) + } + + fn inject_address_change(&mut self, _: &Multiaddr) {} + + fn inject_dial_upgrade_error( + &mut self, + _: Self::OutboundOpenInfo, + _: ConnectionHandlerUpgrErr< + >::Error, + >, + ) { + } + + fn inject_listen_upgrade_error( + &mut self, + _: Self::InboundOpenInfo, + _: ConnectionHandlerUpgrErr< + >::Error, + >, + ) { + } + + fn connection_keep_alive(&self) -> KeepAlive { + KeepAlive::No + } + + fn poll( + &mut self, + _: &mut Context<'_>, + ) -> Poll< + ConnectionHandlerEvent< + Self::OutboundProtocol, + Self::OutboundOpenInfo, + Self::OutEvent, + Self::Error, + >, + > { + Poll::Pending + } +} From 67266c6a667ba71d0757316f835da8f75bf7532b Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 17 Aug 2022 06:43:47 +0200 Subject: [PATCH 38/92] swarm-derive/: Add where clause of behaviour to generated out event (#2819) When generating the `OutEvent` for a `NetworkBehaviour`, add the `where` clause of the `NetworkBehaviour` `struct` to the generated `enum`. --- swarm-derive/src/lib.rs | 4 +++- swarm-derive/tests/test.rs | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/swarm-derive/src/lib.rs b/swarm-derive/src/lib.rs index 8a42220246a..2ac9f978657 100644 --- a/swarm-derive/src/lib.rs +++ b/swarm-derive/src/lib.rs @@ -159,7 +159,9 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { let visibility = &ast.vis; Some(quote! { - #visibility enum #name #impl_generics { + #visibility enum #name #impl_generics + #where_clause + { #(#fields),* } }) diff --git a/swarm-derive/tests/test.rs b/swarm-derive/tests/test.rs index 09048e5e801..d23dd8ed863 100644 --- a/swarm-derive/tests/test.rs +++ b/swarm-derive/tests/test.rs @@ -272,7 +272,7 @@ fn custom_event_mismatching_field_names() { } #[test] -fn where_clause() { +fn bound() { #[allow(dead_code)] #[derive(NetworkBehaviour)] struct Foo { @@ -281,6 +281,19 @@ fn where_clause() { } } +#[test] +fn where_clause() { + #[allow(dead_code)] + #[derive(NetworkBehaviour)] + struct Foo + where + T: Copy + NetworkBehaviour, + { + ping: libp2p::ping::Ping, + bar: T, + } +} + #[test] fn nested_derives_with_import() { #[allow(dead_code)] From d2c50530e91fa7882457bd15163d257d8cf137c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Aug 2022 07:02:21 +0200 Subject: [PATCH 39/92] build(deps): Update prometheus-client requirement from 0.17.0 to 0.18.0 (#2822) * build(deps): Update prometheus-client requirement from 0.17.0 to 0.18.0 Updates the requirements on [prometheus-client](https://github.com/prometheus/client_rust) to permit the latest version. - [Release notes](https://github.com/prometheus/client_rust/releases) - [Changelog](https://github.com/prometheus/client_rust/blob/master/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_rust/compare/v0.17.0...v0.18.0) --- updated-dependencies: - dependency-name: prometheus-client dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- misc/metrics/CHANGELOG.md | 4 ++-- misc/metrics/Cargo.toml | 2 +- protocols/gossipsub/CHANGELOG.md | 4 ++-- protocols/gossipsub/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/misc/metrics/CHANGELOG.md b/misc/metrics/CHANGELOG.md index 06e2163597e..014a4a84ffe 100644 --- a/misc/metrics/CHANGELOG.md +++ b/misc/metrics/CHANGELOG.md @@ -16,9 +16,9 @@ - Update to `libp2p-core` `v0.35.0`. -- Update to `prometheus-client` `v0.17.0`. See [PR 2761]. +- Update to `prometheus-client` `v0.18.0`. See [PR 2822]. -[PR 2761]: https://github.com/libp2p/rust-libp2p/pull/2761/ +[PR 2822]: https://github.com/libp2p/rust-libp2p/pull/2761/ [PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ diff --git a/misc/metrics/Cargo.toml b/misc/metrics/Cargo.toml index 7ccd259e535..4bfeb7aa481 100644 --- a/misc/metrics/Cargo.toml +++ b/misc/metrics/Cargo.toml @@ -26,7 +26,7 @@ libp2p-kad = { version = "0.39.0", path = "../../protocols/kad", optional = true libp2p-ping = { version = "0.38.0", path = "../../protocols/ping", optional = true } libp2p-relay = { version = "0.11.0", path = "../../protocols/relay", optional = true } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } -prometheus-client = "0.17.0" +prometheus-client = "0.18.0" [target.'cfg(not(target_os = "unknown"))'.dependencies] libp2p-gossipsub = { version = "0.40.0", path = "../../protocols/gossipsub", optional = true } diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index 233d3873e98..c7bb155b3c9 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -4,9 +4,9 @@ - Update to `libp2p-core` `v0.35.0`. -- Update to `prometheus-client` `v0.17.0`. See [PR 2761]. +- Update to `prometheus-client` `v0.18.0`. See [PR 2822]. -[PR 2761]: https://github.com/libp2p/rust-libp2p/pull/2761/ +[PR 2822]: https://github.com/libp2p/rust-libp2p/pull/2761/ # 0.39.0 diff --git a/protocols/gossipsub/Cargo.toml b/protocols/gossipsub/Cargo.toml index 5c7f2a16e8f..42b21e41a97 100644 --- a/protocols/gossipsub/Cargo.toml +++ b/protocols/gossipsub/Cargo.toml @@ -31,7 +31,7 @@ serde = { version = "1", optional = true, features = ["derive"] } wasm-timer = "0.2.5" instant = "0.1.11" # Metrics dependencies -prometheus-client = "0.17.0" +prometheus-client = "0.18.0" [dev-dependencies] async-std = "1.6.3" From a2738fd5551c4ab0f234e2d33dd5500768bbaabb Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 17 Aug 2022 08:40:32 +0200 Subject: [PATCH 40/92] swarm-derive/: Derive Debug for generated OutEvent (#2821) When generating an `OutEvent` `enum` definition for a user, derive `Debug` for that `enum`. Why not derive `Clone`, `PartialEq` and `Eq` for the generated `enum` definition? While it is fine to require all sub-`OutEvent`s to implement `Debug`, the same does not apply to traits like `Clone`. I suggest users that need `Clone` to define their own `OutEvent`. --- swarm-derive/src/lib.rs | 1 + swarm-derive/tests/test.rs | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/swarm-derive/src/lib.rs b/swarm-derive/src/lib.rs index 2ac9f978657..51305e38190 100644 --- a/swarm-derive/src/lib.rs +++ b/swarm-derive/src/lib.rs @@ -159,6 +159,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { let visibility = &ast.vis; Some(quote! { + #[derive(::std::fmt::Debug)] #visibility enum #name #impl_generics #where_clause { diff --git a/swarm-derive/tests/test.rs b/swarm-derive/tests/test.rs index d23dd8ed863..f4a313198a9 100644 --- a/swarm-derive/tests/test.rs +++ b/swarm-derive/tests/test.rs @@ -21,6 +21,7 @@ use futures::prelude::*; use libp2p::swarm::{NetworkBehaviour, SwarmEvent}; use libp2p_swarm_derive::*; +use std::fmt::Debug; /// Small utility to check that a type implements `NetworkBehaviour`. #[allow(dead_code)] @@ -275,7 +276,10 @@ fn custom_event_mismatching_field_names() { fn bound() { #[allow(dead_code)] #[derive(NetworkBehaviour)] - struct Foo { + struct Foo + where + ::OutEvent: Debug, + { ping: libp2p::ping::Ping, bar: T, } @@ -288,6 +292,7 @@ fn where_clause() { struct Foo where T: Copy + NetworkBehaviour, + ::OutEvent: Debug, { ping: libp2p::ping::Ping, bar: T, @@ -489,3 +494,21 @@ fn event_process() { }; } } + +#[test] +fn generated_out_event_derive_debug() { + #[allow(dead_code)] + #[derive(NetworkBehaviour)] + struct Foo { + ping: libp2p::ping::Ping, + } + + fn require_debug() + where + T: NetworkBehaviour, + ::OutEvent: Debug, + { + } + + require_debug::(); +} From 475289c19ca3f79fe0cbad075963f4269cd125a8 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 17 Aug 2022 09:03:20 +0200 Subject: [PATCH 41/92] docs/coding-guidelines: Add document (#2780) Add document outlining a set of coding guidelines followed and to be followed across the rust-libp2p code base. Co-authored-by: Thomas Eizinger --- docs/architecture.svg | 39 ++++++ docs/coding-guidelines.md | 287 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 326 insertions(+) create mode 100644 docs/architecture.svg create mode 100644 docs/coding-guidelines.md diff --git a/docs/architecture.svg b/docs/architecture.svg new file mode 100644 index 00000000000..354aaf3dda8 --- /dev/null +++ b/docs/architecture.svg @@ -0,0 +1,39 @@ +Swarmpoll()RootBehaviourpoll()ConnectionPoolpoll()Transportpoll()PingBehaviourpoll()IdentifyBehaviourpoll()KademliaBehaviourpoll() \ No newline at end of file diff --git a/docs/coding-guidelines.md b/docs/coding-guidelines.md new file mode 100644 index 00000000000..a208dd2768c --- /dev/null +++ b/docs/coding-guidelines.md @@ -0,0 +1,287 @@ +# Coding Guidelines + + +**Table of Contents** + +- [Coding Guidelines](#coding-guidelines) + - [Hierarchical State Machines](#hierarchical-state-machines) + - [Conventions for `poll` implementations](#conventions-for-poll-implementations) + - [Prioritize local work over new work from a remote](#prioritize-local-work-over-new-work-from-a-remote) + - [Bound everything](#bound-everything) + - [Channels](#channels) + - [Local queues](#local-queues) + - [Further reading](#further-reading) + - [No premature optimizations](#no-premature-optimizations) + - [Keep things sequential unless proven to be slow](#keep-things-sequential-unless-proven-to-be-slow) + - [Use `async/await` for sequential execution only](#use-asyncawait-for-sequential-execution-only) + - [Don't communicate by sharing memory; share memory by communicating.](#dont-communicate-by-sharing-memory-share-memory-by-communicating) + - [Further Reading](#further-reading) + - [Use iteration not recursion](#use-iteration-not-recursion) + - [Further Reading](#further-reading-1) + + + + +Below is a set of coding guidelines followed across the rust-libp2p code base. + +## Hierarchical State Machines + +If you sqint, rust-libp2p is just a big hierarchy of [state +machines](https://en.wikipedia.org/wiki/Finite-state_machine) where parents pass +events down to their children and children pass events up to their parents. + +![Architecture](architecture.svg) + +

+ Reproduce diagram + + ``` + @startuml + Swarm <|-- RootBehaviour + Swarm <|-- ConnectionPool + Swarm <|-- Transport + RootBehaviour <|-- PingBehaviour + RootBehaviour <|-- IdentifyBehaviour + RootBehaviour <|-- KademliaBehaviour + + Swarm : poll() + RootBehaviour : poll() + ConnectionPool : poll() + Transport : poll() + PingBehaviour : poll() + IdentifyBehaviour : poll() + KademliaBehaviour : poll() + @enduml + ``` +
+ +Using hierarchical state machines is a deliberate choice throughout the +rust-libp2p code base. It makes reasoning about control and data flow simple. It +works well with Rust's `Future` model. It allows fine-grain control e.g. on the +order child state machines are polled. + +The above comes with downsides. It feels more verbose. The mix of control flow (`loop`, `return`, +`break`, `continue`) in `poll` functions together with the asynchronous and thus decoupled +communication via events can be very hard to understand. Both are a form of complexity that we are +trading for correctness and performance which aligns with Rust's and rust-libp2p's goals. + +The architecture pattern of hierarchical state machines should be used wherever possible. + +### Conventions for `poll` implementations + +The `poll` method of a single state machine can be complex especially when that +state machine itself `poll`s many child state machines. The patterns shown below +have proven useful and should be followed across the code base. + +``` rust +fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll{ + loop { + match self.child_1.poll(cx) { + // The child made progress. + Poll::Ready(_) => { + // Either return an event to the parent: + return Poll::Ready(todo!()); + // or `continue`, thus polling `child_1` again. `child_1` can potentially make more progress. Try to exhaust + // it before moving on to the next child. + continue + // but NEVER move to the next child if the current child made progress. Given + // that the current child might be able to make more progress, it did not yet + // register the waker in order for the root task to be woken up later on. Moving + // on to the next child might result in the larger `Future` task to stall as it + // assumes that there is no more progress to be made. + } + + // The child did not make progress. It has registered the waker for a + // later wake up. Proceed with the other children. + Poll::Pending(_) => {} + } + + match self.child_2.poll(cx) { + Poll::Ready(child_2_event) => { + // Events can be dispatched from one child to the other. + self.child_1.handle_event(child_2_event); + + // Either `continue` thus polling `child_1` again, or `return Poll::Ready` with a result to the parent. + todo!() + } + Poll::Pending(_) => {} + } + + match self.child_3.poll(cx) { + Poll::Ready(__) => { + // Either `continue` thus polling `child_1` again, or `return Poll::Ready` with a result to the parent. + todo!() + } + Poll::Pending(_) => {} + } + + // None of the child state machines can make any more progress. Each registered + // the waker in order for the root `Future` task to be woken up again. + return Poll::Pending + } +} +``` + +### Prioritize local work over new work from a remote + +When handling multiple work streams, prioritize local work items over +accepting new work items from a remote. Take the following state machine as an +example, reading and writing from a socket, returning result to its parent: + +``` rust +struct SomeStateMachine { + socket: Socket, + events_to_return_to_parent: VecDeque, + messages_to_send_on_socket: VecDeque, +} + +impl Stream for SomeStateMachine { + type Item = Event; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + loop { + // First priority is returning local finished work. + if let Some(event) = events_to_return_to_parent.pop_front() { + return Poll::Ready(Some(event)); + } + + // Second priority is finishing local work, i.e. sending on the socket. + if let Poll::Ready(()) = socket.poll_ready(cx) { + todo!("Send messages") + continue // Go back to the top. One might be able to send more. + } + + // Last priority is accepting new work, i.e. reading from the socket. + if let Poll::Ready(work_item) = socket.poll_next(cx) { + todo!("Start work on new item") + continue // Go back to the top. There might be more progress to be made. + } + + // At this point in time, there is no more progress to be made. Return + // `Pending` and be woken up later. + return Poll::Pending; + } + } +} +``` + +This priotization provides: +- Low memory footprint as local queues (here `events_to_return_to_parent`) stay small. +- Low latency as accepted local work is not stuck in queues. +- DOS defense as a remote does not control the size of the local queue, nor starves local work with its remote work. + +## Bound everything + +The concept of unboundedness is an illusion. Use bounded mechanisms to prevent +unbounded memory growth and high latencies. + +### Channels + +When using channels (e.g. `futures::channel::mpsc` or `std::sync::mpsc`) +always use the bounded variant, never use the unbounded variant. When using a +bounded channel, a slow consumer eventually slows down a fast producer once +the channel bound is reached, ideally granting the slow consumer more system +resources e.g. CPU time, keeping queues small and thus latencies low. When +using an unbounded channel a fast producer continues being a fast producer, +growing the channel buffer indefinitely, increasing latency until the illusion +of unboundedness breaks and the system runs out of memory. + +One may use an unbounded channel if one enforces backpressure through an +out-of-band mechanism, e.g. the consumer granting the producer send-tokens +through a side-channel. + +### Local queues + +As for channels shared across potentially concurrent actors (e.g. future tasks +or OS threads), the same applies for queues owned by a single actor only. E.g. +reading events from a socket into a `Vec` without some mechanism +bounding the size of that `Vec` again can lead to unbounded memory +growth and high latencies. + +Note that rust-libp2p fails at this guideline, i.e. still has many unbounded +local queues. + +### Further reading + +- https://en.wikipedia.org/wiki/Bufferbloat +- https://apenwarr.ca/log/20170814 +- https://twitter.com/peterbourgon/status/1212800031406739456 + +## No premature optimizations + +Optimizations that add complexity need to be accompanied with a proof of their +effectiveness. + +This as well applies to increasing buffer or channel sizes, as the downside of +such pseudo optimizations is increased memory footprint and latency. + +## Keep things sequential unless proven to be slow + +Concurrency adds complexity. Concurrency adds overhead due to synchronization. +Thus unless proven to be a bottleneck, don't make things concurrent. As an example +the hierarchical `NetworkBehaviour` state machine runs sequentially. It is easy +to debug as it runs sequentially. Thus far there has been no proof that +shows a speed up when running it concurrently. + +## Use `async/await` for sequential execution only + +Using `async/await` for sequential execution makes things significantly simpler. +Though unfortunately using `async/await` does not allow accesing methods on the +object being `await`ed unless paired with some synchronization mechanism like an +`Arc>`. + +Example: Read and once done write from/to a socket. Use `async/await`. + +``` rust +socket.read_exact(&mut read_buf).await; +socket.write(&write_buf).await; +``` + +Example: Read and concurrently write from/to a socket. Use `poll`. + +``` rust +loop { + match socket.poll_read(cx, &mut read_buf) { + Poll::Ready(_) => { + todo!(); + continue; + } + Poll::Pending => {} + } + match socket.poll_write(cx, &write_buf) { + Poll::Ready(_) => { + todo!(); + continue; + } + Poll::Pending => {} + } + + return Poll::Pending; +} +``` + +When providing `async` methods, make it explicit whether it is safe to cancel +the resulting `Future`, i.e. whether it is safe to drop the `Future` returned +by the `async` method. + +## Don't communicate by sharing memory; share memory by communicating. + +The majority of rust-libp2p's code base follows the above Golang philosophy, +e.g. using channels instead of mutexes. This pattern enforces single ownership +over data, which works well with Rust's ownership model and makes reasoning +about data flow easier. + +### Further Reading + +- https://go.dev/blog/codelab-share + +## Use iteration not recursion + +Rust does not support tail call optimization, thus using recursion may grow the +stack potentially unboundedly. Instead use iteration e.g. via `loop` or `for`. + +### Further Reading + +- https://en.wikipedia.org/wiki/Tail_call +- https://stackoverflow.com/questions/65948553/why-is-recursion-not-suggested-in-rust +- https://stackoverflow.com/questions/59257543/when-is-tail-recursion-guaranteed-in-rust From 8931860b2f35e55316860a5fc0affb264c447c61 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Fri, 19 Aug 2022 05:06:55 +0200 Subject: [PATCH 42/92] core/identity: Allow clippy::large-enum-variant on `Keypair` (#2827) --- core/src/identity.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/identity.rs b/core/src/identity.rs index ee431e7ee9c..a2b3943d0e9 100644 --- a/core/src/identity.rs +++ b/core/src/identity.rs @@ -64,6 +64,7 @@ use std::convert::{TryFrom, TryInto}; /// ``` /// #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum Keypair { /// An Ed25519 keypair. Ed25519(ed25519::Keypair), From 95fc6dadb3774058538dba526a3170867ba9b041 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Fri, 19 Aug 2022 18:14:17 +0200 Subject: [PATCH 43/92] transports/quic: drive connection in `QuicMuxer::poll` --- transports/quic/src/muxer.rs | 139 ++++++++++++++++------------------- 1 file changed, 65 insertions(+), 74 deletions(-) diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index 96c6cddf4b6..637bf9a0a41 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -22,7 +22,7 @@ use crate::connection::{Connection, ConnectionEvent}; use crate::error::Error; use futures::{AsyncRead, AsyncWrite}; -use libp2p_core::muxing::StreamMuxer; +use libp2p_core::muxing::{StreamMuxer, StreamMuxerEvent}; use parking_lot::Mutex; use std::{ collections::HashMap, @@ -56,41 +56,83 @@ struct Inner { poll_close_waker: Option, } -impl Inner { - fn poll_connection(&mut self, cx: &mut Context<'_>) { - while let Poll::Ready(event) = self.connection.poll_event(cx) { +/// State of a single substream. +#[derive(Debug, Default, Clone)] +struct SubstreamState { + /// Waker to wake if the substream becomes readable or stopped. + read_waker: Option, + /// Waker to wake if the substream becomes writable or stopped. + write_waker: Option, + /// True if the substream has been finished. + finished: bool, + /// True if the substream has been stopped. + stopped: bool, + /// Waker to wake if the substream becomes closed or stopped. + finished_waker: Option, +} + +impl QuicMuxer { + /// Crate-internal function that builds a [`QuicMuxer`] from a raw connection. + /// + /// # Panic + /// + /// Panics if `connection.is_handshaking()` returns `true`. + pub(crate) fn from_connection(connection: Connection) -> Self { + assert!(!connection.is_handshaking()); + + QuicMuxer { + inner: Arc::new(Mutex::new(Inner { + connection, + substreams: Default::default(), + poll_outbound_waker: None, + poll_close_waker: None, + poll_inbound_waker: None, + })), + } + } +} +impl StreamMuxer for QuicMuxer { + type Substream = Substream; + type Error = Error; + + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + let mut inner = self.inner.lock(); + while let Poll::Ready(event) = inner.connection.poll_event(cx) { match event { ConnectionEvent::Connected => { tracing::warn!("Unexpected Connected event on established QUIC connection"); } ConnectionEvent::ConnectionLost(_) => { - if let Some(waker) = self.poll_close_waker.take() { + if let Some(waker) = inner.poll_close_waker.take() { waker.wake(); } - self.connection.close(); + inner.connection.close(); } ConnectionEvent::StreamOpened => { - if let Some(waker) = self.poll_outbound_waker.take() { + if let Some(waker) = inner.poll_outbound_waker.take() { waker.wake(); } } ConnectionEvent::StreamReadable(substream) => { - if let Some(substream) = self.substreams.get_mut(&substream) { + if let Some(substream) = inner.substreams.get_mut(&substream) { if let Some(waker) = substream.read_waker.take() { waker.wake(); } } } ConnectionEvent::StreamWritable(substream) => { - if let Some(substream) = self.substreams.get_mut(&substream) { + if let Some(substream) = inner.substreams.get_mut(&substream) { if let Some(waker) = substream.write_waker.take() { waker.wake(); } } } ConnectionEvent::StreamFinished(substream) => { - if let Some(substream) = self.substreams.get_mut(&substream) { + if let Some(substream) = inner.substreams.get_mut(&substream) { substream.finished = true; if let Some(waker) = substream.finished_waker.take() { waker.wake(); @@ -98,65 +140,18 @@ impl Inner { } } ConnectionEvent::StreamStopped(substream) => { - if let Some(substream) = self.substreams.get_mut(&substream) { + if let Some(substream) = inner.substreams.get_mut(&substream) { substream.stopped = true; } } ConnectionEvent::StreamAvailable => { - if let Some(waker) = self.poll_inbound_waker.take() { + if let Some(waker) = inner.poll_inbound_waker.take() { waker.wake(); } } } } - } -} - -/// State of a single substream. -#[derive(Debug, Default, Clone)] -struct SubstreamState { - /// Waker to wake if the substream becomes readable or stopped. - read_waker: Option, - /// Waker to wake if the substream becomes writable or stopped. - write_waker: Option, - /// True if the substream has been finished. - finished: bool, - /// True if the substream has been stopped. - stopped: bool, - /// Waker to wake if the substream becomes closed or stopped. - finished_waker: Option, -} - -impl QuicMuxer { - /// Crate-internal function that builds a [`QuicMuxer`] from a raw connection. - /// - /// # Panic - /// - /// Panics if `connection.is_handshaking()` returns `true`. - pub(crate) fn from_connection(connection: Connection) -> Self { - assert!(!connection.is_handshaking()); - - QuicMuxer { - inner: Arc::new(Mutex::new(Inner { - connection, - substreams: Default::default(), - poll_outbound_waker: None, - poll_close_waker: None, - poll_inbound_waker: None, - })), - } - } -} -impl StreamMuxer for QuicMuxer { - type Substream = Substream; - type Error = Error; - - fn poll_address_change( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - self.inner.lock().poll_connection(cx); - // TODO + // TODO: poll address change Poll::Pending } @@ -165,13 +160,12 @@ impl StreamMuxer for QuicMuxer { cx: &mut Context<'_>, ) -> Poll> { let mut inner = self.inner.lock(); - inner.poll_connection(cx); let substream_id = match inner.connection.pop_incoming_substream() { - Some(id) => id, - None => { - inner.poll_inbound_waker = Some(cx.waker().clone()); - return Poll::Pending; - } + Some(id) => id, + None => { + inner.poll_inbound_waker = Some(cx.waker().clone()); + return Poll::Pending; + } }; inner.substreams.insert(substream_id, Default::default()); let substream = Substream::new(substream_id, self.inner.clone()); @@ -183,13 +177,12 @@ impl StreamMuxer for QuicMuxer { cx: &mut Context<'_>, ) -> Poll> { let mut inner = self.inner.lock(); - inner.poll_connection(cx); let substream_id = match inner.connection.pop_outgoing_substream() { - Some(id) => id, - None => { - inner.poll_outbound_waker = Some(cx.waker().clone()); - return Poll::Pending; - } + Some(id) => id, + None => { + inner.poll_outbound_waker = Some(cx.waker().clone()); + return Poll::Pending; + } }; inner.substreams.insert(substream_id, Default::default()); let substream = Substream::new(substream_id, self.inner.clone()); @@ -198,8 +191,6 @@ impl StreamMuxer for QuicMuxer { fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let mut inner = self.inner.lock(); - inner.poll_connection(cx); - if inner.connection.connection.is_drained() { return Poll::Ready(Ok(())); } From 3d3666e1a69c82afa9c966d668c32aae36c87599 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Sat, 20 Aug 2022 05:48:22 +0200 Subject: [PATCH 44/92] *: Enforce no clippy warnings for examples (#2826) --- .cargo/config.toml | 2 +- examples/chat-tokio.rs | 9 ++++----- examples/chat.rs | 1 + examples/file-sharing.rs | 15 ++++++--------- examples/gossipsub-chat.rs | 1 - examples/ipfs-kad.rs | 2 +- examples/ipfs-private.rs | 8 ++++---- 7 files changed, 17 insertions(+), 21 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 9d5619d2c4e..df790f03322 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,3 @@ [alias] # Temporary solution to have clippy config in a single place until https://github.com/rust-lang/rust-clippy/blob/master/doc/roadmap-2021.md#lintstoml-configuration is shipped. -custom-clippy = "clippy --all-features -- -A clippy::type_complexity -A clippy::pedantic -D warnings" +custom-clippy = "clippy --all-features --all-targets -- -A clippy::type_complexity -A clippy::pedantic -D warnings" diff --git a/examples/chat-tokio.rs b/examples/chat-tokio.rs index a082f3ef113..0bd44bdabdc 100644 --- a/examples/chat-tokio.rs +++ b/examples/chat-tokio.rs @@ -91,6 +91,7 @@ async fn main() -> Result<(), Box> { mdns: Mdns, } + #[allow(clippy::large_enum_variant)] enum MyBehaviourEvent { Floodsub(FloodsubEvent), Mdns(MdnsEvent), @@ -112,7 +113,7 @@ async fn main() -> Result<(), Box> { let mut swarm = { let mdns = Mdns::new(Default::default()).await?; let mut behaviour = MyBehaviour { - floodsub: Floodsub::new(peer_id.clone()), + floodsub: Floodsub::new(peer_id), mdns, }; @@ -152,14 +153,12 @@ async fn main() -> Result<(), Box> { SwarmEvent::NewListenAddr { address, .. } => { println!("Listening on {:?}", address); } - SwarmEvent::Behaviour(MyBehaviourEvent::Floodsub(event)) => { - if let FloodsubEvent::Message(message) = event { - println!( + SwarmEvent::Behaviour(MyBehaviourEvent::Floodsub(FloodsubEvent::Message(message))) => { + println!( "Received: '{:?}' from {:?}", String::from_utf8_lossy(&message.data), message.source ); - } } SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(event)) => { match event { diff --git a/examples/chat.rs b/examples/chat.rs index b9569142a41..d6468428567 100644 --- a/examples/chat.rs +++ b/examples/chat.rs @@ -92,6 +92,7 @@ async fn main() -> Result<(), Box> { ignored_member: bool, } + #[allow(clippy::large_enum_variant)] #[derive(Debug)] enum OutEvent { Floodsub(FloodsubEvent), diff --git a/examples/file-sharing.rs b/examples/file-sharing.rs index b90246e0b4f..21fa45d54fc 100644 --- a/examples/file-sharing.rs +++ b/examples/file-sharing.rs @@ -221,7 +221,7 @@ mod network { }; use libp2p::swarm::{ConnectionHandlerUpgrErr, SwarmBuilder, SwarmEvent}; use libp2p::{NetworkBehaviour, Swarm}; - use std::collections::{HashMap, HashSet}; + use std::collections::{hash_map, HashMap, HashSet}; use std::iter; /// Creates the network components, namely: @@ -359,10 +359,7 @@ mod network { channel: ResponseChannel, ) { self.sender - .send(Command::RespondFile { - file: file, - channel, - }) + .send(Command::RespondFile { file, channel }) .await .expect("Command receiver not to be dropped."); } @@ -527,9 +524,7 @@ mod network { peer_addr, sender, } => { - if self.pending_dial.contains_key(&peer_id) { - todo!("Already dialing peer."); - } else { + if let hash_map::Entry::Vacant(e) = self.pending_dial.entry(peer_id) { self.swarm .behaviour_mut() .kademlia @@ -539,12 +534,14 @@ mod network { .dial(peer_addr.with(Protocol::P2p(peer_id.into()))) { Ok(()) => { - self.pending_dial.insert(peer_id, sender); + e.insert(sender); } Err(e) => { let _ = sender.send(Err(Box::new(e))); } } + } else { + todo!("Already dialing peer."); } } Command::StartProviding { file_name, sender } => { diff --git a/examples/gossipsub-chat.rs b/examples/gossipsub-chat.rs index 976fcafb470..d6ea44dcef6 100644 --- a/examples/gossipsub-chat.rs +++ b/examples/gossipsub-chat.rs @@ -101,7 +101,6 @@ async fn main() -> Result<(), Box> { // add an explicit peer if one was provided if let Some(explicit) = std::env::args().nth(2) { - let explicit = explicit.clone(); match explicit.parse() { Ok(id) => gossipsub.add_explicit_peer(&id), Err(err) => println!("Failed to parse explicit peer id: {:?}", err), diff --git a/examples/ipfs-kad.rs b/examples/ipfs-kad.rs index b3e6b211b46..a36ed97737b 100644 --- a/examples/ipfs-kad.rs +++ b/examples/ipfs-kad.rs @@ -34,7 +34,7 @@ use libp2p::{ }; use std::{env, error::Error, str::FromStr, time::Duration}; -const BOOTNODES: [&'static str; 4] = [ +const BOOTNODES: [&str; 4] = [ "QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", "QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", "QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", diff --git a/examples/ipfs-private.rs b/examples/ipfs-private.rs index 00b529bf6f2..93e73cd5976 100644 --- a/examples/ipfs-private.rs +++ b/examples/ipfs-private.rs @@ -92,7 +92,7 @@ fn get_ipfs_path() -> Box { } /// Read the pre shared key file from the given ipfs directory -fn get_psk(path: Box) -> std::io::Result> { +fn get_psk(path: &Path) -> std::io::Result> { let swarm_key_file = path.join("swarm.key"); match fs::read_to_string(swarm_key_file) { Ok(text) => Ok(Some(text)), @@ -136,9 +136,9 @@ fn parse_legacy_multiaddr(text: &str) -> Result> { async fn main() -> Result<(), Box> { env_logger::init(); - let ipfs_path: Box = get_ipfs_path(); + let ipfs_path = get_ipfs_path(); println!("using IPFS_PATH {:?}", ipfs_path); - let psk: Option = get_psk(ipfs_path)? + let psk: Option = get_psk(&ipfs_path)? .map(|text| PreSharedKey::from_str(&text)) .transpose()?; @@ -146,7 +146,7 @@ async fn main() -> Result<(), Box> { let local_key = identity::Keypair::generate_ed25519(); let local_peer_id = PeerId::from(local_key.public()); println!("using random peer id: {:?}", local_peer_id); - for psk in psk { + if let Some(psk) = psk { println!("using swarm key with fingerprint: {}", psk.fingerprint()); } From 217dd2ca22b58d7f707b038cb1c32a127e1992cc Mon Sep 17 00:00:00 2001 From: Max Inden Date: Sat, 20 Aug 2022 07:31:45 +0200 Subject: [PATCH 45/92] clippy.toml: Create config and disallow unbounded channels (#2823) When using channels (e.g. `futures::channel::mpsc` or `std::sync::mpsc`) always use the bounded variant, never use the unbounded variant. When using a bounded channel, a slow consumer eventually slows down a fast producer once the channel bound is reached, ideally granting the slow consumer more system resources e.g. CPU time, keeping queues small and thus latencies low. When using an unbounded channel a fast producer continues being a fast producer, growing the channel buffer indefinitely, increasing latency until the illusion of unboundedness breaks and the system runs out of memory. One may use an unbounded channel if one enforces backpressure through an out-of-band mechanism, e.g. the consumer granting the producer send-tokens through a side-channel. --- clippy.toml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 clippy.toml diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 00000000000..f66cc0ac2da --- /dev/null +++ b/clippy.toml @@ -0,0 +1,3 @@ +disallowed-methods = [ + { path = "futures::channel::mpsc::unbounded", reason = "does not enforce backpressure" }, +] From 0d7c8a5667626b66f370c333aa7c318b57fb035a Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 21 Aug 2022 17:12:21 +0200 Subject: [PATCH 46/92] transports/quic: refactor `Connection::poll_event` --- transports/quic/src/connection.rs | 197 ++++++++++++++---------------- transports/quic/src/endpoint.rs | 43 +------ transports/quic/src/muxer.rs | 7 +- transports/quic/src/upgrade.rs | 44 +++---- 4 files changed, 118 insertions(+), 173 deletions(-) diff --git a/transports/quic/src/connection.rs b/transports/quic/src/connection.rs index 7027735c5e7..afb2b02ce84 100644 --- a/transports/quic/src/connection.rs +++ b/transports/quic/src/connection.rs @@ -26,7 +26,7 @@ //! All interactions with a QUIC connection should be done through this struct. // TODO: docs -use crate::endpoint::Endpoint; +use crate::endpoint::{Endpoint, ToEndpoint}; use async_io::Timer; use futures::{channel::mpsc, prelude::*}; @@ -34,7 +34,6 @@ use libp2p_core::PeerId; use std::{ fmt, net::SocketAddr, - pin::Pin, sync::Arc, task::{Context, Poll}, time::Instant, @@ -48,7 +47,7 @@ pub struct Connection { /// Endpoint this connection belongs to. endpoint: Arc, /// Future whose job is to send a message to the endpoint. Only one at a time. - pending_to_endpoint: Option + Send + Sync>>>, + pending_to_endpoint: Option, /// Events that the endpoint will send in destination to our local [`quinn_proto::Connection`]. /// Passed at initialization. from_endpoint: mpsc::Receiver, @@ -71,6 +70,8 @@ pub struct Connection { /// Contains `None` if it is still open. /// Contains `Some` if and only if a `ConnectionLost` event has been emitted. closed: Option, + + to_endpoint: mpsc::Sender, } /// Error on the connection as a whole. @@ -110,6 +111,7 @@ impl Connection { let is_handshaking = connection.is_handshaking(); Connection { + to_endpoint: endpoint.to_endpoint2.clone(), endpoint, pending_to_endpoint: None, connection, @@ -227,158 +229,100 @@ impl Connection { return Poll::Pending; } - // Process events that the endpoint has sent to us. loop { - match Pin::new(&mut self.from_endpoint).poll_next(cx) { - Poll::Ready(Some(event)) => self.connection.handle_event(event), + match self.from_endpoint.poll_next_unpin(cx) { + Poll::Ready(Some(event)) => { + self.connection.handle_event(event); + continue; + } Poll::Ready(None) => { debug_assert!(self.closed.is_none()); let err = Error::ClosedChannel; self.closed = Some(err.clone()); return Poll::Ready(ConnectionEvent::ConnectionLost(err)); } - Poll::Pending => break, + Poll::Pending => {} } - } - 'send_pending: loop { // Sending the pending event to the endpoint. If the endpoint is too busy, we just // stop the processing here. - // There is a bit of a question in play here: should we continue to accept events - // through `from_endpoint` if `to_endpoint` is busy? // We need to be careful to avoid a potential deadlock if both `from_endpoint` and // `to_endpoint` are full. As such, we continue to transfer data from `from_endpoint` // to the `quinn_proto::Connection` (see above). // However we don't deliver substream-related events to the user as long as // `to_endpoint` is full. This should propagate the back-pressure of `to_endpoint` // being full to the user. - if let Some(pending_to_endpoint) = &mut self.pending_to_endpoint { - match Future::poll(Pin::new(pending_to_endpoint), cx) { + if self.pending_to_endpoint.is_some() { + match self.to_endpoint.poll_ready_unpin(cx) { + Poll::Ready(Ok(())) => { + self.to_endpoint + .start_send(self.pending_to_endpoint.take().expect("is_some")) + .expect("To be ready"); + } + Poll::Ready(Err(_)) => todo!(), Poll::Pending => return Poll::Pending, - Poll::Ready(()) => self.pending_to_endpoint = None, } } - let now = Instant::now(); - // Poll the connection for packets to send on the UDP socket and try to send them on // `to_endpoint`. // FIXME max_datagrams - if let Some(transmit) = self.connection.poll_transmit(now, 1) { - let endpoint = self.endpoint.clone(); - debug_assert!(self.pending_to_endpoint.is_none()); - self.pending_to_endpoint = Some(Box::pin(async move { - // TODO: ECN bits not handled - endpoint - .send_udp_packet(transmit.destination, transmit.contents) - .await; - })); - continue 'send_pending; + if let Some(transmit) = self.connection.poll_transmit(Instant::now(), 1) { + // TODO: ECN bits not handled + self.pending_to_endpoint = Some(ToEndpoint::SendUdpPacket { + destination: transmit.destination, + data: transmit.contents, + }); + continue; } // Timeout system. - // We break out of the following loop until if `poll_timeout()` returns `None` or if - // polling `self.next_timeout` returns `Poll::Pending`. - loop { - if let Some(next_timeout) = &mut self.next_timeout { - match Future::poll(Pin::new(next_timeout), cx) { - Poll::Ready(when) => { - self.connection.handle_timeout(when); - self.next_timeout = None; - } - Poll::Pending => break, + if let Some(when) = self.connection.poll_timeout() { + let mut timer = Timer::at(when); + match timer.poll_unpin(cx) { + Poll::Ready(when) => { + self.connection.handle_timeout(when); + continue; } + Poll::Pending => self.next_timeout = Some(timer), } - if let Some(when) = self.connection.poll_timeout() { - self.next_timeout = Some(Timer::at(when)); - continue; - } - break; } // The connection also needs to be able to send control messages to the endpoint. This is // handled here, and we try to send them on `to_endpoint` as well. - if let Some(endpoint_event) = self.connection.poll_endpoint_events() { - let endpoint = self.endpoint.clone(); + if let Some(event) = self.connection.poll_endpoint_events() { let connection_id = self.connection_id; - debug_assert!(self.pending_to_endpoint.is_none()); - self.pending_to_endpoint = Some(Box::pin(async move { - endpoint - .report_quinn_event(connection_id, endpoint_event) - .await; - })); - continue 'send_pending; + self.pending_to_endpoint = Some(ToEndpoint::ProcessConnectionEvent { + connection_id, + event, + }); + continue; } // The final step consists in handling the events related to the various substreams. - while let Some(event) = self.connection.poll() { - match event { - quinn_proto::Event::Stream(quinn_proto::StreamEvent::Opened { - dir: quinn_proto::Dir::Uni, - }) - | quinn_proto::Event::Stream(quinn_proto::StreamEvent::Available { - dir: quinn_proto::Dir::Uni, - }) - | quinn_proto::Event::DatagramReceived => { - // We don't use datagrams or unidirectional streams. If these events - // happen, it is by some code not compatible with libp2p-quic. - self.connection - .close(Instant::now(), From::from(0u32), Default::default()); - } - quinn_proto::Event::Stream(quinn_proto::StreamEvent::Readable { id }) => { - return Poll::Ready(ConnectionEvent::StreamReadable(id)); - } - quinn_proto::Event::Stream(quinn_proto::StreamEvent::Writable { id }) => { - return Poll::Ready(ConnectionEvent::StreamWritable(id)); - } - quinn_proto::Event::Stream(quinn_proto::StreamEvent::Stopped { - id, .. - }) => { - // The `Stop` QUIC event is more or less similar to a `Reset`, except that - // it applies only on the writing side of the pipe. - return Poll::Ready(ConnectionEvent::StreamStopped(id)); - } - quinn_proto::Event::Stream(quinn_proto::StreamEvent::Available { - dir: quinn_proto::Dir::Bi, - }) => { - return Poll::Ready(ConnectionEvent::StreamAvailable); - } - quinn_proto::Event::Stream(quinn_proto::StreamEvent::Opened { - dir: quinn_proto::Dir::Bi, - }) => { - return Poll::Ready(ConnectionEvent::StreamOpened); - } - quinn_proto::Event::ConnectionLost { reason } => { - debug_assert!(self.closed.is_none()); + match self.connection.poll() { + Some(ev) => match ConnectionEvent::try_from(ev) { + Ok(ConnectionEvent::ConnectionLost(err)) => { self.is_handshaking = false; - let err = Error::Quinn(reason); self.closed = Some(err.clone()); - // self.close(); - // self.connection - // .close(Instant::now(), From::from(0u32), Default::default()); return Poll::Ready(ConnectionEvent::ConnectionLost(err)); } - quinn_proto::Event::Stream(quinn_proto::StreamEvent::Finished { id }) => { - return Poll::Ready(ConnectionEvent::StreamFinished(id)); - } - quinn_proto::Event::Connected => { + Ok(ConnectionEvent::Connected) => { debug_assert!(self.is_handshaking); debug_assert!(!self.connection.is_handshaking()); self.is_handshaking = false; return Poll::Ready(ConnectionEvent::Connected); } - quinn_proto::Event::HandshakeDataReady => { - if !self.is_handshaking { - tracing::error!("Got HandshakeDataReady while not handshaking"); - } + Ok(event) => return Poll::Ready(event), + Err(_proto_ev) => { + // unreachable: We don't use datagrams or unidirectional streams. + continue; } - } + }, + None => {} } - - break; + return Poll::Pending; } - - Poll::Pending } } @@ -423,4 +367,45 @@ pub enum ConnectionEvent { /// A substream has been stopped. This concept is similar to the concept of a substream being /// "reset", as in a TCP socket being reset for example. StreamStopped(quinn_proto::StreamId), + + HandshakeDataReady, +} + +impl TryFrom for ConnectionEvent { + type Error = quinn_proto::Event; + + fn try_from(event: quinn_proto::Event) -> Result { + match event { + quinn_proto::Event::Stream(quinn_proto::StreamEvent::Readable { id }) => { + Ok(ConnectionEvent::StreamReadable(id)) + } + quinn_proto::Event::Stream(quinn_proto::StreamEvent::Writable { id }) => { + Ok(ConnectionEvent::StreamWritable(id)) + } + quinn_proto::Event::Stream(quinn_proto::StreamEvent::Stopped { id, .. }) => { + Ok(ConnectionEvent::StreamStopped(id)) + } + quinn_proto::Event::Stream(quinn_proto::StreamEvent::Available { + dir: quinn_proto::Dir::Bi, + }) => Ok(ConnectionEvent::StreamAvailable), + quinn_proto::Event::Stream(quinn_proto::StreamEvent::Opened { + dir: quinn_proto::Dir::Bi, + }) => Ok(ConnectionEvent::StreamOpened), + quinn_proto::Event::ConnectionLost { reason } => { + Ok(ConnectionEvent::ConnectionLost(Error::Quinn(reason))) + } + quinn_proto::Event::Stream(quinn_proto::StreamEvent::Finished { id }) => { + Ok(ConnectionEvent::StreamFinished(id)) + } + quinn_proto::Event::Connected => Ok(ConnectionEvent::Connected), + quinn_proto::Event::HandshakeDataReady => Ok(ConnectionEvent::HandshakeDataReady), + ev @ quinn_proto::Event::Stream(quinn_proto::StreamEvent::Opened { + dir: quinn_proto::Dir::Uni, + }) + | ev @ quinn_proto::Event::Stream(quinn_proto::StreamEvent::Available { + dir: quinn_proto::Dir::Uni, + }) + | ev @ quinn_proto::Event::DatagramReceived => Err(ev), + } + } } diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index b3e9568a092..b7ca5f2b511 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -91,7 +91,7 @@ pub struct Endpoint { /// Copy of [`Endpoint::to_endpoint`], except not behind a `Mutex`. Used if we want to be /// guaranteed a slot in the messages buffer. - to_endpoint2: mpsc::Sender, + pub to_endpoint2: mpsc::Sender, socket_addr: SocketAddr, } @@ -172,45 +172,6 @@ impl Endpoint { rx.await.expect("background task has crashed") } - /// Asks the endpoint to send a UDP packet. - /// - /// Note that this method only queues the packet and returns as soon as the packet is in queue. - /// There is no guarantee that the packet will actually be sent, but considering that this is - /// a UDP packet, you cannot rely on the packet being delivered anyway. - pub async fn send_udp_packet(&self, destination: SocketAddr, data: impl Into>) { - let _ = self - .to_endpoint - .lock() - .await - .send(ToEndpoint::SendUdpPacket { - destination, - data: data.into(), - }) - .await; - } - - /// Report to the endpoint an event on a [`quinn_proto::Connection`]. - /// - /// This is typically called by a [`Connection`]. - /// - /// If `event.is_drained()` is true, the event indicates that the connection no longer exists. - /// This must therefore be the last event sent using this [`quinn_proto::ConnectionHandle`]. - pub async fn report_quinn_event( - &self, - connection_id: quinn_proto::ConnectionHandle, - event: quinn_proto::EndpointEvent, - ) { - self.to_endpoint - .lock() - .await - .send(ToEndpoint::ProcessConnectionEvent { - connection_id, - event, - }) - .await - .expect("background task has crashed"); - } - /// Similar to [`Endpoint::report_quinn_event`], except that the message sending is guaranteed /// to be instantaneous and to succeed. /// @@ -235,7 +196,7 @@ impl Endpoint { } /// Message sent to the endpoint background task. #[derive(Debug)] -enum ToEndpoint { +pub enum ToEndpoint { /// Instruct the endpoint to start connecting to the given address. Dial { /// UDP address to connect to. diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index 637bf9a0a41..d2c666bf8a3 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -102,8 +102,11 @@ impl StreamMuxer for QuicMuxer { let mut inner = self.inner.lock(); while let Poll::Ready(event) = inner.connection.poll_event(cx) { match event { - ConnectionEvent::Connected => { - tracing::warn!("Unexpected Connected event on established QUIC connection"); + ConnectionEvent::Connected | ConnectionEvent::HandshakeDataReady => { + tracing::warn!( + "Unexpected event {:?} on established QUIC connection", + event + ); } ConnectionEvent::ConnectionLost(_) => { if let Some(waker) = inner.poll_close_waker.take() { diff --git a/transports/quic/src/upgrade.rs b/transports/quic/src/upgrade.rs index 4114c8c2df2..c1cc50110d5 100644 --- a/transports/quic/src/upgrade.rs +++ b/transports/quic/src/upgrade.rs @@ -26,7 +26,7 @@ use crate::{ transport, }; -use futures::prelude::*; +use futures::{prelude::*, ready}; use libp2p_core::PeerId; use std::{ fmt, @@ -57,29 +57,25 @@ impl Future for Upgrade { .as_mut() .expect("Future polled after it has completed"); - let event = Connection::poll_event(connection, cx); - match event { - Poll::Pending => Poll::Pending, - Poll::Ready(ConnectionEvent::Connected) => { - let peer_id = connection.remote_peer_id(); - let muxer = QuicMuxer::from_connection(self.connection.take().unwrap()); - Poll::Ready(Ok((peer_id, muxer))) - } - Poll::Ready(ConnectionEvent::ConnectionLost(err)) => { - Poll::Ready(Err(transport::Error::Established(err))) - } - // Other items are: - // - StreamAvailable - // - StreamOpened - // - StreamReadable - // - StreamWritable - // - StreamFinished - // - StreamStopped - Poll::Ready(_) => { - // They can happen only after we finished handshake and connected to the peer. - // But for `Upgrade` we get `Connected` event, wrap connection into a muxer - // and pass it to the result Stream of muxers. - unreachable!() + loop { + match ready!(connection.poll_event(cx)) { + ConnectionEvent::Connected => { + let peer_id = connection.remote_peer_id(); + let muxer = QuicMuxer::from_connection(self.connection.take().unwrap()); + return Poll::Ready(Ok((peer_id, muxer))); + } + ConnectionEvent::ConnectionLost(err) => { + return Poll::Ready(Err(transport::Error::Established(err))) + } + // Other items are: + // - HandshakeDataReady + // - StreamAvailable + // - StreamOpened + // - StreamReadable + // - StreamWritable + // - StreamFinished + // - StreamStopped + _ => {} } } } From 67b52aaa836c34e4d9c72f29d00c05f907141663 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 21 Aug 2022 17:15:19 +0200 Subject: [PATCH 47/92] transports/quic: rm `Connection::is_handshaking` --- transports/quic/src/connection.rs | 24 ------------------------ transports/quic/src/muxer.rs | 6 ------ 2 files changed, 30 deletions(-) diff --git a/transports/quic/src/connection.rs b/transports/quic/src/connection.rs index afb2b02ce84..17f3b7a0d72 100644 --- a/transports/quic/src/connection.rs +++ b/transports/quic/src/connection.rs @@ -59,13 +59,6 @@ pub struct Connection { connection_id: quinn_proto::ConnectionHandle, /// `Future` that triggers at the `Instant` that `self.connection.poll_timeout()` indicates. next_timeout: Option, - - /// In other to avoid race conditions where a "connected" event happens if we were not - /// handshaking, we cache whether the connection is handshaking and only set this to true - /// after a "connected" event has been received. - /// - /// In other words, this flag indicates whether a "connected" hasn't been received yet. - is_handshaking: bool, /// Contains a `Some` if the connection is closed, with the reason of the closure. /// Contains `None` if it is still open. /// Contains `Some` if and only if a `ConnectionLost` event has been emitted. @@ -108,8 +101,6 @@ impl Connection { from_endpoint: mpsc::Receiver, ) -> Self { assert!(!connection.is_closed()); - let is_handshaking = connection.is_handshaking(); - Connection { to_endpoint: endpoint.to_endpoint2.clone(), endpoint, @@ -118,7 +109,6 @@ impl Connection { next_timeout: None, from_endpoint, connection_id, - is_handshaking, closed: None, } } @@ -146,16 +136,9 @@ impl Connection { self.connection.remote_address() } - /// Returns `true` if this connection is still pending. Returns `false` if we are connected to - /// the remote or if the connection is closed. - pub fn is_handshaking(&self) -> bool { - self.is_handshaking - } - /// Returns the address of the node we're connected to. /// Panics if the connection is still handshaking. pub fn remote_peer_id(&self) -> PeerId { - debug_assert!(!self.is_handshaking()); let session = self.connection.crypto_session(); let identity = session .peer_identity() @@ -303,16 +286,9 @@ impl Connection { match self.connection.poll() { Some(ev) => match ConnectionEvent::try_from(ev) { Ok(ConnectionEvent::ConnectionLost(err)) => { - self.is_handshaking = false; self.closed = Some(err.clone()); return Poll::Ready(ConnectionEvent::ConnectionLost(err)); } - Ok(ConnectionEvent::Connected) => { - debug_assert!(self.is_handshaking); - debug_assert!(!self.connection.is_handshaking()); - self.is_handshaking = false; - return Poll::Ready(ConnectionEvent::Connected); - } Ok(event) => return Poll::Ready(event), Err(_proto_ev) => { // unreachable: We don't use datagrams or unidirectional streams. diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index d2c666bf8a3..b5e34524ba5 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -73,13 +73,7 @@ struct SubstreamState { impl QuicMuxer { /// Crate-internal function that builds a [`QuicMuxer`] from a raw connection. - /// - /// # Panic - /// - /// Panics if `connection.is_handshaking()` returns `true`. pub(crate) fn from_connection(connection: Connection) -> Self { - assert!(!connection.is_handshaking()); - QuicMuxer { inner: Arc::new(Mutex::new(Inner { connection, From 66974fc414aaffb372845d0b59a0eaa8551df187 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 22 Aug 2022 04:52:27 +0200 Subject: [PATCH 48/92] transports/quic: refactor connection closing --- transports/quic/src/connection.rs | 52 +++------ transports/quic/src/endpoint.rs | 23 +--- transports/quic/src/muxer.rs | 183 +++++++++++------------------- transports/quic/tests/smoke.rs | 17 ++- 4 files changed, 96 insertions(+), 179 deletions(-) diff --git a/transports/quic/src/connection.rs b/transports/quic/src/connection.rs index 17f3b7a0d72..a00b9e093d4 100644 --- a/transports/quic/src/connection.rs +++ b/transports/quic/src/connection.rs @@ -59,10 +59,6 @@ pub struct Connection { connection_id: quinn_proto::ConnectionHandle, /// `Future` that triggers at the `Instant` that `self.connection.poll_timeout()` indicates. next_timeout: Option, - /// Contains a `Some` if the connection is closed, with the reason of the closure. - /// Contains `None` if it is still open. - /// Contains `Some` if and only if a `ConnectionLost` event has been emitted. - closed: Option, to_endpoint: mpsc::Sender, } @@ -109,7 +105,6 @@ impl Connection { next_timeout: None, from_endpoint, connection_id, - closed: None, } } @@ -137,7 +132,6 @@ impl Connection { } /// Returns the address of the node we're connected to. - /// Panics if the connection is still handshaking. pub fn remote_peer_id(&self) -> PeerId { let session = self.connection.crypto_session(); let identity = session @@ -157,15 +151,10 @@ impl Connection { /// Start closing the connection. A [`ConnectionEvent::ConnectionLost`] event will be /// produced in the future. pub fn close(&mut self) { - // TODO: what if the user calls this multiple times? // We send a dummy `0` error code with no message, as the API of StreamMuxer doesn't // support this. self.connection .close(Instant::now(), From::from(0u32), Default::default()); - self.endpoint.report_quinn_event_non_block( - self.connection_id, - quinn_proto::EndpointEvent::drained(), - ); } /// Pops a new substream opened by the remote. @@ -206,12 +195,7 @@ impl Connection { /// Polls the connection for an event that happend on it. pub fn poll_event(&mut self, cx: &mut Context<'_>) -> Poll { - // Nothing more can be done if the connection is closed. - // Return `Pending` without registering the waker, essentially freezing the task forever. - if self.closed.is_some() { - return Poll::Pending; - } - + let mut closed = None; loop { match self.from_endpoint.poll_next_unpin(cx) { Poll::Ready(Some(event)) => { @@ -219,10 +203,9 @@ impl Connection { continue; } Poll::Ready(None) => { - debug_assert!(self.closed.is_none()); - let err = Error::ClosedChannel; - self.closed = Some(err.clone()); - return Poll::Ready(ConnectionEvent::ConnectionLost(err)); + if closed.is_none() { + return Poll::Ready(ConnectionEvent::ConnectionLost(Error::ClosedChannel)); + } } Poll::Pending => {} } @@ -241,6 +224,7 @@ impl Connection { self.to_endpoint .start_send(self.pending_to_endpoint.take().expect("is_some")) .expect("To be ready"); + continue; } Poll::Ready(Err(_)) => todo!(), Poll::Pending => return Poll::Pending, @@ -282,18 +266,21 @@ impl Connection { continue; } + if let Some(closed) = closed { + return Poll::Ready(ConnectionEvent::ConnectionLost(closed)); + } + // The final step consists in handling the events related to the various substreams. match self.connection.poll() { Some(ev) => match ConnectionEvent::try_from(ev) { - Ok(ConnectionEvent::ConnectionLost(err)) => { - self.closed = Some(err.clone()); - return Poll::Ready(ConnectionEvent::ConnectionLost(err)); - } - Ok(event) => return Poll::Ready(event), - Err(_proto_ev) => { - // unreachable: We don't use datagrams or unidirectional streams. + Ok(ConnectionEvent::ConnectionLost(reason)) => { + // Continue in the loop once more so that we can send a + // `EndpointEvent::drained` to the endpoint before returning. + closed = Some(reason); continue; } + Ok(event) => return Poll::Ready(event), + Err(_) => unreachable!("We don't use datagrams or unidirectional streams."), }, None => {} } @@ -308,15 +295,6 @@ impl fmt::Debug for Connection { } } -impl Drop for Connection { - fn drop(&mut self) { - let is_drained = self.connection.is_drained(); - if !is_drained { - self.close(); - } - } -} - /// Event generated by the [`Connection`]. #[derive(Debug)] pub enum ConnectionEvent { diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index b7ca5f2b511..83555bb9cd0 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -171,29 +171,8 @@ impl Endpoint { .expect("background task has crashed"); rx.await.expect("background task has crashed") } - - /// Similar to [`Endpoint::report_quinn_event`], except that the message sending is guaranteed - /// to be instantaneous and to succeed. - /// - /// This method bypasses back-pressure mechanisms and is meant to be called only from - /// destructors, where waiting is not advisable. - pub fn report_quinn_event_non_block( - &self, - connection_id: quinn_proto::ConnectionHandle, - event: quinn_proto::EndpointEvent, - ) { - // We implement this by cloning the `mpsc::Sender`. Since each sender is guaranteed a slot - // in the buffer, cloning the sender reserves the slot and sending thus always succeeds. - let result = self - .to_endpoint2 - .clone() - .try_send(ToEndpoint::ProcessConnectionEvent { - connection_id, - event, - }); - assert!(result.is_ok()); - } } + /// Message sent to the endpoint background task. #[derive(Debug)] pub enum ToEndpoint { diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index b5e34524ba5..f3daaf0c657 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -26,9 +26,9 @@ use libp2p_core::muxing::{StreamMuxer, StreamMuxerEvent}; use parking_lot::Mutex; use std::{ collections::HashMap, - io, + io::{self, Write}, pin::Pin, - sync::{Arc, Weak}, + sync::Arc, task::{Context, Poll, Waker}, }; @@ -52,8 +52,8 @@ struct Inner { poll_outbound_waker: Option, /// Waker to wake if a new inbound substream was happened. poll_inbound_waker: Option, - /// Waker to wake if the connection is closed. - poll_close_waker: Option, + /// Waker to wake if the connection should be polled again. + poll_connection_waker: Option, } /// State of a single substream. @@ -63,10 +63,6 @@ struct SubstreamState { read_waker: Option, /// Waker to wake if the substream becomes writable or stopped. write_waker: Option, - /// True if the substream has been finished. - finished: bool, - /// True if the substream has been stopped. - stopped: bool, /// Waker to wake if the substream becomes closed or stopped. finished_waker: Option, } @@ -79,8 +75,8 @@ impl QuicMuxer { connection, substreams: Default::default(), poll_outbound_waker: None, - poll_close_waker: None, poll_inbound_waker: None, + poll_connection_waker: None, })), } } @@ -102,13 +98,9 @@ impl StreamMuxer for QuicMuxer { event ); } - ConnectionEvent::ConnectionLost(_) => { - if let Some(waker) = inner.poll_close_waker.take() { - waker.wake(); - } - inner.connection.close(); + ConnectionEvent::ConnectionLost(err) => { + return Poll::Ready(Err(Error::ConnectionLost(err))) } - ConnectionEvent::StreamOpened => { if let Some(waker) = inner.poll_outbound_waker.take() { waker.wake(); @@ -128,19 +120,17 @@ impl StreamMuxer for QuicMuxer { } } } - ConnectionEvent::StreamFinished(substream) => { + ConnectionEvent::StreamFinished(substream) + | ConnectionEvent::StreamStopped(substream) => { if let Some(substream) = inner.substreams.get_mut(&substream) { - substream.finished = true; + if let Some(waker) = substream.write_waker.take() { + waker.wake(); + } if let Some(waker) = substream.finished_waker.take() { waker.wake(); } } } - ConnectionEvent::StreamStopped(substream) => { - if let Some(substream) = inner.substreams.get_mut(&substream) { - substream.stopped = true; - } - } ConnectionEvent::StreamAvailable => { if let Some(waker) = inner.poll_inbound_waker.take() { waker.wake(); @@ -148,6 +138,7 @@ impl StreamMuxer for QuicMuxer { } } } + inner.poll_connection_waker = Some(cx.waker().clone()); // TODO: poll address change Poll::Pending } @@ -158,7 +149,10 @@ impl StreamMuxer for QuicMuxer { ) -> Poll> { let mut inner = self.inner.lock(); let substream_id = match inner.connection.pop_incoming_substream() { - Some(id) => id, + Some(id) => { + inner.poll_outbound_waker = None; + id + } None => { inner.poll_inbound_waker = Some(cx.waker().clone()); return Poll::Pending; @@ -175,7 +169,10 @@ impl StreamMuxer for QuicMuxer { ) -> Poll> { let mut inner = self.inner.lock(); let substream_id = match inner.connection.pop_outgoing_substream() { - Some(id) => id, + Some(id) => { + inner.poll_outbound_waker = None; + id + } None => { inner.poll_outbound_waker = Some(cx.waker().clone()); return Poll::Pending; @@ -192,55 +189,37 @@ impl StreamMuxer for QuicMuxer { return Poll::Ready(Ok(())); } - if inner.substreams.is_empty() { - let connection = &mut inner.connection; - if !connection.connection.is_closed() { - connection.close(); - if let Some(waker) = inner.poll_inbound_waker.take() { - waker.wake(); - } - } else { - } - while let Poll::Ready(event) = inner.connection.poll_event(cx) { - if let ConnectionEvent::ConnectionLost(_) = event { - return Poll::Ready(Ok(())); - } - } - } else { + if inner.connection.connection.streams().send_streams() != 0 { for substream in inner.substreams.keys().cloned().collect::>() { if let Err(e) = inner.connection.shutdown_substream(substream) { tracing::warn!("substream finish error on muxer close: {}", e); } } } - - // Register `cx.waker()` as being woken up if the connection closes. - inner.poll_close_waker = Some(cx.waker().clone()); - + loop { + if inner.connection.connection.streams().send_streams() == 0 + && !inner.connection.connection.is_closed() + { + inner.connection.close() + } + match inner.connection.poll_event(cx) { + Poll::Ready(ConnectionEvent::ConnectionLost(_)) => return Poll::Ready(Ok(())), + Poll::Ready(_) => {} + Poll::Pending => break, + } + } Poll::Pending } } pub struct Substream { id: quinn_proto::StreamId, - muxer: Weak>, + muxer: Arc>, } impl Substream { fn new(id: quinn_proto::StreamId, muxer: Arc>) -> Self { - Self { - id, - muxer: Arc::downgrade(&muxer), - } - } -} - -impl Drop for Substream { - fn drop(&mut self) { - if let Some(muxer) = self.muxer.upgrade() { - let mut muxer = muxer.lock(); - muxer.substreams.remove(&self.id); - } + Self { id, muxer } } } @@ -249,34 +228,20 @@ impl AsyncRead for Substream { self: Pin<&mut Self>, cx: &mut Context<'_>, mut buf: &mut [u8], - ) -> Poll> { + ) -> Poll> { use quinn_proto::{ReadError, ReadableError}; - use std::io::Write; - - let muxer = self - .muxer - .upgrade() - .expect("StreamMuxer::read_substream: muxer is dead"); - let mut muxer = muxer.lock(); - - let substream_state = muxer - .substreams - .get(&self.id) - .expect("invalid Substream::poll_read API usage"); - if substream_state.stopped { - return Poll::Ready(Ok(0)); - } + let mut muxer = self.muxer.lock(); let mut stream = muxer.connection.connection.recv_stream(self.id); let mut chunks = match stream.read(true) { Ok(chunks) => chunks, Err(ReadableError::UnknownStream) => { - return Poll::Ready(Ok(0)); // FIXME This is a hack, - // a rust client should close substream correctly - // return Poll::Ready(Err(Self::Error::ExpiredStream)) + return Poll::Ready(Ok(0)); } Err(ReadableError::IllegalOrderedRead) => { - panic!("Illegal ordered read can only happen if `stream.read(false)` is used."); + unreachable!( + "Illegal ordered read can only happen if `stream.read(false)` is used." + ); } }; let mut bytes = 0; @@ -290,9 +255,7 @@ impl AsyncRead for Substream { buf.write_all(&chunk.bytes).expect("enough buffer space"); bytes += chunk.bytes.len(); } - Ok(None) => { - break; - } + Ok(None) => break, Err(ReadError::Reset(error_code)) => { tracing::error!( "substream {} was reset with error code {}", @@ -309,12 +272,12 @@ impl AsyncRead for Substream { } } if chunks.finalize().should_transmit() { - if let Some(waker) = muxer.poll_inbound_waker.take() { + if let Some(waker) = muxer.poll_connection_waker.take() { waker.wake(); } } if pending && bytes == 0 { - let mut substream_state = muxer + let substream_state = muxer .substreams .get_mut(&self.id) .expect("known substream; qed"); @@ -332,33 +295,23 @@ impl AsyncWrite for Substream { cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - use quinn_proto::WriteError; - - let muxer = self - .muxer - .upgrade() - .expect("Substream::poll_write: muxer is dead"); - let mut muxer = muxer.lock(); + let mut muxer = self.muxer.lock(); match muxer.connection.connection.send_stream(self.id).write(buf) { Ok(bytes) => Poll::Ready(Ok(bytes)), - Err(WriteError::Blocked) => { - let mut substream = muxer + Err(quinn_proto::WriteError::Blocked) => { + let substream = muxer .substreams .get_mut(&self.id) .expect("known substream; qed"); substream.write_waker = Some(cx.waker().clone()); Poll::Pending } - Err(err @ WriteError::Stopped(_)) => { + Err(err @ quinn_proto::WriteError::Stopped(_)) => { Poll::Ready(Err(io::Error::new(io::ErrorKind::ConnectionReset, err))) } - Err(WriteError::UnknownStream) => { - tracing::error!( - "The application used a connection that is already being \ - closed. This is a bug in the application or in libp2p." - ); - Poll::Pending + Err(quinn_proto::WriteError::UnknownStream) => { + Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())) } } } @@ -369,35 +322,27 @@ impl AsyncWrite for Substream { } fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let muxer = self - .muxer - .upgrade() - .expect("Substream::poll_close: muxer is dead"); - let mut muxer = muxer.lock(); - let muxer = &mut *muxer; - - let mut substream_state = muxer - .substreams - .get_mut(&self.id) - .expect("invalid Substream::poll_close API usage"); - if substream_state.finished { - return Poll::Ready(Ok(())); - } - + let mut muxer = self.muxer.lock(); match muxer.connection.shutdown_substream(self.id) { Ok(()) => { + let substream_state = muxer + .substreams + .get_mut(&self.id) + .expect("Substream is not finished."); substream_state.finished_waker = Some(cx.waker().clone()); Poll::Pending } Err(err @ quinn_proto::FinishError::Stopped(_)) => { Poll::Ready(Err(io::Error::new(io::ErrorKind::ConnectionReset, err))) } - Err(quinn_proto::FinishError::UnknownStream) => { - // Illegal usage of the API. - debug_assert!(false); - Poll::Ready(Ok(())) - // Poll::Ready(Err(Error::ExpiredStream)) FIXME - } + Err(quinn_proto::FinishError::UnknownStream) => Poll::Ready(Ok(())), } } } + +impl Drop for Substream { + fn drop(&mut self) { + let mut muxer = self.muxer.lock(); + muxer.substreams.remove(&self.id); + } +} diff --git a/transports/quic/tests/smoke.rs b/transports/quic/tests/smoke.rs index bb4f1270950..bd8d0682dd9 100644 --- a/transports/quic/tests/smoke.rs +++ b/transports/quic/tests/smoke.rs @@ -13,7 +13,7 @@ use libp2p::request_response::{ RequestResponseEvent, RequestResponseMessage, }; use libp2p::swarm::dial_opts::{DialOpts, PeerCondition}; -use libp2p::swarm::{DialError, Swarm, SwarmEvent}; +use libp2p::swarm::{ConnectionError, DialError, Swarm, SwarmEvent}; use libp2p_quic::{Config as QuicConfig, QuicTransport}; use rand::RngCore; use std::num::NonZeroU8; @@ -179,6 +179,21 @@ async fn smoke() -> Result<()> { e => panic!("{:?}", e), } + a.disconnect_peer_id(*b.local_peer_id()).unwrap(); + + match a.next().await { + Some(SwarmEvent::ConnectionClosed { cause: None, .. }) => {} + e => panic!("{:?}", e), + } + + match b.next().await { + Some(SwarmEvent::ConnectionClosed { + cause: Some(ConnectionError::IO(_)), + .. + }) => {} + e => panic!("{:?}", e), + } + Ok(()) } From 4253080a43f593be9d184e5ec106c2b8ed032904 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 22 Aug 2022 05:14:04 +0200 Subject: [PATCH 49/92] *: Prepare v0.47.0 (#2830) --- CHANGELOG.md | 2 +- core/CHANGELOG.md | 2 +- misc/metrics/CHANGELOG.md | 2 +- misc/prost-codec/CHANGELOG.md | 2 +- muxers/mplex/CHANGELOG.md | 2 +- muxers/yamux/CHANGELOG.md | 2 +- protocols/autonat/CHANGELOG.md | 2 +- protocols/dcutr/CHANGELOG.md | 2 +- protocols/floodsub/CHANGELOG.md | 2 +- protocols/gossipsub/CHANGELOG.md | 2 +- protocols/identify/CHANGELOG.md | 2 +- protocols/kad/CHANGELOG.md | 2 +- protocols/mdns/CHANGELOG.md | 2 +- protocols/ping/CHANGELOG.md | 2 +- protocols/relay/CHANGELOG.md | 2 +- protocols/rendezvous/CHANGELOG.md | 2 +- protocols/request-response/CHANGELOG.md | 2 +- swarm-derive/CHANGELOG.md | 2 +- swarm/CHANGELOG.md | 2 +- transports/deflate/CHANGELOG.md | 2 +- transports/dns/CHANGELOG.md | 2 +- transports/noise/CHANGELOG.md | 2 +- transports/plaintext/CHANGELOG.md | 2 +- transports/tcp/CHANGELOG.md | 2 +- transports/uds/CHANGELOG.md | 2 +- transports/wasm-ext/CHANGELOG.md | 2 +- transports/websocket/CHANGELOG.md | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca42a4e26eb..edbbc8fb1d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,7 +43,7 @@ # `libp2p` facade crate -# 0.47.0 [unreleased] +# 0.47.0 - Update to [`libp2p-dcutr` `v0.5.0`](protocols/dcutr/CHANGELOG.md#050). diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index c377d042106..4c18fa5dc78 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.35.0 [unreleased] +# 0.35.0 - Drop `Unpin` requirement from `SubstreamBox`. See [PR 2762] and [PR 2776]. - Drop `Sync` requirement on `StreamMuxer` for constructing `StreamMuxerBox`. See [PR 2775]. diff --git a/misc/metrics/CHANGELOG.md b/misc/metrics/CHANGELOG.md index 014a4a84ffe..8618e0b7130 100644 --- a/misc/metrics/CHANGELOG.md +++ b/misc/metrics/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.8.0 [unreleased] +# 0.8.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/misc/prost-codec/CHANGELOG.md b/misc/prost-codec/CHANGELOG.md index af426fb1955..d9380ea34ca 100644 --- a/misc/prost-codec/CHANGELOG.md +++ b/misc/prost-codec/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.2.0 [unreleased] +# 0.2.0 - Update to prost(-build) `v0.11`. See [PR 2788]. diff --git a/muxers/mplex/CHANGELOG.md b/muxers/mplex/CHANGELOG.md index 6b374e1b66c..45f2c217ce0 100644 --- a/muxers/mplex/CHANGELOG.md +++ b/muxers/mplex/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.35.0 [unreleased] +# 0.35.0 - Update to `libp2p-core` `v0.35.0` diff --git a/muxers/yamux/CHANGELOG.md b/muxers/yamux/CHANGELOG.md index e8eded11836..5544ad15ab4 100644 --- a/muxers/yamux/CHANGELOG.md +++ b/muxers/yamux/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.39.0 [unreleased] +# 0.39.0 - Update to `libp2p-core` `v0.35.0` diff --git a/protocols/autonat/CHANGELOG.md b/protocols/autonat/CHANGELOG.md index 0c48b41951b..5856a6a3c82 100644 --- a/protocols/autonat/CHANGELOG.md +++ b/protocols/autonat/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.6.0 [unreleased] +# 0.6.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/dcutr/CHANGELOG.md b/protocols/dcutr/CHANGELOG.md index f740b188455..7a5794fda88 100644 --- a/protocols/dcutr/CHANGELOG.md +++ b/protocols/dcutr/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.5.0 [unreleased] +# 0.5.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/floodsub/CHANGELOG.md b/protocols/floodsub/CHANGELOG.md index 89d4dd22b16..2e02a7ded1f 100644 --- a/protocols/floodsub/CHANGELOG.md +++ b/protocols/floodsub/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.38.0 [unreleased] +# 0.38.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index c7bb155b3c9..2c55be28e85 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.40.0 [unreleased] +# 0.40.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/identify/CHANGELOG.md b/protocols/identify/CHANGELOG.md index 38acfad9b64..8821bca3507 100644 --- a/protocols/identify/CHANGELOG.md +++ b/protocols/identify/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.38.0 [unreleased] +# 0.38.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 6b78a6fcbce..09f2035ef2b 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.39.0 [unreleased] +# 0.39.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/mdns/CHANGELOG.md b/protocols/mdns/CHANGELOG.md index e3b37be4c60..c6541f7eccc 100644 --- a/protocols/mdns/CHANGELOG.md +++ b/protocols/mdns/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.39.0 [unreleased] +# 0.39.0 - Update to `libp2p-swarm` `v0.38.0`. - Update to `if-watch` `v1.1.1`. diff --git a/protocols/ping/CHANGELOG.md b/protocols/ping/CHANGELOG.md index e14934fe7a2..d163839733a 100644 --- a/protocols/ping/CHANGELOG.md +++ b/protocols/ping/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.38.0 [unreleased] +# 0.38.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/relay/CHANGELOG.md b/protocols/relay/CHANGELOG.md index 85e066668bc..537abff7edc 100644 --- a/protocols/relay/CHANGELOG.md +++ b/protocols/relay/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.11.0 [unreleased] +# 0.11.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/rendezvous/CHANGELOG.md b/protocols/rendezvous/CHANGELOG.md index c087f77b393..728a1538c9e 100644 --- a/protocols/rendezvous/CHANGELOG.md +++ b/protocols/rendezvous/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.8.0 [unreleased] +# 0.8.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/request-response/CHANGELOG.md b/protocols/request-response/CHANGELOG.md index bf556496fc1..0008f1a1d01 100644 --- a/protocols/request-response/CHANGELOG.md +++ b/protocols/request-response/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.20.0 [unreleased] +# 0.20.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/swarm-derive/CHANGELOG.md b/swarm-derive/CHANGELOG.md index b8b1e4530e0..f9056f6093a 100644 --- a/swarm-derive/CHANGELOG.md +++ b/swarm-derive/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.29.0 - [unreleased] +# 0.29.0 - Generate `NetworkBehaviour::OutEvent` if not provided through `#[behaviour(out_event = "MyOutEvent")]` and event processing is disabled (default). diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index a235c0ae2bc..61175ae0762 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.38.0 [unreleased] +# 0.38.0 - Deprecate `NetworkBehaviourEventProcess`. When deriving `NetworkBehaviour` on a custom `struct` users should either bring their own `OutEvent` via `#[behaviour(out_event = "MyBehaviourEvent")]` or, diff --git a/transports/deflate/CHANGELOG.md b/transports/deflate/CHANGELOG.md index 317a9ab78d3..a2e4112caa2 100644 --- a/transports/deflate/CHANGELOG.md +++ b/transports/deflate/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.35.0 [unreleased] +# 0.35.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/dns/CHANGELOG.md b/transports/dns/CHANGELOG.md index c9b9083cb3a..6c8a49af7b4 100644 --- a/transports/dns/CHANGELOG.md +++ b/transports/dns/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.35.0 [unreleased] +# 0.35.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/noise/CHANGELOG.md b/transports/noise/CHANGELOG.md index 6b323eabd27..7a1db66d1b1 100644 --- a/transports/noise/CHANGELOG.md +++ b/transports/noise/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.38.0 [unreleased] +# 0.38.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/plaintext/CHANGELOG.md b/transports/plaintext/CHANGELOG.md index 7c5c389a0cd..b70d3c5787f 100644 --- a/transports/plaintext/CHANGELOG.md +++ b/transports/plaintext/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.35.0 [unreleased] +# 0.35.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/tcp/CHANGELOG.md b/transports/tcp/CHANGELOG.md index bf7a5e0daba..8e876fd90a9 100644 --- a/transports/tcp/CHANGELOG.md +++ b/transports/tcp/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.35.0 [unreleased] +# 0.35.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/uds/CHANGELOG.md b/transports/uds/CHANGELOG.md index c27c12b8c3e..b2f4751b63f 100644 --- a/transports/uds/CHANGELOG.md +++ b/transports/uds/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.34.0 [unreleased] +# 0.34.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/wasm-ext/CHANGELOG.md b/transports/wasm-ext/CHANGELOG.md index c3438b68b20..323ee80cbe0 100644 --- a/transports/wasm-ext/CHANGELOG.md +++ b/transports/wasm-ext/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.35.0 [unreleased] +# 0.35.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/websocket/CHANGELOG.md b/transports/websocket/CHANGELOG.md index 1a46978cd3b..65f9eea1e96 100644 --- a/transports/websocket/CHANGELOG.md +++ b/transports/websocket/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.37.0 [unreleased] +# 0.37.0 - Update to `libp2p-core` `v0.35.0`. From c88efe84c75d7f52964d22ed82ebe4dff2418f16 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 22 Aug 2022 06:32:07 +0200 Subject: [PATCH 50/92] transports/quic: rm mutex around to_endpoint tx When sending a message to the background task, don't use the `SinkExt::send` future since this requires static ownership of the channel sender. Instead use `Sink::poll_ready` and `Sink::start_send`, which allows us to inline the sending of messages into our poll functions. With this we don't need the Mutex around `to_endpoint` anymore. The background task, the transport, and each connections owns exactly one `Sender`, thus we don't have unbounded growth here. --- transports/quic/src/connection.rs | 25 ++-- transports/quic/src/endpoint.rs | 78 ++++--------- transports/quic/src/transport.rs | 182 ++++++++++++++++++++++-------- 3 files changed, 163 insertions(+), 122 deletions(-) diff --git a/transports/quic/src/connection.rs b/transports/quic/src/connection.rs index a00b9e093d4..b0290fe4ac5 100644 --- a/transports/quic/src/connection.rs +++ b/transports/quic/src/connection.rs @@ -34,7 +34,6 @@ use libp2p_core::PeerId; use std::{ fmt, net::SocketAddr, - sync::Arc, task::{Context, Poll}, time::Instant, }; @@ -45,7 +44,7 @@ use std::{ /// Tied to a specific [`Endpoint`]. pub struct Connection { /// Endpoint this connection belongs to. - endpoint: Arc, + endpoint: Endpoint, /// Future whose job is to send a message to the endpoint. Only one at a time. pending_to_endpoint: Option, /// Events that the endpoint will send in destination to our local [`quinn_proto::Connection`]. @@ -59,8 +58,6 @@ pub struct Connection { connection_id: quinn_proto::ConnectionHandle, /// `Future` that triggers at the `Instant` that `self.connection.poll_timeout()` indicates. next_timeout: Option, - - to_endpoint: mpsc::Sender, } /// Error on the connection as a whole. @@ -91,14 +88,13 @@ impl Connection { /// its methods has ever been called. Failure to comply might lead to logic errors and panics. // TODO: maybe abstract `to_endpoint` more and make it generic? dunno pub fn from_quinn_connection( - endpoint: Arc, + endpoint: Endpoint, connection: quinn_proto::Connection, connection_id: quinn_proto::ConnectionHandle, from_endpoint: mpsc::Receiver, ) -> Self { assert!(!connection.is_closed()); Connection { - to_endpoint: endpoint.to_endpoint2.clone(), endpoint, pending_to_endpoint: None, connection, @@ -113,7 +109,7 @@ impl Connection { /// Works for server connections only. pub fn local_addr(&self) -> SocketAddr { debug_assert_eq!(self.connection.side(), quinn_proto::Side::Server); - let endpoint_addr = self.endpoint.socket_addr(); + let endpoint_addr = self.endpoint.socket_addr; self.connection .local_ip() .map(|ip| SocketAddr::new(ip, endpoint_addr.port())) @@ -121,7 +117,7 @@ impl Connection { // In a normal case scenario this should not happen, because // we get want to get a local addr for a server connection only. tracing::error!("trying to get quinn::local_ip for a client"); - *endpoint_addr + endpoint_addr }) } @@ -219,14 +215,15 @@ impl Connection { // `to_endpoint` is full. This should propagate the back-pressure of `to_endpoint` // being full to the user. if self.pending_to_endpoint.is_some() { - match self.to_endpoint.poll_ready_unpin(cx) { + match self.endpoint.to_endpoint.poll_ready_unpin(cx) { Poll::Ready(Ok(())) => { - self.to_endpoint - .start_send(self.pending_to_endpoint.take().expect("is_some")) - .expect("To be ready"); - continue; + let to_endpoint = self.pending_to_endpoint.take().expect("is some"); + self.endpoint + .to_endpoint + .start_send(to_endpoint) + .expect("Channel is ready."); } - Poll::Ready(Err(_)) => todo!(), + Poll::Ready(Err(_)) => panic!("Background task crashed"), Poll::Pending => return Poll::Pending, } } diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index 83555bb9cd0..a65da3bae60 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -32,7 +32,6 @@ use crate::{connection::Connection, tls, transport}; use futures::{ channel::{mpsc, oneshot}, - lock::Mutex, prelude::*, }; use quinn_proto::{ClientConfig as QuinnClientConfig, ServerConfig as QuinnServerConfig}; @@ -40,7 +39,7 @@ use std::{ collections::{HashMap, VecDeque}, fmt, net::{Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket}, - sync::{Arc, Weak}, + sync::Arc, task::{Poll, Waker}, time::{Duration, Instant}, }; @@ -85,15 +84,12 @@ impl Config { // TODO: expand docs // TODO: Debug trait // TODO: remove useless fields +#[derive(Clone)] pub struct Endpoint { /// Channel to the background of the endpoint. - to_endpoint: Mutex>, + pub to_endpoint: mpsc::Sender, - /// Copy of [`Endpoint::to_endpoint`], except not behind a `Mutex`. Used if we want to be - /// guaranteed a slot in the messages buffer. - pub to_endpoint2: mpsc::Sender, - - socket_addr: SocketAddr, + pub socket_addr: SocketAddr, } impl Endpoint { @@ -101,14 +97,14 @@ impl Endpoint { pub fn new_bidirectional( config: Config, socket_addr: SocketAddr, - ) -> Result<(Arc, mpsc::Receiver), transport::Error> { + ) -> Result<(Endpoint, mpsc::Receiver), transport::Error> { let (new_connections_tx, new_connections_rx) = mpsc::channel(1); let endpoint = Self::new(config, socket_addr, Some(new_connections_tx))?; Ok((endpoint, new_connections_rx)) } /// Builds a new [`Endpoint`] that only supports outbound connections. - pub fn new_dialer(config: Config, is_ipv6: bool) -> Result, transport::Error> { + pub fn new_dialer(config: Config, is_ipv6: bool) -> Result { let socket_addr = if is_ipv6 { SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0) } else { @@ -121,17 +117,15 @@ impl Endpoint { config: Config, socket_addr: SocketAddr, new_connections: Option>, - ) -> Result, transport::Error> { + ) -> Result { // NOT blocking, as per man:bind(2), as we pass an IP address. let socket = std::net::UdpSocket::bind(&socket_addr)?; let (to_endpoint_tx, to_endpoint_rx) = mpsc::channel(32); - let to_endpoint2 = to_endpoint_tx.clone(); - let endpoint = Arc::new(Endpoint { - to_endpoint: Mutex::new(to_endpoint_tx), - to_endpoint2, + let endpoint = Endpoint { + to_endpoint: to_endpoint_tx, socket_addr: socket.local_addr()?, - }); + }; let server_config = new_connections.map(|c| (c, config.server_config.clone())); @@ -140,7 +134,7 @@ impl Endpoint { config.endpoint_config, config.client_config, server_config, - Arc::downgrade(&endpoint), + endpoint.clone(), async_io::Async::::new(socket)?, to_endpoint_rx.fuse(), )) @@ -148,29 +142,6 @@ impl Endpoint { Ok(endpoint) } - - pub fn socket_addr(&self) -> &SocketAddr { - &self.socket_addr - } - - /// Asks the endpoint to start dialing the given address. - /// - /// Note that this method only *starts* the dialing. `Ok` is returned as soon as possible, even - /// when the remote might end up being unreachable. - pub async fn dial(&self, addr: SocketAddr) -> Result { - // The two `expect`s below can panic if the background task has stopped. The background - // task can stop only if the `Endpoint` is destroyed or if the task itself panics. In other - // words, we panic here iff a panic has already happened somewhere else, which is a - // reasonable thing to do. - let (tx, rx) = oneshot::channel(); - self.to_endpoint - .lock() - .await - .send(ToEndpoint::Dial { addr, result: tx }) - .await - .expect("background task has crashed"); - rx.await.expect("background task has crashed") - } } /// Message sent to the endpoint background task. @@ -274,7 +245,7 @@ pub enum ToEndpoint { /// The background task shuts down if `endpoint_weak`, `receiver` or `new_connections` become /// disconnected/invalid. This corresponds to the lifetime of the associated [`Endpoint`]. /// -/// Keep in mind that we pass an `Arc` whenever we create a new connection, which +/// Keep in mind that we pass an `Endpoint` whenever we create a new connection, which /// guarantees that the [`Endpoint`], and therefore the background task, is properly kept alive /// for as long as any QUIC connection is open. /// @@ -282,7 +253,7 @@ async fn background_task( endpoint_config: Arc, client_config: quinn_proto::ClientConfig, server_config: Option<(mpsc::Sender, Arc)>, - endpoint_weak: Weak, + endpoint: Endpoint, udp_socket: async_io::Async, mut receiver: stream::Fuse>, ) { @@ -292,7 +263,7 @@ async fn background_task( }; // The actual QUIC state machine. - let mut endpoint = quinn_proto::Endpoint::new(endpoint_config.clone(), server_config); + let mut proto_endpoint = quinn_proto::Endpoint::new(endpoint_config.clone(), server_config); // List of all active connections, with a sender to notify them of events. let mut alive_connections = HashMap::>::new(); @@ -339,7 +310,7 @@ async fn background_task( // The endpoint might request packets to be sent out. This is handled in priority to avoid // buffering up packets. - if let Some(packet) = endpoint.poll_transmit() { + if let Some(packet) = proto_endpoint.poll_transmit() { debug_assert!(next_packet_out.is_none()); next_packet_out = Some((packet.destination, packet.contents)); continue; @@ -358,7 +329,7 @@ async fn background_task( // name. While we don't use domain names, the underlying rustls library // is based upon the assumption that we do. let (connection_id, connection) = - match endpoint.connect(client_config.clone(), addr, "l") { + match proto_endpoint.connect(client_config.clone(), addr, "l") { Ok(c) => c, Err(err) => { let _ = result.send(Err(err)); @@ -366,14 +337,9 @@ async fn background_task( } }; - let endpoint_arc = match endpoint_weak.upgrade() { - Some(ep) => ep, - None => return, // Shut down the task if the endpoint is dead. - }; - debug_assert_eq!(connection.side(), quinn_proto::Side::Client); let (tx, rx) = mpsc::channel(16); - let connection = Connection::from_quinn_connection(endpoint_arc, connection, connection_id, rx); + let connection = Connection::from_quinn_connection(endpoint.clone(), connection, connection_id, rx); alive_connections.insert(connection_id, tx); let _ = result.send(Ok(connection)); } @@ -391,7 +357,7 @@ async fn background_task( alive_connections.remove(&connection_id); } - let event_back = endpoint.handle_event(connection_id, event); + let event_back = proto_endpoint.handle_event(connection_id, event); if let Some(event_back) = event_back { debug_assert!(!is_drained_event); @@ -467,7 +433,7 @@ async fn background_task( let packet = From::from(&socket_recv_buffer[..packet_len]); let local_ip = udp_socket.get_ref().local_addr().ok().map(|a| a.ip()); // TODO: ECN bits aren't handled - let event = endpoint.handle(Instant::now(), packet_src, local_ip, None, packet); + let event = proto_endpoint.handle(Instant::now(), packet_src, local_ip, None, packet); match event { None => {}, @@ -485,11 +451,7 @@ async fn background_task( debug_assert_eq!(connec.side(), quinn_proto::Side::Server); let (tx, rx) = mpsc::channel(16); alive_connections.insert(connec_id, tx); - let endpoint_arc = match endpoint_weak.upgrade() { - Some(ep) => ep, - None => return, // Shut down the task if the endpoint is dead. - }; - let connection = Connection::from_quinn_connection(endpoint_arc, connec, connec_id, rx); + let connection = Connection::from_quinn_connection(endpoint.clone(), connec, connec_id, rx); // As explained in the documentation, we put this new connection in an // intermediary buffer. At the next loop iteration we will try to move it diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index 8c0f7402f54..26dcac29109 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -23,9 +23,11 @@ //! Combines all the objects in the other modules to implement the trait. use crate::connection::Connection; +use crate::endpoint::ToEndpoint; use crate::Config; use crate::{endpoint::Endpoint, in_addr::InAddr, muxer::QuicMuxer, upgrade::Upgrade}; +use futures::channel::oneshot; use futures::stream::StreamExt; use futures::{channel::mpsc, prelude::*, stream::SelectAll}; @@ -36,10 +38,11 @@ use libp2p_core::{ transport::{ListenerId, TransportError, TransportEvent}, PeerId, Transport, }; +use std::collections::VecDeque; +use std::task::Waker; use std::{ net::SocketAddr, pin::Pin, - sync::Arc, task::{Context, Poll}, }; @@ -55,10 +58,10 @@ pub use quinn_proto::{ pub struct QuicTransport { config: Config, listeners: SelectAll, - /// Endpoints to use for dialing Ipv4 addresses if no matching listener exists. - ipv4_dialer: Option>, - /// Endpoints to use for dialing Ipv6 addresses if no matching listener exists. - ipv6_dialer: Option>, + /// Dialer for Ipv4 addresses if no matching listener exists. + ipv4_dialer: Option, + /// Dialer for Ipv6 addresses if no matching listener exists. + ipv6_dialer: Option, } impl QuicTransport { @@ -132,38 +135,49 @@ impl Transport for QuicTransport { tracing::error!("multiaddr not supported"); return Err(TransportError::MultiaddrNotSupported(addr)); } - let listeners = self + let mut listeners = self .listeners - .iter() + .iter_mut() .filter(|l| { - let listen_addr = l.endpoint.socket_addr(); + let listen_addr = l.endpoint.socket_addr; listen_addr.is_ipv4() == socket_addr.is_ipv4() && listen_addr.ip().is_loopback() == socket_addr.ip().is_loopback() }) .collect::>(); - let endpoint = if listeners.is_empty() { + + let (tx, rx) = oneshot::channel(); + let to_endpoint = ToEndpoint::Dial { + addr: socket_addr, + result: tx, + }; + if listeners.is_empty() { let dialer = match socket_addr { SocketAddr::V4(_) => &mut self.ipv4_dialer, SocketAddr::V6(_) => &mut self.ipv6_dialer, }; - match dialer { - Some(endpoint) => endpoint.clone(), - None => { - let endpoint = Endpoint::new_dialer(self.config.clone(), socket_addr.is_ipv6()) - .map_err(TransportError::Other)?; - let _ = dialer.insert(endpoint.clone()); - endpoint - } + if dialer.is_none() { + let _ = dialer.insert(Dialer::new(self.config.clone(), socket_addr.is_ipv6())?); } + dialer + .as_mut() + .unwrap() + .pending_dials + .push_back(to_endpoint); } else { // Pick a random listener to use for dialing. let n = rand::random::() % listeners.len(); - let listener = listeners.get(n).expect("Can not be out of bound."); - listener.endpoint.clone() + let listener = listeners.get_mut(n).expect("Can not be out of bound."); + listener.pending_dials.push_back(to_endpoint); + if let Some(waker) = listener.waker.take() { + waker.wake() + } }; Ok(async move { - let connection = endpoint.dial(socket_addr).await.map_err(Error::Reach)?; + let connection = rx + .await + .expect("background task has crashed") + .map_err(Error::Reach)?; let final_connec = Upgrade::from_connection(connection).await?; Ok(final_connec) } @@ -185,6 +199,12 @@ impl Transport for QuicTransport { mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { + if let Some(dialer) = self.ipv4_dialer.as_mut() { + dialer.drive_dials(cx) + } + if let Some(dialer) = self.ipv6_dialer.as_mut() { + dialer.drive_dials(cx) + } match self.listeners.poll_next_unpin(cx) { Poll::Ready(Some(ev)) => Poll::Ready(ev), _ => Poll::Pending, @@ -192,9 +212,41 @@ impl Transport for QuicTransport { } } +#[derive(Debug)] +struct Dialer { + endpoint: Endpoint, + pending_dials: VecDeque, +} + +impl Dialer { + fn new(config: Config, is_ipv6: bool) -> Result> { + let endpoint = Endpoint::new_dialer(config, is_ipv6).map_err(TransportError::Other)?; + Ok(Dialer { + endpoint, + pending_dials: VecDeque::new(), + }) + } + + fn drive_dials(&mut self, cx: &mut Context<'_>) { + if !self.pending_dials.is_empty() { + match self.endpoint.to_endpoint.poll_ready_unpin(cx) { + Poll::Ready(Ok(())) => { + let to_endpoint = self.pending_dials.pop_front().expect("!is_empty"); + self.endpoint + .to_endpoint + .start_send(to_endpoint) + .expect("Channel is ready."); + } + Poll::Ready(Err(_)) => panic!("Background task crashed."), + Poll::Pending => {} + } + } + } +} + #[derive(Debug)] struct Listener { - endpoint: Arc, + endpoint: Endpoint, listener_id: ListenerId, @@ -212,6 +264,10 @@ struct Listener { /// Optionally contains a [`TransportEvent::ListenerClosed`] that should be /// reported before the listener's stream is terminated. report_closed: Option::Item>>, + + pending_dials: VecDeque, + + waker: Option, } impl Listener { @@ -228,6 +284,8 @@ impl Listener { new_connections_rx, in_addr, report_closed: None, + pending_dials: VecDeque::new(), + waker: None, }) } @@ -258,9 +316,9 @@ impl Listener { match item { Ok(IfEvent::Up(inet)) => { let ip = inet.addr(); - if self.endpoint.socket_addr().is_ipv4() == ip.is_ipv4() { + if self.endpoint.socket_addr.is_ipv4() == ip.is_ipv4() { let socket_addr = - SocketAddr::new(ip, self.endpoint.socket_addr().port()); + SocketAddr::new(ip, self.endpoint.socket_addr.port()); let ma = socketaddr_to_multiaddr(&socket_addr); tracing::debug!("New listen address: {}", ma); return Some(TransportEvent::NewAddress { @@ -271,9 +329,9 @@ impl Listener { } Ok(IfEvent::Down(inet)) => { let ip = inet.addr(); - if self.endpoint.socket_addr().is_ipv4() == ip.is_ipv4() { + if self.endpoint.socket_addr.is_ipv4() == ip.is_ipv4() { let socket_addr = - SocketAddr::new(ip, self.endpoint.socket_addr().port()); + SocketAddr::new(ip, self.endpoint.socket_addr.port()); let ma = socketaddr_to_multiaddr(&socket_addr); tracing::debug!("Expired listen address: {}", ma); return Some(TransportEvent::AddressExpired { @@ -304,32 +362,56 @@ impl Listener { impl Stream for Listener { type Item = TransportEvent<::ListenerUpgrade, Error>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if let Some(closed) = self.report_closed.as_mut() { - // Listener was closed. - // Report the transport event if there is one. On the next iteration, return - // `Poll::Ready(None)` to terminate the stream. - return Poll::Ready(closed.take()); - } - if let Some(event) = self.poll_if_addr(cx) { - return Poll::Ready(Some(event)); - } - let connection = match futures::ready!(self.new_connections_rx.poll_next_unpin(cx)) { - Some(c) => c, - None => { - self.close(Err(Error::TaskCrashed)); - return self.poll_next(cx); + loop { + if let Some(closed) = self.report_closed.as_mut() { + // Listener was closed. + // Report the transport event if there is one. On the next iteration, return + // `Poll::Ready(None)` to terminate the stream. + return Poll::Ready(closed.take()); } - }; - - let local_addr = socketaddr_to_multiaddr(&connection.local_addr()); - let send_back_addr = socketaddr_to_multiaddr(&connection.remote_addr()); - let event = TransportEvent::Incoming { - upgrade: Upgrade::from_connection(connection), - local_addr, - send_back_addr, - listener_id: self.listener_id, - }; - Poll::Ready(Some(event)) + if let Some(event) = self.poll_if_addr(cx) { + return Poll::Ready(Some(event)); + } + if !self.pending_dials.is_empty() { + match self.endpoint.to_endpoint.poll_ready_unpin(cx) { + Poll::Ready(Ok(_)) => { + let to_endpoint = self + .pending_dials + .pop_front() + .expect("Pending dials is not empty."); + self.endpoint + .to_endpoint + .start_send(to_endpoint) + .expect("Channel is ready"); + } + Poll::Ready(Err(_)) => { + self.close(Err(Error::TaskCrashed)); + continue; + } + Poll::Pending => {} + } + } + match self.new_connections_rx.poll_next_unpin(cx) { + Poll::Ready(Some(connection)) => { + let local_addr = socketaddr_to_multiaddr(&connection.local_addr()); + let send_back_addr = socketaddr_to_multiaddr(&connection.remote_addr()); + let event = TransportEvent::Incoming { + upgrade: Upgrade::from_connection(connection), + local_addr, + send_back_addr, + listener_id: self.listener_id, + }; + return Poll::Ready(Some(event)); + } + Poll::Ready(None) => { + self.close(Err(Error::TaskCrashed)); + continue; + } + Poll::Pending => {} + }; + self.waker = Some(cx.waker().clone()); + return Poll::Pending; + } } } From 0a82be48c2350ccda53f61a2a76707f303287fd8 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 22 Aug 2022 06:39:59 +0200 Subject: [PATCH 51/92] transports/quic/tests: drive peers concurrently --- transports/quic/tests/smoke.rs | 201 +++++++++++++++++---------------- 1 file changed, 103 insertions(+), 98 deletions(-) diff --git a/transports/quic/tests/smoke.rs b/transports/quic/tests/smoke.rs index bd8d0682dd9..0291a16f9f0 100644 --- a/transports/quic/tests/smoke.rs +++ b/transports/quic/tests/smoke.rs @@ -1,6 +1,6 @@ use anyhow::Result; use async_trait::async_trait; -use futures::future::FutureExt; +use futures::future::{join, FutureExt}; use futures::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; use futures::select; use futures::stream::StreamExt; @@ -82,118 +82,123 @@ async fn smoke() -> Result<()> { b.behaviour_mut() .send_request(&Swarm::local_peer_id(&a), Ping(data.clone())); - match b.next().await { - Some(SwarmEvent::Dialing(_)) => {} - e => panic!("{:?}", e), - } + let b_id = *b.local_peer_id(); + + let fut_a = async move { + match a.next().await { + Some(SwarmEvent::IncomingConnection { .. }) => {} + e => panic!("{:?}", e), + }; + + match a.next().await { + Some(SwarmEvent::ConnectionEstablished { .. }) => {} + e => panic!("{:?}", e), + }; + + match a.next().await { + Some(SwarmEvent::Behaviour(RequestResponseEvent::Message { + message: + RequestResponseMessage::Request { + request: Ping(ping), + channel, + .. + }, + .. + })) => { + a.behaviour_mut() + .send_response(channel, Pong(ping)) + .unwrap(); + } + e => panic!("{:?}", e), + } - match a.next().await { - Some(SwarmEvent::IncomingConnection { .. }) => {} - e => panic!("{:?}", e), - }; + match a.next().await { + Some(SwarmEvent::Behaviour(RequestResponseEvent::ResponseSent { .. })) => {} + e => panic!("{:?}", e), + } - match b.next().await { - Some(SwarmEvent::ConnectionEstablished { .. }) => {} - e => panic!("{:?}", e), - }; + a.behaviour_mut() + .send_request(&b_id, Ping(b"another substream".to_vec())); - match a.next().await { - Some(SwarmEvent::ConnectionEstablished { .. }) => {} - e => panic!("{:?}", e), - }; + assert!(a.next().now_or_never().is_none()); - assert!(b.next().now_or_never().is_none()); - - match a.next().await { - Some(SwarmEvent::Behaviour(RequestResponseEvent::Message { - message: - RequestResponseMessage::Request { - request: Ping(ping), - channel, - .. - }, - .. - })) => { - a.behaviour_mut() - .send_response(channel, Pong(ping)) - .unwrap(); + match a.next().await { + Some(SwarmEvent::Behaviour(RequestResponseEvent::Message { + message: + RequestResponseMessage::Response { + response: Pong(data), + .. + }, + .. + })) => assert_eq!(data, b"another substream".to_vec()), + e => panic!("{:?}", e), } - e => panic!("{:?}", e), - } - - match a.next().await { - Some(SwarmEvent::Behaviour(RequestResponseEvent::ResponseSent { .. })) => {} - e => panic!("{:?}", e), - } - - match b.next().await { - Some(SwarmEvent::Behaviour(RequestResponseEvent::Message { - message: - RequestResponseMessage::Response { - response: Pong(pong), - .. - }, - .. - })) => assert_eq!(data, pong), - e => panic!("{:?}", e), - } - a.behaviour_mut().send_request( - &Swarm::local_peer_id(&b), - Ping(b"another substream".to_vec()), - ); + a.disconnect_peer_id(b_id).unwrap(); - assert!(a.next().now_or_never().is_none()); + match a.next().await { + Some(SwarmEvent::ConnectionClosed { cause: None, .. }) => {} + e => panic!("{:?}", e), + } + }; - match b.next().await { - Some(SwarmEvent::Behaviour(RequestResponseEvent::Message { - message: - RequestResponseMessage::Request { - request: Ping(data), - channel, - .. - }, - .. - })) => { - b.behaviour_mut() - .send_response(channel, Pong(data)) - .unwrap(); + let fut_b = async { + match b.next().await { + Some(SwarmEvent::Dialing(_)) => {} + e => panic!("{:?}", e), } - e => panic!("{:?}", e), - } - match b.next().await { - Some(SwarmEvent::Behaviour(RequestResponseEvent::ResponseSent { .. })) => {} - e => panic!("{:?}", e), - } + match b.next().await { + Some(SwarmEvent::ConnectionEstablished { .. }) => {} + e => panic!("{:?}", e), + }; - match a.next().await { - Some(SwarmEvent::Behaviour(RequestResponseEvent::Message { - message: - RequestResponseMessage::Response { - response: Pong(data), - .. - }, - .. - })) => assert_eq!(data, b"another substream".to_vec()), - e => panic!("{:?}", e), - } + assert!(b.next().now_or_never().is_none()); - a.disconnect_peer_id(*b.local_peer_id()).unwrap(); + match b.next().await { + Some(SwarmEvent::Behaviour(RequestResponseEvent::Message { + message: + RequestResponseMessage::Response { + response: Pong(pong), + .. + }, + .. + })) => assert_eq!(data, pong), + e => panic!("{:?}", e), + } - match a.next().await { - Some(SwarmEvent::ConnectionClosed { cause: None, .. }) => {} - e => panic!("{:?}", e), - } + match b.next().await { + Some(SwarmEvent::Behaviour(RequestResponseEvent::Message { + message: + RequestResponseMessage::Request { + request: Ping(data), + channel, + .. + }, + .. + })) => { + b.behaviour_mut() + .send_response(channel, Pong(data)) + .unwrap(); + } + e => panic!("{:?}", e), + } - match b.next().await { - Some(SwarmEvent::ConnectionClosed { - cause: Some(ConnectionError::IO(_)), - .. - }) => {} - e => panic!("{:?}", e), - } + match b.next().await { + Some(SwarmEvent::Behaviour(RequestResponseEvent::ResponseSent { .. })) => {} + e => panic!("{:?}", e), + } + + match b.next().await { + Some(SwarmEvent::ConnectionClosed { + cause: Some(ConnectionError::IO(_)), + .. + }) => {} + e => panic!("{:?}", e), + } + }; + join(fut_a, fut_b).await; Ok(()) } From d610e4b0fb5e46474a8d64b60890bce704726986 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Tue, 23 Aug 2022 09:12:00 +0200 Subject: [PATCH 52/92] protocols/dcutr: Disable `libp2p-core` default features (#2836) --- protocols/dcutr/CHANGELOG.md | 6 ++++++ protocols/dcutr/Cargo.toml | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/protocols/dcutr/CHANGELOG.md b/protocols/dcutr/CHANGELOG.md index 7a5794fda88..8c8837d0d02 100644 --- a/protocols/dcutr/CHANGELOG.md +++ b/protocols/dcutr/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.5.1 + +- Make default features of `libp2p-core` optional. See [PR 2836]. + +[PR 2836]: https://github.com/libp2p/rust-libp2p/pull/2836/ + # 0.5.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/dcutr/Cargo.toml b/protocols/dcutr/Cargo.toml index 3193df1bbe0..c82b5e5274f 100644 --- a/protocols/dcutr/Cargo.toml +++ b/protocols/dcutr/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-dcutr" edition = "2021" rust-version = "1.56.1" description = "Direct connection upgrade through relay" -version = "0.5.0" +version = "0.5.1" authors = ["Max Inden "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -17,7 +17,7 @@ either = "1.6.0" futures = "0.3.1" futures-timer = "3.0" instant = "0.1.11" -libp2p-core = { version = "0.35.0", path = "../../core" } +libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.38.0", path = "../../swarm" } log = "0.4" prost-codec = { version = "0.2", path = "../../misc/prost-codec" } From d92cab8581b634511a0aa54e661570b4dad31830 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Aug 2022 09:51:58 +0200 Subject: [PATCH 53/92] build(deps): Update p256 requirement from 0.10.0 to 0.11.0 (#2636) * build(deps): Update p256 requirement from 0.10.0 to 0.11.0 Updates the requirements on [p256](https://github.com/RustCrypto/elliptic-curves) to permit the latest version. - [Release notes](https://github.com/RustCrypto/elliptic-curves/releases) - [Commits](https://github.com/RustCrypto/elliptic-curves/commits/p256/v0.10.1) --- updated-dependencies: - dependency-name: p256 dependency-type: direct:production ... Signed-off-by: dependabot[bot] * core/: Bump version and add changelog entry Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Inden --- core/CHANGELOG.md | 6 ++++++ core/Cargo.toml | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 4c18fa5dc78..1626a471e03 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.35.1 + +- Update to `p256` `v0.11.0`. See [PR 2636]. + +[PR 2636]: https://github.com/libp2p/rust-libp2p/pull/2636/ + # 0.35.0 - Drop `Unpin` requirement from `SubstreamBox`. See [PR 2762] and [PR 2776]. diff --git a/core/Cargo.toml b/core/Cargo.toml index f0197b675d0..d20934adf1e 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-core" edition = "2021" rust-version = "1.56.1" description = "Core traits and structs of libp2p" -version = "0.35.0" +version = "0.35.1" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -25,7 +25,7 @@ log = "0.4" multiaddr = { version = "0.14.0" } multihash = { version = "0.16", default-features = false, features = ["std", "multihash-impl", "identity", "sha2"] } multistream-select = { version = "0.11", path = "../misc/multistream-select" } -p256 = { version = "0.10.0", default-features = false, features = ["ecdsa"], optional = true } +p256 = { version = "0.11.1", default-features = false, features = ["ecdsa"], optional = true } parking_lot = "0.12.0" pin-project = "1.0.0" prost = "0.11" From ca07ce4d6455583794558c076e2719660abb46b2 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 26 Aug 2022 07:08:33 +0200 Subject: [PATCH 54/92] swarm/behaviour: Remove deprecated NetworkBehaviourEventProcess (#2840) Removes the `NetworkBehaviourEventProcess` and all its associated logic. See deprecation pull request https://github.com/libp2p/rust-libp2p/pull/2784. Find rational in https://github.com/libp2p/rust-libp2p/pull/2751. --- CHANGELOG.md | 22 ++++++++++ Cargo.toml | 30 +++++++------- misc/metrics/CHANGELOG.md | 14 +++++++ misc/metrics/Cargo.toml | 16 ++++---- protocols/autonat/CHANGELOG.md | 6 +++ protocols/autonat/Cargo.toml | 6 +-- protocols/dcutr/CHANGELOG.md | 4 ++ protocols/dcutr/Cargo.toml | 4 +- protocols/floodsub/CHANGELOG.md | 4 ++ protocols/floodsub/Cargo.toml | 4 +- protocols/gossipsub/CHANGELOG.md | 4 ++ protocols/gossipsub/Cargo.toml | 4 +- protocols/identify/CHANGELOG.md | 4 ++ protocols/identify/Cargo.toml | 4 +- protocols/kad/CHANGELOG.md | 4 ++ protocols/kad/Cargo.toml | 4 +- protocols/mdns/CHANGELOG.md | 4 ++ protocols/mdns/Cargo.toml | 4 +- protocols/ping/CHANGELOG.md | 4 ++ protocols/ping/Cargo.toml | 4 +- protocols/relay/CHANGELOG.md | 4 ++ protocols/relay/Cargo.toml | 4 +- protocols/rendezvous/CHANGELOG.md | 4 ++ protocols/rendezvous/Cargo.toml | 4 +- protocols/request-response/CHANGELOG.md | 4 ++ protocols/request-response/Cargo.toml | 4 +- swarm-derive/CHANGELOG.md | 4 ++ swarm-derive/Cargo.toml | 2 +- swarm-derive/src/lib.rs | 53 ++----------------------- swarm-derive/tests/test.rs | 35 ---------------- swarm/CHANGELOG.md | 7 ++++ swarm/Cargo.toml | 2 +- swarm/src/behaviour.rs | 18 --------- swarm/src/behaviour/either.rs | 17 -------- swarm/src/behaviour/toggle.rs | 14 ------- swarm/src/lib.rs | 2 - 36 files changed, 145 insertions(+), 183 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edbbc8fb1d8..b9d574ea35f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,28 @@ # `libp2p` facade crate +# 0.48.0 [unreleased] + +- Update to [`libp2p-dcutr` `v0.6.0`](protocols/dcutr/CHANGELOG.md#060). + +- Update to [`libp2p-rendezvous` `v0.9.0`](protocols/rendezvous/CHANGELOG.md#090). + +- Update to [`libp2p-ping` `v0.39.0`](protocols/ping/CHANGELOG.md#0390). + +- Update to [`libp2p-identify` `v0.39.0`](protocols/identify/CHANGELOG.md#0390). + +- Update to [`libp2p-floodsub` `v0.39.0`](protocols/floodsub/CHANGELOG.md#0390). + +- Update to [`libp2p-relay` `v0.12.0`](protocols/relay/CHANGELOG.md#0120). + +- Update to [`libp2p-metrics` `v0.9.0`](misc/metrics/CHANGELOG.md#090). + +- Update to [`libp2p-kad` `v0.40.0`](protocols/kad/CHANGELOG.md#0400). + +- Update to [`libp2p-autonat` `v0.7.0`](protocols/autonat/CHANGELOG.md#070). + +- Update to [`libp2p-request-response` `v0.21.0`](protocols/request-response/CHANGELOG.md#0210). + # 0.47.0 - Update to [`libp2p-dcutr` `v0.5.0`](protocols/dcutr/CHANGELOG.md#050). diff --git a/Cargo.toml b/Cargo.toml index 75867ddbf4f..b64c2f68756 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p" edition = "2021" rust-version = "1.60.0" description = "Peer-to-peer networking library" -version = "0.47.0" +version = "0.48.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -77,23 +77,23 @@ getrandom = "0.2.3" # Explicit dependency to be used in `wasm-bindgen` feature instant = "0.1.11" # Explicit dependency to be used in `wasm-bindgen` feature lazy_static = "1.2" -libp2p-autonat = { version = "0.6.0", path = "protocols/autonat", optional = true } +libp2p-autonat = { version = "0.7.0", path = "protocols/autonat", optional = true } libp2p-core = { version = "0.35.0", path = "core", default-features = false } -libp2p-dcutr = { version = "0.5.0", path = "protocols/dcutr", optional = true } -libp2p-floodsub = { version = "0.38.0", path = "protocols/floodsub", optional = true } -libp2p-identify = { version = "0.38.0", path = "protocols/identify", optional = true } -libp2p-kad = { version = "0.39.0", path = "protocols/kad", optional = true } -libp2p-metrics = { version = "0.8.0", path = "misc/metrics", optional = true } +libp2p-dcutr = { version = "0.6.0", path = "protocols/dcutr", optional = true } +libp2p-floodsub = { version = "0.39.0", path = "protocols/floodsub", optional = true } +libp2p-identify = { version = "0.39.0", path = "protocols/identify", optional = true } +libp2p-kad = { version = "0.40.0", path = "protocols/kad", optional = true } +libp2p-metrics = { version = "0.9.0", path = "misc/metrics", optional = true } libp2p-mplex = { version = "0.35.0", path = "muxers/mplex", optional = true } libp2p-noise = { version = "0.38.0", path = "transports/noise", optional = true } -libp2p-ping = { version = "0.38.0", path = "protocols/ping", optional = true } +libp2p-ping = { version = "0.39.0", path = "protocols/ping", optional = true } libp2p-plaintext = { version = "0.35.0", path = "transports/plaintext", optional = true } libp2p-pnet = { version = "0.22.0", path = "transports/pnet", optional = true } -libp2p-relay = { version = "0.11.0", path = "protocols/relay", optional = true } -libp2p-rendezvous = { version = "0.8.0", path = "protocols/rendezvous", optional = true } -libp2p-request-response = { version = "0.20.0", path = "protocols/request-response", optional = true } -libp2p-swarm = { version = "0.38.0", path = "swarm" } -libp2p-swarm-derive = { version = "0.29.0", path = "swarm-derive" } +libp2p-relay = { version = "0.12.0", path = "protocols/relay", optional = true } +libp2p-rendezvous = { version = "0.9.0", path = "protocols/rendezvous", optional = true } +libp2p-request-response = { version = "0.21.0", path = "protocols/request-response", optional = true } +libp2p-swarm = { version = "0.39.0", path = "swarm" } +libp2p-swarm-derive = { version = "0.30.0", path = "swarm-derive" } libp2p-uds = { version = "0.34.0", path = "transports/uds", optional = true } libp2p-wasm-ext = { version = "0.35.0", path = "transports/wasm-ext", default-features = false, optional = true } libp2p-yamux = { version = "0.39.0", path = "muxers/yamux", optional = true } @@ -106,12 +106,12 @@ smallvec = "1.6.1" [target.'cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))'.dependencies] libp2p-deflate = { version = "0.35.0", path = "transports/deflate", optional = true } libp2p-dns = { version = "0.35.0", path = "transports/dns", optional = true, default-features = false } -libp2p-mdns = { version = "0.39.0", path = "protocols/mdns", optional = true } +libp2p-mdns = { version = "0.40.0", path = "protocols/mdns", optional = true } libp2p-tcp = { version = "0.35.0", path = "transports/tcp", default-features = false, optional = true } libp2p-websocket = { version = "0.37.0", path = "transports/websocket", optional = true } [target.'cfg(not(target_os = "unknown"))'.dependencies] -libp2p-gossipsub = { version = "0.40.0", path = "protocols/gossipsub", optional = true } +libp2p-gossipsub = { version = "0.41.0", path = "protocols/gossipsub", optional = true } [dev-dependencies] async-std = { version = "1.6.2", features = ["attributes"] } diff --git a/misc/metrics/CHANGELOG.md b/misc/metrics/CHANGELOG.md index 8618e0b7130..72007e39c8b 100644 --- a/misc/metrics/CHANGELOG.md +++ b/misc/metrics/CHANGELOG.md @@ -1,3 +1,17 @@ +# 0.9.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + +- Update to `libp2p-dcutr` `v0.6.0`. + +- Update to `libp2p-ping` `v0.39.0`. + +- Update to `libp2p-identify` `v0.39.0`. + +- Update to `libp2p-relay` `v0.12.0`. + +- Update to `libp2p-kad` `v0.40.0`. + # 0.8.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/misc/metrics/Cargo.toml b/misc/metrics/Cargo.toml index 4bfeb7aa481..fe2e4f3ec85 100644 --- a/misc/metrics/Cargo.toml +++ b/misc/metrics/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-metrics" edition = "2021" rust-version = "1.56.1" description = "Metrics for libp2p" -version = "0.8.0" +version = "0.9.0" authors = ["Max Inden "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -20,16 +20,16 @@ dcutr = ["libp2p-dcutr"] [dependencies] libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } -libp2p-dcutr = { version = "0.5.0", path = "../../protocols/dcutr", optional = true } -libp2p-identify = { version = "0.38.0", path = "../../protocols/identify", optional = true } -libp2p-kad = { version = "0.39.0", path = "../../protocols/kad", optional = true } -libp2p-ping = { version = "0.38.0", path = "../../protocols/ping", optional = true } -libp2p-relay = { version = "0.11.0", path = "../../protocols/relay", optional = true } -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } +libp2p-dcutr = { version = "0.6.0", path = "../../protocols/dcutr", optional = true } +libp2p-identify = { version = "0.39.0", path = "../../protocols/identify", optional = true } +libp2p-kad = { version = "0.40.0", path = "../../protocols/kad", optional = true } +libp2p-ping = { version = "0.39.0", path = "../../protocols/ping", optional = true } +libp2p-relay = { version = "0.12.0", path = "../../protocols/relay", optional = true } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } prometheus-client = "0.18.0" [target.'cfg(not(target_os = "unknown"))'.dependencies] -libp2p-gossipsub = { version = "0.40.0", path = "../../protocols/gossipsub", optional = true } +libp2p-gossipsub = { version = "0.41.0", path = "../../protocols/gossipsub", optional = true } [dev-dependencies] log = "0.4.0" diff --git a/protocols/autonat/CHANGELOG.md b/protocols/autonat/CHANGELOG.md index 5856a6a3c82..f6c4b9d619c 100644 --- a/protocols/autonat/CHANGELOG.md +++ b/protocols/autonat/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.7.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + +- Update to `libp2p-request-response` `v0.21.0`. + # 0.6.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/autonat/Cargo.toml b/protocols/autonat/Cargo.toml index 6ec668e4fdc..e6818a74817 100644 --- a/protocols/autonat/Cargo.toml +++ b/protocols/autonat/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-autonat" edition = "2021" rust-version = "1.56.1" description = "NAT and firewall detection for libp2p" -version = "0.6.0" +version = "0.7.0" authors = ["David Craven ", "Elena Frank "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -19,8 +19,8 @@ futures = "0.3" futures-timer = "3.0" instant = "0.1" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } -libp2p-request-response = { version = "0.20.0", path = "../request-response" } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } +libp2p-request-response = { version = "0.21.0", path = "../request-response" } log = "0.4" rand = "0.8" prost = "0.11" diff --git a/protocols/dcutr/CHANGELOG.md b/protocols/dcutr/CHANGELOG.md index 8c8837d0d02..a572d84bcf0 100644 --- a/protocols/dcutr/CHANGELOG.md +++ b/protocols/dcutr/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.6.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + # 0.5.1 - Make default features of `libp2p-core` optional. See [PR 2836]. diff --git a/protocols/dcutr/Cargo.toml b/protocols/dcutr/Cargo.toml index c82b5e5274f..08d2815c6d9 100644 --- a/protocols/dcutr/Cargo.toml +++ b/protocols/dcutr/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-dcutr" edition = "2021" rust-version = "1.56.1" description = "Direct connection upgrade through relay" -version = "0.5.1" +version = "0.6.0" authors = ["Max Inden "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -18,7 +18,7 @@ futures = "0.3.1" futures-timer = "3.0" instant = "0.1.11" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4" prost-codec = { version = "0.2", path = "../../misc/prost-codec" } prost = "0.11" diff --git a/protocols/floodsub/CHANGELOG.md b/protocols/floodsub/CHANGELOG.md index 2e02a7ded1f..cbe061e6959 100644 --- a/protocols/floodsub/CHANGELOG.md +++ b/protocols/floodsub/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.39.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + # 0.38.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/floodsub/Cargo.toml b/protocols/floodsub/Cargo.toml index 8c2631e5ce8..2b9ef8ee402 100644 --- a/protocols/floodsub/Cargo.toml +++ b/protocols/floodsub/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-floodsub" edition = "2021" rust-version = "1.56.1" description = "Floodsub protocol for libp2p" -version = "0.38.0" +version = "0.39.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -15,7 +15,7 @@ cuckoofilter = "0.5.0" fnv = "1.0" futures = "0.3.1" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4" prost = "0.11" rand = "0.7" diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index 2c55be28e85..dad83493795 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.41.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + # 0.40.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/gossipsub/Cargo.toml b/protocols/gossipsub/Cargo.toml index 42b21e41a97..c551d59cb14 100644 --- a/protocols/gossipsub/Cargo.toml +++ b/protocols/gossipsub/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-gossipsub" edition = "2021" rust-version = "1.56.1" description = "Gossipsub protocol for libp2p" -version = "0.40.0" +version = "0.41.0" authors = ["Age Manning "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -11,7 +11,7 @@ keywords = ["peer-to-peer", "libp2p", "networking"] categories = ["network-programming", "asynchronous"] [dependencies] -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } bytes = "1.0" byteorder = "1.3.4" diff --git a/protocols/identify/CHANGELOG.md b/protocols/identify/CHANGELOG.md index 8821bca3507..47af0838ae8 100644 --- a/protocols/identify/CHANGELOG.md +++ b/protocols/identify/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.39.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + # 0.38.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml index 9db09cd1bf2..d0bc65379ad 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-identify" edition = "2021" rust-version = "1.56.1" description = "Nodes identifcation protocol for libp2p" -version = "0.38.0" +version = "0.39.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -15,7 +15,7 @@ asynchronous-codec = "0.6" futures = "0.3.1" futures-timer = "3.0.2" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4.1" lru = "0.7.2" prost-codec = { version = "0.2", path = "../../misc/prost-codec" } diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 09f2035ef2b..4fef2057008 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.40.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + # 0.39.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index d1910dccbbb..bf7d0957bd3 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-kad" edition = "2021" rust-version = "1.56.1" description = "Kademlia protocol for libp2p" -version = "0.39.0" +version = "0.40.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -19,7 +19,7 @@ asynchronous-codec = "0.6" futures = "0.3.1" log = "0.4" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } prost = "0.11" rand = "0.7.2" sha2 = "0.10.0" diff --git a/protocols/mdns/CHANGELOG.md b/protocols/mdns/CHANGELOG.md index c6541f7eccc..a6b05044fa5 100644 --- a/protocols/mdns/CHANGELOG.md +++ b/protocols/mdns/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.40.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + # 0.39.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/mdns/Cargo.toml b/protocols/mdns/Cargo.toml index bb060c9ed1f..306f052cc69 100644 --- a/protocols/mdns/Cargo.toml +++ b/protocols/mdns/Cargo.toml @@ -2,7 +2,7 @@ name = "libp2p-mdns" edition = "2021" rust-version = "1.56.1" -version = "0.39.0" +version = "0.40.0" description = "Implementation of the libp2p mDNS discovery method" authors = ["Parity Technologies "] license = "MIT" @@ -18,7 +18,7 @@ futures = "0.3.13" if-watch = "1.1.1" lazy_static = "1.4.0" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4.14" rand = "0.8.3" smallvec = "1.6.1" diff --git a/protocols/ping/CHANGELOG.md b/protocols/ping/CHANGELOG.md index d163839733a..cf1f2fedf42 100644 --- a/protocols/ping/CHANGELOG.md +++ b/protocols/ping/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.39.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + # 0.38.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/ping/Cargo.toml b/protocols/ping/Cargo.toml index 14984332db7..568f8f83aac 100644 --- a/protocols/ping/Cargo.toml +++ b/protocols/ping/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-ping" edition = "2021" rust-version = "1.56.1" description = "Ping protocol for libp2p" -version = "0.38.0" +version = "0.39.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -15,7 +15,7 @@ futures = "0.3.1" futures-timer = "3.0.2" instant = "0.1.11" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4.1" rand = "0.7.2" void = "1.0" diff --git a/protocols/relay/CHANGELOG.md b/protocols/relay/CHANGELOG.md index 537abff7edc..e02a3ef8b82 100644 --- a/protocols/relay/CHANGELOG.md +++ b/protocols/relay/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.12.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + # 0.11.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/relay/Cargo.toml b/protocols/relay/Cargo.toml index 4a7396f938b..ee059d02d50 100644 --- a/protocols/relay/Cargo.toml +++ b/protocols/relay/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-relay" edition = "2021" rust-version = "1.56.1" description = "Communications relaying for libp2p" -version = "0.11.0" +version = "0.12.0" authors = ["Parity Technologies ", "Max Inden "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -18,7 +18,7 @@ futures = "0.3.1" futures-timer = "3" instant = "0.1.11" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4" pin-project = "1" prost-codec = { version = "0.2", path = "../../misc/prost-codec" } diff --git a/protocols/rendezvous/CHANGELOG.md b/protocols/rendezvous/CHANGELOG.md index 728a1538c9e..f2ba00df164 100644 --- a/protocols/rendezvous/CHANGELOG.md +++ b/protocols/rendezvous/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.9.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + # 0.8.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/rendezvous/Cargo.toml b/protocols/rendezvous/Cargo.toml index 833fee1f19d..a21dd300447 100644 --- a/protocols/rendezvous/Cargo.toml +++ b/protocols/rendezvous/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-rendezvous" edition = "2021" rust-version = "1.56.1" description = "Rendezvous protocol for libp2p" -version = "0.8.0" +version = "0.9.0" authors = ["The COMIT guys "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -13,7 +13,7 @@ categories = ["network-programming", "asynchronous"] [dependencies] asynchronous-codec = "0.6" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } prost = "0.11" void = "1" log = "0.4" diff --git a/protocols/request-response/CHANGELOG.md b/protocols/request-response/CHANGELOG.md index 0008f1a1d01..aef9f49f72f 100644 --- a/protocols/request-response/CHANGELOG.md +++ b/protocols/request-response/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.21.0 [unreleased] + +- Update to `libp2p-swarm` `v0.39.0`. + # 0.20.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/request-response/Cargo.toml b/protocols/request-response/Cargo.toml index 91f95484f73..c2649de6012 100644 --- a/protocols/request-response/Cargo.toml +++ b/protocols/request-response/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-request-response" edition = "2021" rust-version = "1.56.1" description = "Generic Request/Response Protocols" -version = "0.20.0" +version = "0.21.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -16,7 +16,7 @@ bytes = "1" futures = "0.3.1" instant = "0.1.11" libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } -libp2p-swarm = { version = "0.38.0", path = "../../swarm" } +libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4.11" rand = "0.7" smallvec = "1.6.1" diff --git a/swarm-derive/CHANGELOG.md b/swarm-derive/CHANGELOG.md index f9056f6093a..5cf840c331c 100644 --- a/swarm-derive/CHANGELOG.md +++ b/swarm-derive/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.30.0 - [unreleased] + +- Remove support for removed `NetworkBehaviourEventProcess`. + # 0.29.0 - Generate `NetworkBehaviour::OutEvent` if not provided through `#[behaviour(out_event = diff --git a/swarm-derive/Cargo.toml b/swarm-derive/Cargo.toml index 05ed063257d..89ee54447fc 100644 --- a/swarm-derive/Cargo.toml +++ b/swarm-derive/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-swarm-derive" edition = "2021" rust-version = "1.56.1" description = "Procedural macros of libp2p-core" -version = "0.29.0" +version = "0.30.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" diff --git a/swarm-derive/src/lib.rs b/swarm-derive/src/lib.rs index 51305e38190..0369a67c5ea 100644 --- a/swarm-derive/src/lib.rs +++ b/swarm-derive/src/lib.rs @@ -48,7 +48,6 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { let (_, ty_generics, where_clause) = ast.generics.split_for_impl(); let multiaddr = quote! {::libp2p::core::Multiaddr}; let trait_to_impl = quote! {::libp2p::swarm::NetworkBehaviour}; - let net_behv_event_proc = quote! {::libp2p::swarm::NetworkBehaviourEventProcess}; let either_ident = quote! {::libp2p::core::either::EitherOutput}; let network_behaviour_action = quote! {::libp2p::swarm::NetworkBehaviourAction}; let into_connection_handler = quote! {::libp2p::swarm::IntoConnectionHandler}; @@ -71,28 +70,6 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { quote! {<#(#lf,)* #(#tp,)* #(#cst,)*>} }; - // Whether or not we require the `NetworkBehaviourEventProcess` trait to be implemented. - let event_process = { - let mut event_process = false; - - for meta_items in ast.attrs.iter().filter_map(get_meta_items) { - for meta_item in meta_items { - match meta_item { - syn::NestedMeta::Meta(syn::Meta::NameValue(ref m)) - if m.path.is_ident("event_process") => - { - if let syn::Lit::Bool(ref b) = m.lit { - event_process = b.value - } - } - _ => (), - } - } - } - - event_process - }; - // The fields of the struct we are interested in (no ignored fields). let data_struct_fields = data_struct .fields @@ -121,9 +98,9 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { }) .next(); - match (user_provided_out_event_name, event_process) { + match user_provided_out_event_name { // User provided `OutEvent`. - (Some(name), false) => { + Some(name) => { let definition = None; let from_clauses = data_struct_fields .iter() @@ -135,7 +112,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { (name, definition, from_clauses) } // User did not provide `OutEvent`. Generate it. - (None, false) => { + None => { let name: syn::Type = syn::parse_str(&(ast.ident.to_string() + "Event")).unwrap(); let definition = { let fields = data_struct_fields @@ -170,22 +147,6 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { let from_clauses = vec![]; (name, definition, from_clauses) } - // User uses `NetworkBehaviourEventProcess`. - (name, true) => { - let definition = None; - let from_clauses = data_struct_fields - .iter() - .map(|field| { - let ty = &field.ty; - quote! {Self: #net_behv_event_proc<<#ty as #trait_to_impl>::OutEvent>} - }) - .collect::>(); - ( - name.unwrap_or_else(|| syn::parse_str("()").unwrap()), - definition, - from_clauses, - ) - } } }; @@ -545,13 +506,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { out_handler.unwrap_or(quote! {()}) // TODO: See test `empty`. }; - let generate_event_match_arm = if event_process { - quote! { - std::task::Poll::Ready(#network_behaviour_action::GenerateEvent(event)) => { - #net_behv_event_proc::inject_event(self, event) - } - } - } else { + let generate_event_match_arm = { // If the `NetworkBehaviour`'s `OutEvent` is generated by the derive macro, wrap the sub // `NetworkBehaviour` `OutEvent` in the variant of the generated `OutEvent`. If the // `NetworkBehaviour`'s `OutEvent` is provided by the user, use the corresponding `From` diff --git a/swarm-derive/tests/test.rs b/swarm-derive/tests/test.rs index f4a313198a9..61c95cd8aaa 100644 --- a/swarm-derive/tests/test.rs +++ b/swarm-derive/tests/test.rs @@ -460,41 +460,6 @@ fn mixed_field_order() { } } -#[test] -fn event_process() { - #[allow(dead_code)] - #[derive(NetworkBehaviour)] - #[behaviour(event_process = true)] - struct Foo { - ping: libp2p::ping::Ping, - identify: libp2p::identify::Identify, - } - - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {} - } - - impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { - fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} - } - - #[allow(dead_code, unreachable_code)] - fn bar() { - require_net_behaviour::(); - - let mut _swarm: libp2p::Swarm = unimplemented!(); - - let _ = async { - loop { - match _swarm.select_next_some().await { - SwarmEvent::Behaviour(()) => break, - _ => {} - } - } - }; - } -} - #[test] fn generated_out_event_derive_debug() { #[allow(dead_code)] diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index 61175ae0762..75add0d524a 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -1,3 +1,10 @@ +# 0.39.0 - [unreleased] + +- Remove deprecated `NetworkBehaviourEventProcess`. See [libp2p-swarm v0.38.0 changelog entry] for + migration path. + +[libp2p-swarm v0.38.0 changelog entry]: https://github.com/libp2p/rust-libp2p/blob/master/swarm/CHANGELOG.md#0380 + # 0.38.0 - Deprecate `NetworkBehaviourEventProcess`. When deriving `NetworkBehaviour` on a custom `struct` users diff --git a/swarm/Cargo.toml b/swarm/Cargo.toml index e2829f80093..6f4a87adb0d 100644 --- a/swarm/Cargo.toml +++ b/swarm/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-swarm" edition = "2021" rust-version = "1.56.1" description = "The libp2p swarm" -version = "0.38.0" +version = "0.39.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index c0ac597680c..9c4a10b56cd 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -321,24 +321,6 @@ pub trait PollParameters { fn local_peer_id(&self) -> &PeerId; } -/// When deriving [`NetworkBehaviour`] this trait must by default be implemented for all the -/// possible event types generated by the inner behaviours. -/// -/// You can opt out of this behaviour through `#[behaviour(event_process = false)]`. See the -/// documentation of [`NetworkBehaviour`] for details. -#[deprecated( - since = "0.38.0", - note = "Use `#[behaviour(out_event = \"MyBehaviourEvent\")]` instead. See \ - https://github.com/libp2p/rust-libp2p/blob/master/swarm/CHANGELOG.md#0380 \ - for instructions on how to migrate. Will be removed with \ - https://github.com/libp2p/rust-libp2p/pull/2751." -)] -pub trait NetworkBehaviourEventProcess { - /// Called when one of the fields of the type you're deriving `NetworkBehaviour` on generates - /// an event. - fn inject_event(&mut self, event: TEvent); -} - /// An action that a [`NetworkBehaviour`] can trigger in the [`Swarm`] /// in whose context it is executing. /// diff --git a/swarm/src/behaviour/either.rs b/swarm/src/behaviour/either.rs index fc4c50e63ef..6bb1d95a519 100644 --- a/swarm/src/behaviour/either.rs +++ b/swarm/src/behaviour/either.rs @@ -19,8 +19,6 @@ // DEALINGS IN THE SOFTWARE. use crate::handler::{either::IntoEitherHandler, ConnectionHandler, IntoConnectionHandler}; -#[allow(deprecated)] -pub use crate::NetworkBehaviourEventProcess; use crate::{DialError, NetworkBehaviour, NetworkBehaviourAction, PollParameters}; use either::Either; use libp2p_core::{ @@ -235,18 +233,3 @@ where Poll::Ready(event) } } - -#[allow(deprecated)] -impl NetworkBehaviourEventProcess - for Either -where - TBehaviourLeft: NetworkBehaviourEventProcess, - TBehaviourRight: NetworkBehaviourEventProcess, -{ - fn inject_event(&mut self, event: TEvent) { - match self { - Either::Left(a) => a.inject_event(event), - Either::Right(b) => b.inject_event(event), - } - } -} diff --git a/swarm/src/behaviour/toggle.rs b/swarm/src/behaviour/toggle.rs index 64ebdf779e5..07a15d56da9 100644 --- a/swarm/src/behaviour/toggle.rs +++ b/swarm/src/behaviour/toggle.rs @@ -23,8 +23,6 @@ use crate::handler::{ KeepAlive, SubstreamProtocol, }; use crate::upgrade::{InboundUpgradeSend, OutboundUpgradeSend, SendWrapper}; -#[allow(deprecated)] -pub use crate::NetworkBehaviourEventProcess; use crate::{DialError, NetworkBehaviour, NetworkBehaviourAction, PollParameters}; use either::Either; use libp2p_core::{ @@ -232,18 +230,6 @@ where } } -#[allow(deprecated)] -impl NetworkBehaviourEventProcess for Toggle -where - TBehaviour: NetworkBehaviourEventProcess, -{ - fn inject_event(&mut self, event: TEvent) { - if let Some(inner) = self.inner.as_mut() { - inner.inject_event(event); - } - } -} - /// Implementation of `IntoConnectionHandler` that can be in the disabled state. pub struct ToggleIntoConnectionHandler { inner: Option, diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 38df855cff5..230de4631db 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -63,8 +63,6 @@ pub mod behaviour; pub mod dial_opts; pub mod handler; -#[allow(deprecated)] -pub use behaviour::NetworkBehaviourEventProcess; pub use behaviour::{ CloseConnection, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, }; From a3dec471c046127e8e0d88bc89a881affb56a76c Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 26 Aug 2022 09:02:14 +0200 Subject: [PATCH 55/92] docs/coding-guidelines: Document limit on number of tasks (#2839) Add guideline to limit number of tasks being spawned. --- docs/coding-guidelines.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/coding-guidelines.md b/docs/coding-guidelines.md index a208dd2768c..70a1ef53009 100644 --- a/docs/coding-guidelines.md +++ b/docs/coding-guidelines.md @@ -10,6 +10,7 @@ - [Bound everything](#bound-everything) - [Channels](#channels) - [Local queues](#local-queues) + - [Tasks](#tasks) - [Further reading](#further-reading) - [No premature optimizations](#no-premature-optimizations) - [Keep things sequential unless proven to be slow](#keep-things-sequential-unless-proven-to-be-slow) @@ -201,6 +202,19 @@ growth and high latencies. Note that rust-libp2p fails at this guideline, i.e. still has many unbounded local queues. +### Tasks + +Bound the number of +[tasks](https://docs.rs/futures/latest/futures/task/index.html) being spawned. +As an example, say we spawn one task per incoming request received from a +socket. If the number of pending requests is not bounded by some limit, a +misbehaving or malicious remote peer can send requests at a higher rate than the +local node can respond at. This results in unbounded growth in the number of +requests, and thus unbounded growth in the number of tasks and used memory. + +Simply put, rust-libp2p spawns one task per connection but limits the overall +number of connections, thus adhering to this guideline. + ### Further reading - https://en.wikipedia.org/wiki/Bufferbloat From 247b5536d44329b712d4ffe9096238217365f717 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Sun, 28 Aug 2022 10:51:49 +0200 Subject: [PATCH 56/92] swarm-derive/: Remove support for custom poll method (#2841) With the removal of `NetworkBehaviourEventProcess` there is no more need for a custom poll method. --- CHANGELOG.md | 2 + swarm-derive/CHANGELOG.md | 8 +++- swarm-derive/src/lib.rs | 28 +------------ swarm-derive/tests/test.rs | 81 +------------------------------------- swarm/src/behaviour.rs | 4 -- 5 files changed, 12 insertions(+), 111 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9d574ea35f..20766d4dc19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ # 0.48.0 [unreleased] +- Update to [`libp2p-swarm-derive` `v0.30.0`](swarm-derive/CHANGELOG.md#0300). + - Update to [`libp2p-dcutr` `v0.6.0`](protocols/dcutr/CHANGELOG.md#060). - Update to [`libp2p-rendezvous` `v0.9.0`](protocols/rendezvous/CHANGELOG.md#090). diff --git a/swarm-derive/CHANGELOG.md b/swarm-derive/CHANGELOG.md index 5cf840c331c..4dc5a9769cb 100644 --- a/swarm-derive/CHANGELOG.md +++ b/swarm-derive/CHANGELOG.md @@ -1,6 +1,12 @@ # 0.30.0 - [unreleased] -- Remove support for removed `NetworkBehaviourEventProcess`. +- Remove support for removed `NetworkBehaviourEventProcess`. See [PR 2840]. + +- Remove support for custom `poll` method on `NetworkBehaviour` via `#[behaviour(poll_method = + "poll")]`. See [PR 2841]. + +[PR 2840]: https://github.com/libp2p/rust-libp2p/pull/2840 +[PR 2841]: https://github.com/libp2p/rust-libp2p/pull/2841 # 0.29.0 diff --git a/swarm-derive/src/lib.rs b/swarm-derive/src/lib.rs index 0369a67c5ea..d1e49ef361a 100644 --- a/swarm-derive/src/lib.rs +++ b/swarm-derive/src/lib.rs @@ -23,7 +23,7 @@ use heck::ToUpperCamelCase; use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Ident}; +use syn::{parse_macro_input, Data, DataStruct, DeriveInput}; /// Generates a delegating `NetworkBehaviour` implementation for the struct this is used for. See /// the trait documentation for better description. @@ -433,29 +433,6 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { out_handler.unwrap_or(quote! {()}) // TODO: See test `empty`. }; - // The method to use to poll. - // If we find a `#[behaviour(poll_method = "poll")]` attribute on the struct, we call - // `self.poll()` at the end of the polling. - let poll_method = { - let mut poll_method = quote! {std::task::Poll::Pending}; - for meta_items in ast.attrs.iter().filter_map(get_meta_items) { - for meta_item in meta_items { - match meta_item { - syn::NestedMeta::Meta(syn::Meta::NameValue(ref m)) - if m.path.is_ident("poll_method") => - { - if let syn::Lit::Str(ref s) = m.lit { - let ident: Ident = syn::parse_str(&s.value()).unwrap(); - poll_method = quote! {#name::#ident(self, cx, poll_params)}; - } - } - _ => (), - } - } - } - poll_method - }; - // List of statements to put in `poll()`. // // We poll each child one by one and wrap around the output. @@ -638,8 +615,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { fn poll(&mut self, cx: &mut std::task::Context, poll_params: &mut impl #poll_parameters) -> std::task::Poll<#network_behaviour_action> { use libp2p::futures::prelude::*; #(#poll_stmts)* - let f: std::task::Poll<#network_behaviour_action> = #poll_method; - f + std::task::Poll::Pending } } }; diff --git a/swarm-derive/tests/test.rs b/swarm-derive/tests/test.rs index 61c95cd8aaa..d7b058d2169 100644 --- a/swarm-derive/tests/test.rs +++ b/swarm-derive/tests/test.rs @@ -128,38 +128,7 @@ fn three_fields_non_last_ignored() { } #[test] -fn custom_polling() { - #[allow(dead_code)] - #[derive(NetworkBehaviour)] - #[behaviour(poll_method = "foo")] - struct Foo { - ping: libp2p::ping::Ping, - identify: libp2p::identify::Identify, - } - - impl Foo { - fn foo( - &mut self, - _: &mut std::task::Context, - _: &mut impl libp2p::swarm::PollParameters, - ) -> std::task::Poll< - libp2p::swarm::NetworkBehaviourAction< - ::OutEvent, - ::ConnectionHandler, - >, - > { - std::task::Poll::Pending - } - } - - #[allow(dead_code)] - fn foo() { - require_net_behaviour::(); - } -} - -#[test] -fn custom_event_no_polling() { +fn custom_event() { #[allow(dead_code)] #[derive(NetworkBehaviour)] #[behaviour(out_event = "MyEvent")] @@ -191,54 +160,6 @@ fn custom_event_no_polling() { } } -#[test] -fn custom_event_and_polling() { - #[allow(dead_code)] - #[derive(NetworkBehaviour)] - #[behaviour(poll_method = "foo", out_event = "MyEvent")] - struct Foo { - ping: libp2p::ping::Ping, - identify: libp2p::identify::Identify, - } - - enum MyEvent { - Ping(libp2p::ping::PingEvent), - Identify(libp2p::identify::IdentifyEvent), - } - - impl From for MyEvent { - fn from(event: libp2p::ping::PingEvent) -> Self { - MyEvent::Ping(event) - } - } - - impl From for MyEvent { - fn from(event: libp2p::identify::IdentifyEvent) -> Self { - MyEvent::Identify(event) - } - } - - impl Foo { - fn foo( - &mut self, - _: &mut std::task::Context, - _: &mut impl libp2p::swarm::PollParameters, - ) -> std::task::Poll< - libp2p::swarm::NetworkBehaviourAction< - ::OutEvent, - ::ConnectionHandler, - >, - > { - std::task::Poll::Pending - } - } - - #[allow(dead_code)] - fn foo() { - require_net_behaviour::(); - } -} - #[test] fn custom_event_mismatching_field_names() { #[allow(dead_code)] diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index 9c4a10b56cd..acda2cedc27 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -118,10 +118,6 @@ pub(crate) type THandlerOutEvent = /// } /// ``` /// -/// Optionally one can provide a custom `poll` function through the `#[behaviour(poll_method = -/// "poll")]` attribute. This function must have the same signature as the [`NetworkBehaviour#poll`] -/// function and will be called last within the generated [`NetworkBehaviour`] implementation. -/// /// Struct members that don't implement [`NetworkBehaviour`] must be annotated with /// `#[behaviour(ignore)]`. /// From 6855ab943bd7427a2135b46ad3d08f48fbf10872 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 29 Aug 2022 07:39:47 +0200 Subject: [PATCH 57/92] swarm-derive/: Remove support for ignoring fields on struct (#2842) With the removal of `NetworkBehaviourEventProcess` there is no more need for ignoring fields. --- examples/chat.rs | 6 --- swarm-derive/CHANGELOG.md | 5 +++ swarm-derive/src/lib.rs | 81 ++++++++++++++++---------------------- swarm-derive/tests/test.rs | 48 ---------------------- swarm/src/behaviour.rs | 35 ---------------- 5 files changed, 40 insertions(+), 135 deletions(-) diff --git a/examples/chat.rs b/examples/chat.rs index d6468428567..ee5527bfca7 100644 --- a/examples/chat.rs +++ b/examples/chat.rs @@ -85,11 +85,6 @@ async fn main() -> Result<(), Box> { struct MyBehaviour { floodsub: Floodsub, mdns: Mdns, - - // Struct fields which do not implement NetworkBehaviour need to be ignored - #[behaviour(ignore)] - #[allow(dead_code)] - ignored_member: bool, } #[allow(clippy::large_enum_variant)] @@ -117,7 +112,6 @@ async fn main() -> Result<(), Box> { let mut behaviour = MyBehaviour { floodsub: Floodsub::new(local_peer_id), mdns, - ignored_member: false, }; behaviour.floodsub.subscribe(floodsub_topic.clone()); diff --git a/swarm-derive/CHANGELOG.md b/swarm-derive/CHANGELOG.md index 4dc5a9769cb..fdf01f04814 100644 --- a/swarm-derive/CHANGELOG.md +++ b/swarm-derive/CHANGELOG.md @@ -8,6 +8,11 @@ [PR 2840]: https://github.com/libp2p/rust-libp2p/pull/2840 [PR 2841]: https://github.com/libp2p/rust-libp2p/pull/2841 +- Remove support for non-`NetworkBehaviour` fields on main `struct` via `#[behaviour(ignore)]`. See + [PR 2842]. + +[PR 2842]: https://github.com/libp2p/rust-libp2p/pull/2842 + # 0.29.0 - Generate `NetworkBehaviour::OutEvent` if not provided through `#[behaviour(out_event = diff --git a/swarm-derive/src/lib.rs b/swarm-derive/src/lib.rs index d1e49ef361a..3e3bf5b8067 100644 --- a/swarm-derive/src/lib.rs +++ b/swarm-derive/src/lib.rs @@ -70,13 +70,6 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { quote! {<#(#lf,)* #(#tp,)* #(#cst,)*>} }; - // The fields of the struct we are interested in (no ignored fields). - let data_struct_fields = data_struct - .fields - .iter() - .filter(|f| !is_ignored(f)) - .collect::>(); - let (out_event_name, out_event_definition, out_event_from_clauses) = { // If we find a `#[behaviour(out_event = "Foo")]` attribute on the // struct, we set `Foo` as the out event. If not, the `OutEvent` is @@ -102,7 +95,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // User provided `OutEvent`. Some(name) => { let definition = None; - let from_clauses = data_struct_fields + let from_clauses = data_struct + .fields .iter() .map(|field| { let ty = &field.ty; @@ -115,7 +109,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { None => { let name: syn::Type = syn::parse_str(&(ast.ident.to_string() + "Event")).unwrap(); let definition = { - let fields = data_struct_fields + let fields = data_struct + .fields .iter() .map(|field| { let variant: syn::Variant = syn::parse_str( @@ -152,7 +147,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the `where ...` clause of the trait implementation. let where_clause = { - let additional = data_struct_fields + let additional = data_struct + .fields .iter() .map(|field| { let ty = &field.ty; @@ -174,7 +170,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `addresses_of_peer()`. let addresses_of_peer_stmts = { - data_struct_fields + data_struct + .fields .iter() .enumerate() .map(move |(field_n, field)| match field.ident { @@ -185,7 +182,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_connection_established()`. let inject_connection_established_stmts = { - data_struct_fields.iter().enumerate().map(move |(field_n, field)| { + data_struct.fields.iter().enumerate().map(move |(field_n, field)| { match field.ident { Some(ref i) => quote!{ self.#i.inject_connection_established(peer_id, connection_id, endpoint, errors, other_established); }, None => quote!{ self.#field_n.inject_connection_established(peer_id, connection_id, endpoint, errors, other_established); }, @@ -195,7 +192,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_address_change()`. let inject_address_change_stmts = { - data_struct_fields.iter().enumerate().map(move |(field_n, field)| { + data_struct.fields.iter().enumerate().map(move |(field_n, field)| { match field.ident { Some(ref i) => quote!{ self.#i.inject_address_change(peer_id, connection_id, old, new); }, None => quote!{ self.#field_n.inject_address_change(peer_id, connection_id, old, new); }, @@ -205,7 +202,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_connection_closed()`. let inject_connection_closed_stmts = { - data_struct_fields + data_struct.fields .iter() .enumerate() // The outmost handler belongs to the last behaviour. @@ -234,7 +231,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_dial_failure()`. let inject_dial_failure_stmts = { - data_struct_fields + data_struct + .fields .iter() .enumerate() // The outmost handler belongs to the last behaviour. @@ -268,7 +266,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_listen_failure()`. let inject_listen_failure_stmts = { - data_struct_fields + data_struct.fields .iter() .enumerate() .rev() @@ -296,7 +294,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_new_listener()`. let inject_new_listener_stmts = { - data_struct_fields + data_struct + .fields .iter() .enumerate() .map(move |(field_n, field)| match field.ident { @@ -307,7 +306,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_new_listen_addr()`. let inject_new_listen_addr_stmts = { - data_struct_fields + data_struct + .fields .iter() .enumerate() .map(move |(field_n, field)| match field.ident { @@ -318,7 +318,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_expired_listen_addr()`. let inject_expired_listen_addr_stmts = { - data_struct_fields + data_struct + .fields .iter() .enumerate() .map(move |(field_n, field)| match field.ident { @@ -329,7 +330,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_new_external_addr()`. let inject_new_external_addr_stmts = { - data_struct_fields + data_struct + .fields .iter() .enumerate() .map(move |(field_n, field)| match field.ident { @@ -340,7 +342,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_expired_external_addr()`. let inject_expired_external_addr_stmts = { - data_struct_fields + data_struct + .fields .iter() .enumerate() .map(move |(field_n, field)| match field.ident { @@ -351,7 +354,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_listener_error()`. let inject_listener_error_stmts = { - data_struct_fields + data_struct + .fields .iter() .enumerate() .map(move |(field_n, field)| match field.ident { @@ -362,7 +366,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // Build the list of statements to put in the body of `inject_listener_closed()`. let inject_listener_closed_stmts = { - data_struct_fields + data_struct + .fields .iter() .enumerate() .map(move |(field_n, field)| match field.ident { @@ -375,14 +380,14 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // // The event type is a construction of nested `#either_ident`s of the events of the children. // We call `inject_event` on the corresponding child. - let inject_node_event_stmts = data_struct_fields.iter().enumerate().enumerate().map(|(enum_n, (field_n, field))| { + let inject_node_event_stmts = data_struct.fields.iter().enumerate().enumerate().map(|(enum_n, (field_n, field))| { let mut elem = if enum_n != 0 { quote!{ #either_ident::Second(ev) } } else { quote!{ ev } }; - for _ in 0 .. data_struct_fields.len() - 1 - enum_n { + for _ in 0 .. data_struct.fields.len() - 1 - enum_n { elem = quote!{ #either_ident::First(#elem) }; } @@ -395,7 +400,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // The [`ConnectionHandler`] associated type. let connection_handler_ty = { let mut ph_ty = None; - for field in data_struct_fields.iter() { + for field in data_struct.fields.iter() { let ty = &field.ty; let field_info = quote! { <#ty as #trait_to_impl>::ConnectionHandler }; match ph_ty { @@ -412,7 +417,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { let new_handler = { let mut out_handler = None; - for (field_n, field) in data_struct_fields.iter().enumerate() { + for (field_n, field) in data_struct.fields.iter().enumerate() { let field_name = match field.ident { Some(ref i) => quote! { self.#i }, None => quote! { self.#field_n }, @@ -436,7 +441,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // List of statements to put in `poll()`. // // We poll each child one by one and wrap around the output. - let poll_stmts = data_struct_fields.iter().enumerate().map(|(field_n, field)| { + let poll_stmts = data_struct.fields.iter().enumerate().map(|(field_n, field)| { let field = field .ident .clone() @@ -447,7 +452,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { } else { quote!{ event } }; - for _ in 0 .. data_struct_fields.len() - 1 - field_n { + for _ in 0 .. data_struct.fields.len() - 1 - field_n { wrapped_event = quote!{ #either_ident::First(#wrapped_event) }; } @@ -458,7 +463,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { let provided_handler_and_new_handlers = { let mut out_handler = None; - for (f_n, f) in data_struct_fields.iter().enumerate() { + for (f_n, f) in data_struct.fields.iter().enumerate() { let f_name = match f.ident { Some(ref i) => quote! { self.#i }, None => quote! { self.#f_n }, @@ -637,19 +642,3 @@ fn get_meta_items(attr: &syn::Attribute) -> Option> { None } } - -/// Returns true if a field is marked as ignored by the user. -fn is_ignored(field: &syn::Field) -> bool { - for meta_items in field.attrs.iter().filter_map(get_meta_items) { - for meta_item in meta_items { - match meta_item { - syn::NestedMeta::Meta(syn::Meta::Path(ref m)) if m.is_ident("ignore") => { - return true; - } - _ => (), - } - } - } - - false -} diff --git a/swarm-derive/tests/test.rs b/swarm-derive/tests/test.rs index d7b058d2169..dcddb3a6a3f 100644 --- a/swarm-derive/tests/test.rs +++ b/swarm-derive/tests/test.rs @@ -83,8 +83,6 @@ fn three_fields() { ping: libp2p::ping::Ping, identify: libp2p::identify::Identify, kad: libp2p::kad::Kademlia, - #[behaviour(ignore)] - foo: String, } #[allow(dead_code)] @@ -103,30 +101,6 @@ fn three_fields() { } } -#[test] -fn three_fields_non_last_ignored() { - #[allow(dead_code)] - #[derive(NetworkBehaviour)] - struct Foo { - ping: libp2p::ping::Ping, - #[behaviour(ignore)] - identify: String, - kad: libp2p::kad::Kademlia, - } - - #[allow(dead_code)] - #[allow(unreachable_code)] - fn foo() { - let _out_event: ::OutEvent = unimplemented!(); - match _out_event { - FooEvent::Ping(libp2p::ping::Event { .. }) => {} - FooEvent::Kad(event) => { - let _: libp2p::kad::KademliaEvent = event; - } - } - } -} - #[test] fn custom_event() { #[allow(dead_code)] @@ -359,28 +333,6 @@ fn custom_event_with_either() { } } -#[test] -fn mixed_field_order() { - struct Foo {} - - #[derive(NetworkBehaviour)] - pub struct Behaviour { - #[behaviour(ignore)] - _foo: Foo, - _ping: libp2p::ping::Ping, - #[behaviour(ignore)] - _foo2: Foo, - _identify: libp2p::identify::Identify, - #[behaviour(ignore)] - _foo3: Foo, - } - - #[allow(dead_code)] - fn behaviour() { - require_net_behaviour::(); - } -} - #[test] fn generated_out_event_derive_debug() { #[allow(dead_code)] diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index acda2cedc27..a5bf0e06f06 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -117,41 +117,6 @@ pub(crate) type THandlerOutEvent = /// } /// } /// ``` -/// -/// Struct members that don't implement [`NetworkBehaviour`] must be annotated with -/// `#[behaviour(ignore)]`. -/// -/// ``` rust -/// # use libp2p::identify::{Identify, IdentifyEvent}; -/// # use libp2p::ping::{Ping, PingEvent}; -/// # use libp2p::NetworkBehaviour; -/// #[derive(NetworkBehaviour)] -/// #[behaviour(out_event = "Event")] -/// struct MyBehaviour { -/// identify: Identify, -/// ping: Ping, -/// -/// #[behaviour(ignore)] -/// some_string: String, -/// } -/// # -/// # enum Event { -/// # Identify(IdentifyEvent), -/// # Ping(PingEvent), -/// # } -/// # -/// # impl From for Event { -/// # fn from(event: IdentifyEvent) -> Self { -/// # Self::Identify(event) -/// # } -/// # } -/// # -/// # impl From for Event { -/// # fn from(event: PingEvent) -> Self { -/// # Self::Ping(event) -/// # } -/// # } -/// ``` pub trait NetworkBehaviour: 'static { /// Handler for all the protocols the network behaviour supports. type ConnectionHandler: IntoConnectionHandler; From e01f77bc49f8977843ebbc9a4e43292ff972d3d2 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Tue, 30 Aug 2022 17:20:41 +1000 Subject: [PATCH 58/92] transports/noise: Migrate away from deprecated `sodiumoxide` for tests (#2817) --- transports/noise/Cargo.toml | 3 ++- transports/noise/src/protocol/x25519.rs | 31 +++++++++++-------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/transports/noise/Cargo.toml b/transports/noise/Cargo.toml index 708b3eb286e..351b8d826d3 100644 --- a/transports/noise/Cargo.toml +++ b/transports/noise/Cargo.toml @@ -33,7 +33,8 @@ async-io = "1.2.0" env_logger = "0.9.0" libp2p-tcp = { path = "../../transports/tcp" } quickcheck = "0.9.0" -sodiumoxide = "0.2.5" +libsodium-sys-stable = { version = "1.19.22", features = ["fetch-latest"] } +ed25519-compact = "1.0.11" [build-dependencies] prost-build = "0.11" diff --git a/transports/noise/src/protocol/x25519.rs b/transports/noise/src/protocol/x25519.rs index bc22dcc70b9..297122c325e 100644 --- a/transports/noise/src/protocol/x25519.rs +++ b/transports/noise/src/protocol/x25519.rs @@ -278,10 +278,13 @@ impl snow::types::Dh for Keypair { #[cfg(test)] mod tests { use super::*; + // Use the ed25519_compact for testing + use ed25519_compact; use libp2p_core::identity::ed25519; + // Use the libsodium-sys-stable crypto_sign imports for testing + use libsodium_sys::crypto_sign_ed25519_pk_to_curve25519; + use libsodium_sys::crypto_sign_ed25519_sk_to_curve25519; use quickcheck::*; - use sodiumoxide::crypto::sign; - use std::os::raw::c_int; use x25519_dalek::StaticSecret; // ed25519 to x25519 keypair conversion must yield the same results as @@ -292,9 +295,11 @@ mod tests { let ed25519 = ed25519::Keypair::generate(); let x25519 = Keypair::from(SecretKey::from_ed25519(&ed25519.secret())); - let sodium_sec = ed25519_sk_to_curve25519(&sign::SecretKey(ed25519.encode())); - let sodium_pub = - ed25519_pk_to_curve25519(&sign::PublicKey(ed25519.public().encode().clone())); + let sodium_sec = + ed25519_sk_to_curve25519(&ed25519_compact::SecretKey::new(ed25519.encode())); + let sodium_pub = ed25519_pk_to_curve25519(&ed25519_compact::PublicKey::new( + ed25519.public().encode().clone(), + )); let our_pub = x25519.public.0; // libsodium does the [clamping] of the scalar upon key construction, @@ -327,18 +332,10 @@ mod tests { quickcheck(prop as fn() -> _); } - // Bindings to libsodium's ed25519 to curve25519 key conversions, to check that - // they agree with the conversions performed in this module. - - extern "C" { - pub fn crypto_sign_ed25519_pk_to_curve25519(c: *mut u8, e: *const u8) -> c_int; - pub fn crypto_sign_ed25519_sk_to_curve25519(c: *mut u8, e: *const u8) -> c_int; - } - - pub fn ed25519_pk_to_curve25519(k: &sign::PublicKey) -> Option<[u8; 32]> { + pub fn ed25519_pk_to_curve25519(k: &ed25519_compact::PublicKey) -> Option<[u8; 32]> { let mut out = [0u8; 32]; unsafe { - if crypto_sign_ed25519_pk_to_curve25519(out.as_mut_ptr(), (&k.0).as_ptr()) == 0 { + if crypto_sign_ed25519_pk_to_curve25519(out.as_mut_ptr(), k.as_ptr()) == 0 { Some(out) } else { None @@ -346,10 +343,10 @@ mod tests { } } - pub fn ed25519_sk_to_curve25519(k: &sign::SecretKey) -> Option<[u8; 32]> { + pub fn ed25519_sk_to_curve25519(k: &ed25519_compact::SecretKey) -> Option<[u8; 32]> { let mut out = [0u8; 32]; unsafe { - if crypto_sign_ed25519_sk_to_curve25519(out.as_mut_ptr(), (&k.0).as_ptr()) == 0 { + if crypto_sign_ed25519_sk_to_curve25519(out.as_mut_ptr(), k.as_ptr()) == 0 { Some(out) } else { None From f16561c9600464c5e04bf98d0a5c0da4fa07d835 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Tue, 30 Aug 2022 17:48:26 +1000 Subject: [PATCH 59/92] .github/workflows: Split advisory issues from PR workflows using `cargo-deny` (#2803) --- .github/workflows/cargo-audit.yml | 9 +- .github/workflows/cargo-deny-pr.yml | 22 +++++ deny.toml | 144 ++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/cargo-deny-pr.yml create mode 100644 deny.toml diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml index 0a39eb0dc96..2b5abe19292 100644 --- a/.github/workflows/cargo-audit.yml +++ b/.github/workflows/cargo-audit.yml @@ -2,14 +2,7 @@ name: cargo audit on: schedule: - cron: '0 0 * * *' - push: - paths: - - '**/Cargo.toml' - - '**/Cargo.lock' - pull_request: - paths: - - '**/Cargo.toml' - - '**/Cargo.lock' + jobs: audit: runs-on: ubuntu-latest diff --git a/.github/workflows/cargo-deny-pr.yml b/.github/workflows/cargo-deny-pr.yml new file mode 100644 index 00000000000..16b16d16a65 --- /dev/null +++ b/.github/workflows/cargo-deny-pr.yml @@ -0,0 +1,22 @@ +name: cargo deny +on: + push: + paths: + - '**/Cargo.toml' + pull_request: + paths: + - '**/Cargo.toml' +jobs: + cargo-deny: + runs-on: ubuntu-latest + strategy: + matrix: + checks: + - advisories + - bans licenses sources + + steps: + - uses: actions/checkout@v3 + - uses: EmbarkStudios/cargo-deny-action@v1 + with: + command: check ${{ matrix.checks }} diff --git a/deny.toml b/deny.toml new file mode 100644 index 00000000000..6634887128e --- /dev/null +++ b/deny.toml @@ -0,0 +1,144 @@ +# This section is considered when running `cargo deny check advisories` +# More documentation for the advisories section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html +[advisories] +# The path where the advisory database is cloned/fetched into +db-path = "~/cargo/advisory-db" +# The url of the advisory database to use +db-urls = [ "https://github.com/rustsec/advisory-db" ] +# The lint level for security vulnerabilities +vulnerability = "deny" +# The lint level for unmaintained crates +unmaintained = "warn" +# The lint level for crates that have been yanked from their source registry +yanked = "warn" +# The lint level for crates with security notices. Note that as of +# 2019-12-17 there are no security notice advisories in +# https://github.com/rustsec/advisory-db +notice = "warn" +# A list of advisory IDs to ignore. Note that ignored advisories will still +# output a note when they are encountered. +ignore = [ + #"RUSTSEC-0000-0000", +] +# Threshold for security vulnerabilities, any vulnerability with a CVSS score +# lower than the range specified will be ignored. Note that ignored advisories +# will still output a note when they are encountered. +# * None - CVSS Score 0.0 +# * Low - CVSS Score 0.1 - 3.9 +# * Medium - CVSS Score 4.0 - 6.9 +# * High - CVSS Score 7.0 - 8.9 +# * Critical - CVSS Score 9.0 - 10.0 +#severity-threshold = + +# This section is considered when running `cargo deny check licenses` +# More documentation for the licenses section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html +[licenses] +# The lint level for crates which do not have a detectable license +unlicensed = "deny" +# List of explictly allowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.7 short identifier (+ optional exception)]. +allow = [ + "Apache-2.0", + "BSD-2-Clause", + "MIT", + "Unlicense", +] +# List of explictly disallowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.7 short identifier (+ optional exception)]. +deny = [] +# Lint level for licenses considered copyleft +copyleft = "allow" +# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses +# * both - The license will be approved if it is both OSI-approved *AND* FSF +# * either - The license will be approved if it is either OSI-approved *OR* FSF +# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF +# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved +# * neither - This predicate is ignored and the default lint level is used +allow-osi-fsf-free = "both" +# Lint level used when no other predicates are matched +# 1. License isn't in the allow or deny lists +# 2. License isn't copyleft +# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither" +default = "deny" +# The confidence threshold for detecting a license from license text. +# The higher the value, the more closely the license text must be to the +# canonical license text of a valid SPDX license file. +# [possible values: any between 0.0 and 1.0]. +confidence-threshold = 0.8 +# Allow 1 or more licenses on a per-crate basis, so that particular licenses +# aren't accepted for every possible crate as with the normal allow list +exceptions = [ + # OpenSSL is Apache License v2.0 (ASL v2) + # https://www.openssl.org/blog/blog/2017/03/22/license/ + # ring crate is ISC & MIT + { allow = ["ISC", "MIT", "OpenSSL"], name = "ring" }, + # libp2p is not re-distributing unicode tables data by itself + { allow = ["MIT", "Apache-2.0", "Unicode-DFS-2016"], name = "unicode-ident" }, +] + +# Some crates don't have (easily) machine readable licensing information, +# adding a clarification entry for it allows you to manually specify the +# licensing information +[[licenses.clarify]] +name = "ring" +expression = "ISC AND MIT AND OpenSSL" +license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }] + +[licenses.private] +# If true, ignores workspace crates that aren't published, or are only +# published to private registries +ignore = false +# One or more private registries that you might publish crates to, if a crate +# is only published to private registries, and ignore is true, the crate will +# not have its license(s) checked +#registries = [ +#] + +# This section is considered when running `cargo deny check bans`. +# More documentation about the 'bans' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html +[bans] +# Lint level for when multiple versions of the same crate are detected +multiple-versions = "warn" +# The graph highlighting used when creating dotgraphs for crates +# with multiple versions +# * lowest-version - The path to the lowest versioned duplicate is highlighted +# * simplest-path - The path to the version with the fewest edges is highlighted +# * all - Both lowest-version and simplest-path are used +highlight = "all" +# List of crates that are allowed. Use with care! +#allow = [ +#] +# List of crates to deny +#deny = [ +#] +# Certain crates/versions that will be skipped when doing duplicate detection. +#skip = [ +#] +# Similarly to `skip` allows you to skip certain crates during duplicate +# detection. Unlike skip, it also includes the entire tree of transitive +# dependencies starting at the specified crate, up to a certain depth, which is +# by default infinite +#skip-tree = [ +#] + +# This section is considered when running `cargo deny check sources`. +# More documentation about the 'sources' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html +[sources] +# Lint level for what to happen when a crate from a crate registry that is not +# in the allow list is encountered +unknown-registry = "deny" +# Lint level for what to happen when a crate from a git repository that is not +# in the allow list is encountered +unknown-git = "deny" +# List of URLs for allowed crate registries. Defaults to the crates.io index +# if not specified. If it is specified but empty, no registries are allowed. +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +# List of URLs for allowed Git repositories +#allow-git = [ +#] From 36a27738618bfa0e90c285f1d379f078d2572730 Mon Sep 17 00:00:00 2001 From: Divma <26765164+divagant-martian@users.noreply.github.com> Date: Tue, 30 Aug 2022 03:03:54 -0500 Subject: [PATCH 60/92] *: Update changelogs for prost dep update (#2851) --- core/CHANGELOG.md | 3 +++ protocols/autonat/CHANGELOG.md | 5 +++++ protocols/dcutr/CHANGELOG.md | 4 ++++ protocols/floodsub/CHANGELOG.md | 5 +++++ protocols/gossipsub/CHANGELOG.md | 4 ++++ protocols/identify/CHANGELOG.md | 4 ++++ protocols/kad/CHANGELOG.md | 5 +++++ protocols/relay/CHANGELOG.md | 4 ++++ protocols/rendezvous/CHANGELOG.md | 5 +++++ transports/noise/CHANGELOG.md | 5 +++++ transports/plaintext/CHANGELOG.md | 5 +++++ 11 files changed, 49 insertions(+) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 1626a471e03..8e3bd24906b 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -6,6 +6,8 @@ # 0.35.0 +- Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. + Thus you will need protoc installed locally. See [PR 2788]. - Drop `Unpin` requirement from `SubstreamBox`. See [PR 2762] and [PR 2776]. - Drop `Sync` requirement on `StreamMuxer` for constructing `StreamMuxerBox`. See [PR 2775]. - Use `Pin<&mut Self>` as the receiver type for all `StreamMuxer` poll functions. See [PR 2765]. @@ -19,6 +21,7 @@ [PR 2776]: https://github.com/libp2p/rust-libp2p/pull/2776 [PR 2765]: https://github.com/libp2p/rust-libp2p/pull/2765 [PR 2797]: https://github.com/libp2p/rust-libp2p/pull/2797 +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788 # 0.34.0 diff --git a/protocols/autonat/CHANGELOG.md b/protocols/autonat/CHANGELOG.md index f6c4b9d619c..da0fa1bd1f7 100644 --- a/protocols/autonat/CHANGELOG.md +++ b/protocols/autonat/CHANGELOG.md @@ -6,12 +6,17 @@ # 0.6.0 +- Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. + Thus you will need protoc installed locally. See [PR 2788]. + - Update to `libp2p-swarm` `v0.38.0`. - Update to `libp2p-request-response` `v0.20.0`. - Update to `libp2p-core` `v0.35.0`. +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788 + # 0.5.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/dcutr/CHANGELOG.md b/protocols/dcutr/CHANGELOG.md index a572d84bcf0..16258919748 100644 --- a/protocols/dcutr/CHANGELOG.md +++ b/protocols/dcutr/CHANGELOG.md @@ -10,6 +10,9 @@ # 0.5.0 +- Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. + Thus you will need protoc installed locally. See [PR 2788]. + - Update to `libp2p-swarm` `v0.38.0`. - Expose `PROTOCOL_NAME`. See [PR 2734]. @@ -17,6 +20,7 @@ - Update to `libp2p-core` `v0.35.0`. [PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788 # 0.4.0 diff --git a/protocols/floodsub/CHANGELOG.md b/protocols/floodsub/CHANGELOG.md index cbe061e6959..9f8ea64c43c 100644 --- a/protocols/floodsub/CHANGELOG.md +++ b/protocols/floodsub/CHANGELOG.md @@ -4,10 +4,15 @@ # 0.38.0 +- Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. + Thus you will need protoc installed locally. See [PR 2788]. + - Update to `libp2p-swarm` `v0.38.0`. - Update to `libp2p-core` `v0.35.0`. +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788 + # 0.37.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index dad83493795..48993c987fb 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -4,6 +4,9 @@ # 0.40.0 +- Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. + Thus you will need protoc installed locally. See [PR 2788]. + - Update to `libp2p-swarm` `v0.38.0`. - Update to `libp2p-core` `v0.35.0`. @@ -11,6 +14,7 @@ - Update to `prometheus-client` `v0.18.0`. See [PR 2822]. [PR 2822]: https://github.com/libp2p/rust-libp2p/pull/2761/ +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788 # 0.39.0 diff --git a/protocols/identify/CHANGELOG.md b/protocols/identify/CHANGELOG.md index 47af0838ae8..596e6dcb0eb 100644 --- a/protocols/identify/CHANGELOG.md +++ b/protocols/identify/CHANGELOG.md @@ -4,12 +4,16 @@ # 0.38.0 +- Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. + Thus you will need protoc installed locally. See [PR 2788]. + - Update to `libp2p-swarm` `v0.38.0`. - Expose `PROTOCOL_NAME` and `PUSH_PROTOCOL_NAME`. See [PR 2734]. - Update to `libp2p-core` `v0.35.0`. +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788 [PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ # 0.37.0 diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 4fef2057008..380604b0b66 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -4,10 +4,15 @@ # 0.39.0 +- Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. + Thus you will need protoc installed locally. See [PR 2788]. + - Update to `libp2p-swarm` `v0.38.0`. - Update to `libp2p-core` `v0.35.0`. +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788 + # 0.38.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/protocols/relay/CHANGELOG.md b/protocols/relay/CHANGELOG.md index e02a3ef8b82..d6245cd5c45 100644 --- a/protocols/relay/CHANGELOG.md +++ b/protocols/relay/CHANGELOG.md @@ -4,6 +4,9 @@ # 0.11.0 +- Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. + Thus you will need protoc installed locally. See [PR 2788]. + - Update to `libp2p-swarm` `v0.38.0`. - Expose `HOP_PROTOCOL_NAME` and `STOP_PROTOCOL_NAME`. See [PR 2734]. @@ -11,6 +14,7 @@ - Update to `libp2p-core` `v0.35.0`. [PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/ +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788 # 0.10.0 diff --git a/protocols/rendezvous/CHANGELOG.md b/protocols/rendezvous/CHANGELOG.md index f2ba00df164..cadc355e407 100644 --- a/protocols/rendezvous/CHANGELOG.md +++ b/protocols/rendezvous/CHANGELOG.md @@ -4,10 +4,15 @@ # 0.8.0 +- Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. + Thus you will need protoc installed locally. See [PR 2788]. + - Update to `libp2p-swarm` `v0.38.0`. - Update to `libp2p-core` `v0.35.0`. +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788 + # 0.7.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/transports/noise/CHANGELOG.md b/transports/noise/CHANGELOG.md index 7a1db66d1b1..f17fc29616e 100644 --- a/transports/noise/CHANGELOG.md +++ b/transports/noise/CHANGELOG.md @@ -1,7 +1,12 @@ # 0.38.0 +- Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. + Thus you will need protoc installed locally. See [PR 2788]. + - Update to `libp2p-core` `v0.35.0`. +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788 + # 0.37.0 - Update to `libp2p-core` `v0.34.0`. diff --git a/transports/plaintext/CHANGELOG.md b/transports/plaintext/CHANGELOG.md index b70d3c5787f..9eb4d5551be 100644 --- a/transports/plaintext/CHANGELOG.md +++ b/transports/plaintext/CHANGELOG.md @@ -1,7 +1,12 @@ # 0.35.0 +- Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. + Thus you will need protoc installed locally. See [PR 2788]. + - Update to `libp2p-core` `v0.35.0`. +[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788 + # 0.34.0 - Update to `libp2p-core` `v0.34.0`. From 89f898c69f6e58944e746565c3f8f8a3bbf3324e Mon Sep 17 00:00:00 2001 From: Yolier Galan Tasse Date: Thu, 1 Sep 2022 23:53:38 -0400 Subject: [PATCH 61/92] protocols/mdns: Allow users to choose between async-io and tokio runtime (#2748) Allow users to choose between async-io and tokio runtime in the mdns protocol implementation. `async-io` is a default feature, with an additional `tokio` feature. Fix high CPU usage with Tokio library. --- Cargo.toml | 9 +- examples/chat-tokio.rs | 14 +- protocols/mdns/CHANGELOG.md | 8 + protocols/mdns/Cargo.toml | 23 ++- protocols/mdns/src/behaviour.rs | 43 +++-- protocols/mdns/src/behaviour/iface.rs | 103 ++++++------ protocols/mdns/src/behaviour/socket.rs | 134 +++++++++++++++ protocols/mdns/src/behaviour/timer.rs | 128 +++++++++++++++ protocols/mdns/src/lib.rs | 12 +- .../mdns/tests/{smoke.rs => use-async-std.rs} | 86 ++++------ protocols/mdns/tests/use-tokio.rs | 153 ++++++++++++++++++ src/lib.rs | 7 +- 12 files changed, 590 insertions(+), 130 deletions(-) create mode 100644 protocols/mdns/src/behaviour/socket.rs create mode 100644 protocols/mdns/src/behaviour/timer.rs rename protocols/mdns/tests/{smoke.rs => use-async-std.rs} (87%) create mode 100644 protocols/mdns/tests/use-tokio.rs diff --git a/Cargo.toml b/Cargo.toml index b64c2f68756..7249e70cb4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ default = [ "identify", "kad", "gossipsub", - "mdns", + "mdns-async-io", "mplex", "noise", "ping", @@ -46,7 +46,8 @@ identify = ["dep:libp2p-identify", "libp2p-metrics?/identify"] kad = ["dep:libp2p-kad", "libp2p-metrics?/kad"] gossipsub = ["dep:libp2p-gossipsub", "libp2p-metrics?/gossipsub"] metrics = ["dep:libp2p-metrics"] -mdns = ["dep:libp2p-mdns"] +mdns-async-io = ["dep:libp2p-mdns", "libp2p-mdns?/async-io"] +mdns-tokio = ["dep:libp2p-mdns", "libp2p-mdns?/tokio"] mplex = ["dep:libp2p-mplex"] noise = ["dep:libp2p-noise"] ping = ["dep:libp2p-ping", "libp2p-metrics?/ping"] @@ -106,7 +107,7 @@ smallvec = "1.6.1" [target.'cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))'.dependencies] libp2p-deflate = { version = "0.35.0", path = "transports/deflate", optional = true } libp2p-dns = { version = "0.35.0", path = "transports/dns", optional = true, default-features = false } -libp2p-mdns = { version = "0.40.0", path = "protocols/mdns", optional = true } +libp2p-mdns = { version = "0.40.0", path = "protocols/mdns", optional = true, default-features = false } libp2p-tcp = { version = "0.35.0", path = "transports/tcp", default-features = false, optional = true } libp2p-websocket = { version = "0.37.0", path = "transports/websocket", optional = true } @@ -160,7 +161,7 @@ required-features = ["floodsub"] [[example]] name = "chat-tokio" -required-features = ["tcp-tokio", "mdns"] +required-features = ["tcp-tokio", "mdns-tokio"] [[example]] name = "file-sharing" diff --git a/examples/chat-tokio.rs b/examples/chat-tokio.rs index 0bd44bdabdc..f82d30934c9 100644 --- a/examples/chat-tokio.rs +++ b/examples/chat-tokio.rs @@ -25,7 +25,7 @@ //! The example is run per node as follows: //! //! ```sh -//! cargo run --example chat-tokio --features="tcp-tokio mdns" +//! cargo run --example chat-tokio --features="tcp-tokio mdns-tokio" //! ``` //! //! Alternatively, to run with the minimal set of features and crates: @@ -33,7 +33,7 @@ //! ```sh //!cargo run --example chat-tokio \\ //! --no-default-features \\ -//! --features="floodsub mplex noise tcp-tokio mdns" +//! --features="floodsub mplex noise tcp-tokio mdns-tokio" //! ``` use futures::StreamExt; @@ -41,7 +41,11 @@ use libp2p::{ core::upgrade, floodsub::{self, Floodsub, FloodsubEvent}, identity, - mdns::{Mdns, MdnsEvent}, + mdns::{ + MdnsEvent, + // `TokioMdns` is available through the `mdns-tokio` feature. + TokioMdns, + }, mplex, noise, swarm::{SwarmBuilder, SwarmEvent}, @@ -88,7 +92,7 @@ async fn main() -> Result<(), Box> { #[behaviour(out_event = "MyBehaviourEvent")] struct MyBehaviour { floodsub: Floodsub, - mdns: Mdns, + mdns: TokioMdns, } #[allow(clippy::large_enum_variant)] @@ -111,7 +115,7 @@ async fn main() -> Result<(), Box> { // Create a Swarm to manage peers and events. let mut swarm = { - let mdns = Mdns::new(Default::default()).await?; + let mdns = TokioMdns::new(Default::default()).await?; let mut behaviour = MyBehaviour { floodsub: Floodsub::new(peer_id), mdns, diff --git a/protocols/mdns/CHANGELOG.md b/protocols/mdns/CHANGELOG.md index a6b05044fa5..4a22bdb1c3f 100644 --- a/protocols/mdns/CHANGELOG.md +++ b/protocols/mdns/CHANGELOG.md @@ -2,6 +2,14 @@ - Update to `libp2p-swarm` `v0.39.0`. +- Allow users to choose between async-io and tokio runtime + in the mdns protocol implementation. `async-io` is a default + feature, with an additional `tokio` feature (see [PR 2748]) + +- Fix high CPU usage with Tokio library (see [PR 2748]). + +[PR 2748]: https://github.com/libp2p/rust-libp2p/pull/2748 + # 0.39.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/mdns/Cargo.toml b/protocols/mdns/Cargo.toml index 306f052cc69..10883a82ec0 100644 --- a/protocols/mdns/Cargo.toml +++ b/protocols/mdns/Cargo.toml @@ -11,7 +11,6 @@ keywords = ["peer-to-peer", "libp2p", "networking"] categories = ["network-programming", "asynchronous"] [dependencies] -async-io = "1.3.1" data-encoding = "2.3.2" dns-parser = "0.8.0" futures = "0.3.13" @@ -25,8 +24,26 @@ smallvec = "1.6.1" socket2 = { version = "0.4.0", features = ["all"] } void = "1.0.2" +async-io = { version = "1.3.1", optional = true } +tokio = { version = "1.19", default-features = false, features = ["net", "time"], optional = true} + +[features] +default = ["async-io"] +tokio = ["dep:tokio"] +async-io = ["dep:async-io"] + [dev-dependencies] async-std = { version = "1.9.0", features = ["attributes"] } env_logger = "0.9.0" -libp2p = { path = "../..", default-features = false, features = ["mdns", "tcp-async-io", "dns-async-std", "websocket", "noise", "mplex", "yamux"] } -tokio = { version = "1.15", default-features = false, features = ["macros", "rt", "rt-multi-thread", "time"] } +libp2p = { path = "../..", default-features = false, features = ["mdns-async-io", "tcp-async-io", "dns-async-std", "tcp-tokio", "dns-tokio", "websocket", "noise", "mplex", "yamux"] } +tokio = { version = "1.19", default-features = false, features = ["macros", "rt", "rt-multi-thread", "time"] } + + +[[test]] +name = "use-async-std" +required-features = ["async-io"] + +[[test]] +name = "use-tokio" +required-features = ["tokio"] + diff --git a/protocols/mdns/src/behaviour.rs b/protocols/mdns/src/behaviour.rs index 244b2b784dd..854bd885a22 100644 --- a/protocols/mdns/src/behaviour.rs +++ b/protocols/mdns/src/behaviour.rs @@ -19,11 +19,14 @@ // DEALINGS IN THE SOFTWARE. mod iface; +mod socket; +mod timer; use self::iface::InterfaceState; +use crate::behaviour::{socket::AsyncSocket, timer::Builder}; use crate::MdnsConfig; -use async_io::Timer; use futures::prelude::*; +use futures::Stream; use if_watch::{IfEvent, IfWatcher}; use libp2p_core::transport::ListenerId; use libp2p_core::{Multiaddr, PeerId}; @@ -35,10 +38,24 @@ use smallvec::SmallVec; use std::collections::hash_map::{Entry, HashMap}; use std::{cmp, fmt, io, net::IpAddr, pin::Pin, task::Context, task::Poll, time::Instant}; +#[cfg(feature = "async-io")] +use crate::behaviour::{socket::asio::AsyncUdpSocket, timer::asio::AsyncTimer}; + +/// The type of a [`GenMdns`] using the `async-io` implementation. +#[cfg(feature = "async-io")] +pub type Mdns = GenMdns; + +#[cfg(feature = "tokio")] +use crate::behaviour::{socket::tokio::TokioUdpSocket, timer::tokio::TokioTimer}; + +/// The type of a [`GenMdns`] using the `tokio` implementation. +#[cfg(feature = "tokio")] +pub type TokioMdns = GenMdns; + /// A `NetworkBehaviour` for mDNS. Automatically discovers peers on the local network and adds /// them to the topology. #[derive(Debug)] -pub struct Mdns { +pub struct GenMdns { /// InterfaceState config. config: MdnsConfig, @@ -46,7 +63,7 @@ pub struct Mdns { if_watch: IfWatcher, /// Mdns interface states. - iface_states: HashMap, + iface_states: HashMap>, /// List of nodes that we have discovered, the address, and when their TTL expires. /// @@ -57,10 +74,13 @@ pub struct Mdns { /// Future that fires when the TTL of at least one node in `discovered_nodes` expires. /// /// `None` if `discovered_nodes` is empty. - closest_expiration: Option, + closest_expiration: Option, } -impl Mdns { +impl GenMdns +where + T: Builder, +{ /// Builds a new `Mdns` behaviour. pub async fn new(config: MdnsConfig) -> io::Result { let if_watch = if_watch::IfWatcher::new().await?; @@ -91,11 +111,15 @@ impl Mdns { *expires = now; } } - self.closest_expiration = Some(Timer::at(now)); + self.closest_expiration = Some(T::at(now)); } } -impl NetworkBehaviour for Mdns { +impl NetworkBehaviour for GenMdns +where + T: Builder + Stream, + S: AsyncSocket, +{ type ConnectionHandler = DummyConnectionHandler; type OutEvent = MdnsEvent; @@ -219,8 +243,9 @@ impl NetworkBehaviour for Mdns { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event)); } if let Some(closest_expiration) = closest_expiration { - let mut timer = Timer::at(closest_expiration); - let _ = Pin::new(&mut timer).poll(cx); + let mut timer = T::at(closest_expiration); + let _ = Pin::new(&mut timer).poll_next(cx); + self.closest_expiration = Some(timer); } Poll::Pending diff --git a/protocols/mdns/src/behaviour/iface.rs b/protocols/mdns/src/behaviour/iface.rs index e4971e36b1a..c5bacced138 100644 --- a/protocols/mdns/src/behaviour/iface.rs +++ b/protocols/mdns/src/behaviour/iface.rs @@ -23,9 +23,8 @@ mod query; use self::dns::{build_query, build_query_response, build_service_discovery_response}; use self::query::MdnsPacket; +use crate::behaviour::{socket::AsyncSocket, timer::Builder}; use crate::MdnsConfig; -use async_io::{Async, Timer}; -use futures::prelude::*; use libp2p_core::{address_translation, multiaddr::Protocol, Multiaddr, PeerId}; use libp2p_swarm::PollParameters; use socket2::{Domain, Socket, Type}; @@ -34,20 +33,20 @@ use std::{ io, iter, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket}, pin::Pin, - task::Context, + task::{Context, Poll}, time::{Duration, Instant}, }; /// An mDNS instance for a networking interface. To discover all peers when having multiple /// interfaces an [`InterfaceState`] is required for each interface. #[derive(Debug)] -pub struct InterfaceState { +pub struct InterfaceState { /// Address this instance is bound to. addr: IpAddr, /// Receive socket. - recv_socket: Async, + recv_socket: U, /// Send socket. - send_socket: Async, + send_socket: U, /// Buffer used for receiving data from the main socket. /// RFC6762 discourages packets larger than the interface MTU, but allows sizes of up to 9000 /// bytes, if it can be ensured that all participating devices can handle such large packets. @@ -60,7 +59,7 @@ pub struct InterfaceState { /// Discovery interval. query_interval: Duration, /// Discovery timer. - timeout: Timer, + timeout: T, /// Multicast address. multicast_addr: IpAddr, /// Discovered addresses. @@ -69,7 +68,11 @@ pub struct InterfaceState { ttl: Duration, } -impl InterfaceState { +impl InterfaceState +where + U: AsyncSocket, + T: Builder + futures::Stream, +{ /// Builds a new [`InterfaceState`]. pub fn new(addr: IpAddr, config: MdnsConfig) -> io::Result { log::info!("creating instance on iface {}", addr); @@ -83,7 +86,7 @@ impl InterfaceState { socket.set_multicast_loop_v4(true)?; socket.set_multicast_ttl_v4(255)?; socket.join_multicast_v4(&*crate::IPV4_MDNS_MULTICAST_ADDRESS, &addr)?; - Async::new(UdpSocket::from(socket))? + U::from_std(UdpSocket::from(socket))? } IpAddr::V6(_) => { let socket = Socket::new(Domain::IPV6, Type::DGRAM, Some(socket2::Protocol::UDP))?; @@ -94,7 +97,7 @@ impl InterfaceState { socket.set_multicast_loop_v6(true)?; // TODO: find interface matching addr. socket.join_multicast_v6(&*crate::IPV6_MDNS_MULTICAST_ADDRESS, 0)?; - Async::new(UdpSocket::from(socket))? + U::from_std(UdpSocket::from(socket))? } }; let bind_addr = match addr { @@ -107,7 +110,8 @@ impl InterfaceState { SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0) } }; - let send_socket = Async::new(UdpSocket::bind(bind_addr)?)?; + let send_socket = U::from_std(UdpSocket::bind(bind_addr)?)?; + // randomize timer to prevent all converging and firing at the same time. let query_interval = { use rand::Rng; @@ -127,19 +131,18 @@ impl InterfaceState { send_buffer: Default::default(), discovered: Default::default(), query_interval, - timeout: Timer::interval_at(Instant::now(), query_interval), + timeout: T::interval_at(Instant::now(), query_interval), multicast_addr, ttl: config.ttl, }) } pub fn reset_timer(&mut self) { - self.timeout.set_interval(self.query_interval); + self.timeout = T::interval(self.query_interval); } pub fn fire_timer(&mut self) { - self.timeout - .set_interval_at(Instant::now(), self.query_interval); + self.timeout = T::interval_at(Instant::now(), self.query_interval); } fn inject_mdns_packet(&mut self, packet: MdnsPacket, params: &impl PollParameters) { @@ -171,17 +174,17 @@ impl InterfaceState { let new_expiration = Instant::now() + peer.ttl(); - let mut addrs: Vec = Vec::new(); for addr in peer.addresses() { if let Some(new_addr) = address_translation(addr, &observed) { - addrs.push(new_addr.clone()) + self.discovered.push_back(( + *peer.id(), + new_addr.clone(), + new_expiration, + )); } - addrs.push(addr.clone()) - } - for addr in addrs { self.discovered - .push_back((*peer.id(), addr, new_expiration)); + .push_back((*peer.id(), addr.clone(), new_expiration)); } } } @@ -198,43 +201,49 @@ impl InterfaceState { params: &impl PollParameters, ) -> Option<(PeerId, Multiaddr, Instant)> { // Poll receive socket. - while self.recv_socket.poll_readable(cx).is_ready() { - match self - .recv_socket - .recv_from(&mut self.recv_buffer) - .now_or_never() - { - Some(Ok((len, from))) => { + while let Poll::Ready(data) = + Pin::new(&mut self.recv_socket).poll_read(cx, &mut self.recv_buffer) + { + match data { + Ok((len, from)) => { if let Some(packet) = MdnsPacket::new_from_bytes(&self.recv_buffer[..len], from) { self.inject_mdns_packet(packet, params); } } - Some(Err(err)) => log::error!("Failed reading datagram: {}", err), - None => {} + Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { + // No more bytes available on the socket to read + break; + } + Err(err) => { + log::error!("failed reading datagram: {}", err); + } } } + // Send responses. - while self.send_socket.poll_writable(cx).is_ready() { - if let Some(packet) = self.send_buffer.pop_front() { - match self - .send_socket - .send_to(&packet, SocketAddr::new(self.multicast_addr, 5353)) - .now_or_never() - { - Some(Ok(_)) => log::trace!("sent packet on iface {}", self.addr), - Some(Err(err)) => { - log::error!("error sending packet on iface {}: {}", self.addr, err) - } - None => self.send_buffer.push_front(packet), + while let Some(packet) = self.send_buffer.pop_front() { + match Pin::new(&mut self.send_socket).poll_write( + cx, + &packet, + SocketAddr::new(self.multicast_addr, 5353), + ) { + Poll::Ready(Ok(_)) => log::trace!("sent packet on iface {}", self.addr), + Poll::Ready(Err(err)) => { + log::error!("error sending packet on iface {} {}", self.addr, err); + } + Poll::Pending => { + self.send_buffer.push_front(packet); + break; } - } else if Pin::new(&mut self.timeout).poll_next(cx).is_ready() { - log::trace!("sending query on iface {}", self.addr); - self.send_buffer.push_back(build_query()); - } else { - break; } } + + if Pin::new(&mut self.timeout).poll_next(cx).is_ready() { + log::trace!("sending query on iface {}", self.addr); + self.send_buffer.push_back(build_query()); + } + // Emit discovered event. self.discovered.pop_front() } diff --git a/protocols/mdns/src/behaviour/socket.rs b/protocols/mdns/src/behaviour/socket.rs new file mode 100644 index 00000000000..4406ed33fde --- /dev/null +++ b/protocols/mdns/src/behaviour/socket.rs @@ -0,0 +1,134 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +use std::{ + io::Error, + marker::Unpin, + net::{SocketAddr, UdpSocket}, + task::{Context, Poll}, +}; + +/// Interface that must be implemented by the different runtimes to use the [`UdpSocket`] in async mode +pub trait AsyncSocket: Unpin + Send + 'static { + /// Create the async socket from the [`std::net::UdpSocket`] + fn from_std(socket: UdpSocket) -> std::io::Result + where + Self: Sized; + + /// Attempts to receive a single packet on the socket from the remote address to which it is connected. + fn poll_read( + &mut self, + _cx: &mut Context, + _buf: &mut [u8], + ) -> Poll>; + + /// Attempts to send data on the socket to a given address. + fn poll_write( + &mut self, + _cx: &mut Context, + _packet: &[u8], + _to: SocketAddr, + ) -> Poll>; +} + +#[cfg(feature = "async-io")] +pub mod asio { + use super::*; + use async_io::Async; + use futures::FutureExt; + + /// AsyncIo UdpSocket + pub type AsyncUdpSocket = Async; + + impl AsyncSocket for AsyncUdpSocket { + fn from_std(socket: UdpSocket) -> std::io::Result { + Async::new(socket) + } + + fn poll_read( + &mut self, + cx: &mut Context, + buf: &mut [u8], + ) -> Poll> { + // Poll receive socket. + futures::ready!(self.poll_readable(cx))?; + match self.recv_from(buf).now_or_never() { + Some(data) => Poll::Ready(data), + None => Poll::Pending, + } + } + + fn poll_write( + &mut self, + cx: &mut Context, + packet: &[u8], + to: SocketAddr, + ) -> Poll> { + futures::ready!(self.poll_writable(cx))?; + match self.send_to(packet, to).now_or_never() { + Some(Ok(_)) => Poll::Ready(Ok(())), + Some(Err(err)) => Poll::Ready(Err(err)), + None => Poll::Pending, + } + } + } +} + +#[cfg(feature = "tokio")] +pub mod tokio { + use super::*; + use ::tokio::{io::ReadBuf, net::UdpSocket as TkUdpSocket}; + + /// Tokio ASync Socket` + pub type TokioUdpSocket = TkUdpSocket; + + impl AsyncSocket for TokioUdpSocket { + fn from_std(socket: UdpSocket) -> std::io::Result { + socket.set_nonblocking(true)?; + TokioUdpSocket::from_std(socket) + } + + fn poll_read( + &mut self, + cx: &mut Context, + buf: &mut [u8], + ) -> Poll> { + let mut rbuf = ReadBuf::new(buf); + match self.poll_recv_from(cx, &mut rbuf) { + Poll::Pending => Poll::Pending, + Poll::Ready(Err(err)) => Poll::Ready(Err(err)), + Poll::Ready(Ok(addr)) => Poll::Ready(Ok((rbuf.filled().len(), addr))), + } + } + + fn poll_write( + &mut self, + cx: &mut Context, + packet: &[u8], + to: SocketAddr, + ) -> Poll> { + match self.poll_send_to(cx, packet, to) { + Poll::Pending => Poll::Pending, + Poll::Ready(Err(err)) => Poll::Ready(Err(err)), + Poll::Ready(Ok(_len)) => Poll::Ready(Ok(())), + } + } + } +} diff --git a/protocols/mdns/src/behaviour/timer.rs b/protocols/mdns/src/behaviour/timer.rs new file mode 100644 index 00000000000..fbdeb065b70 --- /dev/null +++ b/protocols/mdns/src/behaviour/timer.rs @@ -0,0 +1,128 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +use std::{ + marker::Unpin, + pin::Pin, + task::{Context, Poll}, + time::{Duration, Instant}, +}; + +/// Simple wrapper for the differents type of timers +#[derive(Debug)] +pub struct Timer { + inner: T, +} + +/// Builder interface to homogenize the differents implementations +pub trait Builder: Send + Unpin + 'static { + /// Creates a timer that emits an event once at the given time instant. + fn at(instant: Instant) -> Self; + + /// Creates a timer that emits events periodically. + fn interval(duration: Duration) -> Self; + + /// Creates a timer that emits events periodically, starting at start. + fn interval_at(start: Instant, duration: Duration) -> Self; +} + +#[cfg(feature = "async-io")] +pub mod asio { + use super::*; + use async_io::Timer as AsioTimer; + use futures::Stream; + + /// Async Timer + pub type AsyncTimer = Timer; + + impl Builder for AsyncTimer { + fn at(instant: Instant) -> Self { + Self { + inner: AsioTimer::at(instant), + } + } + + fn interval(duration: Duration) -> Self { + Self { + inner: AsioTimer::interval(duration), + } + } + + fn interval_at(start: Instant, duration: Duration) -> Self { + Self { + inner: AsioTimer::interval_at(start, duration), + } + } + } + + impl Stream for AsyncTimer { + type Item = Instant; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.inner).poll_next(cx) + } + } +} + +#[cfg(feature = "tokio")] +pub mod tokio { + use super::*; + use ::tokio::time::{self, Instant as TokioInstant, Interval, MissedTickBehavior}; + use futures::Stream; + + /// Tokio wrapper + pub type TokioTimer = Timer; + + impl Builder for TokioTimer { + fn at(instant: Instant) -> Self { + // Taken from: https://docs.rs/async-io/1.7.0/src/async_io/lib.rs.html#91 + let mut inner = time::interval_at( + TokioInstant::from_std(instant), + Duration::new(std::u64::MAX, 1_000_000_000 - 1), + ); + inner.set_missed_tick_behavior(MissedTickBehavior::Skip); + Self { inner } + } + + fn interval(duration: Duration) -> Self { + let mut inner = time::interval_at(TokioInstant::now() + duration, duration); + inner.set_missed_tick_behavior(MissedTickBehavior::Skip); + Self { inner } + } + + fn interval_at(start: Instant, duration: Duration) -> Self { + let mut inner = time::interval_at(TokioInstant::from_std(start), duration); + inner.set_missed_tick_behavior(MissedTickBehavior::Skip); + Self { inner } + } + } + + impl Stream for TokioTimer { + type Item = TokioInstant; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_tick(cx).map(Some) + } + + fn size_hint(&self) -> (usize, Option) { + (std::usize::MAX, None) + } + } +} diff --git a/protocols/mdns/src/lib.rs b/protocols/mdns/src/lib.rs index a99eab691a2..3b484c91daa 100644 --- a/protocols/mdns/src/lib.rs +++ b/protocols/mdns/src/lib.rs @@ -26,16 +26,22 @@ //! //! # Usage //! -//! This crate provides the `Mdns` struct which implements the `NetworkBehaviour` trait. This -//! struct will automatically discover other libp2p nodes on the local network. +//! This crate provides a `Mdns` and `TokioMdns`, depending on the enabled features, which +//! implements the `NetworkBehaviour` trait. This struct will automatically discover other +//! libp2p nodes on the local network. //! use lazy_static::lazy_static; use std::net::{Ipv4Addr, Ipv6Addr}; use std::time::Duration; mod behaviour; +pub use crate::behaviour::{GenMdns, MdnsEvent}; -pub use crate::behaviour::{Mdns, MdnsEvent}; +#[cfg(feature = "async-io")] +pub use crate::behaviour::Mdns; + +#[cfg(feature = "tokio")] +pub use crate::behaviour::TokioMdns; /// The DNS service name for all libp2p peers used to query for addresses. const SERVICE_NAME: &[u8] = b"_p2p._udp.local"; diff --git a/protocols/mdns/tests/smoke.rs b/protocols/mdns/tests/use-async-std.rs similarity index 87% rename from protocols/mdns/tests/smoke.rs rename to protocols/mdns/tests/use-async-std.rs index d123e5abce7..683aed338ce 100644 --- a/protocols/mdns/tests/smoke.rs +++ b/protocols/mdns/tests/use-async-std.rs @@ -28,6 +28,35 @@ use libp2p::{ use std::error::Error; use std::time::Duration; +#[async_std::test] +async fn test_discovery_async_std_ipv4() -> Result<(), Box> { + run_discovery_test(MdnsConfig::default()).await +} + +#[async_std::test] +async fn test_discovery_async_std_ipv6() -> Result<(), Box> { + let config = MdnsConfig { + enable_ipv6: true, + ..Default::default() + }; + run_discovery_test(config).await +} + +#[async_std::test] +async fn test_expired_async_std() -> Result<(), Box> { + env_logger::try_init().ok(); + let config = MdnsConfig { + ttl: Duration::from_secs(1), + query_interval: Duration::from_secs(10), + ..Default::default() + }; + + async_std::future::timeout(Duration::from_secs(6), run_peer_expiration_test(config)) + .await + .map(|_| ()) + .map_err(|e| Box::new(e) as Box) +} + async fn create_swarm(config: MdnsConfig) -> Result, Box> { let id_keys = identity::Keypair::generate_ed25519(); let peer_id = PeerId::from(id_keys.public()); @@ -78,34 +107,6 @@ async fn run_discovery_test(config: MdnsConfig) -> Result<(), Box> { } } -#[async_std::test] -async fn test_discovery_async_std_ipv4() -> Result<(), Box> { - run_discovery_test(MdnsConfig::default()).await -} - -#[tokio::test] -async fn test_discovery_tokio_ipv4() -> Result<(), Box> { - run_discovery_test(MdnsConfig::default()).await -} - -#[async_std::test] -async fn test_discovery_async_std_ipv6() -> Result<(), Box> { - let config = MdnsConfig { - enable_ipv6: true, - ..Default::default() - }; - run_discovery_test(config).await -} - -#[tokio::test] -async fn test_discovery_tokio_ipv6() -> Result<(), Box> { - let config = MdnsConfig { - enable_ipv6: true, - ..Default::default() - }; - run_discovery_test(config).await -} - async fn run_peer_expiration_test(config: MdnsConfig) -> Result<(), Box> { let mut a = create_swarm(config.clone()).await?; let mut b = create_swarm(config).await?; @@ -136,32 +137,3 @@ async fn run_peer_expiration_test(config: MdnsConfig) -> Result<(), Box Result<(), Box> { - env_logger::try_init().ok(); - let config = MdnsConfig { - ttl: Duration::from_secs(1), - query_interval: Duration::from_secs(10), - ..Default::default() - }; - - async_std::future::timeout(Duration::from_secs(6), run_peer_expiration_test(config)) - .await - .map(|_| ()) - .map_err(|e| Box::new(e) as Box) -} - -#[tokio::test] -async fn test_expired_tokio() -> Result<(), Box> { - env_logger::try_init().ok(); - let config = MdnsConfig { - ttl: Duration::from_secs(1), - query_interval: Duration::from_secs(10), - ..Default::default() - }; - - tokio::time::timeout(Duration::from_secs(6), run_peer_expiration_test(config)) - .await - .unwrap() -} diff --git a/protocols/mdns/tests/use-tokio.rs b/protocols/mdns/tests/use-tokio.rs new file mode 100644 index 00000000000..9d6cacd76cb --- /dev/null +++ b/protocols/mdns/tests/use-tokio.rs @@ -0,0 +1,153 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE.use futures::StreamExt; +use futures::StreamExt; +use libp2p::{ + identity, + mdns::{MdnsConfig, MdnsEvent, TokioMdns}, + swarm::{Swarm, SwarmEvent}, + PeerId, +}; +use std::error::Error; +use std::time::Duration; + +#[tokio::test] +async fn test_discovery_tokio_ipv4() -> Result<(), Box> { + run_discovery_test(MdnsConfig::default()).await +} + +#[tokio::test] +async fn test_discovery_tokio_ipv6() -> Result<(), Box> { + let config = MdnsConfig { + enable_ipv6: true, + ..Default::default() + }; + run_discovery_test(config).await +} + +#[tokio::test] +async fn test_expired_tokio() -> Result<(), Box> { + env_logger::try_init().ok(); + let config = MdnsConfig { + ttl: Duration::from_secs(1), + query_interval: Duration::from_secs(10), + ..Default::default() + }; + + run_peer_expiration_test(config).await +} + +async fn create_swarm(config: MdnsConfig) -> Result, Box> { + let id_keys = identity::Keypair::generate_ed25519(); + let peer_id = PeerId::from(id_keys.public()); + let transport = libp2p::tokio_development_transport(id_keys)?; + let behaviour = TokioMdns::new(config).await?; + let mut swarm = Swarm::new(transport, behaviour, peer_id); + swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; + Ok(swarm) +} + +async fn run_discovery_test(config: MdnsConfig) -> Result<(), Box> { + env_logger::try_init().ok(); + let mut a = create_swarm(config.clone()).await?; + let mut b = create_swarm(config).await?; + let mut discovered_a = false; + let mut discovered_b = false; + loop { + futures::select! { + ev = a.select_next_some() => match ev { + SwarmEvent::Behaviour(MdnsEvent::Discovered(peers)) => { + for (peer, _addr) in peers { + if peer == *b.local_peer_id() { + if discovered_a { + return Ok(()); + } else { + discovered_b = true; + } + } + } + } + _ => {} + }, + ev = b.select_next_some() => match ev { + SwarmEvent::Behaviour(MdnsEvent::Discovered(peers)) => { + for (peer, _addr) in peers { + if peer == *a.local_peer_id() { + if discovered_b { + return Ok(()); + } else { + discovered_a = true; + } + } + } + } + _ => {} + } + } + } +} + +async fn run_peer_expiration_test(config: MdnsConfig) -> Result<(), Box> { + let mut a = create_swarm(config.clone()).await?; + let mut b = create_swarm(config).await?; + let expired_at = tokio::time::sleep(Duration::from_secs(15)); + tokio::pin!(expired_at); + + loop { + tokio::select! { + _ev = &mut expired_at => { + panic!(); + }, + ev = a.select_next_some() => match ev { + SwarmEvent::Behaviour(MdnsEvent::Expired(peers)) => { + for (peer, _addr) in peers { + if peer == *b.local_peer_id() { + return Ok(()); + } + } + } + SwarmEvent::Behaviour(MdnsEvent::Discovered(peers)) => { + for (peer, _addr) in peers { + if peer == *b.local_peer_id() { + expired_at.as_mut().reset(tokio::time::Instant::now() + tokio::time::Duration::from_secs(2)); + } + } + } + _ => {} + }, + ev = b.select_next_some() => match ev { + SwarmEvent::Behaviour(MdnsEvent::Expired(peers)) => { + for (peer, _addr) in peers { + if peer == *a.local_peer_id() { + return Ok(()); + } + } + } + SwarmEvent::Behaviour(MdnsEvent::Discovered(peers)) => { + for (peer, _addr) in peers { + if peer == *a.local_peer_id() { + expired_at.as_mut().reset(tokio::time::Instant::now() + tokio::time::Duration::from_secs(2)); + } + } + } + _ => {} + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 6bb577b1f52..3ed00408cb5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,8 +79,11 @@ pub use libp2p_identify as identify; #[cfg_attr(docsrs, doc(cfg(feature = "kad")))] #[doc(inline)] pub use libp2p_kad as kad; -#[cfg(feature = "mdns")] -#[cfg_attr(docsrs, doc(cfg(feature = "mdns")))] +#[cfg(any(feature = "mdns-async-io", feature = "mdns-tokio"))] +#[cfg_attr( + docsrs, + doc(cfg(any(feature = "mdns-tokio", feature = "mdns-async-io"))) +)] #[cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))] #[doc(inline)] pub use libp2p_mdns as mdns; From cee199afca2edb3451fea0869cca17670c394650 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Sat, 3 Sep 2022 03:46:50 +0300 Subject: [PATCH 62/92] protocols/kad: Support multiple protocol names (#2846) Add support for multiple Kademlia protocol names to allow protocol name upgrades. --- protocols/kad/CHANGELOG.md | 6 ++++++ protocols/kad/src/behaviour.rs | 22 ++++++++++++++++++---- protocols/kad/src/protocol.rs | 23 +++++++++++++++-------- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 380604b0b66..01778047583 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -1,7 +1,13 @@ # 0.40.0 [unreleased] +- Add support for multiple protocol names. Update `Kademlia`, `KademliaConfig`, + and `KademliaProtocolConfig` accordingly. See [Issue 2837]. See [PR 2846]. + - Update to `libp2p-swarm` `v0.39.0`. +[Issue 2837]: https://github.com/libp2p/rust-libp2p/issues/2837 +[PR 2846]: https://github.com/libp2p/rust-libp2p/pull/2846 + # 0.39.0 - Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index f40932ad0d3..feba94f550e 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -214,14 +214,28 @@ impl Default for KademliaConfig { } impl KademliaConfig { + /// Sets custom protocol names. + /// + /// Kademlia nodes only communicate with other nodes using the same protocol + /// name. Using custom name(s) therefore allows to segregate the DHT from + /// others, if that is desired. + /// + /// More than one protocol name can be supplied. In this case the node will + /// be able to talk to other nodes supporting any of the provided names. + /// Multiple names must be used with caution to avoid network partitioning. + pub fn set_protocol_names(&mut self, names: Vec>) -> &mut Self { + self.protocol_config.set_protocol_names(names); + self + } + /// Sets a custom protocol name. /// /// Kademlia nodes only communicate with other nodes using the same protocol /// name. Using a custom name therefore allows to segregate the DHT from /// others, if that is desired. + #[deprecated(since = "0.40.0", note = "use `set_protocol_names()` instead")] pub fn set_protocol_name(&mut self, name: impl Into>) -> &mut Self { - self.protocol_config.set_protocol_name(name); - self + self.set_protocol_names(std::iter::once(name.into()).collect()) } /// Sets the timeout for a single query. @@ -403,8 +417,8 @@ where } /// Get the protocol name of this kademlia instance. - pub fn protocol_name(&self) -> &[u8] { - self.protocol_config.protocol_name() + pub fn protocol_names(&self) -> &[Cow<'static, [u8]>] { + self.protocol_config.protocol_names() } /// Creates a new `Kademlia` network behaviour with the given configuration. diff --git a/protocols/kad/src/protocol.rs b/protocols/kad/src/protocol.rs index 656917b54f6..3c00a5059f2 100644 --- a/protocols/kad/src/protocol.rs +++ b/protocols/kad/src/protocol.rs @@ -142,21 +142,28 @@ impl From for proto::message::Peer { // `OutboundUpgrade` to be just a single message #[derive(Debug, Clone)] pub struct KademliaProtocolConfig { - protocol_name: Cow<'static, [u8]>, + protocol_names: Vec>, /// Maximum allowed size of a packet. max_packet_size: usize, } impl KademliaProtocolConfig { /// Returns the configured protocol name. - pub fn protocol_name(&self) -> &[u8] { - &self.protocol_name + pub fn protocol_names(&self) -> &[Cow<'static, [u8]>] { + &self.protocol_names } - /// Modifies the protocol name used on the wire. Can be used to create incompatibilities + /// Modifies the protocol names used on the wire. Can be used to create incompatibilities /// between networks on purpose. + pub fn set_protocol_names(&mut self, names: Vec>) { + self.protocol_names = names; + } + + /// Sets single protocol name used on the wire. Can be used to create incompatibilities + /// between networks on purpose. + #[deprecated(since = "0.40.0", note = "use `set_protocol_names()` instead")] pub fn set_protocol_name(&mut self, name: impl Into>) { - self.protocol_name = name.into(); + self.set_protocol_names(std::iter::once(name.into()).collect()); } /// Modifies the maximum allowed size of a single Kademlia packet. @@ -168,7 +175,7 @@ impl KademliaProtocolConfig { impl Default for KademliaProtocolConfig { fn default() -> Self { KademliaProtocolConfig { - protocol_name: Cow::Borrowed(DEFAULT_PROTO_NAME), + protocol_names: iter::once(Cow::Borrowed(DEFAULT_PROTO_NAME)).collect(), max_packet_size: DEFAULT_MAX_PACKET_SIZE, } } @@ -176,10 +183,10 @@ impl Default for KademliaProtocolConfig { impl UpgradeInfo for KademliaProtocolConfig { type Info = Cow<'static, [u8]>; - type InfoIter = iter::Once; + type InfoIter = std::vec::IntoIter; fn protocol_info(&self) -> Self::InfoIter { - iter::once(self.protocol_name.clone()) + self.protocol_names.clone().into_iter() } } From f04df2901b15145dad223d13f496ca81c04e580b Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Sun, 4 Sep 2022 14:29:39 +0200 Subject: [PATCH 63/92] .git-blame-ignore-revs/: Initialize and add rustfmt commit (#2864) Ignoring certain revisions helps in finding the "correct" commit that touched a file last. For more information, see: https://www.git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revs-fileltfilegt --- .git-blame-ignore-revs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000000..ef1f9254a82 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,8 @@ +# This file contains revisions that are to be ignored by git when running `git blame`. +# +# This does NOT work automatically, you first need to tell Git about this file. +# To do so, run `git config --global blame.ignoreRevsFile .git-blame-ignore-revs`. +# You may want to run this without `--global` if you have a different naming convention for this file in other repositories. +# +# Format with rustfmt +f701b24ec0f99be49444a6e7de950c66b01b2f3f From b8c3b282eee5d6387a9cf2f64af0253e764c1172 Mon Sep 17 00:00:00 2001 From: Alexander Shishenko Date: Mon, 5 Sep 2022 07:31:13 +0300 Subject: [PATCH 64/92] protocols/gossipsub: Allow publishing to anything that implements `Into` (#2862) --- protocols/gossipsub/CHANGELOG.md | 4 ++++ protocols/gossipsub/src/behaviour.rs | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index 48993c987fb..7fa96a4748f 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -2,6 +2,10 @@ - Update to `libp2p-swarm` `v0.39.0`. +- Allow publishing with any `impl Into` as a topic. See [PR 2862]. + +[PR 2862]: https://github.com/libp2p/rust-libp2p/pull/2862 + # 0.40.0 - Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. diff --git a/protocols/gossipsub/src/behaviour.rs b/protocols/gossipsub/src/behaviour.rs index 900e1b43be4..954c68ae24b 100644 --- a/protocols/gossipsub/src/behaviour.rs +++ b/protocols/gossipsub/src/behaviour.rs @@ -587,19 +587,20 @@ where } /// Publishes a message with multiple topics to the network. - pub fn publish( + pub fn publish( &mut self, - topic: Topic, + topic: impl Into, data: impl Into>, ) -> Result { let data = data.into(); + let topic = topic.into(); // Transform the data before building a raw_message. let transformed_data = self .data_transform - .outbound_transform(&topic.hash(), data.clone())?; + .outbound_transform(&topic, data.clone())?; - let raw_message = self.build_raw_message(topic.into(), transformed_data)?; + let raw_message = self.build_raw_message(topic, transformed_data)?; // calculate the message id from the un-transformed data let msg_id = self.config.message_id(&GossipsubMessage { From a40180c3d812b73311af03c5f57cd2bea9455fda Mon Sep 17 00:00:00 2001 From: Laurent Senta Date: Wed, 7 Sep 2022 06:10:01 +0200 Subject: [PATCH 65/92] .github/: Introduce interop tests (#2835) Adds two workflows on push & PR: * `run-ping-interop-cross-version`: runs a Testground interoperability test between multiple versions of rust-libp2p, including master, and the current branch (during a pull request) * `run-ping-interop-cross-implementation`: runs a Testground interoperability test between go-libp2p and rust-libp2p, and the current branch (during a pull request) We rely on the https://github.com/libp2p/test-plans/ repository to retrieve and run the tests. Co-authored-by: Piotr Galar --- .github/workflows/interop-test.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/interop-test.yml diff --git a/.github/workflows/interop-test.yml b/.github/workflows/interop-test.yml new file mode 100644 index 00000000000..9413cce7e95 --- /dev/null +++ b/.github/workflows/interop-test.yml @@ -0,0 +1,27 @@ +on: + pull_request: + push: + branches: + - master +name: Interoperability Testing + +jobs: + # NOTE: during a pull request run, github creates a merge commit referenced in `github.sha` + # that merge commit is not a regular commit. You won't find it with a regular `git checkout SHA` and + # tools like `go get repo@SHA` won't find it. + # + # As a workaround, we generate a path to the actual pull request's commit, it looks like: + # `github.com/external-org/go-libp2p@latest-commit-on-their-branch` + run-ping-interop-cross-version: + uses: "libp2p/test-plans/.github/workflows/run-composition.yml@master" + with: + composition_file: "ping/_compositions/rust-cross-versions.toml" + custom_git_target: github.com/${{ github.event.pull_request.head.repo.full_name || github.event.repository.full_name }} + custom_git_reference: ${{ github.event.pull_request.head.sha || github.sha }} + run-ping-interop-cross-implementation: + uses: "libp2p/test-plans/.github/workflows/run-composition.yml@master" + with: + composition_file: "ping/_compositions/go-rust-interop-latest.toml" + custom_git_target: github.com/${{ github.event.pull_request.head.repo.full_name || github.event.repository.full_name }} + custom_git_reference: ${{ github.event.pull_request.head.sha || github.sha }} + custom_interop_target: rust \ No newline at end of file From 8644c65a2231d467887317ddebc3e079d21f8a29 Mon Sep 17 00:00:00 2001 From: Alexander Shishenko Date: Wed, 7 Sep 2022 09:16:22 +0300 Subject: [PATCH 66/92] core/: Introduce `rsa` feature flag to avoid `ring` dependency (#2860) - Introduce `rsa` feature flag to `libp2p-core`. - Expose `rsa` feature in `libp2p`. - Add `rsa` feature to `libp2p` `default`. --- Cargo.toml | 24 +++++++++++++----------- core/CHANGELOG.md | 7 +++++++ core/Cargo.toml | 5 +++-- core/src/identity.rs | 22 +++++++++++----------- core/src/identity/error.rs | 2 ++ misc/keygen/Cargo.toml | 2 +- misc/metrics/CHANGELOG.md | 2 ++ misc/metrics/Cargo.toml | 2 +- muxers/mplex/CHANGELOG.md | 4 ++++ muxers/mplex/Cargo.toml | 4 ++-- muxers/yamux/CHANGELOG.md | 4 ++++ muxers/yamux/Cargo.toml | 4 ++-- protocols/autonat/CHANGELOG.md | 2 ++ protocols/autonat/Cargo.toml | 2 +- protocols/dcutr/CHANGELOG.md | 2 ++ protocols/dcutr/Cargo.toml | 2 +- protocols/floodsub/CHANGELOG.md | 2 ++ protocols/floodsub/Cargo.toml | 2 +- protocols/gossipsub/CHANGELOG.md | 2 ++ protocols/gossipsub/Cargo.toml | 2 +- protocols/gossipsub/src/protocol.rs | 7 +++++++ protocols/identify/CHANGELOG.md | 2 ++ protocols/identify/Cargo.toml | 2 +- protocols/kad/CHANGELOG.md | 2 ++ protocols/kad/Cargo.toml | 2 +- protocols/mdns/CHANGELOG.md | 2 ++ protocols/mdns/Cargo.toml | 2 +- protocols/ping/CHANGELOG.md | 2 ++ protocols/ping/Cargo.toml | 2 +- protocols/relay/CHANGELOG.md | 2 ++ protocols/relay/Cargo.toml | 2 +- protocols/rendezvous/CHANGELOG.md | 2 ++ protocols/rendezvous/Cargo.toml | 2 +- protocols/request-response/CHANGELOG.md | 2 ++ protocols/request-response/Cargo.toml | 2 +- swarm/CHANGELOG.md | 2 ++ swarm/Cargo.toml | 2 +- transports/deflate/CHANGELOG.md | 4 ++++ transports/deflate/Cargo.toml | 4 ++-- transports/dns/CHANGELOG.md | 4 ++++ transports/dns/Cargo.toml | 4 ++-- transports/noise/CHANGELOG.md | 4 ++++ transports/noise/Cargo.toml | 4 ++-- transports/noise/src/protocol/x25519.rs | 2 ++ transports/plaintext/CHANGELOG.md | 4 ++++ transports/plaintext/Cargo.toml | 4 ++-- transports/tcp/CHANGELOG.md | 4 ++++ transports/tcp/Cargo.toml | 4 ++-- transports/uds/CHANGELOG.md | 4 ++++ transports/uds/Cargo.toml | 4 ++-- transports/wasm-ext/CHANGELOG.md | 4 ++++ transports/wasm-ext/Cargo.toml | 4 ++-- transports/websocket/CHANGELOG.md | 4 ++++ transports/websocket/Cargo.toml | 4 ++-- 54 files changed, 145 insertions(+), 58 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7249e70cb4c..62b8df404f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ default = [ "relay", "request-response", "rendezvous", + "rsa", "secp256k1", "tcp-async-io", "uds", @@ -65,6 +66,7 @@ wasm-ext-websocket = ["wasm-ext", "libp2p-wasm-ext?/websocket"] websocket = ["dep:libp2p-websocket"] yamux = ["dep:libp2p-yamux"] secp256k1 = ["libp2p-core/secp256k1"] +rsa = ["libp2p-core/rsa"] serde = ["libp2p-core/serde", "libp2p-kad?/serde", "libp2p-gossipsub?/serde"] [package.metadata.docs.rs] @@ -79,25 +81,25 @@ instant = "0.1.11" # Explicit dependency to be used in `wasm-bindgen` feature lazy_static = "1.2" libp2p-autonat = { version = "0.7.0", path = "protocols/autonat", optional = true } -libp2p-core = { version = "0.35.0", path = "core", default-features = false } +libp2p-core = { version = "0.36.0", path = "core", default-features = false } libp2p-dcutr = { version = "0.6.0", path = "protocols/dcutr", optional = true } libp2p-floodsub = { version = "0.39.0", path = "protocols/floodsub", optional = true } libp2p-identify = { version = "0.39.0", path = "protocols/identify", optional = true } libp2p-kad = { version = "0.40.0", path = "protocols/kad", optional = true } libp2p-metrics = { version = "0.9.0", path = "misc/metrics", optional = true } -libp2p-mplex = { version = "0.35.0", path = "muxers/mplex", optional = true } -libp2p-noise = { version = "0.38.0", path = "transports/noise", optional = true } +libp2p-mplex = { version = "0.36.0", path = "muxers/mplex", optional = true } +libp2p-noise = { version = "0.39.0", path = "transports/noise", optional = true } libp2p-ping = { version = "0.39.0", path = "protocols/ping", optional = true } -libp2p-plaintext = { version = "0.35.0", path = "transports/plaintext", optional = true } +libp2p-plaintext = { version = "0.36.0", path = "transports/plaintext", optional = true } libp2p-pnet = { version = "0.22.0", path = "transports/pnet", optional = true } libp2p-relay = { version = "0.12.0", path = "protocols/relay", optional = true } libp2p-rendezvous = { version = "0.9.0", path = "protocols/rendezvous", optional = true } libp2p-request-response = { version = "0.21.0", path = "protocols/request-response", optional = true } libp2p-swarm = { version = "0.39.0", path = "swarm" } libp2p-swarm-derive = { version = "0.30.0", path = "swarm-derive" } -libp2p-uds = { version = "0.34.0", path = "transports/uds", optional = true } -libp2p-wasm-ext = { version = "0.35.0", path = "transports/wasm-ext", default-features = false, optional = true } -libp2p-yamux = { version = "0.39.0", path = "muxers/yamux", optional = true } +libp2p-uds = { version = "0.35.0", path = "transports/uds", optional = true } +libp2p-wasm-ext = { version = "0.36.0", path = "transports/wasm-ext", default-features = false, optional = true } +libp2p-yamux = { version = "0.40.0", path = "muxers/yamux", optional = true } multiaddr = { version = "0.14.0" } parking_lot = "0.12.0" pin-project = "1.0.0" @@ -105,11 +107,11 @@ rand = "0.7.3" # Explicit dependency to be used in `wasm-bindgen` feature smallvec = "1.6.1" [target.'cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))'.dependencies] -libp2p-deflate = { version = "0.35.0", path = "transports/deflate", optional = true } -libp2p-dns = { version = "0.35.0", path = "transports/dns", optional = true, default-features = false } +libp2p-deflate = { version = "0.36.0", path = "transports/deflate", optional = true } +libp2p-dns = { version = "0.36.0", path = "transports/dns", optional = true, default-features = false } libp2p-mdns = { version = "0.40.0", path = "protocols/mdns", optional = true, default-features = false } -libp2p-tcp = { version = "0.35.0", path = "transports/tcp", default-features = false, optional = true } -libp2p-websocket = { version = "0.37.0", path = "transports/websocket", optional = true } +libp2p-tcp = { version = "0.36.0", path = "transports/tcp", default-features = false, optional = true } +libp2p-websocket = { version = "0.38.0", path = "transports/websocket", optional = true } [target.'cfg(not(target_os = "unknown"))'.dependencies] libp2p-gossipsub = { version = "0.41.0", path = "protocols/gossipsub", optional = true } diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 8e3bd24906b..f442d68bdb2 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,3 +1,10 @@ +# 0.36.0 [unreleased] + +- Make RSA keypair support optional. To enable RSA support, `rsa` feature should be enabled. + See [PR 2860]. + +[PR 2860]: https://github.com/libp2p/rust-libp2p/pull/2860/ + # 0.35.1 - Update to `p256` `v0.11.0`. See [PR 2636]. diff --git a/core/Cargo.toml b/core/Cargo.toml index d20934adf1e..626daf2cf8e 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-core" edition = "2021" rust-version = "1.56.1" description = "Core traits and structs of libp2p" -version = "0.35.1" +version = "0.36.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -40,7 +40,7 @@ zeroize = "1" _serde = { package = "serde", version = "1", optional = true, features = ["derive"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -ring = { version = "0.16.9", features = ["alloc", "std"], default-features = false } +ring = { version = "0.16.9", features = ["alloc", "std"], default-features = false, optional = true} [dev-dependencies] async-std = { version = "1.6.2", features = ["attributes"] } @@ -62,6 +62,7 @@ prost-build = "0.11" default = [ "secp256k1", "ecdsa" ] secp256k1 = [ "libsecp256k1" ] ecdsa = [ "p256" ] +rsa = [ "dep:ring" ] serde = ["multihash/serde-codec", "_serde"] [[bench]] diff --git a/core/src/identity.rs b/core/src/identity.rs index a2b3943d0e9..73be1c78b57 100644 --- a/core/src/identity.rs +++ b/core/src/identity.rs @@ -35,7 +35,7 @@ #[cfg(feature = "ecdsa")] pub mod ecdsa; pub mod ed25519; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] pub mod rsa; #[cfg(feature = "secp256k1")] pub mod secp256k1; @@ -68,8 +68,8 @@ use std::convert::{TryFrom, TryInto}; pub enum Keypair { /// An Ed25519 keypair. Ed25519(ed25519::Keypair), - #[cfg(not(target_arch = "wasm32"))] /// An RSA keypair. + #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] Rsa(rsa::Keypair), /// A Secp256k1 keypair. #[cfg(feature = "secp256k1")] @@ -101,7 +101,7 @@ impl Keypair { /// format (i.e. unencrypted) as defined in [RFC5208]. /// /// [RFC5208]: https://tools.ietf.org/html/rfc5208#section-5 - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] pub fn rsa_from_pkcs8(pkcs8_der: &mut [u8]) -> Result { rsa::Keypair::from_pkcs8(pkcs8_der).map(Keypair::Rsa) } @@ -122,7 +122,7 @@ impl Keypair { use Keypair::*; match self { Ed25519(ref pair) => Ok(pair.sign(msg)), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] Rsa(ref pair) => pair.sign(msg), #[cfg(feature = "secp256k1")] Secp256k1(ref pair) => pair.secret().sign(msg), @@ -136,7 +136,7 @@ impl Keypair { use Keypair::*; match self { Ed25519(pair) => PublicKey::Ed25519(pair.public()), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] Rsa(pair) => PublicKey::Rsa(pair.public()), #[cfg(feature = "secp256k1")] Secp256k1(pair) => PublicKey::Secp256k1(pair.public().clone()), @@ -154,7 +154,7 @@ impl Keypair { r#type: keys_proto::KeyType::Ed25519.into(), data: data.encode().into(), }, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] Self::Rsa(_) => { return Err(DecodingError::new( "Encoding RSA key into Protobuf is unsupported", @@ -218,7 +218,7 @@ impl zeroize::Zeroize for keys_proto::PrivateKey { pub enum PublicKey { /// A public Ed25519 key. Ed25519(ed25519::PublicKey), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] /// A public RSA key. Rsa(rsa::PublicKey), #[cfg(feature = "secp256k1")] @@ -239,7 +239,7 @@ impl PublicKey { use PublicKey::*; match self { Ed25519(pk) => pk.verify(msg, sig), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] Rsa(pk) => pk.verify(msg, sig), #[cfg(feature = "secp256k1")] Secp256k1(pk) => pk.verify(msg, sig), @@ -286,7 +286,7 @@ impl From<&PublicKey> for keys_proto::PublicKey { r#type: keys_proto::KeyType::Ed25519 as i32, data: key.encode().to_vec(), }, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] PublicKey::Rsa(key) => keys_proto::PublicKey { r#type: keys_proto::KeyType::Rsa as i32, data: key.encode_x509(), @@ -316,11 +316,11 @@ impl TryFrom for PublicKey { keys_proto::KeyType::Ed25519 => { ed25519::PublicKey::decode(&pubkey.data).map(PublicKey::Ed25519) } - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] keys_proto::KeyType::Rsa => { rsa::PublicKey::decode_x509(&pubkey.data).map(PublicKey::Rsa) } - #[cfg(target_arch = "wasm32")] + #[cfg(any(not(feature = "rsa"), target_arch = "wasm32"))] keys_proto::KeyType::Rsa => { log::debug!("support for RSA was disabled at compile-time"); Err(DecodingError::new("Unsupported")) diff --git a/core/src/identity/error.rs b/core/src/identity/error.rs index 76f41278d5d..32c7edc55a4 100644 --- a/core/src/identity/error.rs +++ b/core/src/identity/error.rs @@ -67,6 +67,7 @@ pub struct SigningError { /// An error during encoding of key material. impl SigningError { + #[cfg(any(feature = "secp256k1", feature = "rsa"))] pub(crate) fn new(msg: S) -> Self { Self { msg: msg.to_string(), @@ -74,6 +75,7 @@ impl SigningError { } } + #[cfg(feature = "rsa")] pub(crate) fn source(self, source: impl Error + Send + Sync + 'static) -> Self { Self { source: Some(Box::new(source)), diff --git a/misc/keygen/Cargo.toml b/misc/keygen/Cargo.toml index 4be54014f0a..36e01709df9 100644 --- a/misc/keygen/Cargo.toml +++ b/misc/keygen/Cargo.toml @@ -13,5 +13,5 @@ clap = {version = "3.1.6", features = ["derive"]} zeroize = "1" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" -libp2p-core = { path = "../../core", default-features = false, version = "0.35.0"} +libp2p-core = { path = "../../core", default-features = false, version = "0.36.0"} base64 = "0.13.0" diff --git a/misc/metrics/CHANGELOG.md b/misc/metrics/CHANGELOG.md index 72007e39c8b..974ff3ceac1 100644 --- a/misc/metrics/CHANGELOG.md +++ b/misc/metrics/CHANGELOG.md @@ -12,6 +12,8 @@ - Update to `libp2p-kad` `v0.40.0`. +- Update to `libp2p-core` `v0.36.0`. + # 0.8.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/misc/metrics/Cargo.toml b/misc/metrics/Cargo.toml index fe2e4f3ec85..30df869248c 100644 --- a/misc/metrics/Cargo.toml +++ b/misc/metrics/Cargo.toml @@ -19,7 +19,7 @@ relay = ["libp2p-relay"] dcutr = ["libp2p-dcutr"] [dependencies] -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-dcutr = { version = "0.6.0", path = "../../protocols/dcutr", optional = true } libp2p-identify = { version = "0.39.0", path = "../../protocols/identify", optional = true } libp2p-kad = { version = "0.40.0", path = "../../protocols/kad", optional = true } diff --git a/muxers/mplex/CHANGELOG.md b/muxers/mplex/CHANGELOG.md index 45f2c217ce0..d70a1ff4647 100644 --- a/muxers/mplex/CHANGELOG.md +++ b/muxers/mplex/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.36.0 [unreleased] + +- Update to `libp2p-core` `v0.36.0` + # 0.35.0 - Update to `libp2p-core` `v0.35.0` diff --git a/muxers/mplex/Cargo.toml b/muxers/mplex/Cargo.toml index ac053a5020f..1e4f6974aa3 100644 --- a/muxers/mplex/Cargo.toml +++ b/muxers/mplex/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-mplex" edition = "2021" rust-version = "1.56.1" description = "Mplex multiplexing protocol for libp2p" -version = "0.35.0" +version = "0.36.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] bytes = "1" futures = "0.3.1" asynchronous-codec = "0.6" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } log = "0.4" nohash-hasher = "0.2" parking_lot = "0.12" diff --git a/muxers/yamux/CHANGELOG.md b/muxers/yamux/CHANGELOG.md index 5544ad15ab4..bd5e89a4421 100644 --- a/muxers/yamux/CHANGELOG.md +++ b/muxers/yamux/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.40.0 [unreleased] + +- Update to `libp2p-core` `v0.36.0` + # 0.39.0 - Update to `libp2p-core` `v0.35.0` diff --git a/muxers/yamux/Cargo.toml b/muxers/yamux/Cargo.toml index 02dfb832d8d..1ee7b4ae667 100644 --- a/muxers/yamux/Cargo.toml +++ b/muxers/yamux/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-yamux" edition = "2021" rust-version = "1.56.1" description = "Yamux multiplexing protocol for libp2p" -version = "0.39.0" +version = "0.40.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"] [dependencies] futures = "0.3.1" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } parking_lot = "0.12" thiserror = "1.0" yamux = "0.10.0" diff --git a/protocols/autonat/CHANGELOG.md b/protocols/autonat/CHANGELOG.md index da0fa1bd1f7..aadcb1ee4be 100644 --- a/protocols/autonat/CHANGELOG.md +++ b/protocols/autonat/CHANGELOG.md @@ -4,6 +4,8 @@ - Update to `libp2p-request-response` `v0.21.0`. +- Update to `libp2p-core` `v0.36.0`. + # 0.6.0 - Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. diff --git a/protocols/autonat/Cargo.toml b/protocols/autonat/Cargo.toml index e6818a74817..b5fc9760d6d 100644 --- a/protocols/autonat/Cargo.toml +++ b/protocols/autonat/Cargo.toml @@ -18,7 +18,7 @@ async-trait = "0.1" futures = "0.3" futures-timer = "3.0" instant = "0.1" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.39.0", path = "../../swarm" } libp2p-request-response = { version = "0.21.0", path = "../request-response" } log = "0.4" diff --git a/protocols/dcutr/CHANGELOG.md b/protocols/dcutr/CHANGELOG.md index 16258919748..88be8bd10d0 100644 --- a/protocols/dcutr/CHANGELOG.md +++ b/protocols/dcutr/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.39.0`. +- Update to `libp2p-core` `v0.36.0`. + # 0.5.1 - Make default features of `libp2p-core` optional. See [PR 2836]. diff --git a/protocols/dcutr/Cargo.toml b/protocols/dcutr/Cargo.toml index 08d2815c6d9..bc015ab0d80 100644 --- a/protocols/dcutr/Cargo.toml +++ b/protocols/dcutr/Cargo.toml @@ -17,7 +17,7 @@ either = "1.6.0" futures = "0.3.1" futures-timer = "3.0" instant = "0.1.11" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4" prost-codec = { version = "0.2", path = "../../misc/prost-codec" } diff --git a/protocols/floodsub/CHANGELOG.md b/protocols/floodsub/CHANGELOG.md index 9f8ea64c43c..4c3d9888c4f 100644 --- a/protocols/floodsub/CHANGELOG.md +++ b/protocols/floodsub/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.39.0`. +- Update to `libp2p-core` `v0.36.0`. + # 0.38.0 - Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. diff --git a/protocols/floodsub/Cargo.toml b/protocols/floodsub/Cargo.toml index 2b9ef8ee402..58977415005 100644 --- a/protocols/floodsub/Cargo.toml +++ b/protocols/floodsub/Cargo.toml @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] cuckoofilter = "0.5.0" fnv = "1.0" futures = "0.3.1" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4" prost = "0.11" diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index 7fa96a4748f..d4ff59f4e02 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.39.0`. +- Update to `libp2p-core` `v0.36.0`. + - Allow publishing with any `impl Into` as a topic. See [PR 2862]. [PR 2862]: https://github.com/libp2p/rust-libp2p/pull/2862 diff --git a/protocols/gossipsub/Cargo.toml b/protocols/gossipsub/Cargo.toml index c551d59cb14..2adccfd6607 100644 --- a/protocols/gossipsub/Cargo.toml +++ b/protocols/gossipsub/Cargo.toml @@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"] [dependencies] libp2p-swarm = { version = "0.39.0", path = "../../swarm" } -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } bytes = "1.0" byteorder = "1.3.4" fnv = "1.0.7" diff --git a/protocols/gossipsub/src/protocol.rs b/protocols/gossipsub/src/protocol.rs index ce337c96455..0eb5f4ee56b 100644 --- a/protocols/gossipsub/src/protocol.rs +++ b/protocols/gossipsub/src/protocol.rs @@ -613,6 +613,7 @@ mod tests { struct TestKeypair(Keypair); impl Arbitrary for TestKeypair { + #[cfg(feature = "rsa")] fn arbitrary(g: &mut G) -> Self { let keypair = if g.gen() { // Small enough to be inlined. @@ -624,6 +625,12 @@ mod tests { }; TestKeypair(keypair) } + + #[cfg(not(feature = "rsa"))] + fn arbitrary(_g: &mut G) -> Self { + // Small enough to be inlined. + TestKeypair(Keypair::generate_ed25519()) + } } impl std::fmt::Debug for TestKeypair { diff --git a/protocols/identify/CHANGELOG.md b/protocols/identify/CHANGELOG.md index 596e6dcb0eb..97acce14812 100644 --- a/protocols/identify/CHANGELOG.md +++ b/protocols/identify/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.39.0`. +- Update to `libp2p-core` `v0.36.0`. + # 0.38.0 - Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml index d0bc65379ad..f147c5bb2c8 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] asynchronous-codec = "0.6" futures = "0.3.1" futures-timer = "3.0.2" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4.1" lru = "0.7.2" diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 01778047583..2aee767776b 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -5,6 +5,8 @@ - Update to `libp2p-swarm` `v0.39.0`. +- Update to `libp2p-core` `v0.36.0`. + [Issue 2837]: https://github.com/libp2p/rust-libp2p/issues/2837 [PR 2846]: https://github.com/libp2p/rust-libp2p/pull/2846 diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index bf7d0957bd3..5ccf32b9de8 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -18,7 +18,7 @@ fnv = "1.0" asynchronous-codec = "0.6" futures = "0.3.1" log = "0.4" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.39.0", path = "../../swarm" } prost = "0.11" rand = "0.7.2" diff --git a/protocols/mdns/CHANGELOG.md b/protocols/mdns/CHANGELOG.md index 4a22bdb1c3f..9541e16baf8 100644 --- a/protocols/mdns/CHANGELOG.md +++ b/protocols/mdns/CHANGELOG.md @@ -8,6 +8,8 @@ - Fix high CPU usage with Tokio library (see [PR 2748]). +- Update to `libp2p-core` `v0.36.0`. + [PR 2748]: https://github.com/libp2p/rust-libp2p/pull/2748 # 0.39.0 diff --git a/protocols/mdns/Cargo.toml b/protocols/mdns/Cargo.toml index 10883a82ec0..2ec4ac44958 100644 --- a/protocols/mdns/Cargo.toml +++ b/protocols/mdns/Cargo.toml @@ -16,7 +16,7 @@ dns-parser = "0.8.0" futures = "0.3.13" if-watch = "1.1.1" lazy_static = "1.4.0" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4.14" rand = "0.8.3" diff --git a/protocols/ping/CHANGELOG.md b/protocols/ping/CHANGELOG.md index cf1f2fedf42..a7170eb0569 100644 --- a/protocols/ping/CHANGELOG.md +++ b/protocols/ping/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.39.0`. +- Update to `libp2p-core` `v0.36.0`. + # 0.38.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/ping/Cargo.toml b/protocols/ping/Cargo.toml index 568f8f83aac..aa2b596d5f1 100644 --- a/protocols/ping/Cargo.toml +++ b/protocols/ping/Cargo.toml @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] futures = "0.3.1" futures-timer = "3.0.2" instant = "0.1.11" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4.1" rand = "0.7.2" diff --git a/protocols/relay/CHANGELOG.md b/protocols/relay/CHANGELOG.md index d6245cd5c45..6206eb34514 100644 --- a/protocols/relay/CHANGELOG.md +++ b/protocols/relay/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.39.0`. +- Update to `libp2p-core` `v0.36.0`. + # 0.11.0 - Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. diff --git a/protocols/relay/Cargo.toml b/protocols/relay/Cargo.toml index ee059d02d50..41964edcf41 100644 --- a/protocols/relay/Cargo.toml +++ b/protocols/relay/Cargo.toml @@ -17,7 +17,7 @@ either = "1.6.0" futures = "0.3.1" futures-timer = "3" instant = "0.1.11" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4" pin-project = "1" diff --git a/protocols/rendezvous/CHANGELOG.md b/protocols/rendezvous/CHANGELOG.md index cadc355e407..86838071410 100644 --- a/protocols/rendezvous/CHANGELOG.md +++ b/protocols/rendezvous/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.39.0`. +- Update to `libp2p-core` `v0.36.0`. + # 0.8.0 - Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. diff --git a/protocols/rendezvous/Cargo.toml b/protocols/rendezvous/Cargo.toml index a21dd300447..fadcaf59580 100644 --- a/protocols/rendezvous/Cargo.toml +++ b/protocols/rendezvous/Cargo.toml @@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"] [dependencies] asynchronous-codec = "0.6" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.39.0", path = "../../swarm" } prost = "0.11" void = "1" diff --git a/protocols/request-response/CHANGELOG.md b/protocols/request-response/CHANGELOG.md index aef9f49f72f..97a3d2f55d0 100644 --- a/protocols/request-response/CHANGELOG.md +++ b/protocols/request-response/CHANGELOG.md @@ -2,6 +2,8 @@ - Update to `libp2p-swarm` `v0.39.0`. +- Update to `libp2p-core` `v0.36.0`. + # 0.20.0 - Update to `libp2p-swarm` `v0.38.0`. diff --git a/protocols/request-response/Cargo.toml b/protocols/request-response/Cargo.toml index c2649de6012..76e802cfca4 100644 --- a/protocols/request-response/Cargo.toml +++ b/protocols/request-response/Cargo.toml @@ -15,7 +15,7 @@ async-trait = "0.1" bytes = "1" futures = "0.3.1" instant = "0.1.11" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-swarm = { version = "0.39.0", path = "../../swarm" } log = "0.4.11" rand = "0.7" diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index 75add0d524a..6498ce56835 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -3,6 +3,8 @@ - Remove deprecated `NetworkBehaviourEventProcess`. See [libp2p-swarm v0.38.0 changelog entry] for migration path. +- Update to `libp2p-core` `v0.36.0`. + [libp2p-swarm v0.38.0 changelog entry]: https://github.com/libp2p/rust-libp2p/blob/master/swarm/CHANGELOG.md#0380 # 0.38.0 diff --git a/swarm/Cargo.toml b/swarm/Cargo.toml index 6f4a87adb0d..a22b114f82e 100644 --- a/swarm/Cargo.toml +++ b/swarm/Cargo.toml @@ -16,7 +16,7 @@ fnv = "1.0" futures = "0.3.1" futures-timer = "3.0.2" instant = "0.1.11" -libp2p-core = { version = "0.35.0", path = "../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../core", default-features = false } log = "0.4" pin-project = "1.0.0" rand = "0.7" diff --git a/transports/deflate/CHANGELOG.md b/transports/deflate/CHANGELOG.md index a2e4112caa2..01dbbe84cb5 100644 --- a/transports/deflate/CHANGELOG.md +++ b/transports/deflate/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.36.0 [unreleased] + +- Update to `libp2p-core` `v0.36.0`. + # 0.35.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/deflate/Cargo.toml b/transports/deflate/Cargo.toml index 4ac8661d0a3..904500c1cd0 100644 --- a/transports/deflate/Cargo.toml +++ b/transports/deflate/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-deflate" edition = "2021" rust-version = "1.56.1" description = "Deflate encryption protocol for libp2p" -version = "0.35.0" +version = "0.36.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"] [dependencies] futures = "0.3.1" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } flate2 = "1.0" [dev-dependencies] diff --git a/transports/dns/CHANGELOG.md b/transports/dns/CHANGELOG.md index 6c8a49af7b4..168961e9aa5 100644 --- a/transports/dns/CHANGELOG.md +++ b/transports/dns/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.36.0 [unreleased] + +- Update to `libp2p-core` `v0.36.0`. + # 0.35.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/dns/Cargo.toml b/transports/dns/Cargo.toml index 46ca3aca1af..51c9b688c73 100644 --- a/transports/dns/Cargo.toml +++ b/transports/dns/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-dns" edition = "2021" rust-version = "1.56.1" description = "DNS transport implementation for libp2p" -version = "0.35.0" +version = "0.36.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -11,7 +11,7 @@ keywords = ["peer-to-peer", "libp2p", "networking"] categories = ["network-programming", "asynchronous"] [dependencies] -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } log = "0.4.1" futures = "0.3.1" async-std-resolver = { version = "0.21", optional = true } diff --git a/transports/noise/CHANGELOG.md b/transports/noise/CHANGELOG.md index f17fc29616e..a000bec1d6b 100644 --- a/transports/noise/CHANGELOG.md +++ b/transports/noise/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.39.0 [unreleased] + +- Update to `libp2p-core` `v0.36.0`. + # 0.38.0 - Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. diff --git a/transports/noise/Cargo.toml b/transports/noise/Cargo.toml index 351b8d826d3..5ee9330818d 100644 --- a/transports/noise/Cargo.toml +++ b/transports/noise/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-noise" edition = "2021" rust-version = "1.56.1" description = "Cryptographic handshake protocol using the noise framework." -version = "0.38.0" +version = "0.39.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -13,7 +13,7 @@ bytes = "1" curve25519-dalek = "3.0.0" futures = "0.3.1" lazy_static = "1.2" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } log = "0.4" prost = "0.11" rand = "0.8.3" diff --git a/transports/noise/src/protocol/x25519.rs b/transports/noise/src/protocol/x25519.rs index 297122c325e..0ffa9991ae6 100644 --- a/transports/noise/src/protocol/x25519.rs +++ b/transports/noise/src/protocol/x25519.rs @@ -120,6 +120,7 @@ impl Protocol for X25519 { Ok(PublicKey(X25519(pk))) } + #[allow(irrefutable_let_patterns)] fn linked(id_pk: &identity::PublicKey, dh_pk: &PublicKey) -> bool { if let identity::PublicKey::Ed25519(ref p) = id_pk { PublicKey::from_ed25519(p).as_ref() == dh_pk.as_ref() @@ -162,6 +163,7 @@ impl Keypair { /// > See also: /// > /// > * [Noise: Static Key Reuse](http://www.noiseprotocol.org/noise.html#security-considerations) + #[allow(unreachable_patterns)] pub fn from_identity(id_keys: &identity::Keypair) -> Option> { match id_keys { identity::Keypair::Ed25519(p) => { diff --git a/transports/plaintext/CHANGELOG.md b/transports/plaintext/CHANGELOG.md index 9eb4d5551be..7b962614ee8 100644 --- a/transports/plaintext/CHANGELOG.md +++ b/transports/plaintext/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.36.0 [unreleased] + +- Update to `libp2p-core` `v0.36.0`. + # 0.35.0 - Update prost requirement from 0.10 to 0.11 which no longer installs the protoc Protobuf compiler. diff --git a/transports/plaintext/Cargo.toml b/transports/plaintext/Cargo.toml index 354782d9253..f250c2a4287 100644 --- a/transports/plaintext/Cargo.toml +++ b/transports/plaintext/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-plaintext" edition = "2021" rust-version = "1.56.1" description = "Plaintext encryption dummy protocol for libp2p" -version = "0.35.0" +version = "0.36.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] bytes = "1" futures = "0.3.1" asynchronous-codec = "0.6" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } log = "0.4.8" prost = "0.11" unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] } diff --git a/transports/tcp/CHANGELOG.md b/transports/tcp/CHANGELOG.md index 8e876fd90a9..d426abca833 100644 --- a/transports/tcp/CHANGELOG.md +++ b/transports/tcp/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.36.0 [unreleased] + +- Update to `libp2p-core` `v0.36.0`. + # 0.35.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/tcp/Cargo.toml b/transports/tcp/Cargo.toml index 7273db58c51..d4577c74252 100644 --- a/transports/tcp/Cargo.toml +++ b/transports/tcp/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-tcp" edition = "2021" rust-version = "1.56.1" description = "TCP/IP transport protocol for libp2p" -version = "0.35.0" +version = "0.36.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -18,7 +18,7 @@ if-watch = { version = "1.1.1", optional = true } if-addrs = { version = "0.7.0", optional = true } ipnet = "2.0.0" libc = "0.2.80" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } log = "0.4.11" socket2 = { version = "0.4.0", features = ["all"] } tokio-crate = { package = "tokio", version = "1.19.0", default-features = false, features = ["net"], optional = true } diff --git a/transports/uds/CHANGELOG.md b/transports/uds/CHANGELOG.md index b2f4751b63f..371d5698a85 100644 --- a/transports/uds/CHANGELOG.md +++ b/transports/uds/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.35.0 [unreleased] + +- Update to `libp2p-core` `v0.36.0`. + # 0.34.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/uds/Cargo.toml b/transports/uds/Cargo.toml index e00e6ae09f3..3b7f1eb0a3f 100644 --- a/transports/uds/Cargo.toml +++ b/transports/uds/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-uds" edition = "2021" rust-version = "1.56.1" description = "Unix domain sockets transport for libp2p" -version = "0.34.0" +version = "0.35.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"] [target.'cfg(all(unix, not(target_os = "emscripten")))'.dependencies] async-std = { version = "1.6.2", optional = true } -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } log = "0.4.1" futures = "0.3.1" tokio = { version = "1.15", default-features = false, features = ["net"], optional = true } diff --git a/transports/wasm-ext/CHANGELOG.md b/transports/wasm-ext/CHANGELOG.md index 323ee80cbe0..379d044e493 100644 --- a/transports/wasm-ext/CHANGELOG.md +++ b/transports/wasm-ext/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.36.0 [unreleased] + +- Update to `libp2p-core` `v0.36.0`. + # 0.35.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/wasm-ext/Cargo.toml b/transports/wasm-ext/Cargo.toml index 34926d04b52..6c6a645c8c2 100644 --- a/transports/wasm-ext/Cargo.toml +++ b/transports/wasm-ext/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-wasm-ext" edition = "2021" rust-version = "1.56.1" description = "Allows passing in an external transport in a WASM environment" -version = "0.35.0" +version = "0.36.0" authors = ["Pierre Krieger "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -13,7 +13,7 @@ categories = ["network-programming", "asynchronous"] [dependencies] futures = "0.3.1" js-sys = "0.3.50" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } parity-send-wrapper = "0.1.0" wasm-bindgen = "0.2.42" wasm-bindgen-futures = "0.4.4" diff --git a/transports/websocket/CHANGELOG.md b/transports/websocket/CHANGELOG.md index 65f9eea1e96..1c8c86ddd47 100644 --- a/transports/websocket/CHANGELOG.md +++ b/transports/websocket/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.38.0 [unreleased] + +- Update to `libp2p-core` `v0.36.0`. + # 0.37.0 - Update to `libp2p-core` `v0.35.0`. diff --git a/transports/websocket/Cargo.toml b/transports/websocket/Cargo.toml index 49121c4f22b..b470864a959 100644 --- a/transports/websocket/Cargo.toml +++ b/transports/websocket/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-websocket" edition = "2021" rust-version = "1.56.1" description = "WebSocket transport for libp2p" -version = "0.37.0" +version = "0.38.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"] futures-rustls = "0.22" either = "1.5.3" futures = "0.3.1" -libp2p-core = { version = "0.35.0", path = "../../core", default-features = false } +libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } log = "0.4.8" parking_lot = "0.12.0" quicksink = "0.1" From 2eca38cca03fb76d40fca7b7eba85a4c9a48b902 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 7 Sep 2022 17:08:23 +1000 Subject: [PATCH 67/92] core/upgrade/: Add `ReadyUpgrade` (#2855) --- core/CHANGELOG.md | 3 ++ core/src/upgrade.rs | 2 + core/src/upgrade/ready.rs | 75 ++++++++++++++++++++++++++++++++++ protocols/ping/src/handler.rs | 16 ++++---- protocols/ping/src/protocol.rs | 36 +--------------- 5 files changed, 91 insertions(+), 41 deletions(-) create mode 100644 core/src/upgrade/ready.rs diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index f442d68bdb2..09c06900d34 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -3,6 +3,9 @@ - Make RSA keypair support optional. To enable RSA support, `rsa` feature should be enabled. See [PR 2860]. +- Add `ReadyUpgrade`. See [PR 2855]. + +[PR 2855]: https://github.com/libp2p/rust-libp2p/pull/2855 [PR 2860]: https://github.com/libp2p/rust-libp2p/pull/2860/ # 0.35.1 diff --git a/core/src/upgrade.rs b/core/src/upgrade.rs index 34a27cdf77a..de9ef765e16 100644 --- a/core/src/upgrade.rs +++ b/core/src/upgrade.rs @@ -65,6 +65,7 @@ mod from_fn; mod map; mod optional; mod pending; +mod ready; mod select; mod transfer; @@ -79,6 +80,7 @@ pub use self::{ map::{MapInboundUpgrade, MapInboundUpgradeErr, MapOutboundUpgrade, MapOutboundUpgradeErr}, optional::OptionalUpgrade, pending::PendingUpgrade, + ready::ReadyUpgrade, select::SelectUpgrade, transfer::{read_length_prefixed, read_varint, write_length_prefixed, write_varint}, }; diff --git a/core/src/upgrade/ready.rs b/core/src/upgrade/ready.rs new file mode 100644 index 00000000000..16a9b2867f4 --- /dev/null +++ b/core/src/upgrade/ready.rs @@ -0,0 +1,75 @@ +// Copyright 2022 Protocol Labs. +// Copyright 2017-2018 Parity Technologies (UK) Ltd. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +use crate::upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeInfo}; +use futures::future; +use std::iter; +use void::Void; + +/// Implementation of [`UpgradeInfo`], [`InboundUpgrade`] and [`OutboundUpgrade`] that directly yields the substream. +#[derive(Debug, Copy, Clone)] +pub struct ReadyUpgrade

{ + protocol_name: P, +} + +impl

ReadyUpgrade

{ + pub fn new(protocol_name: P) -> Self { + Self { protocol_name } + } +} + +impl

UpgradeInfo for ReadyUpgrade

+where + P: ProtocolName + Clone, +{ + type Info = P; + type InfoIter = iter::Once

; + + fn protocol_info(&self) -> Self::InfoIter { + iter::once(self.protocol_name.clone()) + } +} + +impl InboundUpgrade for ReadyUpgrade

+where + P: ProtocolName + Clone, +{ + type Output = C; + type Error = Void; + type Future = future::Ready>; + + fn upgrade_inbound(self, stream: C, _: Self::Info) -> Self::Future { + future::ready(Ok(stream)) + } +} + +impl OutboundUpgrade for ReadyUpgrade

+where + P: ProtocolName + Clone, +{ + type Output = C; + type Error = Void; + type Future = future::Ready>; + + fn upgrade_outbound(self, stream: C, _: Self::Info) -> Self::Future { + future::ready(Ok(stream)) + } +} diff --git a/protocols/ping/src/handler.rs b/protocols/ping/src/handler.rs index 850f4ebc05f..f0e71fb070e 100644 --- a/protocols/ping/src/handler.rs +++ b/protocols/ping/src/handler.rs @@ -18,10 +18,11 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::protocol; +use crate::{protocol, PROTOCOL_NAME}; use futures::future::BoxFuture; use futures::prelude::*; use futures_timer::Delay; +use libp2p_core::upgrade::ReadyUpgrade; use libp2p_core::{upgrade::NegotiationError, UpgradeError}; use libp2p_swarm::{ ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, KeepAlive, @@ -225,13 +226,13 @@ impl ConnectionHandler for Handler { type InEvent = Void; type OutEvent = crate::Result; type Error = Failure; - type InboundProtocol = protocol::Ping; - type OutboundProtocol = protocol::Ping; + type InboundProtocol = ReadyUpgrade<&'static [u8]>; + type OutboundProtocol = ReadyUpgrade<&'static [u8]>; type OutboundOpenInfo = (); type InboundOpenInfo = (); - fn listen_protocol(&self) -> SubstreamProtocol { - SubstreamProtocol::new(protocol::Ping, ()) + fn listen_protocol(&self) -> SubstreamProtocol, ()> { + SubstreamProtocol::new(ReadyUpgrade::new(PROTOCOL_NAME), ()) } fn inject_fully_negotiated_inbound(&mut self, stream: NegotiatedSubstream, (): ()) { @@ -274,7 +275,8 @@ impl ConnectionHandler for Handler { fn poll( &mut self, cx: &mut Context<'_>, - ) -> Poll> { + ) -> Poll, (), crate::Result, Self::Error>> + { match self.state { State::Inactive { reported: true } => { return Poll::Pending; // nothing to do on this connection @@ -366,7 +368,7 @@ impl ConnectionHandler for Handler { } None => { self.outbound = Some(PingState::OpenStream); - let protocol = SubstreamProtocol::new(protocol::Ping, ()) + let protocol = SubstreamProtocol::new(ReadyUpgrade::new(PROTOCOL_NAME), ()) .with_timeout(self.config.timeout); return Poll::Ready(ConnectionHandlerEvent::OutboundSubstreamRequest { protocol, diff --git a/protocols/ping/src/protocol.rs b/protocols/ping/src/protocol.rs index 659040e2d7f..3c44adcd0b4 100644 --- a/protocols/ping/src/protocol.rs +++ b/protocols/ping/src/protocol.rs @@ -20,13 +20,10 @@ use futures::prelude::*; use instant::Instant; -use libp2p_core::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}; -use libp2p_swarm::NegotiatedSubstream; use rand::{distributions, prelude::*}; -use std::{io, iter, time::Duration}; -use void::Void; +use std::{io, time::Duration}; -pub const PROTOCOL_NAME: &[u8; 16] = b"/ipfs/ping/1.0.0"; +pub const PROTOCOL_NAME: &[u8] = b"/ipfs/ping/1.0.0"; /// The `Ping` protocol upgrade. /// @@ -52,35 +49,6 @@ pub struct Ping; const PING_SIZE: usize = 32; -impl UpgradeInfo for Ping { - type Info = &'static [u8]; - type InfoIter = iter::Once; - - fn protocol_info(&self) -> Self::InfoIter { - iter::once(PROTOCOL_NAME) - } -} - -impl InboundUpgrade for Ping { - type Output = NegotiatedSubstream; - type Error = Void; - type Future = future::Ready>; - - fn upgrade_inbound(self, stream: NegotiatedSubstream, _: Self::Info) -> Self::Future { - future::ok(stream) - } -} - -impl OutboundUpgrade for Ping { - type Output = NegotiatedSubstream; - type Error = Void; - type Future = future::Ready>; - - fn upgrade_outbound(self, stream: NegotiatedSubstream, _: Self::Info) -> Self::Future { - future::ok(stream) - } -} - /// Sends a ping and waits for the pong. pub async fn send_ping(mut stream: S) -> io::Result<(S, Duration)> where From d2eddf4ff198133c517260fd92cbd3d826983de2 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 7 Sep 2022 17:25:33 +1000 Subject: [PATCH 68/92] muxers/yamux: Remove `OpenSubstreamToken` (#2873) --- muxers/yamux/CHANGELOG.md | 4 ++++ muxers/yamux/src/lib.rs | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/muxers/yamux/CHANGELOG.md b/muxers/yamux/CHANGELOG.md index bd5e89a4421..27566d1fcab 100644 --- a/muxers/yamux/CHANGELOG.md +++ b/muxers/yamux/CHANGELOG.md @@ -2,6 +2,10 @@ - Update to `libp2p-core` `v0.36.0` +- Remove `OpenSubstreamToken` as it is dead code. See [PR 2873]. + +[PR 2873]: https://github.com/libp2p/rust-libp2p/pull/2873/ + # 0.39.0 - Update to `libp2p-core` `v0.35.0` diff --git a/muxers/yamux/src/lib.rs b/muxers/yamux/src/lib.rs index 5b109f2b3b0..1c4c9e7c7c9 100644 --- a/muxers/yamux/src/lib.rs +++ b/muxers/yamux/src/lib.rs @@ -50,10 +50,6 @@ impl fmt::Debug for Yamux { } } -/// A token to poll for an outbound substream. -#[derive(Debug)] -pub struct OpenSubstreamToken(()); - impl Yamux> where C: AsyncRead + AsyncWrite + Send + Unpin + 'static, From 83c67954e9f4c3873b1f311e7bc7c615f5c08447 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 7 Sep 2022 09:44:51 +0200 Subject: [PATCH 69/92] *: Prepare v0.48.0 (#2869) --- CHANGELOG.md | 4 +++- core/CHANGELOG.md | 2 +- misc/metrics/CHANGELOG.md | 2 +- muxers/mplex/CHANGELOG.md | 2 +- muxers/yamux/CHANGELOG.md | 2 +- protocols/autonat/CHANGELOG.md | 2 +- protocols/dcutr/CHANGELOG.md | 2 +- protocols/floodsub/CHANGELOG.md | 2 +- protocols/gossipsub/CHANGELOG.md | 2 +- protocols/identify/CHANGELOG.md | 2 +- protocols/kad/CHANGELOG.md | 2 +- protocols/mdns/CHANGELOG.md | 2 +- protocols/ping/CHANGELOG.md | 2 +- protocols/relay/CHANGELOG.md | 2 +- protocols/rendezvous/CHANGELOG.md | 2 +- protocols/request-response/CHANGELOG.md | 2 +- swarm-derive/CHANGELOG.md | 2 +- swarm/CHANGELOG.md | 2 +- transports/deflate/CHANGELOG.md | 2 +- transports/dns/CHANGELOG.md | 2 +- transports/noise/CHANGELOG.md | 2 +- transports/plaintext/CHANGELOG.md | 2 +- transports/tcp/CHANGELOG.md | 2 +- transports/uds/CHANGELOG.md | 2 +- transports/wasm-ext/CHANGELOG.md | 2 +- transports/websocket/CHANGELOG.md | 2 +- 26 files changed, 28 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20766d4dc19..95e41bb020c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,7 +43,9 @@ # `libp2p` facade crate -# 0.48.0 [unreleased] +# 0.48.0 + +- Update to [`libp2p-core` `v0.36.0`](core/CHANGELOG.md#0360). - Update to [`libp2p-swarm-derive` `v0.30.0`](swarm-derive/CHANGELOG.md#0300). diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 09c06900d34..4a5e07f14f8 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.36.0 [unreleased] +# 0.36.0 - Make RSA keypair support optional. To enable RSA support, `rsa` feature should be enabled. See [PR 2860]. diff --git a/misc/metrics/CHANGELOG.md b/misc/metrics/CHANGELOG.md index 974ff3ceac1..1ce05054600 100644 --- a/misc/metrics/CHANGELOG.md +++ b/misc/metrics/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.9.0 [unreleased] +# 0.9.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/muxers/mplex/CHANGELOG.md b/muxers/mplex/CHANGELOG.md index d70a1ff4647..925013d1e29 100644 --- a/muxers/mplex/CHANGELOG.md +++ b/muxers/mplex/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.36.0 [unreleased] +# 0.36.0 - Update to `libp2p-core` `v0.36.0` diff --git a/muxers/yamux/CHANGELOG.md b/muxers/yamux/CHANGELOG.md index 27566d1fcab..54eb19865a2 100644 --- a/muxers/yamux/CHANGELOG.md +++ b/muxers/yamux/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.40.0 [unreleased] +# 0.40.0 - Update to `libp2p-core` `v0.36.0` diff --git a/protocols/autonat/CHANGELOG.md b/protocols/autonat/CHANGELOG.md index aadcb1ee4be..1b585e7ddf9 100644 --- a/protocols/autonat/CHANGELOG.md +++ b/protocols/autonat/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.7.0 [unreleased] +# 0.7.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/protocols/dcutr/CHANGELOG.md b/protocols/dcutr/CHANGELOG.md index 88be8bd10d0..f6742cf5581 100644 --- a/protocols/dcutr/CHANGELOG.md +++ b/protocols/dcutr/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.6.0 [unreleased] +# 0.6.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/protocols/floodsub/CHANGELOG.md b/protocols/floodsub/CHANGELOG.md index 4c3d9888c4f..5a91e14642a 100644 --- a/protocols/floodsub/CHANGELOG.md +++ b/protocols/floodsub/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.39.0 [unreleased] +# 0.39.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index d4ff59f4e02..1ba36ad6607 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.41.0 [unreleased] +# 0.41.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/protocols/identify/CHANGELOG.md b/protocols/identify/CHANGELOG.md index 97acce14812..1455966b091 100644 --- a/protocols/identify/CHANGELOG.md +++ b/protocols/identify/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.39.0 [unreleased] +# 0.39.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 2aee767776b..d161d93de83 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.40.0 [unreleased] +# 0.40.0 - Add support for multiple protocol names. Update `Kademlia`, `KademliaConfig`, and `KademliaProtocolConfig` accordingly. See [Issue 2837]. See [PR 2846]. diff --git a/protocols/mdns/CHANGELOG.md b/protocols/mdns/CHANGELOG.md index 9541e16baf8..2be2db4079b 100644 --- a/protocols/mdns/CHANGELOG.md +++ b/protocols/mdns/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.40.0 [unreleased] +# 0.40.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/protocols/ping/CHANGELOG.md b/protocols/ping/CHANGELOG.md index a7170eb0569..b1037ac1ef7 100644 --- a/protocols/ping/CHANGELOG.md +++ b/protocols/ping/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.39.0 [unreleased] +# 0.39.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/protocols/relay/CHANGELOG.md b/protocols/relay/CHANGELOG.md index 6206eb34514..1262a250880 100644 --- a/protocols/relay/CHANGELOG.md +++ b/protocols/relay/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.12.0 [unreleased] +# 0.12.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/protocols/rendezvous/CHANGELOG.md b/protocols/rendezvous/CHANGELOG.md index 86838071410..edf55a5d420 100644 --- a/protocols/rendezvous/CHANGELOG.md +++ b/protocols/rendezvous/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.9.0 [unreleased] +# 0.9.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/protocols/request-response/CHANGELOG.md b/protocols/request-response/CHANGELOG.md index 97a3d2f55d0..2e7dd0f84d4 100644 --- a/protocols/request-response/CHANGELOG.md +++ b/protocols/request-response/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.21.0 [unreleased] +# 0.21.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/swarm-derive/CHANGELOG.md b/swarm-derive/CHANGELOG.md index fdf01f04814..79ddf8c8f2e 100644 --- a/swarm-derive/CHANGELOG.md +++ b/swarm-derive/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.30.0 - [unreleased] +# 0.30.0 - Remove support for removed `NetworkBehaviourEventProcess`. See [PR 2840]. diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index 6498ce56835..abf54657cda 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.39.0 - [unreleased] +# 0.39.0 - Remove deprecated `NetworkBehaviourEventProcess`. See [libp2p-swarm v0.38.0 changelog entry] for migration path. diff --git a/transports/deflate/CHANGELOG.md b/transports/deflate/CHANGELOG.md index 01dbbe84cb5..ead0f9cb68f 100644 --- a/transports/deflate/CHANGELOG.md +++ b/transports/deflate/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.36.0 [unreleased] +# 0.36.0 - Update to `libp2p-core` `v0.36.0`. diff --git a/transports/dns/CHANGELOG.md b/transports/dns/CHANGELOG.md index 168961e9aa5..a6c46fa4191 100644 --- a/transports/dns/CHANGELOG.md +++ b/transports/dns/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.36.0 [unreleased] +# 0.36.0 - Update to `libp2p-core` `v0.36.0`. diff --git a/transports/noise/CHANGELOG.md b/transports/noise/CHANGELOG.md index a000bec1d6b..de2c1034a9e 100644 --- a/transports/noise/CHANGELOG.md +++ b/transports/noise/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.39.0 [unreleased] +# 0.39.0 - Update to `libp2p-core` `v0.36.0`. diff --git a/transports/plaintext/CHANGELOG.md b/transports/plaintext/CHANGELOG.md index 7b962614ee8..bb070580986 100644 --- a/transports/plaintext/CHANGELOG.md +++ b/transports/plaintext/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.36.0 [unreleased] +# 0.36.0 - Update to `libp2p-core` `v0.36.0`. diff --git a/transports/tcp/CHANGELOG.md b/transports/tcp/CHANGELOG.md index d426abca833..42cdd64acec 100644 --- a/transports/tcp/CHANGELOG.md +++ b/transports/tcp/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.36.0 [unreleased] +# 0.36.0 - Update to `libp2p-core` `v0.36.0`. diff --git a/transports/uds/CHANGELOG.md b/transports/uds/CHANGELOG.md index 371d5698a85..78f759803ee 100644 --- a/transports/uds/CHANGELOG.md +++ b/transports/uds/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.35.0 [unreleased] +# 0.35.0 - Update to `libp2p-core` `v0.36.0`. diff --git a/transports/wasm-ext/CHANGELOG.md b/transports/wasm-ext/CHANGELOG.md index 379d044e493..0b696f40cce 100644 --- a/transports/wasm-ext/CHANGELOG.md +++ b/transports/wasm-ext/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.36.0 [unreleased] +# 0.36.0 - Update to `libp2p-core` `v0.36.0`. diff --git a/transports/websocket/CHANGELOG.md b/transports/websocket/CHANGELOG.md index 1c8c86ddd47..00ee342d01f 100644 --- a/transports/websocket/CHANGELOG.md +++ b/transports/websocket/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.38.0 [unreleased] +# 0.38.0 - Update to `libp2p-core` `v0.36.0`. From c650dc19db33de49f3c764a6272ffad3e5d22aff Mon Sep 17 00:00:00 2001 From: Alexander Shishenko Date: Thu, 8 Sep 2022 11:30:43 +0300 Subject: [PATCH 70/92] *: Replace _serde with dep:serde in Cargo.toml (#2868) --- core/Cargo.toml | 4 ++-- core/src/lib.rs | 3 --- core/src/peer_id.rs | 2 +- core/tests/serde.rs | 2 -- protocols/kad/Cargo.toml | 4 ++-- protocols/kad/src/lib.rs | 3 --- protocols/kad/src/record.rs | 1 - 7 files changed, 5 insertions(+), 14 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index 626daf2cf8e..3e5285ef6f4 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -37,7 +37,7 @@ thiserror = "1.0" unsigned-varint = "0.7" void = "1" zeroize = "1" -_serde = { package = "serde", version = "1", optional = true, features = ["derive"] } +serde = { version = "1", optional = true, features = ["derive"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ring = { version = "0.16.9", features = ["alloc", "std"], default-features = false, optional = true} @@ -63,7 +63,7 @@ default = [ "secp256k1", "ecdsa" ] secp256k1 = [ "libsecp256k1" ] ecdsa = [ "p256" ] rsa = [ "dep:ring" ] -serde = ["multihash/serde-codec", "_serde"] +serde = ["multihash/serde-codec", "dep:serde"] [[bench]] name = "peer_id" diff --git a/core/src/lib.rs b/core/src/lib.rs index fc5b6c2426e..ac55537eb0b 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -35,9 +35,6 @@ //! define how to upgrade each individual substream to use a protocol. //! See the `upgrade` module. -#[cfg(feature = "serde")] -extern crate _serde as serde; - #[allow(clippy::derive_partial_eq_without_eq)] mod keys_proto { include!(concat!(env!("OUT_DIR"), "/keys_proto.rs")); diff --git a/core/src/peer_id.rs b/core/src/peer_id.rs index d5e4e1496bd..cbe0a13395c 100644 --- a/core/src/peer_id.rs +++ b/core/src/peer_id.rs @@ -183,7 +183,7 @@ impl From for Vec { impl Serialize for PeerId { fn serialize(&self, serializer: S) -> Result where - S: _serde::Serializer, + S: serde::Serializer, { if serializer.is_human_readable() { serializer.serialize_str(&self.to_base58()) diff --git a/core/tests/serde.rs b/core/tests/serde.rs index 3bb98d4a5b6..35796902dd1 100644 --- a/core/tests/serde.rs +++ b/core/tests/serde.rs @@ -4,8 +4,6 @@ use std::str::FromStr; use libp2p_core::PeerId; -extern crate _serde as serde; - #[test] pub fn serialize_peer_id_json() { let peer_id = PeerId::from_str("12D3KooWRNw2pJC9748Fmq4WNV27HoSTcX3r37132FLkQMrbKAiC").unwrap(); diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index 5ccf32b9de8..9aec22c609a 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -29,7 +29,7 @@ unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] } void = "1.0" futures-timer = "3.0.2" instant = "0.1.11" -_serde = { package = "serde", version = "1.0", optional = true, features = ["derive"] } +serde = { version = "1.0", optional = true, features = ["derive"] } thiserror = "1" [dev-dependencies] @@ -43,4 +43,4 @@ quickcheck = "0.9.0" prost-build = "0.11" [features] -serde = ["_serde", "bytes/serde"] +serde = ["dep:serde", "bytes/serde"] diff --git a/protocols/kad/src/lib.rs b/protocols/kad/src/lib.rs index 8c000a00bd2..de6f8159e0b 100644 --- a/protocols/kad/src/lib.rs +++ b/protocols/kad/src/lib.rs @@ -39,9 +39,6 @@ // be useful later for record store #![allow(dead_code)] -#[cfg(feature = "serde")] -extern crate _serde as serde; - pub mod handler; pub mod kbucket; pub mod protocol; diff --git a/protocols/kad/src/record.rs b/protocols/kad/src/record.rs index e321992e5c7..2a40292c243 100644 --- a/protocols/kad/src/record.rs +++ b/protocols/kad/src/record.rs @@ -32,7 +32,6 @@ use std::hash::{Hash, Hasher}; /// The (opaque) key of a record. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(crate = "_serde"))] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Key(Bytes); From fe3e09b710caeaaf26a6ea83e618a19d3c2285a1 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Fri, 9 Sep 2022 23:43:29 +0200 Subject: [PATCH 71/92] transports/quic: upgrade to if-watch v2.0.0 See corresponding change in tcp transport: libp2p#2813. --- transports/quic/Cargo.toml | 2 +- transports/quic/src/in_addr.rs | 100 -------------------- transports/quic/src/lib.rs | 1 - transports/quic/src/transport.rs | 153 +++++++++++++++---------------- 4 files changed, 77 insertions(+), 179 deletions(-) delete mode 100644 transports/quic/src/in_addr.rs diff --git a/transports/quic/Cargo.toml b/transports/quic/Cargo.toml index 0480c0629ed..621ce8d8e05 100644 --- a/transports/quic/Cargo.toml +++ b/transports/quic/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" async-global-executor = "2.0.2" async-io = "1.6.0" futures = "0.3.15" -if-watch = "1.0.0" +if-watch = "2.0.0" libp2p-core = { version = "0.36.0", path = "../../core" } parking_lot = "0.12.0" quinn-proto = { version = "0.8.2", default-features = false, features = ["tls-rustls"] } diff --git a/transports/quic/src/in_addr.rs b/transports/quic/src/in_addr.rs deleted file mode 100644 index 67b6abbf3f3..00000000000 --- a/transports/quic/src/in_addr.rs +++ /dev/null @@ -1,100 +0,0 @@ -use if_watch::{IfEvent, IfWatcher}; - -use futures::{ - future::{BoxFuture, FutureExt}, - stream::Stream, -}; - -use std::{ - io::Result, - net::IpAddr, - ops::DerefMut, - pin::Pin, - task::{Context, Poll}, -}; - -/// Watches for interface changes. -#[derive(Debug)] -pub enum InAddr { - /// The socket accepts connections on a single interface. - One { ip: Option }, - /// The socket accepts connections on all interfaces. - Any { if_watch: Box }, -} - -impl InAddr { - /// If ip is specified then only one `IfEvent::Up` with IpNet(ip)/32 will be generated. - /// If ip is unspecified then `IfEvent::Up/Down` events will be generated for all interfaces. - pub fn new(ip: IpAddr) -> Self { - if ip.is_unspecified() { - let watcher = IfWatch::Pending(IfWatcher::new().boxed()); - InAddr::Any { - if_watch: Box::new(watcher), - } - } else { - InAddr::One { ip: Some(ip) } - } - } -} - -pub enum IfWatch { - Pending(BoxFuture<'static, std::io::Result>), - Ready(Box), -} - -impl std::fmt::Debug for IfWatch { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - IfWatch::Pending(_) => write!(f, "Pending"), - IfWatch::Ready(_) => write!(f, "Ready"), - } - } -} -impl Stream for InAddr { - type Item = Result; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - let me = Pin::into_inner(self); - loop { - match me { - // If the listener is bound to a single interface, make sure the - // address is reported once. - InAddr::One { ip } => { - if let Some(ip) = ip.take() { - return Poll::Ready(Some(Ok(IfEvent::Up(ip.into())))); - } - } - InAddr::Any { if_watch } => { - match if_watch.deref_mut() { - // If we listen on all interfaces, wait for `if-watch` to be ready. - IfWatch::Pending(f) => match futures::ready!(f.poll_unpin(cx)) { - Ok(watcher) => { - *if_watch = Box::new(IfWatch::Ready(Box::new(watcher))); - continue; - } - Err(err) => { - *if_watch = Box::new(IfWatch::Pending(IfWatcher::new().boxed())); - return Poll::Ready(Some(Err(err))); - } - }, - // Consume all events for up/down interface changes. - IfWatch::Ready(watcher) => { - if let Poll::Ready(ev) = watcher.poll_unpin(cx) { - match ev { - Ok(event) => { - return Poll::Ready(Some(Ok(event))); - } - Err(err) => { - return Poll::Ready(Some(Err(err))); - } - } - } - } - } - } - } - break; - } - Poll::Pending - } -} diff --git a/transports/quic/src/lib.rs b/transports/quic/src/lib.rs index 3dca1d3cbe3..2d9a4491bab 100644 --- a/transports/quic/src/lib.rs +++ b/transports/quic/src/lib.rs @@ -55,7 +55,6 @@ mod connection; mod endpoint; mod error; -mod in_addr; mod muxer; mod tls; mod upgrade; diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index 26dcac29109..0aa3295ac0a 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -25,13 +25,14 @@ use crate::connection::Connection; use crate::endpoint::ToEndpoint; use crate::Config; -use crate::{endpoint::Endpoint, in_addr::InAddr, muxer::QuicMuxer, upgrade::Upgrade}; +use crate::{endpoint::Endpoint, muxer::QuicMuxer, upgrade::Upgrade}; use futures::channel::oneshot; +use futures::ready; use futures::stream::StreamExt; use futures::{channel::mpsc, prelude::*, stream::SelectAll}; -use if_watch::IfEvent; +use if_watch::{IfEvent, IfWatcher}; use libp2p_core::{ multiaddr::{Multiaddr, Protocol}, @@ -253,17 +254,13 @@ struct Listener { /// Channel where new connections are being sent. new_connections_rx: mpsc::Receiver, - /// The IP addresses of network interfaces on which the listening socket - /// is accepting connections. - /// - /// If the listen socket listens on all interfaces, these may change over - /// time as interfaces become available or unavailable. - in_addr: InAddr, + if_watcher: Option, - /// Set to `Some` if this [`Listener`] should close. - /// Optionally contains a [`TransportEvent::ListenerClosed`] that should be - /// reported before the listener's stream is terminated. - report_closed: Option::Item>>, + /// Whether the listener was closed and the stream should terminate. + is_closed: bool, + + /// Pending event to reported. + pending_event: Option<::Item>, pending_dials: VecDeque, @@ -276,14 +273,29 @@ impl Listener { socket_addr: SocketAddr, config: Config, ) -> Result { - let in_addr = InAddr::new(socket_addr.ip()); let (endpoint, new_connections_rx) = Endpoint::new_bidirectional(config, socket_addr)?; + + let if_watcher; + let pending_event; + if socket_addr.ip().is_unspecified() { + if_watcher = Some(IfWatcher::new()?); + pending_event = None; + } else { + if_watcher = None; + let ma = socketaddr_to_multiaddr(&endpoint.socket_addr); + pending_event = Some(TransportEvent::NewAddress { + listener_id, + listen_addr: ma, + }) + } + Ok(Listener { endpoint, listener_id, new_connections_rx, - in_addr, - report_closed: None, + if_watcher, + is_closed: false, + pending_event, pending_dials: VecDeque::new(), waker: None, }) @@ -292,68 +304,54 @@ impl Listener { /// Report the listener as closed in a [`TransportEvent::ListenerClosed`] and /// terminate the stream. fn close(&mut self, reason: Result<(), Error>) { - match self.report_closed { - Some(_) => tracing::debug!("Listener was already closed."), - None => { - // Report the listener event as closed. - let _ = self - .report_closed - .insert(Some(TransportEvent::ListenerClosed { - listener_id: self.listener_id, - reason, - })); - } + if self.is_closed { + return; } + self.pending_event = Some(TransportEvent::ListenerClosed { + listener_id: self.listener_id, + reason, + }); + self.is_closed = true; } /// Poll for a next If Event. - fn poll_if_addr(&mut self, cx: &mut Context<'_>) -> Option<::Item> { + fn poll_if_addr(&mut self, cx: &mut Context<'_>) -> Poll<::Item> { + let if_watcher = match self.if_watcher.as_mut() { + Some(iw) => iw, + None => return Poll::Pending, + }; loop { - match self.in_addr.poll_next_unpin(cx) { - Poll::Ready(mut item) => { - if let Some(item) = item.take() { - // Consume all events for up/down interface changes. - match item { - Ok(IfEvent::Up(inet)) => { - let ip = inet.addr(); - if self.endpoint.socket_addr.is_ipv4() == ip.is_ipv4() { - let socket_addr = - SocketAddr::new(ip, self.endpoint.socket_addr.port()); - let ma = socketaddr_to_multiaddr(&socket_addr); - tracing::debug!("New listen address: {}", ma); - return Some(TransportEvent::NewAddress { - listener_id: self.listener_id, - listen_addr: ma, - }); - } - } - Ok(IfEvent::Down(inet)) => { - let ip = inet.addr(); - if self.endpoint.socket_addr.is_ipv4() == ip.is_ipv4() { - let socket_addr = - SocketAddr::new(ip, self.endpoint.socket_addr.port()); - let ma = socketaddr_to_multiaddr(&socket_addr); - tracing::debug!("Expired listen address: {}", ma); - return Some(TransportEvent::AddressExpired { - listener_id: self.listener_id, - listen_addr: ma, - }); - } - } - Err(err) => { - tracing::debug! { - "Failure polling interfaces: {:?}.", - err - }; - return Some(TransportEvent::ListenerError { - listener_id: self.listener_id, - error: err.into(), - }); - } - } + match ready!(if_watcher.poll_if_event(cx)) { + Ok(IfEvent::Up(inet)) => { + let ip = inet.addr(); + if self.endpoint.socket_addr.is_ipv4() == ip.is_ipv4() { + let socket_addr = SocketAddr::new(ip, self.endpoint.socket_addr.port()); + let ma = socketaddr_to_multiaddr(&socket_addr); + tracing::debug!("New listen address: {}", ma); + return Poll::Ready(TransportEvent::NewAddress { + listener_id: self.listener_id, + listen_addr: ma, + }); } } - Poll::Pending => return None, + Ok(IfEvent::Down(inet)) => { + let ip = inet.addr(); + if self.endpoint.socket_addr.is_ipv4() == ip.is_ipv4() { + let socket_addr = SocketAddr::new(ip, self.endpoint.socket_addr.port()); + let ma = socketaddr_to_multiaddr(&socket_addr); + tracing::debug!("Expired listen address: {}", ma); + return Poll::Ready(TransportEvent::AddressExpired { + listener_id: self.listener_id, + listen_addr: ma, + }); + } + } + Err(err) => { + return Poll::Ready(TransportEvent::ListenerError { + listener_id: self.listener_id, + error: err.into(), + }) + } } } } @@ -363,15 +361,16 @@ impl Stream for Listener { type Item = TransportEvent<::ListenerUpgrade, Error>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { loop { - if let Some(closed) = self.report_closed.as_mut() { - // Listener was closed. - // Report the transport event if there is one. On the next iteration, return - // `Poll::Ready(None)` to terminate the stream. - return Poll::Ready(closed.take()); - } - if let Some(event) = self.poll_if_addr(cx) { + if let Some(event) = self.pending_event.take() { return Poll::Ready(Some(event)); } + if self.is_closed { + return Poll::Ready(None); + } + match self.poll_if_addr(cx) { + Poll::Ready(event) => return Poll::Ready(Some(event)), + Poll::Pending => {} + } if !self.pending_dials.is_empty() { match self.endpoint.to_endpoint.poll_ready_unpin(cx) { Poll::Ready(Ok(_)) => { From b6924dbb757d17fbca77e93c5a0e055feb639ad9 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Fri, 9 Sep 2022 23:49:15 +0200 Subject: [PATCH 72/92] transports/quic: fix clippy --- transports/quic/tests/smoke.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/transports/quic/tests/smoke.rs b/transports/quic/tests/smoke.rs index 0291a16f9f0..6a41e4886c3 100644 --- a/transports/quic/tests/smoke.rs +++ b/transports/quic/tests/smoke.rs @@ -77,10 +77,9 @@ async fn smoke() -> Result<()> { let mut data = vec![0; 4096 * 10]; rng.fill_bytes(&mut data); + b.behaviour_mut().add_address(a.local_peer_id(), addr); b.behaviour_mut() - .add_address(&Swarm::local_peer_id(&a), addr); - b.behaviour_mut() - .send_request(&Swarm::local_peer_id(&a), Ping(data.clone())); + .send_request(a.local_peer_id(), Ping(data.clone())); let b_id = *b.local_peer_id(); @@ -405,9 +404,9 @@ fn concurrent_connections_and_streams() { for (listener_peer_id, listener_addr) in &listeners { dialer .behaviour_mut() - .add_address(&listener_peer_id, listener_addr.clone()); + .add_address(listener_peer_id, listener_addr.clone()); - dialer.dial(listener_peer_id.clone()).unwrap(); + dialer.dial(*listener_peer_id).unwrap(); } // Wait for responses to each request. @@ -543,8 +542,8 @@ async fn endpoint_reuse() -> Result<()> { } _ => {} }, - ev = swarm_b.select_next_some() => match ev{ - SwarmEvent::ConnectionEstablished { endpoint, ..} => { + ev = swarm_b.select_next_some() => { + if let SwarmEvent::ConnectionEstablished { endpoint, ..} = ev { match endpoint { ConnectedPoint::Dialer{..} => panic!("Unexpected outbound connection"), ConnectedPoint::Listener {send_back_addr, local_addr} => { @@ -555,7 +554,6 @@ async fn endpoint_reuse() -> Result<()> { } } } - _ => {} }, } } From 689460f03f4dc016d1a1011630fbce5fdee9371d Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sat, 10 Sep 2022 01:00:01 +0200 Subject: [PATCH 73/92] transports/quic: fix smoke test --- transports/quic/tests/smoke.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/transports/quic/tests/smoke.rs b/transports/quic/tests/smoke.rs index 6a41e4886c3..ec174014574 100644 --- a/transports/quic/tests/smoke.rs +++ b/transports/quic/tests/smoke.rs @@ -1,5 +1,6 @@ use anyhow::Result; use async_trait::async_trait; +use futures::channel::oneshot; use futures::future::{join, FutureExt}; use futures::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; use futures::select; @@ -83,6 +84,8 @@ async fn smoke() -> Result<()> { let b_id = *b.local_peer_id(); + let (sync_tx, sync_rx) = oneshot::channel(); + let fut_a = async move { match a.next().await { Some(SwarmEvent::IncomingConnection { .. }) => {} @@ -133,6 +136,8 @@ async fn smoke() -> Result<()> { e => panic!("{:?}", e), } + sync_rx.await.unwrap(); + a.disconnect_peer_id(b_id).unwrap(); match a.next().await { @@ -188,6 +193,8 @@ async fn smoke() -> Result<()> { e => panic!("{:?}", e), } + sync_tx.send(()).unwrap(); + match b.next().await { Some(SwarmEvent::ConnectionClosed { cause: Some(ConnectionError::IO(_)), From 457fb51ee0001bdd99dc8fbc9b275e71b4420d13 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Sat, 10 Sep 2022 12:40:09 +0200 Subject: [PATCH 74/92] transports/tcp: Simplify IfWatcher integration (#2813) With if-watch `2.0.0` `IfWatcher::new` is not async anymore, hence the `IfWatch` wrapping logic is obsolete. Co-authored-by: Thomas Eizinger --- CHANGELOG.md | 4 + Cargo.toml | 4 +- transports/tcp/CHANGELOG.md | 7 + transports/tcp/Cargo.toml | 12 +- transports/tcp/src/lib.rs | 262 ++++++++++-------------- transports/tcp/src/provider.rs | 18 -- transports/tcp/src/provider/async_io.rs | 14 +- transports/tcp/src/provider/tokio.rs | 70 +------ 8 files changed, 124 insertions(+), 267 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95e41bb020c..d28138e1e7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,10 @@ # `libp2p` facade crate +# 0.49.0 - [unreleased] + +- Update to [`libp2p-tcp` `v0.37.0`](transports/tcp/CHANGELOG.md#0370). + # 0.48.0 - Update to [`libp2p-core` `v0.36.0`](core/CHANGELOG.md#0360). diff --git a/Cargo.toml b/Cargo.toml index 62b8df404f8..89e63a4e5cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p" edition = "2021" rust-version = "1.60.0" description = "Peer-to-peer networking library" -version = "0.48.0" +version = "0.49.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -110,7 +110,7 @@ smallvec = "1.6.1" libp2p-deflate = { version = "0.36.0", path = "transports/deflate", optional = true } libp2p-dns = { version = "0.36.0", path = "transports/dns", optional = true, default-features = false } libp2p-mdns = { version = "0.40.0", path = "protocols/mdns", optional = true, default-features = false } -libp2p-tcp = { version = "0.36.0", path = "transports/tcp", default-features = false, optional = true } +libp2p-tcp = { version = "0.37.0", path = "transports/tcp", default-features = false, optional = true } libp2p-websocket = { version = "0.38.0", path = "transports/websocket", optional = true } [target.'cfg(not(target_os = "unknown"))'.dependencies] diff --git a/transports/tcp/CHANGELOG.md b/transports/tcp/CHANGELOG.md index 42cdd64acec..ff34ae49407 100644 --- a/transports/tcp/CHANGELOG.md +++ b/transports/tcp/CHANGELOG.md @@ -1,3 +1,10 @@ +# 0.37.0 - [unreleased] + +- Update to `if-watch` `v2.0.0`. Simplify `IfWatcher` integration. + Use `if_watch::IfWatcher` for all runtimes. See [PR 2813]. + +[PR 2813]: https://github.com/libp2p/rust-libp2p/pull/2813 + # 0.36.0 - Update to `libp2p-core` `v0.36.0`. diff --git a/transports/tcp/Cargo.toml b/transports/tcp/Cargo.toml index d4577c74252..948d9507f0a 100644 --- a/transports/tcp/Cargo.toml +++ b/transports/tcp/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-tcp" edition = "2021" rust-version = "1.56.1" description = "TCP/IP transport protocol for libp2p" -version = "0.36.0" +version = "0.37.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -14,9 +14,7 @@ categories = ["network-programming", "asynchronous"] async-io-crate = { package = "async-io", version = "1.2.0", optional = true } futures = "0.3.8" futures-timer = "3.0" -if-watch = { version = "1.1.1", optional = true } -if-addrs = { version = "0.7.0", optional = true } -ipnet = "2.0.0" +if-watch = "2.0.0" libc = "0.2.80" libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } log = "0.4.11" @@ -25,10 +23,10 @@ tokio-crate = { package = "tokio", version = "1.19.0", default-features = false, [features] default = ["async-io"] -tokio = ["tokio-crate", "if-addrs"] -async-io = ["async-io-crate", "if-watch"] +tokio = ["tokio-crate"] +async-io = ["async-io-crate"] [dev-dependencies] async-std = { version = "1.6.5", features = ["attributes"] } -tokio-crate = { package = "tokio", version = "1.0.1", default-features = false, features = ["net", "rt"] } +tokio-crate = { package = "tokio", version = "1.0.1", default-features = false, features = ["net", "rt", "macros"] } env_logger = "0.9.0" diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 981c896bcb5..f7b897c0d47 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -28,6 +28,7 @@ mod provider; +use if_watch::{IfEvent, IfWatcher}; #[cfg(feature = "async-io")] pub use provider::async_io; @@ -43,9 +44,8 @@ pub use provider::tokio; pub type TokioTcpTransport = GenTcpTransport; use futures::{ - future::{self, BoxFuture, Ready}, + future::{self, Ready}, prelude::*, - ready, }; use futures_timer::Delay; use libp2p_core::{ @@ -64,7 +64,7 @@ use std::{ time::Duration, }; -use provider::{IfEvent, Provider}; +use provider::{Incoming, Provider}; /// The configuration for a TCP/IP transport capability for libp2p. #[derive(Clone, Debug)] @@ -243,6 +243,9 @@ impl GenTcpConfig { /// # use libp2p_core::transport::{ListenerId, TransportEvent}; /// # use libp2p_core::{Multiaddr, Transport}; /// # use std::pin::Pin; + /// # #[cfg(not(feature = "async-io"))] + /// # fn main() {} + /// # /// #[cfg(feature = "async-io")] /// #[async_std::main] /// async fn main() -> std::io::Result<()> { @@ -368,7 +371,25 @@ where socket.bind(&socket_addr.into())?; socket.listen(self.config.backlog as _)?; socket.set_nonblocking(true)?; - TcpListenStream::::new(id, socket.into(), self.port_reuse.clone()) + let listener: TcpListener = socket.into(); + let local_addr = listener.local_addr()?; + + if local_addr.ip().is_unspecified() { + return TcpListenStream::::new( + id, + listener, + Some(IfWatcher::new()?), + self.port_reuse.clone(), + ); + } + + self.port_reuse.register(local_addr.ip(), local_addr.port()); + let listen_addr = ip_to_multiaddr(local_addr.ip(), local_addr.port()); + self.pending_events.push_back(TransportEvent::NewAddress { + listener_id: id, + listen_addr, + }); + TcpListenStream::::new(id, listener, None, self.port_reuse.clone()) } } @@ -398,7 +419,6 @@ impl Transport for GenTcpTransport where T: Provider + Send + 'static, T::Listener: Unpin, - T::IfWatcher: Unpin, T::Stream: Unpin, { type Output = T::Stream; @@ -605,25 +625,6 @@ pub enum TcpListenerEvent { Error(io::Error), } -enum IfWatch { - Pending(BoxFuture<'static, io::Result>), - Ready(TIfWatcher), -} - -/// The listening addresses of a [`TcpListenStream`]. -enum InAddr { - /// The stream accepts connections on a single interface. - One { - addr: IpAddr, - out: Option, - }, - /// The stream accepts connections on all interfaces. - Any { - addrs: HashSet, - if_watch: IfWatch, - }, -} - /// A stream of incoming connections on one or more interfaces. pub struct TcpListenStream where @@ -637,12 +638,12 @@ where listen_addr: SocketAddr, /// The async listening socket for incoming connections. listener: T::Listener, - /// The IP addresses of network interfaces on which the listening socket - /// is accepting connections. + /// Watcher for network interface changes. + /// Reports [`IfEvent`]s for new / deleted ip-addresses when interfaces + /// become or stop being available. /// - /// If the listen socket listens on all interfaces, these may change over - /// time as interfaces become available or unavailable. - in_addr: InAddr, + /// `None` if the socket is only listening on a single interface. + if_watcher: Option, /// The port reuse configuration for outgoing connections. /// /// If enabled, all IP addresses on which this listening stream @@ -666,27 +667,10 @@ where fn new( listener_id: ListenerId, listener: TcpListener, + if_watcher: Option, port_reuse: PortReuse, ) -> io::Result { let listen_addr = listener.local_addr()?; - - let in_addr = if match &listen_addr { - SocketAddr::V4(a) => a.ip().is_unspecified(), - SocketAddr::V6(a) => a.ip().is_unspecified(), - } { - // The `addrs` are populated via `if_watch` when the - // `TcpListenStream` is polled. - InAddr::Any { - addrs: HashSet::new(), - if_watch: IfWatch::Pending(T::if_watcher()), - } - } else { - InAddr::One { - out: Some(ip_to_multiaddr(listen_addr.ip(), listen_addr.port())), - addr: listen_addr.ip(), - } - }; - let listener = T::new_listener(listener)?; Ok(TcpListenStream { @@ -694,7 +678,7 @@ where listener, listener_id, listen_addr, - in_addr, + if_watcher, pause: None, sleep_on_error: Duration::from_millis(100), }) @@ -707,15 +691,16 @@ where /// /// Has no effect if port reuse is disabled. fn disable_port_reuse(&mut self) { - match &self.in_addr { - InAddr::One { addr, .. } => { - self.port_reuse.unregister(*addr, self.listen_addr.port()); - } - InAddr::Any { addrs, .. } => { - for addr in addrs { - self.port_reuse.unregister(*addr, self.listen_addr.port()); + match &self.if_watcher { + Some(if_watcher) => { + for ip_net in if_watcher.iter() { + self.port_reuse + .unregister(ip_net.addr(), self.listen_addr.port()); } } + None => self + .port_reuse + .unregister(self.listen_addr.ip(), self.listen_addr.port()), } } } @@ -734,116 +719,78 @@ where T: Provider, T::Listener: Unpin, T::Stream: Unpin, - T::IfWatcher: Unpin, { type Item = Result, io::Error>; fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let me = Pin::into_inner(self); - loop { - match &mut me.in_addr { - InAddr::Any { if_watch, addrs } => match if_watch { - // If we listen on all interfaces, wait for `if-watch` to be ready. - IfWatch::Pending(f) => match ready!(Pin::new(f).poll(cx)) { - Ok(w) => { - *if_watch = IfWatch::Ready(w); - continue; - } - Err(err) => { - log::debug! { - "Failed to begin observing interfaces: {:?}. Scheduling retry.", - err - }; - *if_watch = IfWatch::Pending(T::if_watcher()); - me.pause = Some(Delay::new(me.sleep_on_error)); - return Poll::Ready(Some(Ok(TcpListenerEvent::Error(err)))); - } - }, - // Consume all events for up/down interface changes. - IfWatch::Ready(watch) => { - while let Poll::Ready(ev) = T::poll_interfaces(watch, cx) { - match ev { - Ok(IfEvent::Up(inet)) => { - let ip = inet.addr(); - if me.listen_addr.is_ipv4() == ip.is_ipv4() && addrs.insert(ip) - { - let ma = ip_to_multiaddr(ip, me.listen_addr.port()); - log::debug!("New listen address: {}", ma); - me.port_reuse.register(ip, me.listen_addr.port()); - return Poll::Ready(Some(Ok( - TcpListenerEvent::NewAddress(ma), - ))); - } - } - Ok(IfEvent::Down(inet)) => { - let ip = inet.addr(); - if me.listen_addr.is_ipv4() == ip.is_ipv4() && addrs.remove(&ip) - { - let ma = ip_to_multiaddr(ip, me.listen_addr.port()); - log::debug!("Expired listen address: {}", ma); - me.port_reuse.unregister(ip, me.listen_addr.port()); - return Poll::Ready(Some(Ok( - TcpListenerEvent::AddressExpired(ma), - ))); - } - } - Err(err) => { - log::debug! { - "Failure polling interfaces: {:?}. Scheduling retry.", - err - }; - me.pause = Some(Delay::new(me.sleep_on_error)); - return Poll::Ready(Some(Ok(TcpListenerEvent::Error(err)))); - } - } - } - } - }, - // If the listener is bound to a single interface, make sure the - // address is registered for port reuse and reported once. - InAddr::One { addr, out } => { - if let Some(multiaddr) = out.take() { - me.port_reuse.register(*addr, me.listen_addr.port()); - return Poll::Ready(Some(Ok(TcpListenerEvent::NewAddress(multiaddr)))); - } + if let Some(mut pause) = me.pause.take() { + match pause.poll_unpin(cx) { + Poll::Ready(_) => {} + Poll::Pending => { + me.pause = Some(pause); + return Poll::Pending; } } + } - if let Some(mut pause) = me.pause.take() { - match Pin::new(&mut pause).poll(cx) { - Poll::Ready(_) => {} - Poll::Pending => { - me.pause = Some(pause); - return Poll::Pending; + if let Some(if_watcher) = me.if_watcher.as_mut() { + while let Poll::Ready(event) = if_watcher.poll_if_event(cx) { + match event { + Ok(IfEvent::Up(inet)) => { + let ip = inet.addr(); + if me.listen_addr.is_ipv4() == ip.is_ipv4() { + let ma = ip_to_multiaddr(ip, me.listen_addr.port()); + log::debug!("New listen address: {}", ma); + me.port_reuse.register(ip, me.listen_addr.port()); + return Poll::Ready(Some(Ok(TcpListenerEvent::NewAddress(ma)))); + } + } + Ok(IfEvent::Down(inet)) => { + let ip = inet.addr(); + if me.listen_addr.is_ipv4() == ip.is_ipv4() { + let ma = ip_to_multiaddr(ip, me.listen_addr.port()); + log::debug!("Expired listen address: {}", ma); + me.port_reuse.unregister(ip, me.listen_addr.port()); + return Poll::Ready(Some(Ok(TcpListenerEvent::AddressExpired(ma)))); + } + } + Err(err) => { + me.pause = Some(Delay::new(me.sleep_on_error)); + return Poll::Ready(Some(Ok(TcpListenerEvent::Error(err)))); } } } + } - // Take the pending connection from the backlog. - let incoming = match T::poll_accept(&mut me.listener, cx) { - Poll::Pending => return Poll::Pending, - Poll::Ready(Ok(incoming)) => incoming, - Poll::Ready(Err(e)) => { - // These errors are non-fatal for the listener stream. - log::error!("error accepting incoming connection: {}", e); - me.pause = Some(Delay::new(me.sleep_on_error)); - return Poll::Ready(Some(Ok(TcpListenerEvent::Error(e)))); - } - }; + // Take the pending connection from the backlog. + match T::poll_accept(&mut me.listener, cx) { + Poll::Ready(Ok(Incoming { + local_addr, + remote_addr, + stream, + })) => { + let local_addr = ip_to_multiaddr(local_addr.ip(), local_addr.port()); + let remote_addr = ip_to_multiaddr(remote_addr.ip(), remote_addr.port()); - let local_addr = ip_to_multiaddr(incoming.local_addr.ip(), incoming.local_addr.port()); - let remote_addr = - ip_to_multiaddr(incoming.remote_addr.ip(), incoming.remote_addr.port()); + log::debug!("Incoming connection from {} at {}", remote_addr, local_addr); - log::debug!("Incoming connection from {} at {}", remote_addr, local_addr); + return Poll::Ready(Some(Ok(TcpListenerEvent::Upgrade { + upgrade: future::ok(stream), + local_addr, + remote_addr, + }))); + } + Poll::Ready(Err(e)) => { + // These errors are non-fatal for the listener stream. + me.pause = Some(Delay::new(me.sleep_on_error)); + return Poll::Ready(Some(Ok(TcpListenerEvent::Error(e)))); + } + Poll::Pending => {} + }; - return Poll::Ready(Some(Ok(TcpListenerEvent::Upgrade { - upgrade: future::ok(incoming.stream), - local_addr, - remote_addr, - }))); - } + Poll::Pending } } @@ -991,7 +938,7 @@ mod tests { #[cfg(feature = "tokio")] { let (ready_tx, ready_rx) = mpsc::channel(1); - let listener = listener::(addr.clone(), ready_tx); + let listener = listener::(addr, ready_tx); let dialer = dialer::(ready_rx); let rt = tokio_crate::runtime::Builder::new_current_thread() .enable_io() @@ -1060,7 +1007,7 @@ mod tests { #[cfg(feature = "tokio")] { let (ready_tx, ready_rx) = mpsc::channel(1); - let listener = listener::(addr.clone(), ready_tx); + let listener = listener::(addr, ready_tx); let dialer = dialer::(ready_rx); let rt = tokio_crate::runtime::Builder::new_current_thread() .enable_io() @@ -1168,7 +1115,7 @@ mod tests { let (ready_tx, ready_rx) = mpsc::channel(1); let (port_reuse_tx, port_reuse_rx) = oneshot::channel(); let listener = listener::(addr.clone(), ready_tx, port_reuse_rx); - let dialer = dialer::(addr.clone(), ready_rx, port_reuse_tx); + let dialer = dialer::(addr, ready_rx, port_reuse_tx); let rt = tokio_crate::runtime::Builder::new_current_thread() .enable_io() .build() @@ -1209,10 +1156,7 @@ mod tests { match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { TransportEvent::NewAddress { listen_addr: addr2, .. - } => { - assert_eq!(addr1, addr2); - return; - } + } => assert_eq!(addr1, addr2), e => panic!("Unexpected transport event: {:?}", e), } } @@ -1229,7 +1173,7 @@ mod tests { #[cfg(feature = "tokio")] { - let listener = listen_twice::(addr.clone()); + let listener = listen_twice::(addr); let rt = tokio_crate::runtime::Builder::new_current_thread() .enable_io() .build() @@ -1267,7 +1211,7 @@ mod tests { .enable_io() .build() .unwrap(); - let new_addr = rt.block_on(listen::(addr.clone())); + let new_addr = rt.block_on(listen::(addr)); assert!(!new_addr.to_string().contains("tcp/0")); } } @@ -1290,7 +1234,7 @@ mod tests { #[cfg(feature = "tokio")] { let mut tcp = TokioTcpTransport::new(GenTcpConfig::new()); - assert!(tcp.listen_on(addr.clone()).is_err()); + assert!(tcp.listen_on(addr).is_err()); } } diff --git a/transports/tcp/src/provider.rs b/transports/tcp/src/provider.rs index 7ebeaa49ee8..a341026e7e6 100644 --- a/transports/tcp/src/provider.rs +++ b/transports/tcp/src/provider.rs @@ -28,18 +28,10 @@ pub mod tokio; use futures::future::BoxFuture; use futures::io::{AsyncRead, AsyncWrite}; -use ipnet::IpNet; use std::net::{SocketAddr, TcpListener, TcpStream}; use std::task::{Context, Poll}; use std::{fmt, io}; -/// An event relating to a change of availability of an address -/// on a network interface. -pub enum IfEvent { - Up(IpNet), - Down(IpNet), -} - /// An incoming connection returned from [`Provider::poll_accept()`]. pub struct Incoming { pub stream: S, @@ -54,12 +46,6 @@ pub trait Provider: Clone + Send + 'static { type Stream: AsyncRead + AsyncWrite + Send + Unpin + fmt::Debug; /// The type of TCP listeners obtained from [`Provider::new_listener`]. type Listener: Send + Unpin; - /// The type of network interface observers obtained from [`Provider::if_watcher`]. - type IfWatcher: Send + Unpin; - - /// Creates an instance of [`Self::IfWatcher`] that can be polled for - /// network interface changes via [`Self::poll_interfaces`]. - fn if_watcher() -> BoxFuture<'static, io::Result>; /// Creates a new listener wrapping the given [`TcpListener`] that /// can be polled for incoming connections via [`Self::poll_accept()`]. @@ -77,8 +63,4 @@ pub trait Provider: Clone + Send + 'static { _: &mut Self::Listener, _: &mut Context<'_>, ) -> Poll>>; - - /// Polls a [`Self::IfWatcher`] for network interface changes, ensuring a task wakeup, - /// if necessary. - fn poll_interfaces(_: &mut Self::IfWatcher, _: &mut Context<'_>) -> Poll>; } diff --git a/transports/tcp/src/provider/async_io.rs b/transports/tcp/src/provider/async_io.rs index acbb4fbdcca..fc613d8fe86 100644 --- a/transports/tcp/src/provider/async_io.rs +++ b/transports/tcp/src/provider/async_io.rs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use super::{IfEvent, Incoming, Provider}; +use super::{Incoming, Provider}; use async_io_crate::Async; use futures::future::{BoxFuture, FutureExt}; @@ -32,11 +32,6 @@ pub enum Tcp {} impl Provider for Tcp { type Stream = Async; type Listener = Async; - type IfWatcher = if_watch::IfWatcher; - - fn if_watcher() -> BoxFuture<'static, io::Result> { - if_watch::IfWatcher::new().boxed() - } fn new_listener(l: net::TcpListener) -> io::Result { Async::new(l) @@ -87,11 +82,4 @@ impl Provider for Tcp { remote_addr, })) } - - fn poll_interfaces(w: &mut Self::IfWatcher, cx: &mut Context<'_>) -> Poll> { - w.poll_unpin(cx).map_ok(|e| match e { - if_watch::IfEvent::Up(a) => IfEvent::Up(a), - if_watch::IfEvent::Down(a) => IfEvent::Down(a), - }) - } } diff --git a/transports/tcp/src/provider/tokio.rs b/transports/tcp/src/provider/tokio.rs index 564eebfa48b..994a12a33c7 100644 --- a/transports/tcp/src/provider/tokio.rs +++ b/transports/tcp/src/provider/tokio.rs @@ -18,45 +18,24 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use super::{IfEvent, Incoming, Provider}; +use super::{Incoming, Provider}; use futures::{ - future::{self, BoxFuture, FutureExt}, + future::{BoxFuture, FutureExt}, prelude::*, }; -use futures_timer::Delay; -use if_addrs::{get_if_addrs, IfAddr}; -use ipnet::{IpNet, Ipv4Net, Ipv6Net}; -use std::collections::HashSet; use std::convert::TryFrom; use std::io; use std::net; use std::pin::Pin; use std::task::{Context, Poll}; -use std::time::Duration; #[derive(Copy, Clone)] pub enum Tcp {} -pub struct IfWatcher { - addrs: HashSet, - delay: Delay, - pending: Vec, -} - impl Provider for Tcp { type Stream = TcpStream; type Listener = tokio_crate::net::TcpListener; - type IfWatcher = IfWatcher; - - fn if_watcher() -> BoxFuture<'static, io::Result> { - future::ready(Ok(IfWatcher { - addrs: HashSet::new(), - delay: Delay::new(Duration::from_secs(0)), - pending: Vec::new(), - })) - .boxed() - } fn new_listener(l: net::TcpListener) -> io::Result { tokio_crate::net::TcpListener::try_from(l) @@ -104,51 +83,6 @@ impl Provider for Tcp { remote_addr, })) } - - fn poll_interfaces(w: &mut Self::IfWatcher, cx: &mut Context<'_>) -> Poll> { - loop { - if let Some(event) = w.pending.pop() { - return Poll::Ready(Ok(event)); - } - - match Pin::new(&mut w.delay).poll(cx) { - Poll::Pending => return Poll::Pending, - Poll::Ready(()) => { - let ifs = get_if_addrs()?; - let addrs = ifs - .into_iter() - .map(|iface| match iface.addr { - IfAddr::V4(ip4) => { - let prefix_len = - (!u32::from_be_bytes(ip4.netmask.octets())).leading_zeros(); - let ipnet = Ipv4Net::new(ip4.ip, prefix_len as u8) - .expect("prefix_len can not exceed 32"); - IpNet::V4(ipnet) - } - IfAddr::V6(ip6) => { - let prefix_len = - (!u128::from_be_bytes(ip6.netmask.octets())).leading_zeros(); - let ipnet = Ipv6Net::new(ip6.ip, prefix_len as u8) - .expect("prefix_len can not exceed 128"); - IpNet::V6(ipnet) - } - }) - .collect::>(); - - for down in w.addrs.difference(&addrs) { - w.pending.push(IfEvent::Down(*down)); - } - - for up in addrs.difference(&w.addrs) { - w.pending.push(IfEvent::Up(*up)); - } - - w.addrs = addrs; - w.delay.reset(Duration::from_secs(10)); - } - } - } - } } /// A [`tokio_crate::net::TcpStream`] that implements [`AsyncRead`] and [`AsyncWrite`]. From 41d39fbf3f5fde7035aaf82413fc7897bf93970d Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sat, 10 Sep 2022 18:34:05 +0200 Subject: [PATCH 75/92] transports/quic: add `Endpoint::try_send` --- transports/quic/src/connection.rs | 27 +++++++------ transports/quic/src/endpoint.rs | 28 +++++++++++-- transports/quic/src/transport.rs | 66 +++++++++++++++---------------- 3 files changed, 71 insertions(+), 50 deletions(-) diff --git a/transports/quic/src/connection.rs b/transports/quic/src/connection.rs index b0290fe4ac5..29ae0596a42 100644 --- a/transports/quic/src/connection.rs +++ b/transports/quic/src/connection.rs @@ -66,6 +66,9 @@ pub enum Error { /// Endpoint has force-killed this connection because it was too busy. #[error("Endpoint has force-killed our connection")] ClosedChannel, + /// The background task driving the endpoint has crashed. + #[error("Background task crashed.")] + TaskCrashed, /// Error in the inner state machine. #[error("{0}")] Quinn(#[from] quinn_proto::ConnectionError), @@ -109,7 +112,7 @@ impl Connection { /// Works for server connections only. pub fn local_addr(&self) -> SocketAddr { debug_assert_eq!(self.connection.side(), quinn_proto::Side::Server); - let endpoint_addr = self.endpoint.socket_addr; + let endpoint_addr = self.endpoint.socket_addr(); self.connection .local_ip() .map(|ip| SocketAddr::new(ip, endpoint_addr.port())) @@ -117,7 +120,7 @@ impl Connection { // In a normal case scenario this should not happen, because // we get want to get a local addr for a server connection only. tracing::error!("trying to get quinn::local_ip for a client"); - endpoint_addr + *endpoint_addr }) } @@ -214,17 +217,17 @@ impl Connection { // However we don't deliver substream-related events to the user as long as // `to_endpoint` is full. This should propagate the back-pressure of `to_endpoint` // being full to the user. - if self.pending_to_endpoint.is_some() { - match self.endpoint.to_endpoint.poll_ready_unpin(cx) { - Poll::Ready(Ok(())) => { - let to_endpoint = self.pending_to_endpoint.take().expect("is some"); - self.endpoint - .to_endpoint - .start_send(to_endpoint) - .expect("Channel is ready."); + if let Some(to_endpoint) = self.pending_to_endpoint.take() { + match self.endpoint.try_send(to_endpoint, cx) { + Ok(Ok(())) => {} + Ok(Err(to_endpoint)) => { + self.pending_to_endpoint = Some(to_endpoint); + return Poll::Pending; + } + Err(_) => { + tracing::error!("Background task crashed."); + return Poll::Ready(ConnectionEvent::ConnectionLost(Error::TaskCrashed)); } - Poll::Ready(Err(_)) => panic!("Background task crashed"), - Poll::Pending => return Poll::Pending, } } diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index a65da3bae60..ed1fb3052d8 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -31,7 +31,10 @@ use crate::{connection::Connection, tls, transport}; use futures::{ - channel::{mpsc, oneshot}, + channel::{ + mpsc::{self, SendError}, + oneshot, + }, prelude::*, }; use quinn_proto::{ClientConfig as QuinnClientConfig, ServerConfig as QuinnServerConfig}; @@ -40,7 +43,7 @@ use std::{ fmt, net::{Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket}, sync::Arc, - task::{Poll, Waker}, + task::{Context, Poll, Waker}, time::{Duration, Instant}, }; @@ -87,9 +90,9 @@ impl Config { #[derive(Clone)] pub struct Endpoint { /// Channel to the background of the endpoint. - pub to_endpoint: mpsc::Sender, + to_endpoint: mpsc::Sender, - pub socket_addr: SocketAddr, + socket_addr: SocketAddr, } impl Endpoint { @@ -142,6 +145,23 @@ impl Endpoint { Ok(endpoint) } + + pub fn socket_addr(&self) -> &SocketAddr { + &self.socket_addr + } + + pub fn try_send( + &mut self, + to_endpoint: ToEndpoint, + cx: &mut Context<'_>, + ) -> Result, SendError> { + match self.to_endpoint.poll_ready_unpin(cx) { + Poll::Ready(Ok(())) => {} + Poll::Ready(Err(err)) => return Err(err), + Poll::Pending => return Ok(Err(to_endpoint)), + }; + self.to_endpoint.start_send(to_endpoint).map(Ok) + } } /// Message sent to the endpoint background task. diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index 0aa3295ac0a..a64dfa053dc 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -27,6 +27,7 @@ use crate::endpoint::ToEndpoint; use crate::Config; use crate::{endpoint::Endpoint, muxer::QuicMuxer, upgrade::Upgrade}; +use futures::channel::mpsc::SendError; use futures::channel::oneshot; use futures::ready; use futures::stream::StreamExt; @@ -140,7 +141,7 @@ impl Transport for QuicTransport { .listeners .iter_mut() .filter(|l| { - let listen_addr = l.endpoint.socket_addr; + let listen_addr = l.endpoint.socket_addr(); listen_addr.is_ipv4() == socket_addr.is_ipv4() && listen_addr.ip().is_loopback() == socket_addr.ip().is_loopback() }) @@ -177,7 +178,7 @@ impl Transport for QuicTransport { Ok(async move { let connection = rx .await - .expect("background task has crashed") + .map_err(|_| Error::TaskCrashed)? .map_err(Error::Reach)?; let final_connec = Upgrade::from_connection(connection).await?; Ok(final_connec) @@ -201,10 +202,18 @@ impl Transport for QuicTransport { cx: &mut Context<'_>, ) -> Poll> { if let Some(dialer) = self.ipv4_dialer.as_mut() { - dialer.drive_dials(cx) + if dialer.drive_dials(cx).is_err() { + // Background task of dialer crashed. + // Drop dialer and all pending dials so that the connection receiver is notified. + self.ipv4_dialer = None; + } } if let Some(dialer) = self.ipv6_dialer.as_mut() { - dialer.drive_dials(cx) + if dialer.drive_dials(cx).is_err() { + // Background task of dialer crashed. + // Drop dialer and all pending dials so that the connection receiver is notified. + self.ipv4_dialer = None; + } } match self.listeners.poll_next_unpin(cx) { Poll::Ready(Some(ev)) => Poll::Ready(ev), @@ -228,20 +237,18 @@ impl Dialer { }) } - fn drive_dials(&mut self, cx: &mut Context<'_>) { - if !self.pending_dials.is_empty() { - match self.endpoint.to_endpoint.poll_ready_unpin(cx) { - Poll::Ready(Ok(())) => { - let to_endpoint = self.pending_dials.pop_front().expect("!is_empty"); - self.endpoint - .to_endpoint - .start_send(to_endpoint) - .expect("Channel is ready."); + fn drive_dials(&mut self, cx: &mut Context<'_>) -> Result<(), SendError> { + if let Some(to_endpoint) = self.pending_dials.pop_front() { + match self.endpoint.try_send(to_endpoint, cx) { + Ok(Ok(())) => {} + Ok(Err(to_endpoint)) => self.pending_dials.push_front(to_endpoint), + Err(err) => { + tracing::error!("Background task of dialing endpoint crashed."); + return Err(err); } - Poll::Ready(Err(_)) => panic!("Background task crashed."), - Poll::Pending => {} } } + Ok(()) } } @@ -282,7 +289,7 @@ impl Listener { pending_event = None; } else { if_watcher = None; - let ma = socketaddr_to_multiaddr(&endpoint.socket_addr); + let ma = socketaddr_to_multiaddr(endpoint.socket_addr()); pending_event = Some(TransportEvent::NewAddress { listener_id, listen_addr: ma, @@ -324,8 +331,8 @@ impl Listener { match ready!(if_watcher.poll_if_event(cx)) { Ok(IfEvent::Up(inet)) => { let ip = inet.addr(); - if self.endpoint.socket_addr.is_ipv4() == ip.is_ipv4() { - let socket_addr = SocketAddr::new(ip, self.endpoint.socket_addr.port()); + if self.endpoint.socket_addr().is_ipv4() == ip.is_ipv4() { + let socket_addr = SocketAddr::new(ip, self.endpoint.socket_addr().port()); let ma = socketaddr_to_multiaddr(&socket_addr); tracing::debug!("New listen address: {}", ma); return Poll::Ready(TransportEvent::NewAddress { @@ -336,8 +343,8 @@ impl Listener { } Ok(IfEvent::Down(inet)) => { let ip = inet.addr(); - if self.endpoint.socket_addr.is_ipv4() == ip.is_ipv4() { - let socket_addr = SocketAddr::new(ip, self.endpoint.socket_addr.port()); + if self.endpoint.socket_addr().is_ipv4() == ip.is_ipv4() { + let socket_addr = SocketAddr::new(ip, self.endpoint.socket_addr().port()); let ma = socketaddr_to_multiaddr(&socket_addr); tracing::debug!("Expired listen address: {}", ma); return Poll::Ready(TransportEvent::AddressExpired { @@ -371,23 +378,14 @@ impl Stream for Listener { Poll::Ready(event) => return Poll::Ready(Some(event)), Poll::Pending => {} } - if !self.pending_dials.is_empty() { - match self.endpoint.to_endpoint.poll_ready_unpin(cx) { - Poll::Ready(Ok(_)) => { - let to_endpoint = self - .pending_dials - .pop_front() - .expect("Pending dials is not empty."); - self.endpoint - .to_endpoint - .start_send(to_endpoint) - .expect("Channel is ready"); - } - Poll::Ready(Err(_)) => { + if let Some(to_endpoint) = self.pending_dials.pop_front() { + match self.endpoint.try_send(to_endpoint, cx) { + Ok(Ok(())) => {} + Ok(Err(to_endpoint)) => self.pending_dials.push_front(to_endpoint), + Err(_) => { self.close(Err(Error::TaskCrashed)); continue; } - Poll::Pending => {} } } match self.new_connections_rx.poll_next_unpin(cx) { From 66c275520d8cf56152cce9a1c24bb4e2c42e0833 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Sun, 11 Sep 2022 16:55:26 +1000 Subject: [PATCH 76/92] swarm/: Fix rare test failure of `multiple_addresses_err` (#2882) In case we accidentally generate the same port twice, we will try to issue two dial attempts to the same address but also expect two dial errors which is exactly what this test is trying to catch. Unfortunately, the assertion is badly written and does not catch duplicate inputs. --- swarm/src/lib.rs | 66 ++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 230de4631db..7faaa43b44d 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -1624,7 +1624,6 @@ mod tests { use libp2p_core::transport::TransportEvent; use libp2p_core::Endpoint; use quickcheck::{quickcheck, Arbitrary, Gen, QuickCheck}; - use rand::prelude::SliceRandom; use rand::Rng; // Test execution state. @@ -2425,60 +2424,51 @@ mod tests { assert!(!swarm.is_connected(&peer_id)); } - #[test] - fn multiple_addresses_err() { + #[async_std::test] + async fn multiple_addresses_err() { // Tries dialing multiple addresses, and makes sure there's one dialing error per address. let target = PeerId::random(); let mut swarm = new_test_swarm::<_, ()>(DummyConnectionHandler::default()).build(); - let mut addresses = Vec::new(); - for _ in 0..3 { - addresses.push(multiaddr![Ip4([0, 0, 0, 0]), Tcp(rand::random::())]); - } - for _ in 0..5 { - addresses.push(multiaddr![Udp(rand::random::())]); - } - addresses.shuffle(&mut rand::thread_rng()); + let addresses = HashSet::from([ + multiaddr![Ip4([0, 0, 0, 0]), Tcp(rand::random::())], + multiaddr![Ip4([0, 0, 0, 0]), Tcp(rand::random::())], + multiaddr![Ip4([0, 0, 0, 0]), Tcp(rand::random::())], + multiaddr![Udp(rand::random::())], + multiaddr![Udp(rand::random::())], + multiaddr![Udp(rand::random::())], + multiaddr![Udp(rand::random::())], + multiaddr![Udp(rand::random::())], + ]); swarm .dial( DialOpts::peer_id(target) - .addresses(addresses.clone()) + .addresses(addresses.iter().cloned().collect()) .build(), ) .unwrap(); - futures::executor::block_on(future::poll_fn(|cx| -> Poll> { - loop { - match swarm.poll_next_unpin(cx) { - Poll::Ready(Some(SwarmEvent::OutgoingConnectionError { - peer_id, - // multiaddr, - error: DialError::Transport(errors), - })) => { - assert_eq!(peer_id.unwrap(), target); + match swarm.next().await.unwrap() { + SwarmEvent::OutgoingConnectionError { + peer_id, + // multiaddr, + error: DialError::Transport(errors), + } => { + assert_eq!(target, peer_id.unwrap()); - let failed_addresses = - errors.into_iter().map(|(addr, _)| addr).collect::>(); - assert_eq!( - failed_addresses, - addresses - .clone() - .into_iter() - .map(|addr| addr.with(Protocol::P2p(target.into()))) - .collect::>() - ); + let failed_addresses = errors.into_iter().map(|(addr, _)| addr).collect::>(); + let expected_addresses = addresses + .into_iter() + .map(|addr| addr.with(Protocol::P2p(target.into()))) + .collect::>(); - return Poll::Ready(Ok(())); - } - Poll::Ready(_) => unreachable!(), - Poll::Pending => break Poll::Pending, - } + assert_eq!(expected_addresses, failed_addresses); } - })) - .unwrap(); + e => panic!("Unexpected event: {e:?}"), + } } #[test] From 72bade1799aeb2658ccf252e291c0a19e9eb0543 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 14 Sep 2022 07:01:41 +0400 Subject: [PATCH 77/92] build(deps): Update env_logger to 0.9 and criterion to 0.4 (#2896) --- core/Cargo.toml | 2 +- misc/metrics/Cargo.toml | 2 +- muxers/mplex/Cargo.toml | 2 +- protocols/dcutr/Cargo.toml | 2 +- protocols/rendezvous/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index 3e5285ef6f4..0970b3e74d6 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -45,7 +45,7 @@ ring = { version = "0.16.9", features = ["alloc", "std"], default-features = fal [dev-dependencies] async-std = { version = "1.6.2", features = ["attributes"] } base64 = "0.13.0" -criterion = "0.3" +criterion = "0.4" libp2p-mplex = { path = "../muxers/mplex" } libp2p-noise = { path = "../transports/noise" } libp2p-tcp = { path = "../transports/tcp" } diff --git a/misc/metrics/Cargo.toml b/misc/metrics/Cargo.toml index 30df869248c..1da1fb583b5 100644 --- a/misc/metrics/Cargo.toml +++ b/misc/metrics/Cargo.toml @@ -33,7 +33,7 @@ libp2p-gossipsub = { version = "0.41.0", path = "../../protocols/gossipsub", op [dev-dependencies] log = "0.4.0" -env_logger = "0.8.1" +env_logger = "0.9.0" futures = "0.3.1" libp2p = { path = "../../", default-features = false, features = ["metrics", "ping", "tcp-async-io", "dns-async-std", "websocket", "noise", "mplex", "yamux"] } hyper = { version="0.14", features = ["server", "tcp", "http1"] } diff --git a/muxers/mplex/Cargo.toml b/muxers/mplex/Cargo.toml index 1e4f6974aa3..d4ea5342262 100644 --- a/muxers/mplex/Cargo.toml +++ b/muxers/mplex/Cargo.toml @@ -24,7 +24,7 @@ unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] } [dev-dependencies] async-std = "1.7.0" -criterion = "0.3" +criterion = "0.4" env_logger = "0.9" futures = "0.3" libp2p-tcp = { path = "../../transports/tcp" } diff --git a/protocols/dcutr/Cargo.toml b/protocols/dcutr/Cargo.toml index bc015ab0d80..dd059e41422 100644 --- a/protocols/dcutr/Cargo.toml +++ b/protocols/dcutr/Cargo.toml @@ -29,7 +29,7 @@ void = "1" prost-build = "0.11" [dev-dependencies] -env_logger = "0.8.3" +env_logger = "0.9.0" libp2p = { path = "../..", default-features = false, features = ["dcutr", "relay", "plaintext", "identify", "tcp-async-io", "ping", "noise", "dns-async-std"] } libp2p-identify = { path = "../identify" } libp2p-plaintext = { path = "../../transports/plaintext" } diff --git a/protocols/rendezvous/Cargo.toml b/protocols/rendezvous/Cargo.toml index fadcaf59580..3eee5c833e6 100644 --- a/protocols/rendezvous/Cargo.toml +++ b/protocols/rendezvous/Cargo.toml @@ -28,7 +28,7 @@ instant = "0.1.11" [dev-dependencies] async-trait = "0.1" -env_logger = "0.8" +env_logger = "0.9.0" libp2p = { path = "../..", default-features = false, features = ["ping", "identify", "tcp-async-io", "dns-async-std", "websocket", "noise", "mplex", "yamux", "rendezvous"] } rand = "0.8" tokio = { version = "1.15", features = [ "rt-multi-thread", "time", "macros", "sync", "process", "fs", "net" ] } From 5906140d38b4298a97a6b3cec9cb9a41962463c0 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Thu, 15 Sep 2022 16:30:32 +0300 Subject: [PATCH 78/92] protocols/kad: Remove deprecated `set_protocol_name()` (#2866) --- CHANGELOG.md | 4 ++++ Cargo.toml | 4 ++-- misc/metrics/CHANGELOG.md | 4 ++++ misc/metrics/Cargo.toml | 4 ++-- protocols/kad/CHANGELOG.md | 7 +++++++ protocols/kad/Cargo.toml | 2 +- protocols/kad/src/behaviour.rs | 10 ---------- protocols/kad/src/protocol.rs | 7 ------- 8 files changed, 20 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d28138e1e7e..0332b09b316 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,10 @@ - Update to [`libp2p-tcp` `v0.37.0`](transports/tcp/CHANGELOG.md#0370). +- Update to [`libp2p-metrics` `v0.10.0`](misc/metrics/CHANGELOG.md#0100). + +- Update to [`libp2p-kad` `v0.41.0`](protocols/kad/CHANGELOG.md#0410). + # 0.48.0 - Update to [`libp2p-core` `v0.36.0`](core/CHANGELOG.md#0360). diff --git a/Cargo.toml b/Cargo.toml index 89e63a4e5cd..f8186286de3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,8 +85,8 @@ libp2p-core = { version = "0.36.0", path = "core", default-features = false } libp2p-dcutr = { version = "0.6.0", path = "protocols/dcutr", optional = true } libp2p-floodsub = { version = "0.39.0", path = "protocols/floodsub", optional = true } libp2p-identify = { version = "0.39.0", path = "protocols/identify", optional = true } -libp2p-kad = { version = "0.40.0", path = "protocols/kad", optional = true } -libp2p-metrics = { version = "0.9.0", path = "misc/metrics", optional = true } +libp2p-kad = { version = "0.41.0", path = "protocols/kad", optional = true } +libp2p-metrics = { version = "0.10.0", path = "misc/metrics", optional = true } libp2p-mplex = { version = "0.36.0", path = "muxers/mplex", optional = true } libp2p-noise = { version = "0.39.0", path = "transports/noise", optional = true } libp2p-ping = { version = "0.39.0", path = "protocols/ping", optional = true } diff --git a/misc/metrics/CHANGELOG.md b/misc/metrics/CHANGELOG.md index 1ce05054600..1b784ffa1f9 100644 --- a/misc/metrics/CHANGELOG.md +++ b/misc/metrics/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.10.0 [unreleased] + +- Update to `libp2p-kad` `v0.41.0`. + # 0.9.0 - Update to `libp2p-swarm` `v0.39.0`. diff --git a/misc/metrics/Cargo.toml b/misc/metrics/Cargo.toml index 1da1fb583b5..1c29fceec24 100644 --- a/misc/metrics/Cargo.toml +++ b/misc/metrics/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-metrics" edition = "2021" rust-version = "1.56.1" description = "Metrics for libp2p" -version = "0.9.0" +version = "0.10.0" authors = ["Max Inden "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -22,7 +22,7 @@ dcutr = ["libp2p-dcutr"] libp2p-core = { version = "0.36.0", path = "../../core", default-features = false } libp2p-dcutr = { version = "0.6.0", path = "../../protocols/dcutr", optional = true } libp2p-identify = { version = "0.39.0", path = "../../protocols/identify", optional = true } -libp2p-kad = { version = "0.40.0", path = "../../protocols/kad", optional = true } +libp2p-kad = { version = "0.41.0", path = "../../protocols/kad", optional = true } libp2p-ping = { version = "0.39.0", path = "../../protocols/ping", optional = true } libp2p-relay = { version = "0.12.0", path = "../../protocols/relay", optional = true } libp2p-swarm = { version = "0.39.0", path = "../../swarm" } diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index d161d93de83..2f41a093019 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -1,3 +1,10 @@ +# 0.41.0 [unreleased] + +- Remove deprecated `set_protocol_name()` from `KademliaConfig` & `KademliaProtocolConfig`. + Use `set_protocol_names()` instead. See [PR 2866]. + +[PR 2866]: https://github.com/libp2p/rust-libp2p/pull/2866 + # 0.40.0 - Add support for multiple protocol names. Update `Kademlia`, `KademliaConfig`, diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index 9aec22c609a..c65e34ecdbc 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-kad" edition = "2021" rust-version = "1.56.1" description = "Kademlia protocol for libp2p" -version = "0.40.0" +version = "0.41.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index feba94f550e..b267f87d386 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -228,16 +228,6 @@ impl KademliaConfig { self } - /// Sets a custom protocol name. - /// - /// Kademlia nodes only communicate with other nodes using the same protocol - /// name. Using a custom name therefore allows to segregate the DHT from - /// others, if that is desired. - #[deprecated(since = "0.40.0", note = "use `set_protocol_names()` instead")] - pub fn set_protocol_name(&mut self, name: impl Into>) -> &mut Self { - self.set_protocol_names(std::iter::once(name.into()).collect()) - } - /// Sets the timeout for a single query. /// /// > **Note**: A single query usually comprises at least as many requests diff --git a/protocols/kad/src/protocol.rs b/protocols/kad/src/protocol.rs index 3c00a5059f2..707edd8fe02 100644 --- a/protocols/kad/src/protocol.rs +++ b/protocols/kad/src/protocol.rs @@ -159,13 +159,6 @@ impl KademliaProtocolConfig { self.protocol_names = names; } - /// Sets single protocol name used on the wire. Can be used to create incompatibilities - /// between networks on purpose. - #[deprecated(since = "0.40.0", note = "use `set_protocol_names()` instead")] - pub fn set_protocol_name(&mut self, name: impl Into>) { - self.set_protocol_names(std::iter::once(name.into()).collect()); - } - /// Modifies the maximum allowed size of a single Kademlia packet. pub fn set_max_packet_size(&mut self, size: usize) { self.max_packet_size = size; From 2c739e9bdb2c51199b7ade7f3aa0cb65671e5721 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 11:41:35 +1000 Subject: [PATCH 79/92] protocols/noise: Introduce `NoiseAuthenticated::xx` constructor with X25519 DH key exchange (#2887) Co-authored-by: Max Inden --- Cargo.toml | 2 +- core/tests/transport_upgrade.rs | 10 ++-------- examples/chat-tokio.rs | 10 ++++------ examples/ipfs-private.rs | 5 +---- protocols/dcutr/examples/client.rs | 9 ++++----- protocols/gossipsub/src/lib.rs | 3 +-- protocols/kad/src/behaviour/test.rs | 5 +---- protocols/ping/tests/ping.rs | 5 +---- protocols/relay/examples/relay_v2.rs | 9 ++++----- protocols/rendezvous/tests/harness.rs | 9 ++------- protocols/request-response/tests/ping.rs | 8 +++----- src/lib.rs | 12 ++---------- transports/noise/CHANGELOG.md | 7 +++++++ transports/noise/Cargo.toml | 2 +- transports/noise/src/lib.rs | 18 +++++++++++++++--- transports/noise/tests/smoke.rs | 6 +++--- 16 files changed, 52 insertions(+), 68 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f8186286de3..0b67edda7f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,7 +88,7 @@ libp2p-identify = { version = "0.39.0", path = "protocols/identify", optional = libp2p-kad = { version = "0.41.0", path = "protocols/kad", optional = true } libp2p-metrics = { version = "0.10.0", path = "misc/metrics", optional = true } libp2p-mplex = { version = "0.36.0", path = "muxers/mplex", optional = true } -libp2p-noise = { version = "0.39.0", path = "transports/noise", optional = true } +libp2p-noise = { version = "0.39.1", path = "transports/noise", optional = true } libp2p-ping = { version = "0.39.0", path = "protocols/ping", optional = true } libp2p-plaintext = { version = "0.36.0", path = "transports/plaintext", optional = true } libp2p-pnet = { version = "0.22.0", path = "transports/pnet", optional = true } diff --git a/core/tests/transport_upgrade.rs b/core/tests/transport_upgrade.rs index 723a04b0780..dac84534369 100644 --- a/core/tests/transport_upgrade.rs +++ b/core/tests/transport_upgrade.rs @@ -79,12 +79,9 @@ where fn upgrade_pipeline() { let listener_keys = identity::Keypair::generate_ed25519(); let listener_id = listener_keys.public().to_peer_id(); - let listener_noise_keys = noise::Keypair::::new() - .into_authentic(&listener_keys) - .unwrap(); let mut listener_transport = MemoryTransport::default() .upgrade(upgrade::Version::V1) - .authenticate(noise::NoiseConfig::xx(listener_noise_keys).into_authenticated()) + .authenticate(noise::NoiseAuthenticated::xx(&listener_keys).unwrap()) .apply(HelloUpgrade {}) .apply(HelloUpgrade {}) .apply(HelloUpgrade {}) @@ -93,12 +90,9 @@ fn upgrade_pipeline() { let dialer_keys = identity::Keypair::generate_ed25519(); let dialer_id = dialer_keys.public().to_peer_id(); - let dialer_noise_keys = noise::Keypair::::new() - .into_authentic(&dialer_keys) - .unwrap(); let mut dialer_transport = MemoryTransport::default() .upgrade(upgrade::Version::V1) - .authenticate(noise::NoiseConfig::xx(dialer_noise_keys).into_authenticated()) + .authenticate(noise::NoiseAuthenticated::xx(&dialer_keys).unwrap()) .apply(HelloUpgrade {}) .apply(HelloUpgrade {}) .apply(HelloUpgrade {}) diff --git a/examples/chat-tokio.rs b/examples/chat-tokio.rs index f82d30934c9..5ee00f9eedc 100644 --- a/examples/chat-tokio.rs +++ b/examples/chat-tokio.rs @@ -70,16 +70,14 @@ async fn main() -> Result<(), Box> { let peer_id = PeerId::from(id_keys.public()); println!("Local peer id: {:?}", peer_id); - // Create a keypair for authenticated encryption of the transport. - let noise_keys = noise::Keypair::::new() - .into_authentic(&id_keys) - .expect("Signing libp2p-noise static DH keypair failed."); - // Create a tokio-based TCP transport use noise for authenticated // encryption and Mplex for multiplexing of substreams on a TCP stream. let transport = TokioTcpTransport::new(GenTcpConfig::default().nodelay(true)) .upgrade(upgrade::Version::V1) - .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) + .authenticate( + noise::NoiseAuthenticated::xx(&id_keys) + .expect("Signing libp2p-noise static DH keypair failed."), + ) .multiplex(mplex::MplexConfig::new()) .boxed(); diff --git a/examples/ipfs-private.rs b/examples/ipfs-private.rs index 93e73cd5976..c0596816919 100644 --- a/examples/ipfs-private.rs +++ b/examples/ipfs-private.rs @@ -57,10 +57,7 @@ pub fn build_transport( key_pair: identity::Keypair, psk: Option, ) -> transport::Boxed<(PeerId, StreamMuxerBox)> { - let noise_keys = noise::Keypair::::new() - .into_authentic(&key_pair) - .unwrap(); - let noise_config = noise::NoiseConfig::xx(noise_keys).into_authenticated(); + let noise_config = noise::NoiseAuthenticated::xx(&key_pair).unwrap(); let yamux_config = YamuxConfig::default(); let base_transport = TcpTransport::new(GenTcpConfig::default().nodelay(true)); diff --git a/protocols/dcutr/examples/client.rs b/protocols/dcutr/examples/client.rs index dd73b7d3ac3..54448ff635d 100644 --- a/protocols/dcutr/examples/client.rs +++ b/protocols/dcutr/examples/client.rs @@ -89,10 +89,6 @@ fn main() -> Result<(), Box> { let (relay_transport, client) = Client::new_transport_and_behaviour(local_peer_id); - let noise_keys = noise::Keypair::::new() - .into_authentic(&local_key) - .expect("Signing libp2p-noise static DH keypair failed."); - let transport = OrTransport::new( relay_transport, block_on(DnsConfig::system(TcpTransport::new( @@ -101,7 +97,10 @@ fn main() -> Result<(), Box> { .unwrap(), ) .upgrade(upgrade::Version::V1) - .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) + .authenticate( + noise::NoiseAuthenticated::xx(&local_key) + .expect("Signing libp2p-noise static DH keypair failed."), + ) .multiplex(libp2p_yamux::YamuxConfig::default()) .boxed(); diff --git a/protocols/gossipsub/src/lib.rs b/protocols/gossipsub/src/lib.rs index d86263aace4..4022a23185d 100644 --- a/protocols/gossipsub/src/lib.rs +++ b/protocols/gossipsub/src/lib.rs @@ -97,10 +97,9 @@ //! //! // Set up an encrypted TCP Transport over the Mplex //! // This is test transport (memory). -//! let noise_keys = libp2p_noise::Keypair::::new().into_authentic(&local_key).unwrap(); //! let transport = MemoryTransport::default() //! .upgrade(libp2p_core::upgrade::Version::V1) -//! .authenticate(libp2p_noise::NoiseConfig::xx(noise_keys).into_authenticated()) +//! .authenticate(libp2p_noise::NoiseAuthenticated::xx(&local_key).unwrap()) //! .multiplex(libp2p_mplex::MplexConfig::new()) //! .boxed(); //! diff --git a/protocols/kad/src/behaviour/test.rs b/protocols/kad/src/behaviour/test.rs index 1f67be5a19d..aab7fa0ef28 100644 --- a/protocols/kad/src/behaviour/test.rs +++ b/protocols/kad/src/behaviour/test.rs @@ -56,12 +56,9 @@ fn build_node() -> (Multiaddr, TestSwarm) { fn build_node_with_config(cfg: KademliaConfig) -> (Multiaddr, TestSwarm) { let local_key = identity::Keypair::generate_ed25519(); let local_public_key = local_key.public(); - let noise_keys = noise::Keypair::::new() - .into_authentic(&local_key) - .unwrap(); let transport = MemoryTransport::default() .upgrade(upgrade::Version::V1) - .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) + .authenticate(noise::NoiseAuthenticated::xx(&local_key).unwrap()) .multiplex(yamux::YamuxConfig::default()) .boxed(); diff --git a/protocols/ping/tests/ping.rs b/protocols/ping/tests/ping.rs index ac45949ced7..2f75c09fb3d 100644 --- a/protocols/ping/tests/ping.rs +++ b/protocols/ping/tests/ping.rs @@ -243,14 +243,11 @@ fn unsupported_doesnt_fail() { fn mk_transport(muxer: MuxerChoice) -> (PeerId, transport::Boxed<(PeerId, StreamMuxerBox)>) { let id_keys = identity::Keypair::generate_ed25519(); let peer_id = id_keys.public().to_peer_id(); - let noise_keys = noise::Keypair::::new() - .into_authentic(&id_keys) - .unwrap(); ( peer_id, TcpTransport::new(GenTcpConfig::default().nodelay(true)) .upgrade(upgrade::Version::V1) - .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) + .authenticate(noise::NoiseAuthenticated::xx(&id_keys).unwrap()) .multiplex(match muxer { MuxerChoice::Yamux => upgrade::EitherUpgrade::A(yamux::YamuxConfig::default()), MuxerChoice::Mplex => upgrade::EitherUpgrade::B(mplex::MplexConfig::default()), diff --git a/protocols/relay/examples/relay_v2.rs b/protocols/relay/examples/relay_v2.rs index 25d0bb7fc94..b89c88b2829 100644 --- a/protocols/relay/examples/relay_v2.rs +++ b/protocols/relay/examples/relay_v2.rs @@ -48,13 +48,12 @@ fn main() -> Result<(), Box> { let tcp_transport = TcpTransport::default(); - let noise_keys = noise::Keypair::::new() - .into_authentic(&local_key) - .expect("Signing libp2p-noise static DH keypair failed."); - let transport = tcp_transport .upgrade(upgrade::Version::V1) - .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) + .authenticate( + noise::NoiseAuthenticated::xx(&local_key) + .expect("Signing libp2p-noise static DH keypair failed."), + ) .multiplex(libp2p_yamux::YamuxConfig::default()) .boxed(); diff --git a/protocols/rendezvous/tests/harness.rs b/protocols/rendezvous/tests/harness.rs index 555a5476bab..30dace245ff 100644 --- a/protocols/rendezvous/tests/harness.rs +++ b/protocols/rendezvous/tests/harness.rs @@ -27,7 +27,7 @@ use libp2p::core::transport::MemoryTransport; use libp2p::core::upgrade::SelectUpgrade; use libp2p::core::{identity, Multiaddr, PeerId, Transport}; use libp2p::mplex::MplexConfig; -use libp2p::noise::{Keypair, NoiseConfig, X25519Spec}; +use libp2p::noise::NoiseAuthenticated; use libp2p::swarm::{AddressScore, NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent}; use libp2p::yamux::YamuxConfig; use std::fmt::Debug; @@ -43,14 +43,9 @@ where let identity = identity::Keypair::generate_ed25519(); let peer_id = PeerId::from(identity.public()); - let dh_keys = Keypair::::new() - .into_authentic(&identity) - .expect("failed to create dh_keys"); - let noise = NoiseConfig::xx(dh_keys).into_authenticated(); - let transport = MemoryTransport::default() .upgrade(Version::V1) - .authenticate(noise) + .authenticate(NoiseAuthenticated::xx(&identity).unwrap()) .multiplex(SelectUpgrade::new( YamuxConfig::default(), MplexConfig::new(), diff --git a/protocols/request-response/tests/ping.rs b/protocols/request-response/tests/ping.rs index 8cbc06e7444..bfb8641c106 100644 --- a/protocols/request-response/tests/ping.rs +++ b/protocols/request-response/tests/ping.rs @@ -29,7 +29,7 @@ use libp2p_core::{ upgrade::{self, read_length_prefixed, write_length_prefixed}, Multiaddr, PeerId, }; -use libp2p_noise::{Keypair, NoiseConfig, X25519Spec}; +use libp2p_noise::NoiseAuthenticated; use libp2p_request_response::*; use libp2p_swarm::{Swarm, SwarmEvent}; use libp2p_tcp::{GenTcpConfig, TcpTransport}; @@ -295,14 +295,12 @@ fn emits_inbound_connection_closed_if_channel_is_dropped() { fn mk_transport() -> (PeerId, transport::Boxed<(PeerId, StreamMuxerBox)>) { let id_keys = identity::Keypair::generate_ed25519(); let peer_id = id_keys.public().to_peer_id(); - let noise_keys = Keypair::::new() - .into_authentic(&id_keys) - .unwrap(); + ( peer_id, TcpTransport::new(GenTcpConfig::default().nodelay(true)) .upgrade(upgrade::Version::V1) - .authenticate(NoiseConfig::xx(noise_keys).into_authenticated()) + .authenticate(NoiseAuthenticated::xx(&id_keys).unwrap()) .multiplex(libp2p_yamux::YamuxConfig::default()) .boxed(), ) diff --git a/src/lib.rs b/src/lib.rs index 3ed00408cb5..96a197cf516 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -217,13 +217,9 @@ pub async fn development_transport( dns_tcp.or_transport(ws_dns_tcp) }; - let noise_keys = noise::Keypair::::new() - .into_authentic(&keypair) - .expect("Signing libp2p-noise static DH keypair failed."); - Ok(transport .upgrade(core::upgrade::Version::V1) - .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) + .authenticate(noise::NoiseAuthenticated::xx(&keypair).unwrap()) .multiplex(core::upgrade::SelectUpgrade::new( yamux::YamuxConfig::default(), mplex::MplexConfig::default(), @@ -277,13 +273,9 @@ pub fn tokio_development_transport( dns_tcp.or_transport(ws_dns_tcp) }; - let noise_keys = noise::Keypair::::new() - .into_authentic(&keypair) - .expect("Signing libp2p-noise static DH keypair failed."); - Ok(transport .upgrade(core::upgrade::Version::V1) - .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) + .authenticate(noise::NoiseAuthenticated::xx(&keypair).unwrap()) .multiplex(core::upgrade::SelectUpgrade::new( yamux::YamuxConfig::default(), mplex::MplexConfig::default(), diff --git a/transports/noise/CHANGELOG.md b/transports/noise/CHANGELOG.md index de2c1034a9e..1416aab4e30 100644 --- a/transports/noise/CHANGELOG.md +++ b/transports/noise/CHANGELOG.md @@ -1,3 +1,10 @@ +# 0.39.1 [unreleased] + +- Introduce `NoiseAuthenticated::xx` constructor, assuming a X25519 DH key exchange. An XX key exchange and X25519 keys + are the most common way of using noise in libp2p and thus deserve a convenience constructor. See [PR 2887]. + +[PR 2887]: https://github.com/libp2p/rust-libp2p/pull/2887 + # 0.39.0 - Update to `libp2p-core` `v0.36.0`. diff --git a/transports/noise/Cargo.toml b/transports/noise/Cargo.toml index 5ee9330818d..8fef520cb9a 100644 --- a/transports/noise/Cargo.toml +++ b/transports/noise/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-noise" edition = "2021" rust-version = "1.56.1" description = "Cryptographic handshake protocol using the noise framework." -version = "0.39.0" +version = "0.39.1" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index ee609fd028d..1712176d7ef 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -41,12 +41,11 @@ //! ``` //! use libp2p_core::{identity, Transport, upgrade}; //! use libp2p_tcp::TcpTransport; -//! use libp2p_noise::{Keypair, X25519Spec, NoiseConfig}; +//! use libp2p_noise::{Keypair, X25519Spec, NoiseAuthenticated}; //! //! # fn main() { //! let id_keys = identity::Keypair::generate_ed25519(); -//! let dh_keys = Keypair::::new().into_authentic(&id_keys).unwrap(); -//! let noise = NoiseConfig::xx(dh_keys).into_authenticated(); +//! let noise = NoiseAuthenticated::xx(&id_keys).unwrap(); //! let builder = TcpTransport::default().upgrade(upgrade::Version::V1).authenticate(noise); //! // let transport = builder.multiplex(...); //! # } @@ -357,6 +356,19 @@ pub struct NoiseAuthenticated { config: NoiseConfig, } +impl NoiseAuthenticated { + /// Create a new [`NoiseAuthenticated`] for the `XX` handshake pattern using X25519 DH keys. + /// + /// For now, this is the only combination that is guaranteed to be compatible with other libp2p implementations. + pub fn xx(id_keys: &identity::Keypair) -> Result { + let dh_keys = Keypair::::new(); + let noise_keys = dh_keys.into_authentic(id_keys)?; + let config = NoiseConfig::xx(noise_keys); + + Ok(config.into_authenticated()) + } +} + impl UpgradeInfo for NoiseAuthenticated where NoiseConfig: UpgradeInfo, diff --git a/transports/noise/tests/smoke.rs b/transports/noise/tests/smoke.rs index 0148d03b4d6..14d09621dd9 100644 --- a/transports/noise/tests/smoke.rs +++ b/transports/noise/tests/smoke.rs @@ -27,7 +27,8 @@ use libp2p_core::identity; use libp2p_core::transport::{self, Transport}; use libp2p_core::upgrade::{self, apply_inbound, apply_outbound, Negotiated}; use libp2p_noise::{ - Keypair, NoiseConfig, NoiseError, NoiseOutput, RemoteIdentity, X25519Spec, X25519, + Keypair, NoiseAuthenticated, NoiseConfig, NoiseError, NoiseOutput, RemoteIdentity, X25519Spec, + X25519, }; use libp2p_tcp::TcpTransport; use log::info; @@ -39,8 +40,7 @@ fn core_upgrade_compat() { // Tests API compaibility with the libp2p-core upgrade API, // i.e. if it compiles, the "test" is considered a success. let id_keys = identity::Keypair::generate_ed25519(); - let dh_keys = Keypair::::new().into_authentic(&id_keys).unwrap(); - let noise = NoiseConfig::xx(dh_keys).into_authenticated(); + let noise = NoiseAuthenticated::xx(&id_keys).unwrap(); let _ = TcpTransport::default() .upgrade(upgrade::Version::V1) .authenticate(noise); From c81b06a9b2c0b4cb8d7f8af1acd7a916ec93d12b Mon Sep 17 00:00:00 2001 From: Hannes <55623006+umgefahren@users.noreply.github.com> Date: Fri, 16 Sep 2022 16:30:11 +0200 Subject: [PATCH 80/92] *: Fix various clippy warnings (#2900) --- protocols/gossipsub/src/behaviour.rs | 19 ++++++++----------- protocols/kad/src/handler.rs | 18 ++---------------- protocols/mdns/src/behaviour/iface.rs | 4 ++-- protocols/mdns/src/behaviour/iface/dns.rs | 2 +- 4 files changed, 13 insertions(+), 30 deletions(-) diff --git a/protocols/gossipsub/src/behaviour.rs b/protocols/gossipsub/src/behaviour.rs index 954c68ae24b..21dd77562df 100644 --- a/protocols/gossipsub/src/behaviour.rs +++ b/protocols/gossipsub/src/behaviour.rs @@ -649,7 +649,7 @@ where set.iter() .filter(|p| { self.explicit_peers.contains(*p) - || !self.score_below_threshold(*p, |ts| ts.publish_threshold).0 + || !self.score_below_threshold(p, |ts| ts.publish_threshold).0 }) .cloned(), ); @@ -946,14 +946,11 @@ where ); // remove explicit peers, peers with negative scores, and backoffed peers - peers = peers - .into_iter() - .filter(|p| { - !self.explicit_peers.contains(p) - && !self.score_below_threshold(p, |_| 0.0).0 - && !self.backoffs.is_backoff_with_slack(topic_hash, p) - }) - .collect(); + peers.retain(|p| { + !self.explicit_peers.contains(p) + && !self.score_below_threshold(p, |_| 0.0).0 + && !self.backoffs.is_backoff_with_slack(topic_hash, p) + }); // Add up to mesh_n of them them to the mesh // NOTE: These aren't randomly added, currently FIFO @@ -1625,7 +1622,7 @@ where // //TODO: Once signed records are spec'd: Can we use peerInfo without any IDs if they have a // signed peer record? - px = px.into_iter().filter(|p| p.peer_id.is_some()).collect(); + px.retain(|p| p.peer_id.is_some()); if px.len() > n { // only use at most prune_peers many random peers let mut rng = thread_rng(); @@ -3204,7 +3201,7 @@ where debug!("Peer disconnected: {}", peer_id); { let topics = match self.peer_topics.get(peer_id) { - Some(topics) => (topics), + Some(topics) => topics, None => { debug_assert!( self.blacklisted_peers.contains(peer_id), diff --git a/protocols/kad/src/handler.rs b/protocols/kad/src/handler.rs index bcadb57f44c..5be9ae17737 100644 --- a/protocols/kad/src/handler.rs +++ b/protocols/kad/src/handler.rs @@ -658,14 +658,7 @@ where let pos = self .inbound_substreams .iter() - .position(|state| match state { - InboundSubstreamState::WaitingUser(ref conn_id, _) - if conn_id == &request_id.connec_unique_id => - { - true - } - _ => false, - }); + .position(|state| matches!(state, InboundSubstreamState::WaitingUser(ref conn_id, _) if conn_id == &request_id.connec_unique_id)); if let Some(pos) = pos { let (conn_id, substream) = match self.inbound_substreams.remove(pos) { @@ -737,14 +730,7 @@ where let pos = self .inbound_substreams .iter() - .position(|state| match state { - InboundSubstreamState::WaitingUser(ref conn_id, _) - if conn_id == &request_id.connec_unique_id => - { - true - } - _ => false, - }); + .position(|state| matches!(state, InboundSubstreamState::WaitingUser(ref conn_id, _) if conn_id == &request_id.connec_unique_id)); if let Some(pos) = pos { let (conn_id, substream) = match self.inbound_substreams.remove(pos) { diff --git a/protocols/mdns/src/behaviour/iface.rs b/protocols/mdns/src/behaviour/iface.rs index c5bacced138..b2d0506b226 100644 --- a/protocols/mdns/src/behaviour/iface.rs +++ b/protocols/mdns/src/behaviour/iface.rs @@ -85,7 +85,7 @@ where socket.bind(&SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 5353).into())?; socket.set_multicast_loop_v4(true)?; socket.set_multicast_ttl_v4(255)?; - socket.join_multicast_v4(&*crate::IPV4_MDNS_MULTICAST_ADDRESS, &addr)?; + socket.join_multicast_v4(&crate::IPV4_MDNS_MULTICAST_ADDRESS, &addr)?; U::from_std(UdpSocket::from(socket))? } IpAddr::V6(_) => { @@ -96,7 +96,7 @@ where socket.bind(&SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 5353).into())?; socket.set_multicast_loop_v6(true)?; // TODO: find interface matching addr. - socket.join_multicast_v6(&*crate::IPV6_MDNS_MULTICAST_ADDRESS, 0)?; + socket.join_multicast_v6(&crate::IPV6_MDNS_MULTICAST_ADDRESS, 0)?; U::from_std(UdpSocket::from(socket))? } }; diff --git a/protocols/mdns/src/behaviour/iface/dns.rs b/protocols/mdns/src/behaviour/iface/dns.rs index 5bb190f4c2c..4590e1e266e 100644 --- a/protocols/mdns/src/behaviour/iface/dns.rs +++ b/protocols/mdns/src/behaviour/iface/dns.rs @@ -246,7 +246,7 @@ fn query_response_packet(id: u16, peer_id: &[u8], records: &[Vec], ttl: u32) fn duration_to_secs(duration: Duration) -> u32 { let secs = duration .as_secs() - .saturating_add(if duration.subsec_nanos() > 0 { 1 } else { 0 }); + .saturating_add(u64::from(duration.subsec_nanos() > 0)); cmp::min(secs, From::from(u32::max_value())) as u32 } From 2025de3ef0898ffa99545bd50aef868516c7f226 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Sat, 17 Sep 2022 00:57:41 +1000 Subject: [PATCH 81/92] swarm-derive/: Allow for templated behaviours (#2907) This patch fixes an issue where we couldn't use type parameters on a behaviour with a custom out event that had different type parameters. --- CHANGELOG.md | 2 ++ Cargo.toml | 2 +- swarm-derive/CHANGELOG.md | 7 +++++ swarm-derive/Cargo.toml | 3 +- swarm-derive/src/lib.rs | 10 ++++-- swarm-derive/tests/test.rs | 62 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 82 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0332b09b316..2aa74dae1df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ - Update to [`libp2p-tcp` `v0.37.0`](transports/tcp/CHANGELOG.md#0370). +- Update to [`libp2p-swarm-derive` `v0.30.1`](swarm-derive/CHANGELOG.md#0301). + - Update to [`libp2p-metrics` `v0.10.0`](misc/metrics/CHANGELOG.md#0100). - Update to [`libp2p-kad` `v0.41.0`](protocols/kad/CHANGELOG.md#0410). diff --git a/Cargo.toml b/Cargo.toml index 0b67edda7f3..3f82880528b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,7 +96,7 @@ libp2p-relay = { version = "0.12.0", path = "protocols/relay", optional = true } libp2p-rendezvous = { version = "0.9.0", path = "protocols/rendezvous", optional = true } libp2p-request-response = { version = "0.21.0", path = "protocols/request-response", optional = true } libp2p-swarm = { version = "0.39.0", path = "swarm" } -libp2p-swarm-derive = { version = "0.30.0", path = "swarm-derive" } +libp2p-swarm-derive = { version = "0.30.1", path = "swarm-derive" } libp2p-uds = { version = "0.35.0", path = "transports/uds", optional = true } libp2p-wasm-ext = { version = "0.36.0", path = "transports/wasm-ext", default-features = false, optional = true } libp2p-yamux = { version = "0.40.0", path = "muxers/yamux", optional = true } diff --git a/swarm-derive/CHANGELOG.md b/swarm-derive/CHANGELOG.md index 79ddf8c8f2e..464bec7fe95 100644 --- a/swarm-derive/CHANGELOG.md +++ b/swarm-derive/CHANGELOG.md @@ -1,3 +1,10 @@ +# 0.30.1 [unreleased] + +- Fix an issue where the derive would generate bad code if the type parameters between the behaviour and a custom + out event differed. See [PR 2907]. + +[PR 2907]: https://github.com/libp2p/rust-libp2p/pull/2907 + # 0.30.0 - Remove support for removed `NetworkBehaviourEventProcess`. See [PR 2840]. diff --git a/swarm-derive/Cargo.toml b/swarm-derive/Cargo.toml index 89ee54447fc..1d2c54a9da1 100644 --- a/swarm-derive/Cargo.toml +++ b/swarm-derive/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-swarm-derive" edition = "2021" rust-version = "1.56.1" description = "Procedural macros of libp2p-core" -version = "0.30.0" +version = "0.30.1" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -22,3 +22,4 @@ syn = { version = "1.0.8", default-features = false, features = ["clone-impls", libp2p = { path = "../", default-features = false, features = ["ping", "identify", "kad"] } either = "1.6.0" futures = "0.3.1" +void = "1" diff --git a/swarm-derive/src/lib.rs b/swarm-derive/src/lib.rs index 3e3bf5b8067..6899ba7d79d 100644 --- a/swarm-derive/src/lib.rs +++ b/swarm-derive/src/lib.rs @@ -100,7 +100,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { .iter() .map(|field| { let ty = &field.ty; - quote! {#name #ty_generics: From< <#ty as #trait_to_impl>::OutEvent >} + quote! {#name: From< <#ty as #trait_to_impl>::OutEvent >} }) .collect::>(); (name, definition, from_clauses) @@ -537,6 +537,12 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { }) }); + let out_event_reference = if out_event_definition.is_some() { + quote! { #out_event_name #ty_generics } + } else { + quote! { #out_event_name } + }; + // Now the magic happens. let final_quote = quote! { #out_event_definition @@ -545,7 +551,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { #where_clause { type ConnectionHandler = #connection_handler_ty; - type OutEvent = #out_event_name #ty_generics; + type OutEvent = #out_event_reference; fn new_handler(&mut self) -> Self::ConnectionHandler { use #into_connection_handler; diff --git a/swarm-derive/tests/test.rs b/swarm-derive/tests/test.rs index dcddb3a6a3f..e0f77eefd30 100644 --- a/swarm-derive/tests/test.rs +++ b/swarm-derive/tests/test.rs @@ -350,3 +350,65 @@ fn generated_out_event_derive_debug() { require_debug::(); } + +#[test] +fn custom_out_event_no_type_parameters() { + use libp2p::core::connection::ConnectionId; + use libp2p::swarm::handler::DummyConnectionHandler; + use libp2p::swarm::{ + ConnectionHandler, IntoConnectionHandler, NetworkBehaviourAction, PollParameters, + }; + use libp2p::PeerId; + use std::task::Context; + use std::task::Poll; + + pub struct TemplatedBehaviour { + _data: T, + } + + impl NetworkBehaviour for TemplatedBehaviour { + type ConnectionHandler = DummyConnectionHandler; + type OutEvent = void::Void; + + fn new_handler(&mut self) -> Self::ConnectionHandler { + DummyConnectionHandler::default() + } + + fn inject_event( + &mut self, + _peer: PeerId, + _connection: ConnectionId, + message: <::Handler as ConnectionHandler>::OutEvent, + ) { + void::unreachable(message); + } + + fn poll( + &mut self, + _ctx: &mut Context, + _: &mut impl PollParameters, + ) -> Poll> { + Poll::Pending + } + } + + #[derive(NetworkBehaviour)] + #[behaviour(out_event = "OutEvent")] + struct Behaviour { + custom: TemplatedBehaviour, + } + + #[derive(Debug)] + enum OutEvent { + None, + } + + impl From for OutEvent { + fn from(_e: void::Void) -> Self { + Self::None + } + } + + require_net_behaviour::>(); + require_net_behaviour::>(); +} From 4e027b1739d6f3dc6754a5dc15720dfb3b3fcf88 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Mon, 19 Sep 2022 03:15:58 +0200 Subject: [PATCH 82/92] transports/quic: handle substream being dropped --- transports/quic/src/muxer.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index f3daaf0c657..4014a72a860 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -24,6 +24,7 @@ use crate::error::Error; use futures::{AsyncRead, AsyncWrite}; use libp2p_core::muxing::{StreamMuxer, StreamMuxerEvent}; use parking_lot::Mutex; +use quinn_proto::FinishError; use std::{ collections::HashMap, io::{self, Write}, @@ -123,6 +124,9 @@ impl StreamMuxer for QuicMuxer { ConnectionEvent::StreamFinished(substream) | ConnectionEvent::StreamStopped(substream) => { if let Some(substream) = inner.substreams.get_mut(&substream) { + if let Some(waker) = substream.read_waker.take() { + waker.wake(); + } if let Some(waker) = substream.write_waker.take() { waker.wake(); } @@ -344,5 +348,19 @@ impl Drop for Substream { fn drop(&mut self) { let mut muxer = self.muxer.lock(); muxer.substreams.remove(&self.id); + let _ = muxer + .connection + .connection + .recv_stream(self.id) + .stop(0u32.into()); + let mut send_stream = muxer.connection.connection.send_stream(self.id); + match send_stream.finish() { + Ok(()) => {} + // Already finished or reset, which is fine. + Err(FinishError::UnknownStream) => {} + Err(FinishError::Stopped(reason)) => { + let _ = send_stream.reset(reason); + } + } } } From bdba780ee5eaf20d6035a76343ac941ecfd4f0b3 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Mon, 19 Sep 2022 03:44:04 +0200 Subject: [PATCH 83/92] transports/quic: return err on read after reset --- transports/quic/src/muxer.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index 4014a72a860..4cfdc48afa7 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -260,14 +260,8 @@ impl AsyncRead for Substream { bytes += chunk.bytes.len(); } Ok(None) => break, - Err(ReadError::Reset(error_code)) => { - tracing::error!( - "substream {} was reset with error code {}", - self.id, - error_code - ); - bytes = 0; - break; + Err(err @ ReadError::Reset(_)) => { + return Poll::Ready(Err(io::Error::new(io::ErrorKind::ConnectionReset, err))) } Err(ReadError::Blocked) => { pending = true; From 40cb4f33ffbb6d22ada1c00c620aa780e25130ee Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Mon, 19 Sep 2022 04:11:37 +0200 Subject: [PATCH 84/92] transports/quic: apply comments from code review --- transports/quic/src/connection.rs | 3 +-- transports/quic/src/transport.rs | 9 +++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/transports/quic/src/connection.rs b/transports/quic/src/connection.rs index 29ae0596a42..c1060d69870 100644 --- a/transports/quic/src/connection.rs +++ b/transports/quic/src/connection.rs @@ -67,7 +67,7 @@ pub enum Error { #[error("Endpoint has force-killed our connection")] ClosedChannel, /// The background task driving the endpoint has crashed. - #[error("Background task crashed.")] + #[error("Background task crashed")] TaskCrashed, /// Error in the inner state machine. #[error("{0}")] @@ -225,7 +225,6 @@ impl Connection { return Poll::Pending; } Err(_) => { - tracing::error!("Background task crashed."); return Poll::Ready(ConnectionEvent::ConnectionLost(Error::TaskCrashed)); } } diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index a64dfa053dc..24f9d21d6c0 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -27,11 +27,10 @@ use crate::endpoint::ToEndpoint; use crate::Config; use crate::{endpoint::Endpoint, muxer::QuicMuxer, upgrade::Upgrade}; -use futures::channel::mpsc::SendError; -use futures::channel::oneshot; +use futures::channel::{mpsc, oneshot}; use futures::ready; use futures::stream::StreamExt; -use futures::{channel::mpsc, prelude::*, stream::SelectAll}; +use futures::{prelude::*, stream::SelectAll}; use if_watch::{IfEvent, IfWatcher}; @@ -134,7 +133,6 @@ impl Transport for QuicTransport { let socket_addr = multiaddr_to_socketaddr(&addr) .ok_or_else(|| TransportError::MultiaddrNotSupported(addr.clone()))?; if socket_addr.port() == 0 || socket_addr.ip().is_unspecified() { - tracing::error!("multiaddr not supported"); return Err(TransportError::MultiaddrNotSupported(addr)); } let mut listeners = self @@ -237,13 +235,12 @@ impl Dialer { }) } - fn drive_dials(&mut self, cx: &mut Context<'_>) -> Result<(), SendError> { + fn drive_dials(&mut self, cx: &mut Context<'_>) -> Result<(), mpsc::SendError> { if let Some(to_endpoint) = self.pending_dials.pop_front() { match self.endpoint.try_send(to_endpoint, cx) { Ok(Ok(())) => {} Ok(Err(to_endpoint)) => self.pending_dials.push_front(to_endpoint), Err(err) => { - tracing::error!("Background task of dialing endpoint crashed."); return Err(err); } } From f8d143030b8399bf47d3b84343a4149870249f30 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Tue, 20 Sep 2022 14:10:17 +0200 Subject: [PATCH 85/92] transports/quic: better naming, fix docs --- transports/quic/src/connection.rs | 49 ++++++++++++++++--------------- transports/quic/src/muxer.rs | 13 ++++---- transports/quic/src/transport.rs | 5 +++- 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/transports/quic/src/connection.rs b/transports/quic/src/connection.rs index c1060d69870..53ecf3b41cc 100644 --- a/transports/quic/src/connection.rs +++ b/transports/quic/src/connection.rs @@ -45,7 +45,7 @@ use std::{ pub struct Connection { /// Endpoint this connection belongs to. endpoint: Endpoint, - /// Future whose job is to send a message to the endpoint. Only one at a time. + /// Pending message to be sent to the background task that is driving the endpoint. pending_to_endpoint: Option, /// Events that the endpoint will send in destination to our local [`quinn_proto::Connection`]. /// Passed at initialization. @@ -96,7 +96,7 @@ impl Connection { connection_id: quinn_proto::ConnectionHandle, from_endpoint: mpsc::Receiver, ) -> Self { - assert!(!connection.is_closed()); + debug_assert!(!connection.is_closed()); Connection { endpoint, pending_to_endpoint: None, @@ -107,21 +107,24 @@ impl Connection { } } - /// The local address which was used when the peer established the connection. + /// The local address which was used when the remote established the connection to us. /// - /// Works for server connections only. - pub fn local_addr(&self) -> SocketAddr { - debug_assert_eq!(self.connection.side(), quinn_proto::Side::Server); + /// `None` for client connections. + pub fn local_addr(&self) -> Option { + if self.connection.side().is_client() { + return None; + } let endpoint_addr = self.endpoint.socket_addr(); - self.connection - .local_ip() - .map(|ip| SocketAddr::new(ip, endpoint_addr.port())) - .unwrap_or_else(|| { - // In a normal case scenario this should not happen, because - // we get want to get a local addr for a server connection only. - tracing::error!("trying to get quinn::local_ip for a client"); - *endpoint_addr - }) + + // Local address may differ from the socket address if the socket is + // bound to a wildcard address. + let addr = match self.connection.local_ip() { + Some(ip) => SocketAddr::new(ip, endpoint_addr.port()), + // TODO: `quinn_proto::Connection::local_ip` is only supported for linux, + // so for other platforms we currently still return the endpoint address. + None => *endpoint_addr, + }; + Some(addr) } /// Returns the address of the node we're connected to. @@ -160,7 +163,7 @@ impl Connection { /// /// If `None` is returned, then a [`ConnectionEvent::StreamAvailable`] event will later be /// produced when a substream is available. - pub fn pop_incoming_substream(&mut self) -> Option { + pub fn accept_substream(&mut self) -> Option { self.connection.streams().accept(quinn_proto::Dir::Bi) } @@ -171,7 +174,7 @@ impl Connection { /// /// If `None` is returned, then a [`ConnectionEvent::StreamOpened`] event will later be /// produced when a substream is available. - pub fn pop_outgoing_substream(&mut self) -> Option { + pub fn open_substream(&mut self) -> Option { self.connection.streams().open(quinn_proto::Dir::Bi) } @@ -183,16 +186,14 @@ impl Connection { /// On success, a [`quinn_proto::StreamEvent::Finished`] event will later be produced when the /// substream has been effectively closed. A [`ConnectionEvent::StreamStopped`] event can also /// be emitted. - pub fn shutdown_substream( + pub fn finish_substream( &mut self, id: quinn_proto::StreamId, ) -> Result<(), quinn_proto::FinishError> { - // closes the write end of the substream without waiting for the remote to receive the - // event. use flush substream to wait for the remote to receive the event. self.connection.send_stream(id).finish() } - /// Polls the connection for an event that happend on it. + /// Polls the connection for an event that happened on it. pub fn poll_event(&mut self, cx: &mut Context<'_>) -> Poll { let mut closed = None; loop { @@ -303,10 +304,10 @@ pub enum ConnectionEvent { /// Connection has been closed and can no longer be used. ConnectionLost(Error), - /// Generated after [`Connection::pop_incoming_substream`] has been called and has returned + /// Generated after [`Connection::accept_substream`] has been called and has returned /// `None`. After this event has been generated, this method is guaranteed to return `Some`. StreamAvailable, - /// Generated after [`Connection::pop_outgoing_substream`] has been called and has returned + /// Generated after [`Connection::open_substream`] has been called and has returned /// `None`. After this event has been generated, this method is guaranteed to return `Some`. StreamOpened, @@ -315,7 +316,7 @@ pub enum ConnectionEvent { /// Generated after `write_substream` has returned a `Blocked` error. StreamWritable(quinn_proto::StreamId), - /// Generated after [`Connection::shutdown_substream`] has been called. + /// Generated after [`Connection::finish_substream`] has been called. StreamFinished(quinn_proto::StreamId), /// A substream has been stopped. This concept is similar to the concept of a substream being /// "reset", as in a TCP socket being reset for example. diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index 4cfdc48afa7..5ccf8753c2b 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -82,6 +82,7 @@ impl QuicMuxer { } } } + impl StreamMuxer for QuicMuxer { type Substream = Substream; type Error = Error; @@ -94,7 +95,8 @@ impl StreamMuxer for QuicMuxer { while let Poll::Ready(event) = inner.connection.poll_event(cx) { match event { ConnectionEvent::Connected | ConnectionEvent::HandshakeDataReady => { - tracing::warn!( + debug_assert!( + false, "Unexpected event {:?} on established QUIC connection", event ); @@ -143,7 +145,6 @@ impl StreamMuxer for QuicMuxer { } } inner.poll_connection_waker = Some(cx.waker().clone()); - // TODO: poll address change Poll::Pending } @@ -152,7 +153,7 @@ impl StreamMuxer for QuicMuxer { cx: &mut Context<'_>, ) -> Poll> { let mut inner = self.inner.lock(); - let substream_id = match inner.connection.pop_incoming_substream() { + let substream_id = match inner.connection.accept_substream() { Some(id) => { inner.poll_outbound_waker = None; id @@ -172,7 +173,7 @@ impl StreamMuxer for QuicMuxer { cx: &mut Context<'_>, ) -> Poll> { let mut inner = self.inner.lock(); - let substream_id = match inner.connection.pop_outgoing_substream() { + let substream_id = match inner.connection.open_substream() { Some(id) => { inner.poll_outbound_waker = None; id @@ -195,7 +196,7 @@ impl StreamMuxer for QuicMuxer { if inner.connection.connection.streams().send_streams() != 0 { for substream in inner.substreams.keys().cloned().collect::>() { - if let Err(e) = inner.connection.shutdown_substream(substream) { + if let Err(e) = inner.connection.finish_substream(substream) { tracing::warn!("substream finish error on muxer close: {}", e); } } @@ -321,7 +322,7 @@ impl AsyncWrite for Substream { fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let mut muxer = self.muxer.lock(); - match muxer.connection.shutdown_substream(self.id) { + match muxer.connection.finish_substream(self.id) { Ok(()) => { let substream_state = muxer .substreams diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index 24f9d21d6c0..1f36a804027 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -387,7 +387,10 @@ impl Stream for Listener { } match self.new_connections_rx.poll_next_unpin(cx) { Poll::Ready(Some(connection)) => { - let local_addr = socketaddr_to_multiaddr(&connection.local_addr()); + let local_addr = connection + .local_addr() + .expect("exists for server connections."); + let local_addr = socketaddr_to_multiaddr(&local_addr); let send_back_addr = socketaddr_to_multiaddr(&connection.remote_addr()); let event = TransportEvent::Incoming { upgrade: Upgrade::from_connection(connection), From 4c3229b812f26ac22ccc848d6e4a3fbca6a5b284 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Tue, 20 Sep 2022 14:17:45 +0200 Subject: [PATCH 86/92] transports/quic: add doc for `Endpoint:try_send` --- transports/quic/src/endpoint.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index ed1fb3052d8..ede1000a6a9 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -150,6 +150,13 @@ impl Endpoint { &self.socket_addr } + /// Try to send a message to the background task without blocking. + /// + /// This first polls the channel for capacity. + /// If the channel is full, the message is returned in `Ok(Err(_))` + /// and the context's waker is registered for wake-up. + /// + /// If the background task crashed `Err` is returned. pub fn try_send( &mut self, to_endpoint: ToEndpoint, From e393fe5fbcdbe04f53f0233c8b5efdbecc0dabf4 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Tue, 20 Sep 2022 14:54:32 +0200 Subject: [PATCH 87/92] transports/quic: add `ip_to_listenaddr` --- transports/quic/src/transport.rs | 33 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index 1f36a804027..0029b31a157 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -40,6 +40,7 @@ use libp2p_core::{ PeerId, Transport, }; use std::collections::VecDeque; +use std::net::IpAddr; use std::task::Waker; use std::{ net::SocketAddr, @@ -327,26 +328,20 @@ impl Listener { loop { match ready!(if_watcher.poll_if_event(cx)) { Ok(IfEvent::Up(inet)) => { - let ip = inet.addr(); - if self.endpoint.socket_addr().is_ipv4() == ip.is_ipv4() { - let socket_addr = SocketAddr::new(ip, self.endpoint.socket_addr().port()); - let ma = socketaddr_to_multiaddr(&socket_addr); - tracing::debug!("New listen address: {}", ma); + if let Some(addr) = ip_to_listenaddr(&self.endpoint, inet.addr()) { + tracing::debug!("New listen address: {}", addr); return Poll::Ready(TransportEvent::NewAddress { listener_id: self.listener_id, - listen_addr: ma, + listen_addr: addr, }); } } Ok(IfEvent::Down(inet)) => { - let ip = inet.addr(); - if self.endpoint.socket_addr().is_ipv4() == ip.is_ipv4() { - let socket_addr = SocketAddr::new(ip, self.endpoint.socket_addr().port()); - let ma = socketaddr_to_multiaddr(&socket_addr); - tracing::debug!("Expired listen address: {}", ma); + if let Some(addr) = ip_to_listenaddr(&self.endpoint, inet.addr()) { + tracing::debug!("Expired listen address: {}", addr); return Poll::Ready(TransportEvent::AddressExpired { listener_id: self.listener_id, - listen_addr: ma, + listen_addr: addr, }); } } @@ -412,6 +407,20 @@ impl Stream for Listener { } } +/// Turn an [`IpAddr`] into a listen-address for the endpoint. +/// +/// Returns `None` if the address is not the same socket family as the +/// address that the endpoint is bound to. +pub fn ip_to_listenaddr(endpoint: &Endpoint, ip: IpAddr) -> Option { + // True if either both addresses are Ipv4 or both Ipv6. + let is_same_ip_family = endpoint.socket_addr().is_ipv4() == ip.is_ipv4(); + if !is_same_ip_family { + return None; + } + let socket_addr = SocketAddr::new(ip, endpoint.socket_addr().port()); + Some(socketaddr_to_multiaddr(&socket_addr)) +} + /// Tries to turn a QUIC multiaddress into a UDP [`SocketAddr`]. Returns None if the format /// of the multiaddr is wrong. pub fn multiaddr_to_socketaddr(addr: &Multiaddr) -> Option { From d28db187c8157ecb7f121ab7897866d96cbbdddf Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Tue, 20 Sep 2022 15:23:53 +0200 Subject: [PATCH 88/92] transports/quic: disable connection migration --- transports/quic/src/endpoint.rs | 4 ++++ transports/quic/src/muxer.rs | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index ede1000a6a9..3a4c0daa17f 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -72,6 +72,10 @@ impl Config { let mut server_config = QuinnServerConfig::with_crypto(Arc::new(server_tls_config)); server_config.transport = Arc::clone(&transport); + // Disables connection migration. + // Long-term this should be enabled, however we then need to handle address change + // on connections in the `QuicMuxer`. + server_config.migration(false); let mut client_config = QuinnClientConfig::new(Arc::new(client_tls_config)); client_config.transport = transport; diff --git a/transports/quic/src/muxer.rs b/transports/quic/src/muxer.rs index 5ccf8753c2b..f2b6d3366bb 100644 --- a/transports/quic/src/muxer.rs +++ b/transports/quic/src/muxer.rs @@ -92,6 +92,8 @@ impl StreamMuxer for QuicMuxer { cx: &mut Context<'_>, ) -> Poll> { let mut inner = self.inner.lock(); + // Poll the inner [`quinn_proto::Connection`] for events and wake + // the wakers of related poll-based methods. while let Poll::Ready(event) = inner.connection.poll_event(cx) { match event { ConnectionEvent::Connected | ConnectionEvent::HandshakeDataReady => { @@ -145,6 +147,10 @@ impl StreamMuxer for QuicMuxer { } } inner.poll_connection_waker = Some(cx.waker().clone()); + + // TODO: If connection migration is enabled (currently disabled) address + // change on the connection needs to be handled. + Poll::Pending } From 42db0ede6601b6cc40e18fc20d54489bfc2d18a1 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Tue, 20 Sep 2022 15:36:54 +0200 Subject: [PATCH 89/92] transports/quic: minor fix --- transports/quic/src/transport.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index 0029b31a157..e915a29d532 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -328,20 +328,20 @@ impl Listener { loop { match ready!(if_watcher.poll_if_event(cx)) { Ok(IfEvent::Up(inet)) => { - if let Some(addr) = ip_to_listenaddr(&self.endpoint, inet.addr()) { - tracing::debug!("New listen address: {}", addr); + if let Some(listen_addr) = ip_to_listenaddr(&self.endpoint, inet.addr()) { + tracing::debug!("New listen address: {}", listen_addr); return Poll::Ready(TransportEvent::NewAddress { listener_id: self.listener_id, - listen_addr: addr, + listen_addr, }); } } Ok(IfEvent::Down(inet)) => { - if let Some(addr) = ip_to_listenaddr(&self.endpoint, inet.addr()) { - tracing::debug!("Expired listen address: {}", addr); + if let Some(listen_addr) = ip_to_listenaddr(&self.endpoint, inet.addr()) { + tracing::debug!("Expired listen address: {}", listen_addr); return Poll::Ready(TransportEvent::AddressExpired { listener_id: self.listener_id, - listen_addr: addr, + listen_addr, }); } } From d46b72e9af0a85038d5f79cc6b877eed61fe8109 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Tue, 20 Sep 2022 16:53:42 +0200 Subject: [PATCH 90/92] transports/quic: minor fixes --- transports/quic/src/connection.rs | 2 -- transports/quic/src/endpoint.rs | 23 +++++++++-------------- transports/quic/tests/smoke.rs | 8 -------- 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/transports/quic/src/connection.rs b/transports/quic/src/connection.rs index 53ecf3b41cc..8b3f371ffe0 100644 --- a/transports/quic/src/connection.rs +++ b/transports/quic/src/connection.rs @@ -89,7 +89,6 @@ impl Connection { /// /// This function assumes that the [`quinn_proto::Connection`] is completely fresh and none of /// its methods has ever been called. Failure to comply might lead to logic errors and panics. - // TODO: maybe abstract `to_endpoint` more and make it generic? dunno pub fn from_quinn_connection( endpoint: Endpoint, connection: quinn_proto::Connection, @@ -128,7 +127,6 @@ impl Connection { } /// Returns the address of the node we're connected to. - // TODO: can change /!\ pub fn remote_addr(&self) -> SocketAddr { self.connection.remote_address() } diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index 3a4c0daa17f..53e36299ecd 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -88,14 +88,12 @@ impl Config { } /// Object containing all the QUIC resources shared between all connections. -// TODO: expand docs -// TODO: Debug trait -// TODO: remove useless fields #[derive(Clone)] pub struct Endpoint { /// Channel to the background of the endpoint. to_endpoint: mpsc::Sender, - + /// Address that the socket is bound to. + /// Note: this may be a wildcard ip address. socket_addr: SocketAddr, } @@ -201,7 +199,7 @@ pub enum ToEndpoint { }, } -/// Task that runs in the background for as long as the endpont is alive. Responsible for +/// Task that runs in the background for as long as the endpoint is alive. Responsible for /// processing messages and the UDP socket. /// /// The `receiver` parameter must be the receiving side of the `Endpoint::to_endpoint` sender. @@ -223,13 +221,11 @@ pub enum ToEndpoint { /// in play: /// /// - One channel, represented by `Endpoint::to_endpoint` and `receiver`, that communicates -/// messages from [`Endpoint`] to the background task and from the [`Connection`] to the -/// background task. +/// messages from [`Endpoint`] to the background task. /// - One channel per each existing connection that communicates messages from the background /// task to that [`Connection`]. /// - One channel for the background task to send newly-opened connections to. The receiving -/// side is normally processed by a "listener" as defined by the [`libp2p_core::Transport`] -/// trait. +/// side is processed by the [`crate::transport::Listener`]. /// /// In order to avoid an unbounded buffering of events, we prioritize sending data on the UDP /// socket over everything else. If the network interface is too busy to process our packets, @@ -342,7 +338,6 @@ async fn background_task( // The endpoint might request packets to be sent out. This is handled in priority to avoid // buffering up packets. if let Some(packet) = proto_endpoint.poll_transmit() { - debug_assert!(next_packet_out.is_none()); next_packet_out = Some((packet.destination, packet.contents)); continue; } @@ -352,9 +347,7 @@ async fn background_task( // Received a message from a different part of the code requesting us to // do something. match message { - // Shut down if the endpoint has shut down. - None => return, - + None => unreachable!("Sender side is never dropped or closed."), Some(ToEndpoint::Dial { addr, result }) => { // This `"l"` seems necessary because an empty string is an invalid domain // name. While we don't use domain names, the underlying rustls library @@ -501,6 +494,8 @@ async fn background_task( impl fmt::Debug for Endpoint { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Endpoint").finish() + f.debug_struct("Endpoint") + .field("socket_addr", &self.socket_addr) + .finish() } } diff --git a/transports/quic/tests/smoke.rs b/transports/quic/tests/smoke.rs index ec174014574..d6507e73c45 100644 --- a/transports/quic/tests/smoke.rs +++ b/transports/quic/tests/smoke.rs @@ -31,14 +31,6 @@ async fn create_swarm(keylog: bool) -> Result>> let config = QuicConfig::new(&keypair).unwrap(); let transport = QuicTransport::new(config); - // TODO: - // transport - // .transport - // .max_idle_timeout(Some(quinn_proto::VarInt::from_u32(1_000u32).into())); - // if keylog { - // transport.enable_keylogger(); - // } - let transport = Transport::map(transport, |(peer, muxer), _| { (peer, StreamMuxerBox::new(muxer)) }) From ec3c74a812fadc7b0fc95e582a5f8d1d13571b27 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Tue, 20 Sep 2022 20:37:17 +0200 Subject: [PATCH 91/92] transports/quic: rework forwarding of new connections The existing implementation was based on an old API of the quinn_proto Endpoint which by now has changed. In particular we can not explicitly `accept` new connections on the endpoint anymore. Instead if there is a new connections and our channel for new connections is full because the endpoint is too busy, we now simply drop the connection to backpressure the remote. --- swarm-derive/src/lib.rs | 2 +- transports/quic/src/endpoint.rs | 99 ++++++++++++--------------------- 2 files changed, 38 insertions(+), 63 deletions(-) diff --git a/swarm-derive/src/lib.rs b/swarm-derive/src/lib.rs index 6899ba7d79d..5f901ed6ff8 100644 --- a/swarm-derive/src/lib.rs +++ b/swarm-derive/src/lib.rs @@ -125,7 +125,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { ) .unwrap(); let ty = &field.ty; - quote! {#variant(<#ty as NetworkBehaviour>::OutEvent)} + quote! {#variant(<#ty as ::libp2p::swarm::NetworkBehaviour>::OutEvent)} }) .collect::>(); let visibility = &ast.vis; diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index 53e36299ecd..d81c5045b4d 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -39,11 +39,11 @@ use futures::{ }; use quinn_proto::{ClientConfig as QuinnClientConfig, ServerConfig as QuinnServerConfig}; use std::{ - collections::{HashMap, VecDeque}, + collections::HashMap, fmt, net::{Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket}, sync::Arc, - task::{Context, Poll, Waker}, + task::{Context, Poll}, time::{Duration, Instant}, }; @@ -298,19 +298,10 @@ async fn background_task( // Buffer where we write packets received from the UDP socket. let mut socket_recv_buffer = vec![0; 65536]; - // The quinn_proto endpoint can give us new connections for as long as its accept buffer - // isn't full. This buffer is used to push these new connections while we are waiting to - // send them on the `new_connections` channel. We only call `endpoint.accept()` when we remove - // an element from this list, which guarantees that it doesn't grow unbounded. - // TODO: with_capacity? - let mut queued_new_connections = VecDeque::new(); - // Next packet waiting to be transmitted on the UDP socket, if any. - // Note that this variable isn't strictly necessary, but it reduces code duplication in the - // code below. let mut next_packet_out: Option<(SocketAddr, Vec)> = None; - let mut new_connection_waker: Option = None; + let mut is_orphaned = false; // Main loop of the task. loop { @@ -343,7 +334,7 @@ async fn background_task( } futures::select! { - message = receiver.next().fuse() => { + message = receiver.next() => { // Received a message from a different part of the code requesting us to // do something. match message { @@ -379,6 +370,13 @@ async fn background_task( let is_drained_event = event.is_drained(); if is_drained_event { alive_connections.remove(&connection_id); + if is_orphaned && alive_connections.is_empty() { + tracing::info!( + "Listener closed and no active connections remain. Shutting down the background task." + ); + return; + } + } let event_back = proto_endpoint.handle_event(connection_id, event); @@ -401,46 +399,6 @@ async fn background_task( } } } - - // The future we create here wakes up if two conditions are fulfilled: - // - // - The `new_connections` channel is ready to accept a new element. - // - `queued_new_connections` is not empty. - // - // When this happens, we pop an element from `queued_new_connections`, put it on the - // channel, and call `endpoint.accept()`, thereby allowing the QUIC state machine to - // feed a new incoming connection to us. - readiness = { - let active = !queued_new_connections.is_empty(); - let new_connections = &mut new_connections; - let new_connection_waker = &mut new_connection_waker; - future::poll_fn(move |cx| { - match new_connections.as_mut() { - Some(ref mut c) if active => { - c.poll_ready(cx) - } - _ => { - let _ = new_connection_waker.insert(cx.waker().clone()); - Poll::Pending - } - } - }) - .fuse() - } => { - if readiness.is_err() { - // new_connections channel has been dropped, meaning that the endpoint has - // been destroyed. - return; - } - - let elem = queued_new_connections.pop_front() - .expect("if queue is empty, the future above is always Pending; qed"); - let new_connections = new_connections.as_mut().expect("in case of None, the future above is always Pending; qed"); - new_connections.start_send(elem) - .expect("future is waken up only if poll_ready returned Ready; qed"); - //endpoint.accept(); - } - result = udp_socket.recv_from(&mut socket_recv_buffer).fuse() => { let (packet_len, packet_src) = match result { Ok(v) => v, @@ -473,17 +431,34 @@ async fn background_task( // A new connection has been received. `connec_id` is a newly-allocated // identifier. debug_assert_eq!(connec.side(), quinn_proto::Side::Server); + let connection_tx = match new_connections.as_mut() { + Some(tx) => tx, + None => { + tracing::warn!( + "Endpoint reported a new connection even though server capabilities are disabled." + ); + continue + } + }; + let (tx, rx) = mpsc::channel(16); - alive_connections.insert(connec_id, tx); let connection = Connection::from_quinn_connection(endpoint.clone(), connec, connec_id, rx); - - // As explained in the documentation, we put this new connection in an - // intermediary buffer. At the next loop iteration we will try to move it - // to the `new_connections` channel. We call `endpoint.accept()` only once - // the element has successfully been sent on `new_connections`. - queued_new_connections.push_back(connection); - if let Some(waker) = new_connection_waker.take() { - waker.wake(); + match connection_tx.try_send(connection) { + Ok(()) => { + alive_connections.insert(connec_id, tx); + } + Err(e) if e.is_disconnected() => { + // Listener was closed. + proto_endpoint.reject_new_connections(); + new_connections = None; + is_orphaned = true; + if alive_connections.is_empty() { + return; + } + } + _ => tracing::warn!( + "Dropping new incoming connection because the channel to the listener is full." + ) } }, } From b7103aa146621a6aa1504dc1a0b51d634883f9ae Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Tue, 20 Sep 2022 22:57:40 +0200 Subject: [PATCH 92/92] transports/quic: fix broken intra-doc link --- transports/quic/src/endpoint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index d81c5045b4d..3c34dd3b391 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -47,7 +47,7 @@ use std::{ time::{Duration, Instant}, }; -/// Represents the configuration for the [`Endpoint`]. +/// Represents the configuration for the QUIC endpoint. #[derive(Debug, Clone)] pub struct Config { /// The client configuration to pass to `quinn_proto`. @@ -225,7 +225,7 @@ pub enum ToEndpoint { /// - One channel per each existing connection that communicates messages from the background /// task to that [`Connection`]. /// - One channel for the background task to send newly-opened connections to. The receiving -/// side is processed by the [`crate::transport::Listener`]. +/// side is processed by the [`QuicTransport`][crate::QuicTransport]. /// /// In order to avoid an unbounded buffering of events, we prioritize sending data on the UDP /// socket over everything else. If the network interface is too busy to process our packets,