Skip to content

Commit

Permalink
protocols/rendezvous: Implement protocol (#2107)
Browse files Browse the repository at this point in the history
Implement the libp2p rendezvous protocol.

> A lightweight mechanism for generalized peer discovery. It can be used for
bootstrap purposes, real time peer discovery, application specific routing, and
so on.

Co-authored-by: rishflab <rishflab@hotmail.com>
Co-authored-by: Daniel Karzel <daniel@comit.network>
  • Loading branch information
3 people committed Sep 7, 2021
1 parent c1ae8a0 commit adcfdc0
Show file tree
Hide file tree
Showing 32 changed files with 4,463 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [`libp2p-ping` CHANGELOG](protocols/ping/CHANGELOG.md)
- [`libp2p-relay` CHANGELOG](protocols/relay/CHANGELOG.md)
- [`libp2p-request-response` CHANGELOG](protocols/request-response/CHANGELOG.md)
- [`libp2p-rendezvous` CHANGELOG](protocols/rendezvous/CHANGELOG.md)

## Transport Protocols & Upgrades

Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ default = [
"pnet",
"relay",
"request-response",
"rendezvous",
"secp256k1",
"tcp-async-io",
"uds",
Expand All @@ -48,6 +49,7 @@ plaintext = ["libp2p-plaintext"]
pnet = ["libp2p-pnet"]
relay = ["libp2p-relay"]
request-response = ["libp2p-request-response"]
rendezvous = ["libp2p-rendezvous"]
tcp-async-io = ["libp2p-tcp", "libp2p-tcp/async-io"]
tcp-tokio = ["libp2p-tcp", "libp2p-tcp/tokio"]
uds = ["libp2p-uds"]
Expand Down Expand Up @@ -78,6 +80,7 @@ libp2p-ping = { version = "0.31.0", path = "protocols/ping", optional = true }
libp2p-plaintext = { version = "0.30.0", path = "transports/plaintext", optional = true }
libp2p-pnet = { version = "0.22.0", path = "transports/pnet", optional = true }
libp2p-relay = { version = "0.4.0", path = "protocols/relay", optional = true }
libp2p-rendezvous = { version = "0.1.0", path = "protocols/rendezvous", optional = true }
libp2p-request-response = { version = "0.13.0", path = "protocols/request-response", optional = true }
libp2p-swarm = { version = "0.31.0", path = "swarm" }
libp2p-swarm-derive = { version = "0.25.0", path = "swarm-derive" }
Expand Down Expand Up @@ -115,6 +118,7 @@ members = [
"muxers/yamux",
"protocols/floodsub",
"protocols/gossipsub",
"protocols/rendezvous",
"protocols/identify",
"protocols/kad",
"protocols/mdns",
Expand Down
6 changes: 6 additions & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,19 @@
- Remove deprecated functions `upgrade::write_one`, `upgrade::write_with_len_prefix`
and `upgrade::read_one` (see [PR 2213]).

- Add `SignedEnvelope` and `PeerRecord` according to [RFC0002] and [RFC0003]
(see [PR 2107]).

[PR 2145]: https://github.com/libp2p/rust-libp2p/pull/2145
[PR 2213]: https://github.com/libp2p/rust-libp2p/pull/2213
[PR 2142]: https://github.com/libp2p/rust-libp2p/pull/2142
[PR 2137]: https://github.com/libp2p/rust-libp2p/pull/2137
[PR 2183]: https://github.com/libp2p/rust-libp2p/pull/2183
[PR 2191]: https://github.com/libp2p/rust-libp2p/pull/2191
[PR 2195]: https://github.com/libp2p/rust-libp2p/pull/2195
[PR 2107]: https://github.com/libp2p/rust-libp2p/pull/2107
[RFC0002]: https://github.com/libp2p/specs/blob/master/RFC/0002-signed-envelopes.md
[RFC0003]: https://github.com/libp2p/specs/blob/master/RFC/0003-routing-records.md

# 0.29.0 [2021-07-12]

Expand Down
10 changes: 9 additions & 1 deletion core/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,13 @@
// DEALINGS IN THE SOFTWARE.

fn main() {
prost_build::compile_protos(&["src/keys.proto"], &["src"]).unwrap();
prost_build::compile_protos(
&[
"src/keys.proto",
"src/envelope.proto",
"src/peer_record.proto",
],
&["src"],
)
.unwrap();
}
30 changes: 30 additions & 0 deletions core/src/envelope.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
syntax = "proto3";

package envelope_proto;

import "keys.proto";

// Envelope encloses a signed payload produced by a peer, along with the public
// key of the keypair it was signed with so that it can be statelessly validated
// by the receiver.
//
// The payload is prefixed with a byte string that determines the type, so it
// can be deserialized deterministically. Often, this byte string is a
// multicodec.
message Envelope {
// public_key is the public key of the keypair the enclosed payload was
// signed with.
keys_proto.PublicKey public_key = 1;

// payload_type encodes the type of payload, so that it can be deserialized
// deterministically.
bytes payload_type = 2;

// payload is the actual payload carried inside this envelope.
bytes payload = 3;

// signature is the signature produced by the private key corresponding to
// the enclosed public key, over the payload, prefixing a domain string for
// additional security.
bytes signature = 5;
}
57 changes: 36 additions & 21 deletions core/src/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub mod error;

use self::error::*;
use crate::{keys_proto, PeerId};
use std::convert::{TryFrom, TryInto};

/// Identity keypair of a node.
///
Expand Down Expand Up @@ -205,6 +206,7 @@ impl PublicKey {
/// that the signature has been produced by the corresponding
/// private key (authenticity), and that the message has not been
/// tampered with (integrity).
#[must_use]
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
use PublicKey::*;
match self {
Expand All @@ -221,7 +223,35 @@ impl PublicKey {
pub fn to_protobuf_encoding(&self) -> Vec<u8> {
use prost::Message;

let public_key = match self {
let public_key = keys_proto::PublicKey::from(self);

let mut buf = Vec::with_capacity(public_key.encoded_len());
public_key
.encode(&mut buf)
.expect("Vec<u8> provides capacity as needed");
buf
}

/// Decode a public key from a protobuf structure, e.g. read from storage
/// or received from another node.
pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<PublicKey, DecodingError> {
use prost::Message;

let pubkey = keys_proto::PublicKey::decode(bytes)
.map_err(|e| DecodingError::new("Protobuf").source(e))?;

pubkey.try_into()
}

/// Convert the `PublicKey` into the corresponding `PeerId`.
pub fn to_peer_id(&self) -> PeerId {
self.into()
}
}

impl From<&PublicKey> for keys_proto::PublicKey {
fn from(key: &PublicKey) -> Self {
match key {
PublicKey::Ed25519(key) => keys_proto::PublicKey {
r#type: keys_proto::KeyType::Ed25519 as i32,
data: key.encode().to_vec(),
Expand All @@ -236,24 +266,14 @@ impl PublicKey {
r#type: keys_proto::KeyType::Secp256k1 as i32,
data: key.encode().to_vec(),
},
};

let mut buf = Vec::with_capacity(public_key.encoded_len());
public_key
.encode(&mut buf)
.expect("Vec<u8> provides capacity as needed");
buf
}
}
}

/// Decode a public key from a protobuf structure, e.g. read from storage
/// or received from another node.
pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<PublicKey, DecodingError> {
use prost::Message;

#[allow(unused_mut)] // Due to conditional compilation.
let mut pubkey = keys_proto::PublicKey::decode(bytes)
.map_err(|e| DecodingError::new("Protobuf").source(e))?;
impl TryFrom<keys_proto::PublicKey> for PublicKey {
type Error = DecodingError;

fn try_from(pubkey: keys_proto::PublicKey) -> Result<Self, Self::Error> {
let key_type = keys_proto::KeyType::from_i32(pubkey.r#type)
.ok_or_else(|| DecodingError::new(format!("unknown key type: {}", pubkey.r#type)))?;

Expand Down Expand Up @@ -281,11 +301,6 @@ impl PublicKey {
}
}
}

/// Convert the `PublicKey` into the corresponding `PeerId`.
pub fn to_peer_id(&self) -> PeerId {
self.into()
}
}

#[cfg(test)]
Expand Down
12 changes: 12 additions & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ mod keys_proto {
include!(concat!(env!("OUT_DIR"), "/keys_proto.rs"));
}

mod envelope_proto {
include!(concat!(env!("OUT_DIR"), "/envelope_proto.rs"));
}

mod peer_record_proto {
include!(concat!(env!("OUT_DIR"), "/peer_record_proto.rs"));
}

/// Multi-address re-export.
pub use multiaddr;
pub type Negotiated<T> = multistream_select::Negotiated<T>;
Expand All @@ -51,6 +59,8 @@ pub mod either;
pub mod identity;
pub mod muxing;
pub mod network;
pub mod peer_record;
pub mod signed_envelope;
pub mod transport;
pub mod upgrade;

Expand All @@ -61,6 +71,8 @@ pub use multihash;
pub use muxing::StreamMuxer;
pub use network::Network;
pub use peer_id::PeerId;
pub use peer_record::PeerRecord;
pub use signed_envelope::SignedEnvelope;
pub use translation::address_translation;
pub use transport::Transport;
pub use upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeError, UpgradeInfo};
Expand Down
2 changes: 1 addition & 1 deletion core/src/network/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ where
/// A connection may close if
///
/// * it encounters an error, which includes the connection being
/// closed by the remote. In this case `error` is `Some`.
/// closed by the remote. In this case `error` is `ome`.
/// * it was actively closed by [`EstablishedConnection::start_close`],
/// i.e. a successful, orderly close. In this case `error` is `None`.
/// * it was actively closed by [`super::peer::ConnectedPeer::disconnect`] or
Expand Down
27 changes: 27 additions & 0 deletions core/src/peer_record.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
syntax = "proto3";

package peer_record_proto;

// PeerRecord messages contain information that is useful to share with other peers.
// Currently, a PeerRecord contains the public listen addresses for a peer, but this
// is expected to expand to include other information in the future.
//
// PeerRecords are designed to be serialized to bytes and placed inside of
// SignedEnvelopes before sharing with other peers.
message PeerRecord {

// AddressInfo is a wrapper around a binary multiaddr. It is defined as a
// separate message to allow us to add per-address metadata in the future.
message AddressInfo {
bytes multiaddr = 1;
}

// peer_id contains a libp2p peer id in its binary representation.
bytes peer_id = 1;

// seq contains a monotonically-increasing sequence counter to order PeerRecords in time.
uint64 seq = 2;

// addresses is a list of public listen addresses for the peer.
repeated AddressInfo addresses = 3;
}

0 comments on commit adcfdc0

Please sign in to comment.