Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# Version 0.15.0 (2020-01-24)

- Added `libp2p-gossipsub`.
- Added `SwarmBuilder::executor` to allow configuring which tasks executor to use.
- Added `TokioTcpConfig` in `libp2p-tcp` and `TokioUdsConfig` in `libp2p-uds` behind `tokio` features. These structs use `tokio` and require a `tokio` runtime executor to be configured via `SwarmBuilder::executor`.
- Changed the `OutboundUpgrade` and `InboundUpgrade` traits to no longer be passed a `Negotiated<C>` but just a `C`. The `Negotiated` is now in the trait bounds requirements of `ProtocolsHandler`.
- Fixed `libp2p-wasm-ext` returning `Err(WouldBlock)` rather than `Pending`.
- Fixed `libp2p-dns` not segregating DNS4 and DNS6.
- Removed some unnecessary `Unpin` requirements on futures.
- Changed `Mdns::new` to no longer be `async`.
- Fixed `libp2p-kad` keeping connections alive when it shouldn't.
- Fixed `InboundUpgrade` not always properly implemented on `NoiseConfig`.

# Version 0.14.0-alpha.1 (2020-01-07)

- Upgraded the crate to stable futures.
Expand Down
43 changes: 23 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.14.0-alpha.1"
version = "0.15.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
Expand All @@ -19,31 +19,33 @@ futures = "0.3.1"
multiaddr = { package = "parity-multiaddr", version = "0.7.0", path = "misc/multiaddr" }
multihash = { package = "parity-multihash", version = "0.2.1", path = "misc/multihash" }
lazy_static = "1.2"
libp2p-mplex = { version = "0.14.0-alpha.1", path = "muxers/mplex" }
libp2p-identify = { version = "0.14.0-alpha.1", path = "protocols/identify" }
libp2p-kad = { version = "0.14.0-alpha.1", path = "protocols/kad" }
libp2p-floodsub = { version = "0.14.0-alpha.1", path = "protocols/floodsub" }
libp2p-ping = { version = "0.14.0-alpha.1", path = "protocols/ping" }
libp2p-plaintext = { version = "0.14.0-alpha.1", path = "protocols/plaintext" }
libp2p-core = { version = "0.14.0-alpha.1", path = "core" }
libp2p-core-derive = { version = "0.14.0-alpha.1", path = "misc/core-derive" }
libp2p-secio = { version = "0.14.0-alpha.1", path = "protocols/secio", default-features = false }
libp2p-swarm = { version = "0.4.0-alpha.1", path = "swarm" }
libp2p-uds = { version = "0.14.0-alpha.1", path = "transports/uds" }
libp2p-wasm-ext = { version = "0.7.0-alpha.1", path = "transports/wasm-ext" }
libp2p-yamux = { version = "0.14.0-alpha.1", path = "muxers/yamux" }
libp2p-mplex = { version = "0.15.0", path = "muxers/mplex" }
libp2p-identify = { version = "0.15.0", path = "protocols/identify" }
libp2p-kad = { version = "0.15.0", path = "protocols/kad" }
libp2p-floodsub = { version = "0.15.0", path = "protocols/floodsub" }
libp2p-gossipsub = { version = "0.15.0", path = "./protocols/gossipsub" }
libp2p-ping = { version = "0.15.0", path = "protocols/ping" }
libp2p-plaintext = { version = "0.15.0", path = "protocols/plaintext" }
libp2p-pnet = { version = "0.15.0", path = "protocols/pnet" }
libp2p-core = { version = "0.15.0", path = "core" }
libp2p-core-derive = { version = "0.15.0", path = "misc/core-derive" }
libp2p-secio = { version = "0.15.0", path = "protocols/secio", default-features = false }
libp2p-swarm = { version = "0.5.0", path = "swarm" }
libp2p-uds = { version = "0.15.0", path = "transports/uds" }
libp2p-wasm-ext = { version = "0.8.0", path = "transports/wasm-ext" }
libp2p-yamux = { version = "0.15.0", path = "muxers/yamux" }
parking_lot = "0.10.0"
pin-project = "0.4.6"
smallvec = "1.0"
wasm-timer = "0.2.4"

[target.'cfg(not(any(target_os = "emscripten", target_os = "unknown")))'.dependencies]
libp2p-deflate = { version = "0.6.0-alpha.1", path = "protocols/deflate" }
libp2p-dns = { version = "0.14.0-alpha.1", path = "transports/dns" }
libp2p-mdns = { version = "0.14.0-alpha.1", path = "misc/mdns" }
libp2p-noise = { version = "0.12.0-alpha.1", path = "protocols/noise" }
libp2p-tcp = { version = "0.14.0-alpha.1", path = "transports/tcp" }
libp2p-websocket = { version = "0.14.0-alpha.1", path = "transports/websocket", optional = true }
libp2p-deflate = { version = "0.7.0", path = "protocols/deflate" }
libp2p-dns = { version = "0.15.0", path = "transports/dns" }
libp2p-mdns = { version = "0.15.0", path = "misc/mdns" }
libp2p-noise = { version = "0.13.0", path = "protocols/noise" }
libp2p-tcp = { version = "0.15.0", path = "transports/tcp" }
libp2p-websocket = { version = "0.15.0", path = "transports/websocket", optional = true }

[dev-dependencies]
async-std = "1.0"
Expand All @@ -62,6 +64,7 @@ members = [
"muxers/mplex",
"muxers/yamux",
"protocols/floodsub",
"protocols/gossipsub",
"protocols/identify",
"protocols/kad",
"protocols/noise",
Expand Down
10 changes: 5 additions & 5 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.14.0-alpha.1"
version = "0.15.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
Expand Down Expand Up @@ -41,10 +41,10 @@ untrusted = "0.7.0"
[dev-dependencies]
assert_matches = "1.3"
async-std = "1.0"
libp2p-mplex = { version = "0.14.0-alpha.1", path = "../muxers/mplex" }
libp2p-secio = { version = "0.14.0-alpha.1", path = "../protocols/secio" }
libp2p-swarm = { version = "0.4.0-alpha.1", path = "../swarm" }
libp2p-tcp = { version = "0.14.0-alpha.1", path = "../transports/tcp" }
libp2p-mplex = { version = "0.15.0", path = "../muxers/mplex" }
libp2p-secio = { version = "0.15.0", path = "../protocols/secio" }
libp2p-swarm = { version = "0.5.0", path = "../swarm" }
libp2p-tcp = { version = "0.15.0", path = "../transports/tcp" }
quickcheck = "0.9.0"
wasm-timer = "0.2"

Expand Down
File renamed without changes.
File renamed without changes.
168 changes: 118 additions & 50 deletions core/src/peer_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,17 @@ use crate::PublicKey;
use bs58;
use thiserror::Error;
use multihash;
use std::{convert::TryFrom, fmt, str::FromStr};
use std::{convert::TryFrom, fmt, hash, str::FromStr};

/// Public keys with byte-lengths smaller than `MAX_INLINE_KEY_LENGTH` will be
/// automatically used as the peer id using an identity multihash.
//
// Note: see `from_public_key` for how this value will be used in the future.
const _MAX_INLINE_KEY_LENGTH: usize = 42;
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, PartialEq, Eq, Hash)]
#[derive(Clone, Eq)]
pub struct PeerId {
multihash: multihash::Multihash,
}
Expand All @@ -55,32 +53,28 @@ impl fmt::Display for PeerId {

impl PeerId {
/// Builds a `PeerId` from a public key.
#[inline]
pub fn from_public_key(key: PublicKey) -> PeerId {
let key_enc = key.into_protobuf_encoding();

// Note: the correct behaviour, according to the libp2p specifications, is the
// commented-out code, which consists it transmitting small keys un-hashed. However, this
// version and all previous versions of rust-libp2p always hash the key. Starting from
// version 0.13, rust-libp2p accepts both hashed and non-hashed keys as input
// (see `from_bytes`). Starting from version 0.14, rust-libp2p will switch to not hashing
// the key (a.k.a. the correct behaviour).
// Note: before 0.12, this was incorrectly implemented and `SHA2256` was always used.
// Starting from version 0.13, rust-libp2p accepts both hashed and non-hashed keys as
// input (see `from_bytes`). Starting from version 0.16, rust-libp2p will switch to
// not hashing the key (a.k.a. the correct behaviour).
// In other words, rust-libp2p 0.13 is compatible with all versions of rust-libp2p.
// Rust-libp2p 0.12 and below is **NOT** compatible with rust-libp2p 0.14 and above.
/*let hash_algorithm = if key_enc.len() <= MAX_INLINE_KEY_LENGTH {
// Rust-libp2p 0.12 and below is **NOT** compatible with rust-libp2p 0.16 and above.
let hash_algorithm = if key_enc.len() <= MAX_INLINE_KEY_LENGTH {
multihash::Hash::Identity
} else {
multihash::Hash::SHA2256
};*/
let hash_algorithm = multihash::Hash::SHA2256;
};

let multihash = multihash::encode(hash_algorithm, &key_enc)
.expect("identity and sha2-256 are always supported by known public key types");
PeerId { multihash }
}

/// Checks whether `data` is a valid `PeerId`. If so, returns the `PeerId`. If not, returns
/// back the data as an error.
#[inline]
pub fn from_bytes(data: Vec<u8>) -> Result<PeerId, Vec<u8>> {
match multihash::Multihash::from_bytes(data) {
Ok(multihash) => {
Expand All @@ -98,7 +92,6 @@ impl PeerId {

/// Turns a `Multihash` into a `PeerId`. If the multihash doesn't use the correct algorithm,
/// returns back the data as an error.
#[inline]
pub fn from_multihash(data: multihash::Multihash) -> Result<PeerId, multihash::Multihash> {
if data.algorithm() == multihash::Hash::SHA2256 || data.algorithm() == multihash::Hash::Identity {
Ok(PeerId { multihash: data })
Expand All @@ -110,7 +103,6 @@ impl PeerId {
/// Generates a random peer ID from a cryptographically secure PRNG.
///
/// This is useful for randomly walking on a DHT, or for testing purposes.
#[inline]
pub fn random() -> PeerId {
PeerId {
multihash: multihash::Multihash::random(multihash::Hash::SHA2256)
Expand All @@ -120,31 +112,22 @@ impl PeerId {
/// Returns a raw bytes representation of this `PeerId`.
///
/// Note that this is not the same as the public key of the peer.
#[inline]
pub fn into_bytes(self) -> Vec<u8> {
self.multihash.into_bytes()
}

/// Returns a raw bytes representation of this `PeerId`.
///
/// Note that this is not the same as the public key of the peer.
#[inline]
pub fn as_bytes(&self) -> &[u8] {
self.multihash.as_bytes()
}

/// Returns a base-58 encoded string of this `PeerId`.
#[inline]
pub fn to_base58(&self) -> String {
bs58::encode(self.multihash.as_bytes()).into_string()
}

/// Returns the raw bytes of the hash of this `PeerId`.
#[inline]
pub fn digest(&self) -> &[u8] {
self.multihash.digest()
}

/// 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
Expand All @@ -160,6 +143,25 @@ impl PeerId {
}
}

impl hash::Hash for PeerId {
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher
{
match self.multihash.algorithm() {
multihash::Hash::Identity => {
let sha256 = multihash::encode(multihash::Hash::SHA2256, self.multihash.digest())
.expect("encoding a SHA2256 multihash never fails; qed");
hash::Hash::hash(sha256.digest(), state)
},
multihash::Hash::SHA2256 => {
hash::Hash::hash(self.multihash.digest(), state)
},
_ => unreachable!("PeerId can only be built from Identity or SHA2256; qed")
}
}
}

impl From<PublicKey> for PeerId {
#[inline]
fn from(key: PublicKey) -> PeerId {
Expand All @@ -183,38 +185,45 @@ impl TryFrom<multihash::Multihash> for PeerId {
}
}

impl PartialEq<multihash::Multihash> for PeerId {
#[inline]
fn eq(&self, other: &multihash::Multihash) -> bool {
&self.multihash == other
}
}

impl PartialEq<PeerId> for multihash::Multihash {
#[inline]
impl PartialEq<PeerId> for PeerId {
fn eq(&self, other: &PeerId) -> bool {
self == &other.multihash
}
}

impl AsRef<multihash::Multihash> for PeerId {
#[inline]
fn as_ref(&self) -> &multihash::Multihash {
&self.multihash
match (self.multihash.algorithm(), other.multihash.algorithm()) {
(multihash::Hash::SHA2256, multihash::Hash::SHA2256) => {
self.multihash.digest() == other.multihash.digest()
},
(multihash::Hash::Identity, multihash::Hash::Identity) => {
self.multihash.digest() == other.multihash.digest()
},
(multihash::Hash::SHA2256, multihash::Hash::Identity) => {
multihash::encode(multihash::Hash::SHA2256, other.multihash.digest())
.map(|mh| mh == self.multihash)
.unwrap_or(false)
},
(multihash::Hash::Identity, multihash::Hash::SHA2256) => {
multihash::encode(multihash::Hash::SHA2256, self.multihash.digest())
.map(|mh| mh == other.multihash)
.unwrap_or(false)
},
_ => false
}
}
}

// TODO: The semantics of that function aren't very precise. It is possible for two `PeerId`s to
// compare equal while their bytes representation are not. Right now, this `AsRef`
// implementation is only used to define precedence over two `PeerId`s in case of a
// simultaneous connection between two nodes. Since the simultaneous connection system
// is planned to be removed (https://github.com/libp2p/rust-libp2p/issues/912), we went for
// we keeping that function with the intent of removing it as soon as possible.
impl AsRef<[u8]> for PeerId {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}

impl Into<multihash::Multihash> for PeerId {
#[inline]
fn into(self) -> multihash::Multihash {
self.multihash
impl From<PeerId> for multihash::Multihash {
fn from(peer_id: PeerId) -> Self {
peer_id.multihash
}
}

Expand All @@ -239,6 +248,7 @@ impl FromStr for PeerId {
#[cfg(test)]
mod tests {
use crate::{PeerId, identity};
use std::{convert::TryFrom as _, hash::{self, Hasher as _}};

#[test]
fn peer_id_is_public_key() {
Expand Down Expand Up @@ -268,4 +278,62 @@ mod tests {
assert_eq!(peer_id, PeerId::from_bytes(peer_id.clone().into_bytes()).unwrap());
}
}

#[test]
fn peer_id_identity_equal_to_sha2256() {
let random_bytes = (0..64).map(|_| rand::random::<u8>()).collect::<Vec<u8>>();
let mh1 = multihash::encode(multihash::Hash::SHA2256, &random_bytes).unwrap();
let mh2 = multihash::encode(multihash::Hash::Identity, &random_bytes).unwrap();
let peer_id1 = PeerId::try_from(mh1).unwrap();
let peer_id2 = PeerId::try_from(mh2).unwrap();
assert_eq!(peer_id1, peer_id2);
assert_eq!(peer_id2, peer_id1);
}

#[test]
fn peer_id_identity_hashes_equal_to_sha2256() {
let random_bytes = (0..64).map(|_| rand::random::<u8>()).collect::<Vec<u8>>();
let mh1 = multihash::encode(multihash::Hash::SHA2256, &random_bytes).unwrap();
let mh2 = multihash::encode(multihash::Hash::Identity, &random_bytes).unwrap();
let peer_id1 = PeerId::try_from(mh1).unwrap();
let peer_id2 = PeerId::try_from(mh2).unwrap();

let mut hasher1 = fnv::FnvHasher::with_key(0);
hash::Hash::hash(&peer_id1, &mut hasher1);
let mut hasher2 = fnv::FnvHasher::with_key(0);
hash::Hash::hash(&peer_id2, &mut hasher2);

assert_eq!(hasher1.finish(), hasher2.finish());
}

#[test]
fn peer_id_equal_across_algorithms() {
use multihash::Hash;
use quickcheck::{Arbitrary, Gen};

#[derive(Debug, Clone, PartialEq, Eq)]
struct HashAlgo(Hash);

impl Arbitrary for HashAlgo {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
match g.next_u32() % 4 { // make Hash::Identity more likely
0 => HashAlgo(Hash::SHA2256),
_ => HashAlgo(Hash::Identity)
}
}
}

fn property(data: Vec<u8>, algo1: HashAlgo, algo2: HashAlgo) -> bool {
let a = PeerId::try_from(multihash::encode(algo1.0, &data).unwrap()).unwrap();
let b = PeerId::try_from(multihash::encode(algo2.0, &data).unwrap()).unwrap();

if algo1 == algo2 || algo1.0 == Hash::Identity || algo2.0 == Hash::Identity {
a == b
} else {
a != b
}
}

quickcheck::quickcheck(property as fn(Vec<u8>, HashAlgo, HashAlgo) -> bool)
}
}
File renamed without changes.
File renamed without changes.
Loading