Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: replace ProtocolName with AsRef<str> #3746

Merged
merged 34 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
869fdef
Enforce `ProtocolName` to return `&str`
thomaseizinger Apr 6, 2023
aece9ca
Merge branch 'master' into feat/string-protocols-3
thomaseizinger Apr 26, 2023
e2a588b
Delete `ProtocolName`
thomaseizinger Apr 26, 2023
291a8f8
Merge branch 'master' into feat/string-protocols-3
thomaseizinger Apr 26, 2023
3b5bdb0
Fix compile errors after merge
thomaseizinger Apr 26, 2023
7104ac4
Fix doc tests
thomaseizinger Apr 26, 2023
3debac4
Fix gossipsub tests
thomaseizinger Apr 26, 2023
94dd0e3
Delete some either stuff
thomaseizinger Apr 26, 2023
131d54f
Delete `FileExchangeProtocol`
thomaseizinger Apr 26, 2023
bacf561
Fixup error message
thomaseizinger Apr 26, 2023
3547664
Fix gossipsub config mess
thomaseizinger Apr 26, 2023
07f6b1c
Merge branch 'master' into feat/string-protocols-3
thomaseizinger Apr 26, 2023
b2993b1
Buffer error for invalid protocols
thomaseizinger Apr 26, 2023
0e45467
Merge branch 'master' into feat/string-protocols-3
thomaseizinger Apr 27, 2023
07c2eea
Fix gossipsub tests
thomaseizinger Apr 27, 2023
1dff42c
Extract protocol into dedicated submodule
thomaseizinger Apr 27, 2023
da4a465
Rename to `StreamProtocol`
thomaseizinger Apr 27, 2023
12e52e4
Remove unused import
thomaseizinger Apr 27, 2023
da08042
Merge branch 'master' into feat/string-protocols-3
thomaseizinger Apr 27, 2023
0f860c6
Restore getter on config
thomaseizinger Apr 28, 2023
c387bf7
Prevent construction of error and rename to `new`
thomaseizinger Apr 28, 2023
1b3cc24
Add changelog entries
thomaseizinger Apr 28, 2023
dc2c4ff
Merge branch 'master' into feat/string-protocols-3
thomaseizinger Apr 28, 2023
446c24f
Merge branch 'master' into feat/string-protocols-3
thomaseizinger Apr 28, 2023
0dcdb02
Merge branch 'master' into feat/string-protocols-3
thomaseizinger Apr 28, 2023
f0827f9
Fix formatting
thomaseizinger Apr 28, 2023
be95810
Merge branch 'master' into feat/string-protocols-3
thomaseizinger May 1, 2023
be823ca
Fix compile error for new noise upgrade
thomaseizinger May 1, 2023
e99dedb
Merge branch 'master' into feat/string-protocols-3
thomaseizinger May 2, 2023
2236e37
Merge branch 'master' into feat/string-protocols-3
thomaseizinger May 2, 2023
35bb177
Fix compile error
thomaseizinger May 2, 2023
1bd1803
Merge branch 'master' into feat/string-protocols-3
thomaseizinger May 2, 2023
1ff5285
Merge branch 'master' into feat/string-protocols-3
thomaseizinger May 2, 2023
87e5539
Merge branch 'master' into feat/string-protocols-3
mergify[bot] May 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
[PR 3715]: https://github.com/libp2p/rust-libp2p/pull/3715
[PR 3867]: https://github.com/libp2p/rust-libp2p/pull/3867

- Enforce protocol names to be valid UTF8 strings as required by the [spec].
We delete the `ProtocolName` trait and replace it with a requirement for `AsRef<str>`.
See [PR 3746]

[spec]: https://github.com/libp2p/specs/blob/master/connections/README.md#multistream-select
[PR 3746]: https://github.com/libp2p/rust-libp2p/pull/3746

## 0.39.2

- Deprecate `upgrade::from_fn` without replacement as it is not used within `rust-libp2p`.
Expand Down
17 changes: 1 addition & 16 deletions core/src/either.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::muxing::StreamMuxerEvent;
use crate::{
muxing::StreamMuxer,
transport::{ListenerId, Transport, TransportError, TransportEvent},
Multiaddr, ProtocolName,
Multiaddr,
};
use either::Either;
use futures::prelude::*;
Expand Down Expand Up @@ -115,21 +115,6 @@ where
}
}

#[derive(Debug, Clone)]
pub enum EitherName<A, B> {
A(A),
B(B),
}

impl<A: ProtocolName, B: ProtocolName> ProtocolName for EitherName<A, B> {
fn protocol_name(&self) -> &[u8] {
match self {
EitherName::A(a) => a.protocol_name(),
EitherName::B(b) => b.protocol_name(),
}
}
}

impl<A, B> Transport for Either<A, B>
where
B: Transport,
Expand Down
2 changes: 1 addition & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ pub use peer_record::PeerRecord;
pub use signed_envelope::SignedEnvelope;
pub use translation::address_translation;
pub use transport::Transport;
pub use upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeError, UpgradeInfo};
pub use upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeError, UpgradeInfo};

#[derive(Debug, thiserror::Error)]
pub struct DecodeError(String);
Expand Down
49 changes: 1 addition & 48 deletions core/src/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,58 +80,11 @@ pub use self::{
pub use crate::Negotiated;
pub use multistream_select::{NegotiatedComplete, NegotiationError, ProtocolError, Version};

/// Types serving as protocol names.
///
/// # Context
///
/// In situations where we provide a list of protocols that we support,
/// the elements of that list are required to implement the [`ProtocolName`] trait.
///
/// Libp2p will call [`ProtocolName::protocol_name`] on each element of that list, and transmit the
/// returned value on the network. If the remote accepts a given protocol, the element
/// serves as the return value of the function that performed the negotiation.
///
/// # Example
///
/// ```
/// use libp2p_core::ProtocolName;
///
/// enum MyProtocolName {
/// Version1,
/// Version2,
/// Version3,
/// }
///
/// impl ProtocolName for MyProtocolName {
/// fn protocol_name(&self) -> &[u8] {
/// match *self {
/// MyProtocolName::Version1 => b"/myproto/1.0",
/// MyProtocolName::Version2 => b"/myproto/2.0",
/// MyProtocolName::Version3 => b"/myproto/3.0",
/// }
/// }
/// }
/// ```
///
pub trait ProtocolName {
/// The protocol name as bytes. Transmitted on the network.
///
/// **Note:** Valid protocol names must start with `/` and
/// not exceed 140 bytes in length.
fn protocol_name(&self) -> &[u8];
}

impl<T: AsRef<[u8]>> ProtocolName for T {
fn protocol_name(&self) -> &[u8] {
self.as_ref()
}
}

/// Common trait for upgrades that can be applied on inbound substreams, outbound substreams,
/// or both.
pub trait UpgradeInfo {
/// Opaque type representing a negotiable protocol.
type Info: ProtocolName + Clone;
type Info: AsRef<str> + Clone;
/// Iterator returned by `protocol_info`.
type InfoIter: IntoIterator<Item = Self::Info>;

Expand Down
104 changes: 17 additions & 87 deletions core/src/upgrade/apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use crate::upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeError};
use crate::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeError};
use crate::{connection::ConnectedPoint, Negotiated};
use futures::{future::Either, prelude::*};
use log::debug;
use multistream_select::{self, DialerSelectFuture, ListenerSelectFuture};
use std::{iter, mem, pin::Pin, task::Context, task::Poll};
use std::{mem, pin::Pin, task::Context, task::Poll};

pub(crate) use multistream_select::Version;
use smallvec::SmallVec;
use std::fmt;

// TODO: Still needed?
/// Applies an upgrade to the inbound and outbound direction of a connection or substream.
Expand Down Expand Up @@ -55,14 +53,9 @@ where
C: AsyncRead + AsyncWrite + Unpin,
U: InboundUpgrade<Negotiated<C>>,
{
let iter = up
.protocol_info()
.into_iter()
.map(NameWrap as fn(_) -> NameWrap<_>);
let future = multistream_select::listener_select_proto(conn, iter);
InboundUpgradeApply {
inner: InboundUpgradeApplyState::Init {
future,
future: multistream_select::listener_select_proto(conn, up.protocol_info().into_iter()),
upgrade: up,
},
}
Expand All @@ -74,14 +67,9 @@ where
C: AsyncRead + AsyncWrite + Unpin,
U: OutboundUpgrade<Negotiated<C>>,
{
let iter = up
.protocol_info()
.into_iter()
.map(NameWrap as fn(_) -> NameWrap<_>);
let future = multistream_select::dialer_select_proto(conn, iter, v);
OutboundUpgradeApply {
inner: OutboundUpgradeApplyState::Init {
future,
future: multistream_select::dialer_select_proto(conn, up.protocol_info(), v),
upgrade: up,
},
}
Expand All @@ -96,18 +84,19 @@ where
inner: InboundUpgradeApplyState<C, U>,
}

#[allow(clippy::large_enum_variant)]
enum InboundUpgradeApplyState<C, U>
where
C: AsyncRead + AsyncWrite + Unpin,
U: InboundUpgrade<Negotiated<C>>,
{
Init {
future: ListenerSelectFuture<C, NameWrap<U::Info>>,
future: ListenerSelectFuture<C, U::Info>,
upgrade: U,
},
Upgrade {
future: Pin<Box<U::Future>>,
name: SmallVec<[u8; 32]>,
name: String,
},
Undefined,
}
Expand Down Expand Up @@ -140,10 +129,9 @@ where
return Poll::Pending;
}
};
let name = SmallVec::from_slice(info.protocol_name());
self.inner = InboundUpgradeApplyState::Upgrade {
future: Box::pin(upgrade.upgrade_inbound(io, info.0)),
name,
future: Box::pin(upgrade.upgrade_inbound(io, info.clone())),
name: info.as_ref().to_owned(),
};
}
InboundUpgradeApplyState::Upgrade { mut future, name } => {
Expand All @@ -153,14 +141,11 @@ where
return Poll::Pending;
}
Poll::Ready(Ok(x)) => {
log::trace!("Upgraded inbound stream to {}", DisplayProtocolName(name));
log::trace!("Upgraded inbound stream to {name}");
return Poll::Ready(Ok(x));
}
Poll::Ready(Err(e)) => {
debug!(
"Failed to upgrade inbound stream to {}",
DisplayProtocolName(name)
);
debug!("Failed to upgrade inbound stream to {name}");
return Poll::Ready(Err(UpgradeError::Apply(e)));
}
}
Expand Down Expand Up @@ -188,12 +173,12 @@ where
U: OutboundUpgrade<Negotiated<C>>,
{
Init {
future: DialerSelectFuture<C, NameWrapIter<<U::InfoIter as IntoIterator>::IntoIter>>,
future: DialerSelectFuture<C, <U::InfoIter as IntoIterator>::IntoIter>,
upgrade: U,
},
Upgrade {
future: Pin<Box<U::Future>>,
name: SmallVec<[u8; 32]>,
name: String,
},
Undefined,
}
Expand Down Expand Up @@ -226,10 +211,9 @@ where
return Poll::Pending;
}
};
let name = SmallVec::from_slice(info.protocol_name());
self.inner = OutboundUpgradeApplyState::Upgrade {
future: Box::pin(upgrade.upgrade_outbound(connection, info.0)),
name,
future: Box::pin(upgrade.upgrade_outbound(connection, info.clone())),
name: info.as_ref().to_owned(),
};
}
OutboundUpgradeApplyState::Upgrade { mut future, name } => {
Expand All @@ -239,17 +223,11 @@ where
return Poll::Pending;
}
Poll::Ready(Ok(x)) => {
log::trace!(
"Upgraded outbound stream to {}",
DisplayProtocolName(name)
);
log::trace!("Upgraded outbound stream to {name}",);
return Poll::Ready(Ok(x));
}
Poll::Ready(Err(e)) => {
debug!(
"Failed to upgrade outbound stream to {}",
DisplayProtocolName(name)
);
debug!("Failed to upgrade outbound stream to {name}",);
return Poll::Ready(Err(UpgradeError::Apply(e)));
}
}
Expand All @@ -261,51 +239,3 @@ where
}
}
}

type NameWrapIter<I> = iter::Map<I, fn(<I as Iterator>::Item) -> NameWrap<<I as Iterator>::Item>>;

/// Wrapper type to expose an `AsRef<[u8]>` impl for all types implementing `ProtocolName`.
#[derive(Clone)]
struct NameWrap<N>(N);
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved

impl<N: ProtocolName> AsRef<[u8]> for NameWrap<N> {
fn as_ref(&self) -> &[u8] {
self.0.protocol_name()
}
}

/// Wrapper for printing a [`ProtocolName`] that is expected to be mostly ASCII
pub(crate) struct DisplayProtocolName<N>(pub(crate) N);

impl<N: ProtocolName> fmt::Display for DisplayProtocolName<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use fmt::Write;
for byte in self.0.protocol_name() {
if (b' '..=b'~').contains(byte) {
f.write_char(char::from(*byte))?;
} else {
write!(f, "<{byte:02X}>")?;
}
}
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn display_protocol_name() {
assert_eq!(DisplayProtocolName(b"/hello/1.0").to_string(), "/hello/1.0");
assert_eq!(DisplayProtocolName("/hellö/").to_string(), "/hell<C3><B6>/");
assert_eq!(
DisplayProtocolName((0u8..=255).collect::<Vec<_>>()).to_string(),
(0..32)
.map(|c| format!("<{c:02X}>"))
.chain((32..127).map(|c| format!("{}", char::from_u32(c).unwrap())))
.chain((127..256).map(|c| format!("<{c:02X}>")))
.collect::<String>()
);
}
}
2 changes: 1 addition & 1 deletion core/src/upgrade/denied.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use void::Void;
pub struct DeniedUpgrade;

impl UpgradeInfo for DeniedUpgrade {
type Info = &'static [u8];
type Info = &'static str;
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved
type InfoIter = iter::Empty<Self::Info>;

fn protocol_info(&self) -> Self::InfoIter {
Expand Down
16 changes: 8 additions & 8 deletions core/src/upgrade/either.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
// DEALINGS IN THE SOFTWARE.

use crate::{
either::{EitherFuture, EitherName},
either::EitherFuture,
upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo},
};
use either::Either;
Expand All @@ -31,16 +31,16 @@ where
A: UpgradeInfo,
B: UpgradeInfo,
{
type Info = EitherName<A::Info, B::Info>;
type Info = Either<A::Info, B::Info>;
type InfoIter = Either<
Map<<A::InfoIter as IntoIterator>::IntoIter, fn(A::Info) -> Self::Info>,
Map<<B::InfoIter as IntoIterator>::IntoIter, fn(B::Info) -> Self::Info>,
>;

fn protocol_info(&self) -> Self::InfoIter {
match self {
Either::Left(a) => Either::Left(a.protocol_info().into_iter().map(EitherName::A)),
Either::Right(b) => Either::Right(b.protocol_info().into_iter().map(EitherName::B)),
Either::Left(a) => Either::Left(a.protocol_info().into_iter().map(Either::Left)),
Either::Right(b) => Either::Right(b.protocol_info().into_iter().map(Either::Right)),
}
}
}
Expand All @@ -56,10 +56,10 @@ where

fn upgrade_inbound(self, sock: C, info: Self::Info) -> Self::Future {
match (self, info) {
(Either::Left(a), EitherName::A(info)) => {
(Either::Left(a), Either::Left(info)) => {
EitherFuture::First(a.upgrade_inbound(sock, info))
}
(Either::Right(b), EitherName::B(info)) => {
(Either::Right(b), Either::Right(info)) => {
EitherFuture::Second(b.upgrade_inbound(sock, info))
}
_ => panic!("Invalid invocation of EitherUpgrade::upgrade_inbound"),
Expand All @@ -78,10 +78,10 @@ where

fn upgrade_outbound(self, sock: C, info: Self::Info) -> Self::Future {
match (self, info) {
(Either::Left(a), EitherName::A(info)) => {
(Either::Left(a), Either::Left(info)) => {
EitherFuture::First(a.upgrade_outbound(sock, info))
}
(Either::Right(b), EitherName::B(info)) => {
(Either::Right(b), Either::Right(info)) => {
EitherFuture::Second(b.upgrade_outbound(sock, info))
}
_ => panic!("Invalid invocation of EitherUpgrade::upgrade_outbound"),
Expand Down
Loading