Skip to content

Commit bdd6607

Browse files
feat!: make /p2p type-safe (#83)
1 parent 13a1e9e commit bdd6607

File tree

5 files changed

+53
-26
lines changed

5 files changed

+53
-26
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
# 0.18.0 - unreleased
22

33
- Add `WebTransport` instance for `Multiaddr`. See [PR 70].
4+
45
- Disable all features of `multihash`. See [PR 77].
6+
57
- Mark `Protocol` as `#[non_exhaustive]`. See [PR 82].
68

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

14+
- Make `/p2p` typesafe, i.e. have `Protocol::P2p` contain a `PeerId` instead of a `Multihash`.
15+
See [PR 83].
16+
1217
[multiformats/multiaddr discussion]: https://github.com/multiformats/multiaddr/pull/150#issuecomment-1468791586
1318
[PR 70]: https://github.com/multiformats/rust-multiaddr/pull/70
1419
[PR 77]: https://github.com/multiformats/rust-multiaddr/pull/77
1520
[PR 82]: https://github.com/multiformats/rust-multiaddr/pull/82
21+
[PR 83]: https://github.com/multiformats/rust-multiaddr/pull/83
1622

1723
# 0.17.1
1824

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ arrayref = "0.3"
1818
byteorder = "1.3.1"
1919
data-encoding = "2.1"
2020
multibase = "0.9.1"
21-
multihash = { version = "0.18", default-features = false, features = ["std"] }
21+
multihash = "0.19"
2222
percent-encoding = "2.1.0"
2323
serde = "1.0.70"
2424
static_assertions = "1.1"
2525
unsigned-varint = "0.7"
2626
url = { version = "2.1.0", optional = true, default-features = false }
27+
libp2p-identity = { version = "0.2.0", features = ["peerid"] }
2728

2829
[dev-dependencies]
2930
bincode = "1"

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
///! Implementation of [multiaddr](https://github.com/multiformats/multiaddr) in Rust.
1+
//! Implementation of [multiaddr](https://github.com/multiformats/multiaddr) in Rust.
2+
23
pub use multihash;
34

45
mod errors;

src/protocol.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{Error, Result};
33
use arrayref::array_ref;
44
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
55
use data_encoding::BASE32;
6-
use multihash::MultihashGeneric;
6+
use libp2p_identity::PeerId;
77
use std::{
88
borrow::Cow,
99
convert::From,
@@ -57,7 +57,7 @@ const WSS_WITH_PATH: u32 = 4780; // Note: not standard
5757
/// The `64` defines the allocation size for the digest within the `Multihash`.
5858
/// This allows us to use hashes such as SHA512.
5959
/// 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!).
60-
type Multihash = MultihashGeneric<64>;
60+
type Multihash = multihash::Multihash<64>;
6161

6262
const PATH_SEGMENT_ENCODE_SET: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
6363
.add(b'%')
@@ -99,7 +99,7 @@ pub enum Protocol<'a> {
9999
Memory(u64),
100100
Onion(Cow<'a, [u8; 10]>, u16),
101101
Onion3(Onion3Addr<'a>),
102-
P2p(Multihash),
102+
P2p(PeerId),
103103
P2pCircuit,
104104
Quic,
105105
QuicV1,
@@ -179,7 +179,9 @@ impl<'a> Protocol<'a> {
179179
"p2p" => {
180180
let s = iter.next().ok_or(Error::InvalidProtocolString)?;
181181
let decoded = multibase::Base::Base58Btc.decode(s)?;
182-
Ok(Protocol::P2p(Multihash::from_bytes(&decoded)?))
182+
let peer_id =
183+
PeerId::from_bytes(&decoded).map_err(|e| Error::ParsingError(Box::new(e)))?;
184+
Ok(Protocol::P2p(peer_id))
183185
}
184186
"http" => Ok(Protocol::Http),
185187
"https" => Ok(Protocol::Https),
@@ -324,7 +326,12 @@ impl<'a> Protocol<'a> {
324326
P2P => {
325327
let (n, input) = decode::usize(input)?;
326328
let (data, rest) = split_at(n, input)?;
327-
Ok((Protocol::P2p(Multihash::from_bytes(data)?), rest))
329+
Ok((
330+
Protocol::P2p(
331+
PeerId::from_bytes(data).map_err(|e| Error::ParsingError(Box::new(e)))?,
332+
),
333+
rest,
334+
))
328335
}
329336
P2P_CIRCUIT => Ok((Protocol::P2pCircuit, input)),
330337
QUIC => Ok((Protocol::Quic, input)),
@@ -436,9 +443,9 @@ impl<'a> Protocol<'a> {
436443
w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
437444
w.write_all(bytes)?
438445
}
439-
Protocol::P2p(multihash) => {
446+
Protocol::P2p(peer_id) => {
440447
w.write_all(encode::u32(P2P, &mut buf))?;
441-
let bytes = multihash.to_bytes();
448+
let bytes = peer_id.to_bytes();
442449
w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
443450
w.write_all(&bytes)?
444451
}

tests/lib.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use data_encoding::HEXUPPER;
2+
use libp2p_identity::PeerId;
23
use multiaddr::*;
3-
use multihash::MultihashGeneric;
4+
use multihash::Multihash;
45
use quickcheck::{Arbitrary, Gen, QuickCheck};
56
use std::{
67
borrow::Cow,
@@ -122,7 +123,7 @@ impl Arbitrary for Proto {
122123
.unwrap();
123124
Proto(Onion3((a, std::cmp::max(1, u16::arbitrary(g))).into()))
124125
}
125-
17 => Proto(P2p(Mh::arbitrary(g).0)),
126+
17 => Proto(P2p(PId::arbitrary(g).0)),
126127
18 => Proto(P2pCircuit),
127128
19 => Proto(Quic),
128129
20 => Proto(QuicV1),
@@ -143,13 +144,24 @@ impl Arbitrary for Proto {
143144
}
144145

145146
#[derive(Clone, Debug)]
146-
struct Mh(MultihashGeneric<64>);
147+
struct Mh(Multihash<64>);
147148

148149
impl Arbitrary for Mh {
149150
fn arbitrary(g: &mut Gen) -> Self {
150151
let mut hash: [u8; 32] = [0; 32];
151152
hash.fill_with(|| u8::arbitrary(g));
152-
Mh(MultihashGeneric::wrap(0x0, &hash).expect("The digest size is never too large"))
153+
Mh(Multihash::wrap(0x0, &hash).expect("The digest size is never too large"))
154+
}
155+
}
156+
157+
#[derive(Clone, Debug)]
158+
struct PId(PeerId);
159+
160+
impl Arbitrary for PId {
161+
fn arbitrary(g: &mut Gen) -> Self {
162+
let mh = Mh::arbitrary(g);
163+
164+
PId(PeerId::from_multihash(mh.0).expect("identity multihash works if digest size < 64"))
153165
}
154166
}
155167

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

180-
fn multihash(s: &str) -> MultihashGeneric<64> {
181-
MultihashGeneric::from_bytes(&multibase::Base::Base58Btc.decode(s).unwrap()).unwrap()
192+
fn peer_id(s: &str) -> PeerId {
193+
s.parse().unwrap()
182194
}
183195

184196
#[test]
@@ -231,7 +243,7 @@ fn construct_success() {
231243
ma_valid(
232244
"/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
233245
"A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
234-
vec![P2p(multihash(
246+
vec![P2p(peer_id(
235247
"QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
236248
))],
237249
);
@@ -253,7 +265,7 @@ fn construct_success() {
253265
"/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
254266
"A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B0604D2",
255267
vec![
256-
P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")),
268+
P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")),
257269
Tcp(1234),
258270
],
259271
);
@@ -277,30 +289,30 @@ fn construct_success() {
277289
"047F000001A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
278290
vec![
279291
Ip4(local),
280-
P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")),
292+
P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")),
281293
],
282294
);
283295
ma_valid("/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
284296
"047F000001A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B0604D2",
285-
vec![Ip4(local), P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")), Tcp(1234)]);
297+
vec![Ip4(local), P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC")), Tcp(1234)]);
286298
// /unix/a/b/c/d/e,
287299
// /unix/stdio,
288300
// /ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f,
289301
// /ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio
290302
ma_valid("/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/ws/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
291303
"29200108A07AC542013AC986FFFE317095061F40DD03A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
292-
vec![Ip6(addr6), Tcp(8000), Ws("/".into()), P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))
304+
vec![Ip6(addr6), Tcp(8000), Ws("/".into()), P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))
293305
]);
294306
ma_valid("/p2p-webrtc-star/ip4/127.0.0.1/tcp/9090/ws/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
295307
"9302047F000001062382DD03A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
296-
vec![P2pWebRtcStar, Ip4(local), Tcp(9090), Ws("/".into()), P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))
308+
vec![P2pWebRtcStar, Ip4(local), Tcp(9090), Ws("/".into()), P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))
297309
]);
298310
ma_valid("/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/wss/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
299311
"29200108A07AC542013AC986FFFE317095061F40DE03A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
300-
vec![Ip6(addr6), Tcp(8000), Wss("/".into()), P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))]);
312+
vec![Ip6(addr6), Tcp(8000), Wss("/".into()), P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))]);
301313
ma_valid("/ip4/127.0.0.1/tcp/9090/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
302314
"047F000001062382A202A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B",
303-
vec![Ip4(local), Tcp(9090), P2pCircuit, P2p(multihash("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))]);
315+
vec![Ip4(local), Tcp(9090), P2pCircuit, P2p(peer_id("QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"))]);
304316

305317
ma_valid(
306318
"/onion/aaimaq4ygg2iegci:80",
@@ -332,7 +344,7 @@ fn construct_success() {
332344
ma_valid(
333345
"/dnsaddr/sjc-1.bootstrap.libp2p.io/tcp/1234/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
334346
"3819736A632D312E626F6F7473747261702E6C69627032702E696F0604D2A50322122006B3608AA000274049EB28AD8E793A26FF6FAB281A7D3BD77CD18EB745DFAABB",
335-
vec![Dnsaddr(Cow::Borrowed("sjc-1.bootstrap.libp2p.io")), Tcp(1234), P2p(multihash("QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"))]
347+
vec![Dnsaddr(Cow::Borrowed("sjc-1.bootstrap.libp2p.io")), Tcp(1234), P2p(peer_id("QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"))]
336348
);
337349
ma_valid(
338350
"/ip4/127.0.0.1/tcp/127/ws",
@@ -371,7 +383,7 @@ fn construct_success() {
371383
Ip4(local),
372384
Udp(1234),
373385
WebRTCDirect,
374-
Certhash(MultihashGeneric::from_bytes(&decoded).unwrap()),
386+
Certhash(Multihash::from_bytes(&decoded).unwrap()),
375387
],
376388
);
377389

@@ -390,7 +402,7 @@ fn construct_success() {
390402
Ip4(local),
391403
Udp(1234),
392404
WebTransport,
393-
Certhash(MultihashGeneric::from_bytes(&decoded).unwrap()),
405+
Certhash(Multihash::from_bytes(&decoded).unwrap()),
394406
],
395407
);
396408
}

0 commit comments

Comments
 (0)