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

Stack allocated PeerId #1874

Merged
merged 13 commits into from
Dec 15, 2020
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
- [`parity-multiaddr` CHANGELOG](misc/multiaddr/CHANGELOG.md)
- [`libp2p-core-derive` CHANGELOG](misc/core-derive/CHANGELOG.md)

# Version 0.33.0 [unreleased]

- Update `libp2p-core` and all dependent crates.

# Version 0.32.2 [2020-12-10]

- Update `libp2p-websocket`.
Expand Down
40 changes: 20 additions & 20 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "libp2p"
edition = "2018"
description = "Peer-to-peer networking library"
version = "0.32.2"
version = "0.33.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
Expand Down Expand Up @@ -61,34 +61,34 @@ atomic = "0.5.0"
bytes = "0.5"
futures = "0.3.1"
lazy_static = "1.2"
libp2p-core = { version = "0.25.2", path = "core" }
libp2p-core = { version = "0.26.0", path = "core" }
libp2p-core-derive = { version = "0.21.0", path = "misc/core-derive" }
libp2p-floodsub = { version = "0.25.0", path = "protocols/floodsub", optional = true }
libp2p-gossipsub = { version = "0.25.0", path = "./protocols/gossipsub", optional = true }
libp2p-identify = { version = "0.25.0", path = "protocols/identify", optional = true }
libp2p-kad = { version = "0.26.0", path = "protocols/kad", optional = true }
libp2p-mplex = { version = "0.25.0", path = "muxers/mplex", optional = true }
libp2p-noise = { version = "0.27.0", path = "protocols/noise", optional = true }
libp2p-ping = { version = "0.25.0", path = "protocols/ping", optional = true }
libp2p-plaintext = { version = "0.25.0", path = "protocols/plaintext", optional = true }
libp2p-floodsub = { version = "0.26.0", path = "protocols/floodsub", optional = true }
libp2p-gossipsub = { version = "0.26.0", path = "./protocols/gossipsub", optional = true }
libp2p-identify = { version = "0.26.0", path = "protocols/identify", optional = true }
libp2p-kad = { version = "0.27.0", path = "protocols/kad", optional = true }
libp2p-mplex = { version = "0.26.0", path = "muxers/mplex", optional = true }
libp2p-noise = { version = "0.28.0", path = "protocols/noise", optional = true }
libp2p-ping = { version = "0.26.0", path = "protocols/ping", optional = true }
libp2p-plaintext = { version = "0.26.0", path = "protocols/plaintext", optional = true }
libp2p-pnet = { version = "0.19.2", path = "protocols/pnet", optional = true }
libp2p-request-response = { version = "0.7.0", path = "protocols/request-response", optional = true }
libp2p-swarm = { version = "0.25.0", path = "swarm" }
libp2p-uds = { version = "0.25.0", path = "transports/uds", optional = true }
libp2p-wasm-ext = { version = "0.25.0", path = "transports/wasm-ext", optional = true }
libp2p-yamux = { version = "0.28.0", path = "muxers/yamux", optional = true }
libp2p-request-response = { version = "0.8.0", path = "protocols/request-response", optional = true }
libp2p-swarm = { version = "0.26.0", path = "swarm" }
libp2p-uds = { version = "0.26.0", path = "transports/uds", optional = true }
libp2p-wasm-ext = { version = "0.26.0", path = "transports/wasm-ext", optional = true }
libp2p-yamux = { version = "0.29.0", path = "muxers/yamux", optional = true }
multiaddr = { package = "parity-multiaddr", version = "0.10.0", path = "misc/multiaddr" }
parking_lot = "0.11.0"
pin-project = "1.0.0"
smallvec = "1.0"
wasm-timer = "0.2.4"

[target.'cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))'.dependencies]
libp2p-deflate = { version = "0.25.0", path = "protocols/deflate", optional = true }
libp2p-dns = { version = "0.25.0", path = "transports/dns", optional = true }
libp2p-mdns = { version = "0.26.0", path = "protocols/mdns", optional = true }
libp2p-tcp = { version = "0.25.1", path = "transports/tcp", optional = true }
libp2p-websocket = { version = "0.26.3", path = "transports/websocket", optional = true }
libp2p-deflate = { version = "0.26.0", path = "protocols/deflate", optional = true }
libp2p-dns = { version = "0.26.0", path = "transports/dns", optional = true }
libp2p-mdns = { version = "0.27.0", path = "protocols/mdns", optional = true }
libp2p-tcp = { version = "0.26.0", path = "transports/tcp", optional = true }
libp2p-websocket = { version = "0.27.0", path = "transports/websocket", optional = true }

[dev-dependencies]
async-std = "1.6.2"
Expand Down
5 changes: 5 additions & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 0.26.0 [unreleased]

- Make `PeerId` be `Copy`, including small `PeerId` API changes.
[PR 1874](https://github.com/libp2p/rust-libp2p/pull/1874/).

# 0.25.2 [2020-12-02]

- Require `multistream-select-0.9.1`.
Expand Down
3 changes: 1 addition & 2 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "libp2p-core"
edition = "2018"
description = "Core traits and structs of libp2p"
version = "0.25.2"
version = "0.26.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
Expand All @@ -12,7 +12,6 @@ categories = ["network-programming", "asynchronous"]
[dependencies]
asn1_der = "0.6.1"
bs58 = "0.4.0"
bytes = "0.5"
ed25519-dalek = "1.0.1"
either = "1.5"
fnv = "1.0"
Expand Down
6 changes: 3 additions & 3 deletions core/benches/peer_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use libp2p_core::{identity, PeerId};

fn from_bytes(c: &mut Criterion) {
let peer_id_bytes = identity::Keypair::generate_ed25519()
.public()
.into_peer_id()
.into_bytes();
.to_bytes();

c.bench_function("from_bytes", |b| {
b.iter(|| {
black_box(PeerId::from_bytes(peer_id_bytes.clone()).unwrap());
black_box(PeerId::from_bytes(&peer_id_bytes).unwrap());
})
});
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/network/peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ where
}

self.network.pool.add(connection, connected)
.map(|_id| ConnectedPeer {
.map(move |_id| ConnectedPeer {
network: self.network,
peer_id: self.peer_id,
})
Expand Down
115 changes: 29 additions & 86 deletions core/src/peer_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@
// DEALINGS IN THE SOFTWARE.

use crate::PublicKey;
use bytes::Bytes;
use thiserror::Error;
use multihash::{Code, Multihash, MultihashDigest};
use multihash::{Code, Error, Multihash, MultihashDigest};
use rand::Rng;
use std::{convert::TryFrom, borrow::Borrow, fmt, hash, str::FromStr, cmp};
use std::{convert::TryFrom, fmt, str::FromStr};
use thiserror::Error;

/// Public keys with byte-lengths smaller than `MAX_INLINE_KEY_LENGTH` will be
/// automatically used as the peer id using an identity multihash.
Expand All @@ -32,10 +31,9 @@ const MAX_INLINE_KEY_LENGTH: usize = 42;
/// Identifier of a peer of the network.
///
/// The data is a multihash of the public key of the peer.
// TODO: maybe keep things in decoded version?
#[derive(Clone, Eq)]
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
dvc94ch marked this conversation as resolved.
Show resolved Hide resolved
pub struct PeerId {
multihash: Bytes,
multihash: Multihash,
}

impl fmt::Debug for PeerId {
Expand All @@ -52,21 +50,6 @@ impl fmt::Display for PeerId {
}
}

impl cmp::PartialOrd for PeerId {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(Ord::cmp(self, other))
}
}

impl cmp::Ord for PeerId {
fn cmp(&self, other: &Self) -> cmp::Ordering {
// must use borrow, because as_bytes is not consistent with equality
let lhs: &[u8] = self.borrow();
let rhs: &[u8] = other.borrow();
lhs.cmp(rhs)
}
}

impl PeerId {
/// Builds a `PeerId` from a public key.
pub fn from_public_key(key: PublicKey) -> PeerId {
Expand All @@ -78,18 +61,15 @@ impl PeerId {
Code::Sha2_256
};

let multihash = hash_algorithm.digest(&key_enc).to_bytes().into();
let multihash = hash_algorithm.digest(&key_enc);

PeerId { multihash }
}

/// Checks whether `data` is a valid `PeerId`. If so, returns the `PeerId`. If not, returns
/// back the data as an error.
pub fn from_bytes(data: Vec<u8>) -> Result<PeerId, Vec<u8>> {
match Multihash::from_bytes(&data) {
Ok(multihash) => PeerId::from_multihash(multihash).map_err(|_| data),
Err(_err) => Err(data),
}
/// Parses a `PeerId` from bytes.
pub fn from_bytes(data: &[u8]) -> Result<PeerId, Error> {
Ok(PeerId::from_multihash(Multihash::from_bytes(&data)?)
.map_err(|mh| Error::UnsupportedCode(mh.code()))?)
}

/// Tries to turn a `Multihash` into a `PeerId`.
Expand All @@ -99,9 +79,9 @@ impl PeerId {
/// peer ID, it is returned as an `Err`.
pub fn from_multihash(multihash: Multihash) -> Result<PeerId, Multihash> {
match Code::try_from(multihash.code()) {
Ok(Code::Sha2_256) => Ok(PeerId { multihash: multihash.to_bytes().into() }),
Ok(Code::Sha2_256) => Ok(PeerId { multihash }),
Ok(Code::Identity) if multihash.digest().len() <= MAX_INLINE_KEY_LENGTH
=> Ok(PeerId { multihash: multihash.to_bytes().into() }),
=> Ok(PeerId { multihash }),
_ => Err(multihash)
}
}
Expand All @@ -113,54 +93,29 @@ impl PeerId {
let peer_id = rand::thread_rng().gen::<[u8; 32]>();
PeerId {
multihash: Multihash::wrap(Code::Identity.into(), &peer_id)
.expect("The digest size is never too large").to_bytes().into()
.expect("The digest size is never too large")
}
}

/// Returns a raw bytes representation of this `PeerId`.
///
/// **NOTE:** This byte representation is not necessarily consistent with
/// equality of peer IDs. That is, two peer IDs may be considered equal
/// while having a different byte representation as per `into_bytes`.
pub fn into_bytes(self) -> Vec<u8> {
self.multihash.to_vec()
}

/// Returns a raw bytes representation of this `PeerId`.
///
/// **NOTE:** This byte representation is not necessarily consistent with
/// equality of peer IDs. That is, two peer IDs may be considered equal
/// while having a different byte representation as per `as_bytes`.
pub fn as_bytes(&self) -> &[u8] {
&self.multihash
pub fn to_bytes(&self) -> Vec<u8> {
self.multihash.to_bytes()
}

/// Returns a base-58 encoded string of this `PeerId`.
pub fn to_base58(&self) -> String {
bs58::encode(self.borrow() as &[u8]).into_string()
bs58::encode(self.to_bytes()).into_string()
}

/// Checks whether the public key passed as parameter matches the public key of this `PeerId`.
///
/// Returns `None` if this `PeerId`s hash algorithm is not supported when encoding the
/// given public key, otherwise `Some` boolean as the result of an equality check.
pub fn is_public_key(&self, public_key: &PublicKey) -> Option<bool> {
let multihash = Multihash::from_bytes(&self.multihash)
.expect("Internal multihash is always a valid");
let alg = Code::try_from(multihash.code())
let alg = Code::try_from(self.multihash.code())
.expect("Internal multihash is always a valid `Code`");
let enc = public_key.clone().into_protobuf_encoding();
Some(alg.digest(&enc) == multihash)
}
}

impl hash::Hash for PeerId {
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher
{
let digest = self.borrow() as &[u8];
hash::Hash::hash(digest, state)
Some(alg.digest(&enc) == self.multihash)
}
}

Expand All @@ -174,7 +129,7 @@ impl TryFrom<Vec<u8>> for PeerId {
type Error = Vec<u8>;

fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
PeerId::from_bytes(value)
PeerId::from_bytes(&value).map_err(|_| value)
}
}

Expand All @@ -186,33 +141,21 @@ impl TryFrom<Multihash> for PeerId {
}
}

impl PartialEq<PeerId> for PeerId {
fn eq(&self, other: &PeerId) -> bool {
let self_digest = self.borrow() as &[u8];
let other_digest = other.borrow() as &[u8];
self_digest == other_digest
}
}

impl Borrow<[u8]> for PeerId {
fn borrow(&self) -> &[u8] {
impl AsRef<Multihash> for PeerId {
fn as_ref(&self) -> &Multihash {
&self.multihash
}
}

/// **NOTE:** This byte representation is not necessarily consistent with
/// equality of peer IDs. That is, two peer IDs may be considered equal
/// while having a different byte representation as per `AsRef<[u8]>`.
impl AsRef<[u8]> for PeerId {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
impl From<PeerId> for Multihash {
fn from(peer_id: PeerId) -> Self {
peer_id.multihash
}
}

impl From<PeerId> for Multihash {
impl From<PeerId> for Vec<u8> {
fn from(peer_id: PeerId) -> Self {
Multihash::from_bytes(&peer_id.multihash)
.expect("PeerIds always contain valid Multihashes")
peer_id.to_bytes()
}
}

Expand All @@ -230,7 +173,7 @@ impl FromStr for PeerId {
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
let bytes = bs58::decode(s).into_vec()?;
PeerId::from_bytes(bytes).map_err(|_| ParseError::MultiHash)
PeerId::from_bytes(&bytes).map_err(|_| ParseError::MultiHash)
}
}

Expand All @@ -248,7 +191,7 @@ mod tests {
#[test]
fn peer_id_into_bytes_then_from_bytes() {
let peer_id = identity::Keypair::generate_ed25519().public().into_peer_id();
let second = PeerId::from_bytes(peer_id.clone().into_bytes()).unwrap();
let second = PeerId::from_bytes(&peer_id.to_bytes()).unwrap();
assert_eq!(peer_id, second);
}

Expand All @@ -263,7 +206,7 @@ mod tests {
fn random_peer_id_is_valid() {
for _ in 0 .. 5000 {
let peer_id = PeerId::random();
assert_eq!(peer_id, PeerId::from_bytes(peer_id.clone().into_bytes()).unwrap());
assert_eq!(peer_id, PeerId::from_bytes(&peer_id.to_bytes()).unwrap());
}
}
}
4 changes: 4 additions & 0 deletions muxers/mplex/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.26.0 [unreleased]

- Update `libp2p-core`.

# 0.25.0 [2020-11-25]

- Update `libp2p-core`.
Expand Down
4 changes: 2 additions & 2 deletions muxers/mplex/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "libp2p-mplex"
edition = "2018"
description = "Mplex multiplexing protocol for libp2p"
version = "0.25.0"
version = "0.26.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
Expand All @@ -13,7 +13,7 @@ categories = ["network-programming", "asynchronous"]
bytes = "0.5"
futures = "0.3.1"
futures_codec = "0.4.1"
libp2p-core = { version = "0.25.0", path = "../../core" }
libp2p-core = { version = "0.26.0", path = "../../core" }
log = "0.4"
nohash-hasher = "0.2"
parking_lot = "0.11"
Expand Down
4 changes: 4 additions & 0 deletions muxers/yamux/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.29.0 [unreleased]

- Update `libp2p-core`.

# 0.28.0 [2020-11-25]

- Update `libp2p-core`.
Expand Down
Loading