From c89e68bfb6cd926d07400f47dff437ccd584f5a6 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 8 Feb 2018 12:00:25 +0100 Subject: [PATCH] Add a proper PeerId to Peerstore (#115) --- example/src/lib.rs | 4 +- libp2p-peerstore/Cargo.toml | 1 + libp2p-peerstore/src/json_peerstore.rs | 6 +- libp2p-peerstore/src/lib.rs | 73 ++++++++++++++++++++++++- libp2p-peerstore/src/peerstore_tests.rs | 16 +++--- 5 files changed, 84 insertions(+), 16 deletions(-) diff --git a/example/src/lib.rs b/example/src/lib.rs index 5c68ed5a..18a78c85 100644 --- a/example/src/lib.rs +++ b/example/src/lib.rs @@ -22,7 +22,7 @@ extern crate libp2p_peerstore; extern crate libp2p_swarm; extern crate multiaddr; -use libp2p_peerstore::{PeerAccess, Peerstore}; +use libp2p_peerstore::{PeerId, PeerAccess, Peerstore}; use multiaddr::Multiaddr; use std::time::Duration; @@ -58,7 +58,7 @@ where peer_store .clone() - .peer_or_create(&public_key) + .peer_or_create(&PeerId::from_bytes(public_key).unwrap()) .add_addr(multiaddr, ttl.clone()); } } diff --git a/libp2p-peerstore/Cargo.toml b/libp2p-peerstore/Cargo.toml index d5acbaab..c574f540 100644 --- a/libp2p-peerstore/Cargo.toml +++ b/libp2p-peerstore/Cargo.toml @@ -9,6 +9,7 @@ datastore = { path = "../datastore" } futures = "0.1.0" owning_ref = "0.3.3" multiaddr = "0.2" +multihash = "0.7.0" serde = "1.0" serde_derive = "1.0" diff --git a/libp2p-peerstore/src/json_peerstore.rs b/libp2p-peerstore/src/json_peerstore.rs index e91846f0..1083a446 100644 --- a/libp2p-peerstore/src/json_peerstore.rs +++ b/libp2p-peerstore/src/json_peerstore.rs @@ -67,13 +67,13 @@ impl<'a> Peerstore for &'a JsonPeerstore { #[inline] fn peer(self, peer_id: &PeerId) -> Option { - let hash = peer_id.to_base58(); + let hash = peer_id.as_bytes().to_base58(); self.store.lock(hash.into()).map(JsonPeerstoreAccess) } #[inline] fn peer_or_create(self, peer_id: &PeerId) -> Self::PeerAccess { - let hash = peer_id.to_base58(); + let hash = peer_id.as_bytes().to_base58(); JsonPeerstoreAccess(self.store.lock_or_create(hash.into())) } @@ -90,7 +90,7 @@ impl<'a> Peerstore for &'a JsonPeerstore { let list = query.filter_map(|(key, _)| { // We filter out invalid elements. This can happen if the JSON storage file was // corrupted or manually modified by the user. - key.from_base58().ok() + PeerId::from_bytes(key.from_base58().ok()?).ok() }) .collect() .wait(); // Wait can never block for the JSON datastore. diff --git a/libp2p-peerstore/src/lib.rs b/libp2p-peerstore/src/lib.rs index ea7598c0..0e74fcd3 100644 --- a/libp2p-peerstore/src/lib.rs +++ b/libp2p-peerstore/src/lib.rs @@ -42,13 +42,13 @@ //! //! # fn main() { //! use libp2p_peerstore::memory_peerstore::MemoryPeerstore; -//! use libp2p_peerstore::{Peerstore, PeerAccess}; +//! use libp2p_peerstore::{PeerId, Peerstore, PeerAccess}; //! use multiaddr::Multiaddr; //! use std::time::Duration; //! //! // In this example we use a `MemoryPeerstore`, but you can easily swap it for another backend. //! let mut peerstore = MemoryPeerstore::empty(); -//! let peer_id = vec![1, 2, 3, 4]; +//! let peer_id = PeerId::from_public_key(&[1, 2, 3, 4]); //! //! // Let's write some information about a peer. //! { @@ -73,11 +73,15 @@ extern crate base58; extern crate datastore; extern crate futures; extern crate multiaddr; +extern crate multihash; extern crate owning_ref; extern crate serde; #[macro_use] extern crate serde_derive; +use std::fmt; +use base58::ToBase58; + pub use self::peerstore::{Peerstore, PeerAccess}; #[macro_use] @@ -88,5 +92,68 @@ pub mod memory_peerstore; mod peerstore; mod peer_info; -pub type PeerId = Vec; pub type TTL = std::time::Duration; + +/// 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)] +pub struct PeerId { + multihash: Vec, +} + +impl fmt::Debug for PeerId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "PeerId({})", self.multihash.to_base58()) + } +} + +impl PeerId { + /// Builds a `PeerId` from a public key. + #[inline] + pub fn from_public_key(public_key: &[u8]) -> PeerId { + let data = multihash::encode(multihash::Hash::SHA2256, public_key) + .expect("sha2-256 is always supported"); + PeerId { multihash: data } + } + + /// 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) -> Result> { + match multihash::decode(&data) { + Ok(_) => Ok(PeerId { multihash: data }), + Err(_) => Err(data), + } + } + + /// Returns a raw bytes representation of this `PeerId`. + #[inline] + pub fn into_bytes(self) -> Vec { + self.multihash + } + + /// Returns a raw bytes representation of this `PeerId`. + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.multihash + } + + /// Returns the raw bytes of the hash of this `PeerId`. + #[inline] + pub fn hash(&self) -> &[u8] { + let multihash::Multihash { digest, .. } = multihash::decode(&self.multihash) + .expect("our inner value should always be valid"); + digest + } + + /// Checks whether the public key passed as parameter matches the public key of this `PeerId`. + pub fn is_public_key(&self, public_key: &[u8]) -> bool { + let multihash::Multihash { alg, .. } = multihash::decode(&self.multihash) + .expect("our inner value should always be valid"); + let compare = multihash::encode(alg, public_key) + .expect("unsupported multihash algorithm"); // TODO: what to do here? + compare == self.multihash + } +} diff --git a/libp2p-peerstore/src/peerstore_tests.rs b/libp2p-peerstore/src/peerstore_tests.rs index 08dc30a9..d5986010 100644 --- a/libp2p-peerstore/src/peerstore_tests.rs +++ b/libp2p-peerstore/src/peerstore_tests.rs @@ -32,14 +32,14 @@ macro_rules! peerstore_tests { extern crate multihash; use std::thread; use std::time::Duration; - use {Peerstore, PeerAccess}; + use {Peerstore, PeerAccess, PeerId}; use multiaddr::Multiaddr; #[test] fn initially_empty() { $($stmt;)* let peer_store = $create_peerstore; - let peer_id = multihash::encode(multihash::Hash::SHA2512, &[1, 2, 3]).unwrap(); + let peer_id = PeerId::from_public_key(&[1, 2, 3]); assert_eq!(peer_store.peers().count(), 0); assert!(peer_store.peer(&peer_id).is_none()); } @@ -48,7 +48,7 @@ macro_rules! peerstore_tests { fn set_pub_key_then_retreive() { $($stmt;)* let peer_store = $create_peerstore; - let peer_id = multihash::encode(multihash::Hash::SHA2512, &[1, 2, 3]).unwrap(); + let peer_id = PeerId::from_public_key(&[1, 2, 3]); peer_store.peer_or_create(&peer_id).set_pub_key(vec![9, 8, 7]); @@ -61,7 +61,7 @@ macro_rules! peerstore_tests { fn set_then_get_addr() { $($stmt;)* let peer_store = $create_peerstore; - let peer_id = multihash::encode(multihash::Hash::SHA2512, &[1, 2, 3]).unwrap(); + let peer_id = PeerId::from_public_key(&[1, 2, 3]); let addr = "/ip4/0.0.0.0/tcp/0".parse::().unwrap(); peer_store.peer_or_create(&peer_id).add_addr(addr.clone(), Duration::from_millis(5000)); @@ -75,7 +75,7 @@ macro_rules! peerstore_tests { // Add an already-expired address to a peer. $($stmt;)* let peer_store = $create_peerstore; - let peer_id = multihash::encode(multihash::Hash::SHA2512, &[1, 2, 3]).unwrap(); + let peer_id = PeerId::from_public_key(&[1, 2, 3]); let addr = "/ip4/0.0.0.0/tcp/0".parse::().unwrap(); peer_store.peer_or_create(&peer_id).add_addr(addr.clone(), Duration::from_millis(0)); @@ -89,7 +89,7 @@ macro_rules! peerstore_tests { fn clear_addrs() { $($stmt;)* let peer_store = $create_peerstore; - let peer_id = multihash::encode(multihash::Hash::SHA2512, &[1, 2, 3]).unwrap(); + let peer_id = PeerId::from_public_key(&[1, 2, 3]); let addr = "/ip4/0.0.0.0/tcp/0".parse::().unwrap(); peer_store.peer_or_create(&peer_id).add_addr(addr.clone(), Duration::from_millis(5000)); @@ -103,7 +103,7 @@ macro_rules! peerstore_tests { fn no_update_ttl() { $($stmt;)* let peer_store = $create_peerstore; - let peer_id = multihash::encode(multihash::Hash::SHA2512, &[1, 2, 3]).unwrap(); + let peer_id = PeerId::from_public_key(&[1, 2, 3]); let addr1 = "/ip4/0.0.0.0/tcp/0".parse::().unwrap(); let addr2 = "/ip4/0.0.0.1/tcp/0".parse::().unwrap(); @@ -122,7 +122,7 @@ macro_rules! peerstore_tests { fn force_update_ttl() { $($stmt;)* let peer_store = $create_peerstore; - let peer_id = multihash::encode(multihash::Hash::SHA2512, &[1, 2, 3]).unwrap(); + let peer_id = PeerId::from_public_key(&[1, 2, 3]); let addr1 = "/ip4/0.0.0.0/tcp/0".parse::().unwrap(); let addr2 = "/ip4/0.0.0.1/tcp/0".parse::().unwrap();