diff --git a/Cargo.toml b/Cargo.toml index e3d17d8029d..e9203fbaa37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ wasm-ext-websocket = ["wasm-ext", "libp2p-wasm-ext/websocket"] websocket = ["libp2p-websocket"] yamux = ["libp2p-yamux"] secp256k1 = ["libp2p-core/secp256k1"] +serde = ["libp2p-core/serde", "libp2p-kad/serde", "libp2p-gossipsub/serde"] [package.metadata.docs.rs] all-features = true diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 88094516c9d..e66d75019cd 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -11,10 +11,13 @@ - Add `ConnectedPoint::is_relayed` (see [PR 2392]). +- Implement `Serialize` and `Deserialize` for `PeerId` (see [PR 2408]) + [PR 2339]: https://github.com/libp2p/rust-libp2p/pull/2339 [PR 2350]: https://github.com/libp2p/rust-libp2p/pull/2350 [PR 2352]: https://github.com/libp2p/rust-libp2p/pull/2352 [PR 2392]: https://github.com/libp2p/rust-libp2p/pull/2392 +[PR 2408]: https://github.com/libp2p/rust-libp2p/pull/2408 # 0.30.1 [2021-11-16] diff --git a/core/Cargo.toml b/core/Cargo.toml index 60c348fe258..e4423de3fa0 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -37,6 +37,7 @@ thiserror = "1.0" unsigned-varint = "0.7" void = "1" zeroize = "1" +_serde = { package = "serde", version = "1", optional = true, features = ["derive"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ring = { version = "0.16.9", features = ["alloc", "std"], default-features = false } @@ -48,6 +49,8 @@ criterion = "0.3" libp2p-mplex = { path = "../muxers/mplex" } libp2p-noise = { path = "../transports/noise" } libp2p-tcp = { path = "../transports/tcp" } +serde_json = "1.0" +rmp-serde = "0.15" multihash = { version = "0.14", default-features = false, features = ["arb"] } quickcheck = "0.9.0" rand07 = { package = "rand", version = "0.7" } @@ -59,6 +62,7 @@ prost-build = "0.9" default = [ "secp256k1", "ecdsa" ] secp256k1 = [ "libsecp256k1" ] ecdsa = [ "p256" ] +serde = ["multihash/serde-codec", "_serde"] [[bench]] name = "peer_id" diff --git a/core/src/lib.rs b/core/src/lib.rs index 1a7d841e342..594fb6681dc 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -35,6 +35,9 @@ //! define how to upgrade each individual substream to use a protocol. //! See the `upgrade` module. +#[cfg(feature = "serde")] +extern crate _serde as serde; + mod keys_proto { include!(concat!(env!("OUT_DIR"), "/keys_proto.rs")); } diff --git a/core/src/peer_id.rs b/core/src/peer_id.rs index 6e3823e64ed..518adcabd6c 100644 --- a/core/src/peer_id.rs +++ b/core/src/peer_id.rs @@ -24,6 +24,9 @@ use rand::Rng; use std::{convert::TryFrom, fmt, str::FromStr}; use thiserror::Error; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + /// Public keys with byte-lengths smaller than `MAX_INLINE_KEY_LENGTH` will be /// automatically used as the peer id using an identity multihash. const MAX_INLINE_KEY_LENGTH: usize = 42; @@ -164,6 +167,60 @@ impl From for Vec { } } +#[cfg(feature = "serde")] +impl Serialize for PeerId { + fn serialize(&self, serializer: S) -> Result + where + S: _serde::Serializer, + { + if serializer.is_human_readable() { + serializer.serialize_str(&self.to_base58()) + } else { + serializer.serialize_bytes(&self.to_bytes()[..]) + } + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for PeerId { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use serde::de::*; + + struct PeerIdVisitor; + + impl<'de> Visitor<'de> for PeerIdVisitor { + type Value = PeerId; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "valid peer id") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + PeerId::from_bytes(v).map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self)) + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + PeerId::from_str(v).map_err(|_| Error::invalid_value(Unexpected::Str(v), &self)) + } + } + + if deserializer.is_human_readable() { + deserializer.deserialize_str(PeerIdVisitor) + } else { + deserializer.deserialize_bytes(PeerIdVisitor) + } + } +} + #[derive(Debug, Error)] pub enum ParseError { #[error("base-58 decode error: {0}")] diff --git a/core/tests/serde.rs b/core/tests/serde.rs new file mode 100644 index 00000000000..3bb98d4a5b6 --- /dev/null +++ b/core/tests/serde.rs @@ -0,0 +1,52 @@ +#![cfg(feature = "serde")] + +use std::str::FromStr; + +use libp2p_core::PeerId; + +extern crate _serde as serde; + +#[test] +pub fn serialize_peer_id_json() { + let peer_id = PeerId::from_str("12D3KooWRNw2pJC9748Fmq4WNV27HoSTcX3r37132FLkQMrbKAiC").unwrap(); + let json = serde_json::to_string(&peer_id).unwrap(); + assert_eq!( + json, + r#""12D3KooWRNw2pJC9748Fmq4WNV27HoSTcX3r37132FLkQMrbKAiC""# + ) +} + +#[test] +pub fn serialize_peer_id_msgpack() { + let peer_id = PeerId::from_str("12D3KooWRNw2pJC9748Fmq4WNV27HoSTcX3r37132FLkQMrbKAiC").unwrap(); + let buf = rmp_serde::to_vec(&peer_id).unwrap(); + assert_eq!( + &buf[..], + &[ + 0xc4, 38, // msgpack buffer header + 0x00, 0x24, 0x08, 0x01, 0x12, 0x20, 0xe7, 0x37, 0x0c, 0x66, 0xef, 0xec, 0x80, 0x00, + 0xd5, 0x87, 0xfc, 0x41, 0x65, 0x92, 0x8e, 0xe0, 0x75, 0x5f, 0x94, 0x86, 0xcb, 0x5c, + 0xf0, 0xf7, 0x80, 0xd8, 0xe0, 0x6c, 0x98, 0xce, 0x7d, 0xa9 + ] + ); +} + +#[test] +pub fn deserialize_peer_id_json() { + let peer_id = PeerId::from_str("12D3KooWRNw2pJC9748Fmq4WNV27HoSTcX3r37132FLkQMrbKAiC").unwrap(); + let json = r#""12D3KooWRNw2pJC9748Fmq4WNV27HoSTcX3r37132FLkQMrbKAiC""#; + assert_eq!(peer_id, serde_json::from_str(json).unwrap()) +} + +#[test] +pub fn deserialize_peer_id_msgpack() { + let peer_id = PeerId::from_str("12D3KooWRNw2pJC9748Fmq4WNV27HoSTcX3r37132FLkQMrbKAiC").unwrap(); + let buf = &[ + 0xc4, 38, // msgpack buffer header + 0x00, 0x24, 0x08, 0x01, 0x12, 0x20, 0xe7, 0x37, 0x0c, 0x66, 0xef, 0xec, 0x80, 0x00, 0xd5, + 0x87, 0xfc, 0x41, 0x65, 0x92, 0x8e, 0xe0, 0x75, 0x5f, 0x94, 0x86, 0xcb, 0x5c, 0xf0, 0xf7, + 0x80, 0xd8, 0xe0, 0x6c, 0x98, 0xce, 0x7d, 0xa9, + ]; + + assert_eq!(peer_id, rmp_serde::from_read(&mut &buf[..]).unwrap()); +} diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index 5e2910d13eb..07e9f2ade52 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -9,11 +9,14 @@ - Improve bandwidth performance by tracking IWANTs and reducing duplicate sends (see [PR 2327]). +- Implement `Serialize` and `Deserialize` for `MessageId` and `FastMessageId` (see [PR 2408]) + - Fix `GossipsubConfigBuilder::build()` requiring `&self` to live for `'static` (see [PR 2409]) [PR 2346]: https://github.com/libp2p/rust-libp2p/pull/2346 [PR 2339]: https://github.com/libp2p/rust-libp2p/pull/2339 [PR 2327]: https://github.com/libp2p/rust-libp2p/pull/2327 +[PR 2408]: https://github.com/libp2p/rust-libp2p/pull/2408 [PR 2409]: https://github.com/libp2p/rust-libp2p/pull/2409 # 0.34.0 [2021-11-16] diff --git a/protocols/gossipsub/Cargo.toml b/protocols/gossipsub/Cargo.toml index d408ec15a41..2b3fef066ac 100644 --- a/protocols/gossipsub/Cargo.toml +++ b/protocols/gossipsub/Cargo.toml @@ -30,6 +30,7 @@ regex = "1.4.0" futures-timer = "3.0.2" pin-project = "1.0.8" instant = "0.1.11" +serde = { version = "1", optional = true, features = ["derive"] } # Metrics dependencies open-metrics-client = "0.14.0" diff --git a/protocols/gossipsub/src/types.rs b/protocols/gossipsub/src/types.rs index f9c2ddaeb57..fe7663d6cba 100644 --- a/protocols/gossipsub/src/types.rs +++ b/protocols/gossipsub/src/types.rs @@ -27,6 +27,9 @@ use prost::Message; use std::fmt; use std::fmt::Debug; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + #[derive(Debug)] /// Validation kinds from the application for received messages. pub enum MessageAcceptance { @@ -42,6 +45,7 @@ pub enum MessageAcceptance { /// Macro for declaring message id types macro_rules! declare_message_id_type { ($name: ident, $name_string: expr) => { + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct $name(pub Vec); diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 9be1e2f1222..eb5ff7d1309 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -6,8 +6,11 @@ - Derive `Clone` for `KademliaEvent` (see [PR 2411]) +- Derive `Serialize`, `Deserialize` for `store::record::Key` (see [PR 2408]) + [PR 2339]: https://github.com/libp2p/rust-libp2p/pull/2339 [PR 2411]: https://github.com/libp2p/rust-libp2p/pull/2411 +[PR 2408]: https://github.com/libp2p/rust-libp2p/pull/2408 # 0.33.0 [2021-11-16] diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index 9007180f3f4..d5da320f422 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -29,6 +29,7 @@ unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] } void = "1.0" futures-timer = "3.0.2" instant = "0.1.11" +_serde = { package = "serde", version = "1.0", optional = true, features = ["derive"] } thiserror = "1" [dev-dependencies] @@ -40,3 +41,6 @@ quickcheck = "0.9.0" [build-dependencies] prost-build = "0.9" + +[features] +serde = ["_serde", "bytes/serde"] diff --git a/protocols/kad/src/lib.rs b/protocols/kad/src/lib.rs index d8734ec0d80..ef4943b2fb9 100644 --- a/protocols/kad/src/lib.rs +++ b/protocols/kad/src/lib.rs @@ -24,6 +24,9 @@ // be useful later for record store #![allow(dead_code)] +#[cfg(feature = "serde")] +extern crate _serde as serde; + pub mod handler; pub mod kbucket; pub mod protocol; diff --git a/protocols/kad/src/record.rs b/protocols/kad/src/record.rs index e8e05670c79..e321992e5c7 100644 --- a/protocols/kad/src/record.rs +++ b/protocols/kad/src/record.rs @@ -25,10 +25,14 @@ pub mod store; use bytes::Bytes; use instant::Instant; use libp2p_core::{multihash::Multihash, Multiaddr, PeerId}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; use std::borrow::Borrow; use std::hash::{Hash, Hasher}; /// The (opaque) key of a record. +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(crate = "_serde"))] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Key(Bytes);