Skip to content

Commit

Permalink
feat!: make /p2p type-safe (#83)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomaseizinger authored Jun 7, 2023
1 parent 13a1e9e commit bdd6607
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 26 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
# 0.18.0 - unreleased

- Add `WebTransport` instance for `Multiaddr`. See [PR 70].

- Disable all features of `multihash`. See [PR 77].

- Mark `Protocol` as `#[non_exhaustive]`. See [PR 82].

- Rename `Protocol::WebRTC` to `Protocol::WebRTCDirect`.
See [multiformats/multiaddr discussion] for context.
Remove deprecated support for `/webrtc` in favor of the existing `/webrtc-direct` string representation.
**Note that this is a breaking change.**

- Make `/p2p` typesafe, i.e. have `Protocol::P2p` contain a `PeerId` instead of a `Multihash`.
See [PR 83].

[multiformats/multiaddr discussion]: https://github.com/multiformats/multiaddr/pull/150#issuecomment-1468791586
[PR 70]: https://github.com/multiformats/rust-multiaddr/pull/70
[PR 77]: https://github.com/multiformats/rust-multiaddr/pull/77
[PR 82]: https://github.com/multiformats/rust-multiaddr/pull/82
[PR 83]: https://github.com/multiformats/rust-multiaddr/pull/83

# 0.17.1

Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ arrayref = "0.3"
byteorder = "1.3.1"
data-encoding = "2.1"
multibase = "0.9.1"
multihash = { version = "0.18", default-features = false, features = ["std"] }
multihash = "0.19"
percent-encoding = "2.1.0"
serde = "1.0.70"
static_assertions = "1.1"
unsigned-varint = "0.7"
url = { version = "2.1.0", optional = true, default-features = false }
libp2p-identity = { version = "0.2.0", features = ["peerid"] }

[dev-dependencies]
bincode = "1"
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
///! Implementation of [multiaddr](https://github.com/multiformats/multiaddr) in Rust.
//! Implementation of [multiaddr](https://github.com/multiformats/multiaddr) in Rust.

pub use multihash;

mod errors;
Expand Down
21 changes: 14 additions & 7 deletions src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{Error, Result};
use arrayref::array_ref;
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
use data_encoding::BASE32;
use multihash::MultihashGeneric;
use libp2p_identity::PeerId;
use std::{
borrow::Cow,
convert::From,
Expand Down Expand Up @@ -57,7 +57,7 @@ const WSS_WITH_PATH: u32 = 4780; // Note: not standard
/// The `64` defines the allocation size for the digest within the `Multihash`.
/// This allows us to use hashes such as SHA512.
/// In case protocols like `/certhash` ever support hashes larger than that, we will need to update this size here (which will be a breaking change!).
type Multihash = MultihashGeneric<64>;
type Multihash = multihash::Multihash<64>;

const PATH_SEGMENT_ENCODE_SET: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
.add(b'%')
Expand Down Expand Up @@ -99,7 +99,7 @@ pub enum Protocol<'a> {
Memory(u64),
Onion(Cow<'a, [u8; 10]>, u16),
Onion3(Onion3Addr<'a>),
P2p(Multihash),
P2p(PeerId),
P2pCircuit,
Quic,
QuicV1,
Expand Down Expand Up @@ -179,7 +179,9 @@ impl<'a> Protocol<'a> {
"p2p" => {
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
let decoded = multibase::Base::Base58Btc.decode(s)?;
Ok(Protocol::P2p(Multihash::from_bytes(&decoded)?))
let peer_id =
PeerId::from_bytes(&decoded).map_err(|e| Error::ParsingError(Box::new(e)))?;
Ok(Protocol::P2p(peer_id))
}
"http" => Ok(Protocol::Http),
"https" => Ok(Protocol::Https),
Expand Down Expand Up @@ -324,7 +326,12 @@ impl<'a> Protocol<'a> {
P2P => {
let (n, input) = decode::usize(input)?;
let (data, rest) = split_at(n, input)?;
Ok((Protocol::P2p(Multihash::from_bytes(data)?), rest))
Ok((
Protocol::P2p(
PeerId::from_bytes(data).map_err(|e| Error::ParsingError(Box::new(e)))?,
),
rest,
))
}
P2P_CIRCUIT => Ok((Protocol::P2pCircuit, input)),
QUIC => Ok((Protocol::Quic, input)),
Expand Down Expand Up @@ -436,9 +443,9 @@ impl<'a> Protocol<'a> {
w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
w.write_all(bytes)?
}
Protocol::P2p(multihash) => {
Protocol::P2p(peer_id) => {
w.write_all(encode::u32(P2P, &mut buf))?;
let bytes = multihash.to_bytes();
let bytes = peer_id.to_bytes();
w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
w.write_all(&bytes)?
}
Expand Down
46 changes: 29 additions & 17 deletions tests/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use data_encoding::HEXUPPER;
use libp2p_identity::PeerId;
use multiaddr::*;
use multihash::MultihashGeneric;
use multihash::Multihash;
use quickcheck::{Arbitrary, Gen, QuickCheck};
use std::{
borrow::Cow,
Expand Down Expand Up @@ -122,7 +123,7 @@ impl Arbitrary for Proto {
.unwrap();
Proto(Onion3((a, std::cmp::max(1, u16::arbitrary(g))).into()))
}
17 => Proto(P2p(Mh::arbitrary(g).0)),
17 => Proto(P2p(PId::arbitrary(g).0)),
18 => Proto(P2pCircuit),
19 => Proto(Quic),
20 => Proto(QuicV1),
Expand All @@ -143,13 +144,24 @@ impl Arbitrary for Proto {
}

#[derive(Clone, Debug)]
struct Mh(MultihashGeneric<64>);
struct Mh(Multihash<64>);

impl Arbitrary for Mh {
fn arbitrary(g: &mut Gen) -> Self {
let mut hash: [u8; 32] = [0; 32];
hash.fill_with(|| u8::arbitrary(g));
Mh(MultihashGeneric::wrap(0x0, &hash).expect("The digest size is never too large"))
Mh(Multihash::wrap(0x0, &hash).expect("The digest size is never too large"))
}
}

#[derive(Clone, Debug)]
struct PId(PeerId);

impl Arbitrary for PId {
fn arbitrary(g: &mut Gen) -> Self {
let mh = Mh::arbitrary(g);

PId(PeerId::from_multihash(mh.0).expect("identity multihash works if digest size < 64"))
}
}

Expand Down Expand Up @@ -177,8 +189,8 @@ fn ma_valid(source: &str, target: &str, protocols: Vec<Protocol<'_>>) {
);
}

fn multihash(s: &str) -> MultihashGeneric<64> {
MultihashGeneric::from_bytes(&multibase::Base::Base58Btc.decode(s).unwrap()).unwrap()
fn peer_id(s: &str) -> PeerId {
s.parse().unwrap()
}

#[test]
Expand Down Expand Up @@ -231,7 +243,7 @@ fn construct_success() {
ma_valid(
"/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
vec![P2p(multihash(
vec![P2p(peer_id(
"QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
))],
);
Expand All @@ -253,7 +265,7 @@ fn construct_success() {
"/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
"A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B0604D2",
vec![
P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")),
P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")),
Tcp(1234),
],
);
Expand All @@ -277,30 +289,30 @@ fn construct_success() {
"047F000001A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
vec![
Ip4(local),
P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")),
P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")),
],
);
ma_valid("/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
"047F000001A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B0604D2",
vec![Ip4(local), P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")), Tcp(1234)]);
vec![Ip4(local), P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")), Tcp(1234)]);
// /unix/a/b/c/d/e,
// /unix/stdio,
// /ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f,
// /ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio
ma_valid("/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/ws/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"29200108A07AC542013AC986FFFE317095061F40DD03A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
vec![Ip6(addr6), Tcp(8000), Ws("/".into()), P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))
vec![Ip6(addr6), Tcp(8000), Ws("/".into()), P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))
]);
ma_valid("/p2p-webrtc-star/ip4/127.0.0.1/tcp/9090/ws/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"9302047F000001062382DD03A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
vec![P2pWebRtcStar, Ip4(local), Tcp(9090), Ws("/".into()), P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))
vec![P2pWebRtcStar, Ip4(local), Tcp(9090), Ws("/".into()), P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))
]);
ma_valid("/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/wss/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"29200108A07AC542013AC986FFFE317095061F40DE03A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
vec![Ip6(addr6), Tcp(8000), Wss("/".into()), P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))]);
vec![Ip6(addr6), Tcp(8000), Wss("/".into()), P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))]);
ma_valid("/ip4/127.0.0.1/tcp/9090/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"047F000001062382A202A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
vec![Ip4(local), Tcp(9090), P2pCircuit, P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))]);
vec![Ip4(local), Tcp(9090), P2pCircuit, P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))]);

ma_valid(
"/onion/aaimaq4ygg2iegci:80",
Expand Down Expand Up @@ -332,7 +344,7 @@ fn construct_success() {
ma_valid(
"/dnsaddr/sjc-1.bootstrap.libp2p.io/tcp/1234/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
"3819736A632D312E626F6F7473747261702E6C69627032702E696F0604D2A50322122006B3608AA000274049EB28AD8E793A26FF6FAB281A7D3BD77CD18EB745DFAABB",
vec![Dnsaddr(Cow::Borrowed("sjc-1.bootstrap.libp2p.io")), Tcp(1234), P2p(multihash("QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"))]
vec![Dnsaddr(Cow::Borrowed("sjc-1.bootstrap.libp2p.io")), Tcp(1234), P2p(peer_id("QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"))]
);
ma_valid(
"/ip4/127.0.0.1/tcp/127/ws",
Expand Down Expand Up @@ -371,7 +383,7 @@ fn construct_success() {
Ip4(local),
Udp(1234),
WebRTCDirect,
Certhash(MultihashGeneric::from_bytes(&decoded).unwrap()),
Certhash(Multihash::from_bytes(&decoded).unwrap()),
],
);

Expand All @@ -390,7 +402,7 @@ fn construct_success() {
Ip4(local),
Udp(1234),
WebTransport,
Certhash(MultihashGeneric::from_bytes(&decoded).unwrap()),
Certhash(Multihash::from_bytes(&decoded).unwrap()),
],
);
}
Expand Down

0 comments on commit bdd6607

Please sign in to comment.