feat: migrate to quick-protobuf

Instead of relying on `protoc` and buildscripts, we generate the bindings using `pb-rs` and version them within our codebase. This makes for a better IDE integration, a faster build and an easier use of `rust-libp2p` because we don't force the `protoc` dependency onto them.

Resolves #3024.

Pull-Request: #3312.
This commit is contained in:
Miguel Guarniz
2023-03-02 05:45:07 -05:00
committed by GitHub
parent 4910160bea
commit db82e0210e
141 changed files with 3662 additions and 1276 deletions

View File

@ -293,3 +293,30 @@ jobs:
echo "PR title is too long (greater than 72 characters)" echo "PR title is too long (greater than 72 characters)"
exit 1 exit 1
fi fi
check-proto-files:
name: Check for changes in proto files
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 # v2.2.0
- run: cargo install --version 0.10.0 pb-rs --locked
- name: Glob match
uses: tj-actions/glob@v16
id: glob
with:
files: |
**/generated/*.proto
- name: Generate proto files
run: pb-rs --dont_use_cow ${{ steps.glob.outputs.paths }}
- name: Ensure generated files are unmodified # https://stackoverflow.com/a/5737794
run: |
git_status=$(git status --porcelain)
echo $git_status
test -z "$git_status"

179
Cargo.lock generated
View File

@ -1407,12 +1407,6 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.25" version = "1.0.25"
@ -2177,8 +2171,7 @@ dependencies = [
"libp2p-tcp", "libp2p-tcp",
"libp2p-yamux", "libp2p-yamux",
"log", "log",
"prost", "quick-protobuf",
"prost-build",
"rand 0.8.5", "rand 0.8.5",
] ]
@ -2208,8 +2201,7 @@ dependencies = [
"p256 0.12.0", "p256 0.12.0",
"parking_lot 0.12.1", "parking_lot 0.12.1",
"pin-project", "pin-project",
"prost", "quick-protobuf",
"prost-build",
"quickcheck-ext", "quickcheck-ext",
"rand 0.8.5", "rand 0.8.5",
"ring", "ring",
@ -2248,9 +2240,8 @@ dependencies = [
"libp2p-tcp", "libp2p-tcp",
"libp2p-yamux", "libp2p-yamux",
"log", "log",
"prost", "quick-protobuf",
"prost-build", "quick-protobuf-codec",
"prost-codec",
"rand 0.8.5", "rand 0.8.5",
"thiserror", "thiserror",
"void", "void",
@ -2296,9 +2287,8 @@ dependencies = [
"libp2p-core", "libp2p-core",
"libp2p-swarm", "libp2p-swarm",
"log", "log",
"prost", "quick-protobuf",
"prost-build", "quick-protobuf-codec",
"prost-codec",
"rand 0.8.5", "rand 0.8.5",
"smallvec", "smallvec",
"thiserror", "thiserror",
@ -2327,9 +2317,8 @@ dependencies = [
"libp2p-yamux", "libp2p-yamux",
"log", "log",
"prometheus-client", "prometheus-client",
"prost", "quick-protobuf",
"prost-build", "quick-protobuf-codec",
"prost-codec",
"quickcheck-ext", "quickcheck-ext",
"rand 0.8.5", "rand 0.8.5",
"regex", "regex",
@ -2359,9 +2348,8 @@ dependencies = [
"libp2p-yamux", "libp2p-yamux",
"log", "log",
"lru", "lru",
"prost", "quick-protobuf",
"prost-build", "quick-protobuf-codec",
"prost-codec",
"smallvec", "smallvec",
"thiserror", "thiserror",
"void", "void",
@ -2385,8 +2373,7 @@ dependencies = [
"libp2p-swarm", "libp2p-swarm",
"libp2p-yamux", "libp2p-yamux",
"log", "log",
"prost", "quick-protobuf",
"prost-build",
"quickcheck-ext", "quickcheck-ext",
"rand 0.8.5", "rand 0.8.5",
"serde", "serde",
@ -2493,8 +2480,7 @@ dependencies = [
"libsodium-sys-stable", "libsodium-sys-stable",
"log", "log",
"once_cell", "once_cell",
"prost", "quick-protobuf",
"prost-build",
"quickcheck-ext", "quickcheck-ext",
"rand 0.8.5", "rand 0.8.5",
"sha2 0.10.6", "sha2 0.10.6",
@ -2536,8 +2522,7 @@ dependencies = [
"futures", "futures",
"libp2p-core", "libp2p-core",
"log", "log",
"prost", "quick-protobuf",
"prost-build",
"quickcheck-ext", "quickcheck-ext",
"rand 0.8.5", "rand 0.8.5",
"unsigned-varint", "unsigned-varint",
@ -2611,9 +2596,8 @@ dependencies = [
"libp2p-tcp", "libp2p-tcp",
"libp2p-yamux", "libp2p-yamux",
"log", "log",
"prost", "quick-protobuf",
"prost-build", "quick-protobuf-codec",
"prost-codec",
"quickcheck-ext", "quickcheck-ext",
"rand 0.8.5", "rand 0.8.5",
"static_assertions", "static_assertions",
@ -2641,9 +2625,8 @@ dependencies = [
"libp2p-tcp", "libp2p-tcp",
"libp2p-yamux", "libp2p-yamux",
"log", "log",
"prost", "quick-protobuf",
"prost-build", "quick-protobuf-codec",
"prost-codec",
"rand 0.8.5", "rand 0.8.5",
"thiserror", "thiserror",
"tokio", "tokio",
@ -2787,9 +2770,8 @@ dependencies = [
"libp2p-swarm", "libp2p-swarm",
"log", "log",
"multihash", "multihash",
"prost", "quick-protobuf",
"prost-build", "quick-protobuf-codec",
"prost-codec",
"quickcheck", "quickcheck",
"rand 0.8.5", "rand 0.8.5",
"rcgen 0.9.3", "rcgen 0.9.3",
@ -3103,12 +3085,6 @@ dependencies = [
"synstructure", "synstructure",
] ]
[[package]]
name = "multimap"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]] [[package]]
name = "multistream-select" name = "multistream-select"
version = "0.12.1" version = "0.12.1"
@ -3441,16 +3417,6 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "petgraph"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.0.12" version = "1.0.12"
@ -3593,16 +3559,6 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "prettyplease"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78"
dependencies = [
"proc-macro2",
"syn",
]
[[package]] [[package]]
name = "primeorder" name = "primeorder"
version = "0.12.1" version = "0.12.1"
@ -3678,78 +3634,32 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "prost"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537"
dependencies = [
"bytes",
"prost-derive",
]
[[package]]
name = "prost-build"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12"
dependencies = [
"bytes",
"heck",
"itertools",
"lazy_static",
"log",
"multimap",
"petgraph",
"prettyplease",
"prost",
"prost-types",
"regex",
"syn",
"tempfile",
"which",
]
[[package]]
name = "prost-codec"
version = "0.3.0"
dependencies = [
"asynchronous-codec",
"bytes",
"prost",
"prost-build",
"thiserror",
"unsigned-varint",
]
[[package]]
name = "prost-derive"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "prost-types"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88"
dependencies = [
"prost",
]
[[package]] [[package]]
name = "quick-error" name = "quick-error"
version = "1.2.3" version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quick-protobuf"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f"
dependencies = [
"byteorder",
]
[[package]]
name = "quick-protobuf-codec"
version = "0.1.0"
dependencies = [
"asynchronous-codec",
"bytes",
"quick-protobuf",
"thiserror",
"unsigned-varint",
]
[[package]] [[package]]
name = "quickcheck" name = "quickcheck"
version = "1.0.3" version = "1.0.3"
@ -5374,17 +5284,6 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "which"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
dependencies = [
"either",
"libc",
"once_cell",
]
[[package]] [[package]]
name = "widestring" name = "widestring"
version = "0.5.1" version = "0.5.1"

View File

@ -146,7 +146,7 @@ members = [
"misc/multistream-select", "misc/multistream-select",
"misc/rw-stream-sink", "misc/rw-stream-sink",
"misc/keygen", "misc/keygen",
"misc/prost-codec", "misc/quick-protobuf-codec",
"misc/quickcheck-ext", "misc/quickcheck-ext",
"muxers/mplex", "muxers/mplex",
"muxers/yamux", "muxers/yamux",

View File

@ -2,7 +2,9 @@
- Move `ConnectionId` to `libp2p-swarm`. See [PR 3221]. - Move `ConnectionId` to `libp2p-swarm`. See [PR 3221].
- Move `PendingPoint` to `libp2p-swarm` and make it crate-private. See [PR 3221]. - Move `PendingPoint` to `libp2p-swarm` and make it crate-private. See [PR 3221].
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
[PR 3221]: https://github.com/libp2p/rust-libp2p/pull/3221 [PR 3221]: https://github.com/libp2p/rust-libp2p/pull/3221
# 0.38.0 # 0.38.0

View File

@ -27,7 +27,7 @@ multistream-select = { version = "0.12.1", path = "../misc/multistream-select" }
p256 = { version = "0.12.0", default-features = false, features = ["ecdsa", "std"], optional = true } p256 = { version = "0.12.0", default-features = false, features = ["ecdsa", "std"], optional = true }
parking_lot = "0.12.0" parking_lot = "0.12.0"
pin-project = "1.0.0" pin-project = "1.0.0"
prost = "0.11" quick-protobuf = "0.8"
once_cell = "1.17.1" once_cell = "1.17.1"
rand = "0.8" rand = "0.8"
rw-stream-sink = { version = "0.3.0", path = "../misc/rw-stream-sink" } rw-stream-sink = { version = "0.3.0", path = "../misc/rw-stream-sink" }
@ -54,9 +54,6 @@ quickcheck = { package = "quickcheck-ext", path = "../misc/quickcheck-ext" }
rmp-serde = "1.0" rmp-serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
[build-dependencies]
prost-build = "0.11"
[features] [features]
secp256k1 = [ "libsecp256k1" ] secp256k1 = [ "libsecp256k1" ]
ecdsa = [ "p256" ] ecdsa = [ "p256" ]

View File

@ -1,31 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
fn main() {
prost_build::compile_protos(
&[
"src/keys.proto",
"src/envelope.proto",
"src/peer_record.proto",
],
&["src"],
)
.unwrap();
}

View File

@ -0,0 +1,59 @@
// Automatically generated rust module for 'envelope.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Envelope {
pub public_key: Option<keys_proto::PublicKey>,
pub payload_type: Vec<u8>,
pub payload: Vec<u8>,
pub signature: Vec<u8>,
}
impl<'a> MessageRead<'a> for Envelope {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.public_key = Some(r.read_message::<keys_proto::PublicKey>(bytes)?),
Ok(18) => msg.payload_type = r.read_bytes(bytes)?.to_owned(),
Ok(26) => msg.payload = r.read_bytes(bytes)?.to_owned(),
Ok(42) => msg.signature = r.read_bytes(bytes)?.to_owned(),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Envelope {
fn get_size(&self) -> usize {
0
+ self.public_key.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
+ if self.payload_type.is_empty() { 0 } else { 1 + sizeof_len((&self.payload_type).len()) }
+ if self.payload.is_empty() { 0 } else { 1 + sizeof_len((&self.payload).len()) }
+ if self.signature.is_empty() { 0 } else { 1 + sizeof_len((&self.signature).len()) }
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.public_key { w.write_with_tag(10, |w| w.write_message(s))?; }
if !self.payload_type.is_empty() { w.write_with_tag(18, |w| w.write_bytes(&**&self.payload_type))?; }
if !self.payload.is_empty() { w.write_with_tag(26, |w| w.write_bytes(&**&self.payload))?; }
if !self.signature.is_empty() { w.write_with_tag(42, |w| w.write_bytes(&**&self.signature))?; }
Ok(())
}
}

View File

@ -0,0 +1,125 @@
// Automatically generated rust module for 'keys.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::*;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum KeyType {
RSA = 0,
Ed25519 = 1,
Secp256k1 = 2,
ECDSA = 3,
}
impl Default for KeyType {
fn default() -> Self {
KeyType::RSA
}
}
impl From<i32> for KeyType {
fn from(i: i32) -> Self {
match i {
0 => KeyType::RSA,
1 => KeyType::Ed25519,
2 => KeyType::Secp256k1,
3 => KeyType::ECDSA,
_ => Self::default(),
}
}
}
impl<'a> From<&'a str> for KeyType {
fn from(s: &'a str) -> Self {
match s {
"RSA" => KeyType::RSA,
"Ed25519" => KeyType::Ed25519,
"Secp256k1" => KeyType::Secp256k1,
"ECDSA" => KeyType::ECDSA,
_ => Self::default(),
}
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct PublicKey {
pub Type: keys_proto::KeyType,
pub Data: Vec<u8>,
}
impl<'a> MessageRead<'a> for PublicKey {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.Type = r.read_enum(bytes)?,
Ok(18) => msg.Data = r.read_bytes(bytes)?.to_owned(),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for PublicKey {
fn get_size(&self) -> usize {
0
+ 1 + sizeof_varint(*(&self.Type) as u64)
+ 1 + sizeof_len((&self.Data).len())
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
w.write_with_tag(8, |w| w.write_enum(*&self.Type as i32))?;
w.write_with_tag(18, |w| w.write_bytes(&**&self.Data))?;
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct PrivateKey {
pub Type: keys_proto::KeyType,
pub Data: Vec<u8>,
}
impl<'a> MessageRead<'a> for PrivateKey {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.Type = r.read_enum(bytes)?,
Ok(18) => msg.Data = r.read_bytes(bytes)?.to_owned(),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for PrivateKey {
fn get_size(&self) -> usize {
0
+ 1 + sizeof_varint(*(&self.Type) as u64)
+ 1 + sizeof_len((&self.Data).len())
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
w.write_with_tag(8, |w| w.write_enum(*&self.Type as i32))?;
w.write_with_tag(18, |w| w.write_bytes(&**&self.Data))?;
Ok(())
}
}

View File

@ -0,0 +1,4 @@
// Automatically generated mod.rs
pub mod envelope_proto;
pub mod keys_proto;
pub mod peer_record_proto;

View File

@ -0,0 +1,93 @@
// Automatically generated rust module for 'peer_record.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct PeerRecord {
pub peer_id: Vec<u8>,
pub seq: u64,
pub addresses: Vec<peer_record_proto::mod_PeerRecord::AddressInfo>,
}
impl<'a> MessageRead<'a> for PeerRecord {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.peer_id = r.read_bytes(bytes)?.to_owned(),
Ok(16) => msg.seq = r.read_uint64(bytes)?,
Ok(26) => msg.addresses.push(r.read_message::<peer_record_proto::mod_PeerRecord::AddressInfo>(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for PeerRecord {
fn get_size(&self) -> usize {
0
+ if self.peer_id.is_empty() { 0 } else { 1 + sizeof_len((&self.peer_id).len()) }
+ if self.seq == 0u64 { 0 } else { 1 + sizeof_varint(*(&self.seq) as u64) }
+ self.addresses.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if !self.peer_id.is_empty() { w.write_with_tag(10, |w| w.write_bytes(&**&self.peer_id))?; }
if self.seq != 0u64 { w.write_with_tag(16, |w| w.write_uint64(*&self.seq))?; }
for s in &self.addresses { w.write_with_tag(26, |w| w.write_message(s))?; }
Ok(())
}
}
pub mod mod_PeerRecord {
use super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct AddressInfo {
pub multiaddr: Vec<u8>,
}
impl<'a> MessageRead<'a> for AddressInfo {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.multiaddr = r.read_bytes(bytes)?.to_owned(),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for AddressInfo {
fn get_size(&self) -> usize {
0
+ if self.multiaddr.is_empty() { 0 } else { 1 + sizeof_len((&self.multiaddr).len()) }
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if !self.multiaddr.is_empty() { w.write_with_tag(10, |w| w.write_bytes(&**&self.multiaddr))?; }
Ok(())
}
}
}

View File

@ -43,7 +43,8 @@ pub mod secp256k1;
pub mod error; pub mod error;
use self::error::*; use self::error::*;
use crate::{keys_proto, PeerId}; use crate::{proto, PeerId};
use quick_protobuf::{BytesReader, Writer};
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
/// Identity keypair of a node. /// Identity keypair of a node.
@ -147,12 +148,12 @@ impl Keypair {
/// Encode a private key as protobuf structure. /// Encode a private key as protobuf structure.
pub fn to_protobuf_encoding(&self) -> Result<Vec<u8>, DecodingError> { pub fn to_protobuf_encoding(&self) -> Result<Vec<u8>, DecodingError> {
use prost::Message; use quick_protobuf::MessageWrite;
let pk = match self { let pk = match self {
Self::Ed25519(data) => keys_proto::PrivateKey { Self::Ed25519(data) => proto::PrivateKey {
r#type: keys_proto::KeyType::Ed25519.into(), Type: proto::KeyType::Ed25519,
data: data.encode().into(), Data: data.encode().to_vec(),
}, },
#[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))]
Self::Rsa(_) => return Err(DecodingError::encoding_unsupported("RSA")), Self::Rsa(_) => return Err(DecodingError::encoding_unsupported("RSA")),
@ -162,35 +163,38 @@ impl Keypair {
Self::Ecdsa(_) => return Err(DecodingError::encoding_unsupported("ECDSA")), Self::Ecdsa(_) => return Err(DecodingError::encoding_unsupported("ECDSA")),
}; };
Ok(pk.encode_to_vec()) let mut buf = Vec::with_capacity(pk.get_size());
let mut writer = Writer::new(&mut buf);
pk.write_message(&mut writer).expect("Encoding to succeed");
Ok(buf)
} }
/// Decode a private key from a protobuf structure and parse it as a [`Keypair`]. /// Decode a private key from a protobuf structure and parse it as a [`Keypair`].
pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<Keypair, DecodingError> { pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<Keypair, DecodingError> {
use prost::Message; use quick_protobuf::MessageRead;
let mut private_key = keys_proto::PrivateKey::decode(bytes) let mut reader = BytesReader::from_bytes(bytes);
let mut private_key = proto::PrivateKey::from_reader(&mut reader, bytes)
.map_err(|e| DecodingError::bad_protobuf("private key bytes", e)) .map_err(|e| DecodingError::bad_protobuf("private key bytes", e))
.map(zeroize::Zeroizing::new)?; .map(zeroize::Zeroizing::new)?;
let key_type = keys_proto::KeyType::from_i32(private_key.r#type) match private_key.Type {
.ok_or_else(|| DecodingError::unknown_key_type(private_key.r#type))?; proto::KeyType::Ed25519 => {
ed25519::Keypair::decode(&mut private_key.Data).map(Keypair::Ed25519)
match key_type {
keys_proto::KeyType::Ed25519 => {
ed25519::Keypair::decode(&mut private_key.data).map(Keypair::Ed25519)
} }
keys_proto::KeyType::Rsa => Err(DecodingError::decoding_unsupported("RSA")), proto::KeyType::RSA => Err(DecodingError::decoding_unsupported("RSA")),
keys_proto::KeyType::Secp256k1 => Err(DecodingError::decoding_unsupported("secp256k1")), proto::KeyType::Secp256k1 => Err(DecodingError::decoding_unsupported("secp256k1")),
keys_proto::KeyType::Ecdsa => Err(DecodingError::decoding_unsupported("ECDSA")), proto::KeyType::ECDSA => Err(DecodingError::decoding_unsupported("ECDSA")),
} }
} }
} }
impl zeroize::Zeroize for keys_proto::PrivateKey { impl zeroize::Zeroize for proto::PrivateKey {
fn zeroize(&mut self) { fn zeroize(&mut self) {
self.r#type.zeroize(); // KeyType cannot be zeroized.
self.data.zeroize(); self.Type = proto::KeyType::default();
self.Data.zeroize();
} }
} }
@ -232,23 +236,27 @@ impl PublicKey {
/// Encode the public key into a protobuf structure for storage or /// Encode the public key into a protobuf structure for storage or
/// exchange with other nodes. /// exchange with other nodes.
pub fn to_protobuf_encoding(&self) -> Vec<u8> { pub fn to_protobuf_encoding(&self) -> Vec<u8> {
use prost::Message; use quick_protobuf::MessageWrite;
let public_key = keys_proto::PublicKey::from(self); let public_key = proto::PublicKey::from(self);
let mut buf = Vec::with_capacity(public_key.encoded_len()); let mut buf = Vec::with_capacity(public_key.get_size());
let mut writer = Writer::new(&mut buf);
public_key public_key
.encode(&mut buf) .write_message(&mut writer)
.expect("Vec<u8> provides capacity as needed"); .expect("Encoding to succeed");
buf buf
} }
/// Decode a public key from a protobuf structure, e.g. read from storage /// Decode a public key from a protobuf structure, e.g. read from storage
/// or received from another node. /// or received from another node.
pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<PublicKey, DecodingError> { pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<PublicKey, DecodingError> {
use prost::Message; use quick_protobuf::MessageRead;
let pubkey = keys_proto::PublicKey::decode(bytes) let mut reader = BytesReader::from_bytes(bytes);
let pubkey = proto::PublicKey::from_reader(&mut reader, bytes)
.map_err(|e| DecodingError::bad_protobuf("public key bytes", e))?; .map_err(|e| DecodingError::bad_protobuf("public key bytes", e))?;
pubkey.try_into() pubkey.try_into()
@ -260,67 +268,62 @@ impl PublicKey {
} }
} }
impl From<&PublicKey> for keys_proto::PublicKey { impl From<&PublicKey> for proto::PublicKey {
fn from(key: &PublicKey) -> Self { fn from(key: &PublicKey) -> Self {
match key { match key {
PublicKey::Ed25519(key) => keys_proto::PublicKey { PublicKey::Ed25519(key) => proto::PublicKey {
r#type: keys_proto::KeyType::Ed25519 as i32, Type: proto::KeyType::Ed25519,
data: key.encode().to_vec(), Data: key.encode().to_vec(),
}, },
#[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))]
PublicKey::Rsa(key) => keys_proto::PublicKey { PublicKey::Rsa(key) => proto::PublicKey {
r#type: keys_proto::KeyType::Rsa as i32, Type: proto::KeyType::RSA,
data: key.encode_x509(), Data: key.encode_x509(),
}, },
#[cfg(feature = "secp256k1")] #[cfg(feature = "secp256k1")]
PublicKey::Secp256k1(key) => keys_proto::PublicKey { PublicKey::Secp256k1(key) => proto::PublicKey {
r#type: keys_proto::KeyType::Secp256k1 as i32, Type: proto::KeyType::Secp256k1,
data: key.encode().to_vec(), Data: key.encode().to_vec(),
}, },
#[cfg(feature = "ecdsa")] #[cfg(feature = "ecdsa")]
PublicKey::Ecdsa(key) => keys_proto::PublicKey { PublicKey::Ecdsa(key) => proto::PublicKey {
r#type: keys_proto::KeyType::Ecdsa as i32, Type: proto::KeyType::ECDSA,
data: key.encode_der(), Data: key.encode_der(),
}, },
} }
} }
} }
impl TryFrom<keys_proto::PublicKey> for PublicKey { impl TryFrom<proto::PublicKey> for PublicKey {
type Error = DecodingError; type Error = DecodingError;
fn try_from(pubkey: keys_proto::PublicKey) -> Result<Self, Self::Error> { fn try_from(pubkey: proto::PublicKey) -> Result<Self, Self::Error> {
let key_type = keys_proto::KeyType::from_i32(pubkey.r#type) match pubkey.Type {
.ok_or_else(|| DecodingError::unknown_key_type(pubkey.r#type))?; proto::KeyType::Ed25519 => {
ed25519::PublicKey::decode(&pubkey.Data).map(PublicKey::Ed25519)
match key_type {
keys_proto::KeyType::Ed25519 => {
ed25519::PublicKey::decode(&pubkey.data).map(PublicKey::Ed25519)
} }
#[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))]
keys_proto::KeyType::Rsa => { proto::KeyType::RSA => rsa::PublicKey::decode_x509(&pubkey.Data).map(PublicKey::Rsa),
rsa::PublicKey::decode_x509(&pubkey.data).map(PublicKey::Rsa)
}
#[cfg(any(not(feature = "rsa"), target_arch = "wasm32"))] #[cfg(any(not(feature = "rsa"), target_arch = "wasm32"))]
keys_proto::KeyType::Rsa => { proto::KeyType::RSA => {
log::debug!("support for RSA was disabled at compile-time"); log::debug!("support for RSA was disabled at compile-time");
Err(DecodingError::missing_feature("rsa")) Err(DecodingError::missing_feature("rsa"))
} }
#[cfg(feature = "secp256k1")] #[cfg(feature = "secp256k1")]
keys_proto::KeyType::Secp256k1 => { proto::KeyType::Secp256k1 => {
secp256k1::PublicKey::decode(&pubkey.data).map(PublicKey::Secp256k1) secp256k1::PublicKey::decode(&pubkey.Data).map(PublicKey::Secp256k1)
} }
#[cfg(not(feature = "secp256k1"))] #[cfg(not(feature = "secp256k1"))]
keys_proto::KeyType::Secp256k1 => { proto::KeyType::Secp256k1 => {
log::debug!("support for secp256k1 was disabled at compile-time"); log::debug!("support for secp256k1 was disabled at compile-time");
Err(DecodingError::missing_feature("secp256k1")) Err(DecodingError::missing_feature("secp256k1"))
} }
#[cfg(feature = "ecdsa")] #[cfg(feature = "ecdsa")]
keys_proto::KeyType::Ecdsa => { proto::KeyType::ECDSA => {
ecdsa::PublicKey::decode_der(&pubkey.data).map(PublicKey::Ecdsa) ecdsa::PublicKey::decode_der(&pubkey.Data).map(PublicKey::Ecdsa)
} }
#[cfg(not(feature = "ecdsa"))] #[cfg(not(feature = "ecdsa"))]
keys_proto::KeyType::Ecdsa => { proto::KeyType::ECDSA => {
log::debug!("support for ECDSA was disabled at compile-time"); log::debug!("support for ECDSA was disabled at compile-time");
Err(DecodingError::missing_feature("ecdsa")) Err(DecodingError::missing_feature("ecdsa"))
} }

View File

@ -68,13 +68,6 @@ impl DecodingError {
} }
} }
pub(crate) fn unknown_key_type(key_type: i32) -> Self {
Self {
msg: format!("unknown key-type {key_type}"),
source: None,
}
}
pub(crate) fn decoding_unsupported(key_type: &'static str) -> Self { pub(crate) fn decoding_unsupported(key_type: &'static str) -> Self {
Self { Self {
msg: format!("decoding {key_type} key from Protobuf is unsupported"), msg: format!("decoding {key_type} key from Protobuf is unsupported"),

View File

@ -37,22 +37,18 @@
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#[allow(clippy::derive_partial_eq_without_eq)] mod proto {
mod keys_proto { include!("generated/mod.rs");
include!(concat!(env!("OUT_DIR"), "/keys_proto.rs")); pub use self::{
} envelope_proto::*, keys_proto::*, peer_record_proto::mod_PeerRecord::*,
peer_record_proto::PeerRecord,
mod envelope_proto { };
include!(concat!(env!("OUT_DIR"), "/envelope_proto.rs"));
}
#[allow(clippy::derive_partial_eq_without_eq)]
mod peer_record_proto {
include!(concat!(env!("OUT_DIR"), "/peer_record_proto.rs"));
} }
/// Multi-address re-export. /// Multi-address re-export.
pub use multiaddr; pub use multiaddr;
use std::fmt;
use std::fmt::Formatter;
pub type Negotiated<T> = multistream_select::Negotiated<T>; pub type Negotiated<T> = multistream_select::Negotiated<T>;
mod peer_id; mod peer_id;
@ -80,6 +76,17 @@ pub use translation::address_translation;
pub use transport::Transport; pub use transport::Transport;
pub use upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeError, UpgradeInfo}; pub use upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeError, UpgradeInfo};
#[derive(thiserror::Error, Debug)] #[derive(Debug, thiserror::Error)]
#[error(transparent)] pub struct DecodeError(String);
pub struct DecodeError(prost::DecodeError);
impl From<quick_protobuf::Error> for DecodeError {
fn from(e: quick_protobuf::Error) -> Self {
Self(e.to_string())
}
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}

View File

@ -1,8 +1,10 @@
use crate::identity::error::SigningError; use crate::identity::error::SigningError;
use crate::identity::Keypair; use crate::identity::Keypair;
use crate::proto;
use crate::signed_envelope::SignedEnvelope; use crate::signed_envelope::SignedEnvelope;
use crate::{peer_record_proto, signed_envelope, DecodeError, Multiaddr, PeerId}; use crate::{signed_envelope, DecodeError, Multiaddr, PeerId};
use instant::SystemTime; use instant::SystemTime;
use quick_protobuf::{BytesReader, Writer};
use std::convert::TryInto; use std::convert::TryInto;
const PAYLOAD_TYPE: &str = "/libp2p/routing-state-record"; const PAYLOAD_TYPE: &str = "/libp2p/routing-state-record";
@ -29,11 +31,13 @@ impl PeerRecord {
/// ///
/// If this function succeeds, the [`SignedEnvelope`] contained a peer record with a valid signature and can hence be considered authenticated. /// If this function succeeds, the [`SignedEnvelope`] contained a peer record with a valid signature and can hence be considered authenticated.
pub fn from_signed_envelope(envelope: SignedEnvelope) -> Result<Self, FromEnvelopeError> { pub fn from_signed_envelope(envelope: SignedEnvelope) -> Result<Self, FromEnvelopeError> {
use prost::Message; use quick_protobuf::MessageRead;
let (payload, signing_key) = let (payload, signing_key) =
envelope.payload_and_signing_key(String::from(DOMAIN_SEP), PAYLOAD_TYPE.as_bytes())?; envelope.payload_and_signing_key(String::from(DOMAIN_SEP), PAYLOAD_TYPE.as_bytes())?;
let record = peer_record_proto::PeerRecord::decode(payload).map_err(DecodeError)?; let mut reader = BytesReader::from_bytes(payload);
let record =
proto::PeerRecord::from_reader(&mut reader, payload).map_err(DecodeError::from)?;
let peer_id = PeerId::from_bytes(&record.peer_id)?; let peer_id = PeerId::from_bytes(&record.peer_id)?;
@ -45,7 +49,7 @@ impl PeerRecord {
let addresses = record let addresses = record
.addresses .addresses
.into_iter() .into_iter()
.map(|a| a.multiaddr.try_into()) .map(|a| a.multiaddr.to_vec().try_into())
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
Ok(Self { Ok(Self {
@ -60,7 +64,7 @@ impl PeerRecord {
/// ///
/// This is the same key that is used for authenticating every libp2p connection of your application, i.e. what you use when setting up your [`crate::transport::Transport`]. /// This is the same key that is used for authenticating every libp2p connection of your application, i.e. what you use when setting up your [`crate::transport::Transport`].
pub fn new(key: &Keypair, addresses: Vec<Multiaddr>) -> Result<Self, SigningError> { pub fn new(key: &Keypair, addresses: Vec<Multiaddr>) -> Result<Self, SigningError> {
use prost::Message; use quick_protobuf::MessageWrite;
let seq = SystemTime::now() let seq = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
@ -69,21 +73,23 @@ impl PeerRecord {
let peer_id = key.public().to_peer_id(); let peer_id = key.public().to_peer_id();
let payload = { let payload = {
let record = peer_record_proto::PeerRecord { let record = proto::PeerRecord {
peer_id: peer_id.to_bytes(), peer_id: peer_id.to_bytes(),
seq, seq,
addresses: addresses addresses: addresses
.iter() .iter()
.map(|m| peer_record_proto::peer_record::AddressInfo { .map(|m| proto::AddressInfo {
multiaddr: m.to_vec(), multiaddr: m.to_vec(),
}) })
.collect(), .collect(),
}; };
let mut buf = Vec::with_capacity(record.encoded_len()); let mut buf = Vec::with_capacity(record.get_size());
let mut writer = Writer::new(&mut buf);
record record
.encode(&mut buf) .write_message(&mut writer)
.expect("Vec<u8> provides capacity as needed"); .expect("Encoding to succeed");
buf buf
}; };
@ -162,7 +168,7 @@ mod tests {
#[test] #[test]
fn mismatched_signature() { fn mismatched_signature() {
use prost::Message; use quick_protobuf::MessageWrite;
let addr: Multiaddr = HOME.parse().unwrap(); let addr: Multiaddr = HOME.parse().unwrap();
@ -171,18 +177,20 @@ mod tests {
let identity_b = Keypair::generate_ed25519(); let identity_b = Keypair::generate_ed25519();
let payload = { let payload = {
let record = peer_record_proto::PeerRecord { let record = proto::PeerRecord {
peer_id: identity_a.public().to_peer_id().to_bytes(), peer_id: identity_a.public().to_peer_id().to_bytes(),
seq: 0, seq: 0,
addresses: vec![peer_record_proto::peer_record::AddressInfo { addresses: vec![proto::AddressInfo {
multiaddr: addr.to_vec(), multiaddr: addr.to_vec(),
}], }],
}; };
let mut buf = Vec::with_capacity(record.encoded_len()); let mut buf = Vec::with_capacity(record.get_size());
let mut writer = Writer::new(&mut buf);
record record
.encode(&mut buf) .write_message(&mut writer)
.expect("Vec<u8> provides capacity as needed"); .expect("Encoding to succeed");
buf buf
}; };

View File

@ -1,6 +1,7 @@
use crate::identity::error::SigningError; use crate::identity::error::SigningError;
use crate::identity::Keypair; use crate::identity::Keypair;
use crate::{identity, DecodeError, PublicKey}; use crate::{identity, proto, DecodeError, PublicKey};
use quick_protobuf::{BytesReader, Writer};
use std::convert::TryInto; use std::convert::TryInto;
use std::fmt; use std::fmt;
use unsigned_varint::encode::usize_buffer; use unsigned_varint::encode::usize_buffer;
@ -73,37 +74,41 @@ impl SignedEnvelope {
/// Encode this [`SignedEnvelope`] using the protobuf encoding specified in the RFC. /// Encode this [`SignedEnvelope`] using the protobuf encoding specified in the RFC.
pub fn into_protobuf_encoding(self) -> Vec<u8> { pub fn into_protobuf_encoding(self) -> Vec<u8> {
use prost::Message; use quick_protobuf::MessageWrite;
let envelope = crate::envelope_proto::Envelope { let envelope = proto::Envelope {
public_key: Some((&self.key).into()), public_key: Some((&self.key).into()),
payload_type: self.payload_type, payload_type: self.payload_type,
payload: self.payload, payload: self.payload,
signature: self.signature, signature: self.signature,
}; };
let mut buf = Vec::with_capacity(envelope.encoded_len()); let mut buf = Vec::with_capacity(envelope.get_size());
let mut writer = Writer::new(&mut buf);
envelope envelope
.encode(&mut buf) .write_message(&mut writer)
.expect("Vec<u8> provides capacity as needed"); .expect("Encoding to succeed");
buf buf
} }
/// Decode a [`SignedEnvelope`] using the protobuf encoding specified in the RFC. /// Decode a [`SignedEnvelope`] using the protobuf encoding specified in the RFC.
pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<Self, DecodingError> { pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<Self, DecodingError> {
use prost::Message; use quick_protobuf::MessageRead;
let envelope = crate::envelope_proto::Envelope::decode(bytes).map_err(DecodeError)?; let mut reader = BytesReader::from_bytes(bytes);
let envelope =
proto::Envelope::from_reader(&mut reader, bytes).map_err(DecodeError::from)?;
Ok(Self { Ok(Self {
key: envelope key: envelope
.public_key .public_key
.ok_or(DecodingError::MissingPublicKey)? .ok_or(DecodingError::MissingPublicKey)?
.try_into()?, .try_into()?,
payload_type: envelope.payload_type, payload_type: envelope.payload_type.to_vec(),
payload: envelope.payload, payload: envelope.payload.to_vec(),
signature: envelope.signature, signature: envelope.signature.to_vec(),
}) })
} }
} }

View File

@ -4,7 +4,7 @@ FROM rust:1.67.0
# Setup protoc. TODO this breaks reproducibility and uses an old version of protoc. # Setup protoc. TODO this breaks reproducibility and uses an old version of protoc.
# In the future protobuf generated files will be checked in, so we can remove this # In the future protobuf generated files will be checked in, so we can remove this
WORKDIR /protoc-setup WORKDIR /protoc-setup
RUN apt-get update && apt-get install -y cmake protobuf-compiler RUN apt-get update && apt-get install -y cmake
# Run with access to the target cache to speed up builds # Run with access to the target cache to speed up builds
WORKDIR /workspace WORKDIR /workspace

View File

@ -1,16 +0,0 @@
# 0.3.0
- Implement `From` trait for `std::io::Error`. See [PR 2622].
- Don't leak `prost` dependency in `Error` type. See [PR 3058].
- Update `rust-version` to reflect the actual MSRV: 1.60.0. See [PR 3090].
[PR 2622]: https://github.com/libp2p/rust-libp2p/pull/2622/
[PR 3058]: https://github.com/libp2p/rust-libp2p/pull/3058/
[PR 3090]: https://github.com/libp2p/rust-libp2p/pull/3090
# 0.2.0
- Update to prost(-build) `v0.11`. See [PR 2788].
[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788/

View File

@ -0,0 +1,5 @@
# 0.1.0 [unreleased]
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312

View File

@ -1,9 +1,9 @@
[package] [package]
name = "prost-codec" name = "quick-protobuf-codec"
edition = "2021" edition = "2021"
rust-version = "1.60.0" rust-version = "1.60.0"
description = "Asynchronous de-/encoding of Protobuf structs using asynchronous-codec, unsigned-varint and prost." description = "Asynchronous de-/encoding of Protobuf structs using asynchronous-codec, unsigned-varint and quick-protobuf."
version = "0.3.0" version = "0.1.0"
authors = ["Max Inden <mail@max-inden.de>"] authors = ["Max Inden <mail@max-inden.de>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -13,12 +13,9 @@ categories = ["asynchronous"]
[dependencies] [dependencies]
asynchronous-codec = { version = "0.6" } asynchronous-codec = { version = "0.6" }
bytes = { version = "1" } bytes = { version = "1" }
prost = "0.11"
thiserror = "1.0" thiserror = "1.0"
unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] } unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] }
quick-protobuf = "0.8"
[dev-dependencies]
prost-build = "0.11"
# Passing arguments to the docsrs builder in order to properly document cfg's. # Passing arguments to the docsrs builder in order to properly document cfg's.
# More information: https://docs.rs/about/builds#cross-compiling # More information: https://docs.rs/about/builds#cross-compiling

View File

@ -1,15 +1,14 @@
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
use asynchronous_codec::{Decoder, Encoder}; use asynchronous_codec::{Decoder, Encoder};
use bytes::BytesMut; use bytes::{Bytes, BytesMut};
use prost::Message; use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
use std::io::Cursor;
use std::marker::PhantomData; use std::marker::PhantomData;
use unsigned_varint::codec::UviBytes; use unsigned_varint::codec::UviBytes;
/// [`Codec`] implements [`Encoder`] and [`Decoder`], uses [`unsigned_varint`] /// [`Codec`] implements [`Encoder`] and [`Decoder`], uses [`unsigned_varint`]
/// to prefix messages with their length and uses [`prost`] and a provided /// to prefix messages with their length and uses [`quick_protobuf`] and a provided
/// `struct` implementing [`Message`] to do the encoding. /// `struct` implementing [`MessageRead`] and [`MessageWrite`] to do the encoding.
pub struct Codec<In, Out = In> { pub struct Codec<In, Out = In> {
uvi: UviBytes, uvi: UviBytes,
phantom: PhantomData<(In, Out)>, phantom: PhantomData<(In, Out)>,
@ -31,21 +30,25 @@ impl<In, Out> Codec<In, Out> {
} }
} }
impl<In: Message, Out> Encoder for Codec<In, Out> { impl<In: MessageWrite, Out> Encoder for Codec<In, Out> {
type Item = In; type Item = In;
type Error = Error; type Error = Error;
fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> { fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
let mut encoded_msg = BytesMut::new(); let mut encoded_msg = Vec::new();
item.encode(&mut encoded_msg) let mut writer = Writer::new(&mut encoded_msg);
.expect("BytesMut to have sufficient capacity."); item.write_message(&mut writer)
self.uvi.encode(encoded_msg.freeze(), dst)?; .expect("Encoding to succeed");
self.uvi.encode(Bytes::from(encoded_msg), dst)?;
Ok(()) Ok(())
} }
} }
impl<In, Out: Message + Default> Decoder for Codec<In, Out> { impl<In, Out> Decoder for Codec<In, Out>
where
Out: for<'a> MessageRead<'a>,
{
type Item = Out; type Item = Out;
type Error = Error; type Error = Error;
@ -55,9 +58,9 @@ impl<In, Out: Message + Default> Decoder for Codec<In, Out> {
Some(msg) => msg, Some(msg) => msg,
}; };
let message = Message::decode(Cursor::new(msg)) let mut reader = BytesReader::from_bytes(&msg);
let message = Self::Item::from_reader(&mut reader, &msg)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?; .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
Ok(Some(message)) Ok(Some(message))
} }
} }

View File

@ -8,6 +8,9 @@
- Update to `libp2p-swarm` `v0.42.0`. - Update to `libp2p-swarm` `v0.42.0`.
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
[PR 3153]: https://github.com/libp2p/rust-libp2p/pull/3153 [PR 3153]: https://github.com/libp2p/rust-libp2p/pull/3153
# 0.9.1 # 0.9.1

View File

@ -10,9 +10,6 @@ repository = "https://github.com/libp2p/rust-libp2p"
keywords = ["peer-to-peer", "libp2p", "networking"] keywords = ["peer-to-peer", "libp2p", "networking"]
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous"]
[build-dependencies]
prost-build = "0.11"
[dependencies] [dependencies]
async-trait = "0.1" async-trait = "0.1"
futures = "0.3" futures = "0.3"
@ -23,7 +20,7 @@ libp2p-swarm = { version = "0.42.0", path = "../../swarm" }
libp2p-request-response = { version = "0.24.0", path = "../request-response" } libp2p-request-response = { version = "0.24.0", path = "../request-response" }
log = "0.4" log = "0.4"
rand = "0.8" rand = "0.8"
prost = "0.11" quick-protobuf = "0.8"
[dev-dependencies] [dev-dependencies]
async-std = { version = "1.10", features = ["attributes"] } async-std = { version = "1.10", features = ["attributes"] }

View File

@ -1,23 +0,0 @@
// Copyright 2021 Protocol Labs.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
fn main() {
prost_build::compile_protos(&["src/structs.proto"], &["src"]).unwrap();
}

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod structs;

View File

@ -0,0 +1,242 @@
// Automatically generated rust module for 'structs.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Message {
pub type_pb: Option<structs::mod_Message::MessageType>,
pub dial: Option<structs::mod_Message::Dial>,
pub dialResponse: Option<structs::mod_Message::DialResponse>,
}
impl<'a> MessageRead<'a> for Message {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.type_pb = Some(r.read_enum(bytes)?),
Ok(18) => msg.dial = Some(r.read_message::<structs::mod_Message::Dial>(bytes)?),
Ok(26) => msg.dialResponse = Some(r.read_message::<structs::mod_Message::DialResponse>(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Message {
fn get_size(&self) -> usize {
0
+ self.type_pb.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64))
+ self.dial.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
+ self.dialResponse.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.type_pb { w.write_with_tag(8, |w| w.write_enum(*s as i32))?; }
if let Some(ref s) = self.dial { w.write_with_tag(18, |w| w.write_message(s))?; }
if let Some(ref s) = self.dialResponse { w.write_with_tag(26, |w| w.write_message(s))?; }
Ok(())
}
}
pub mod mod_Message {
use super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct PeerInfo {
pub id: Option<Vec<u8>>,
pub addrs: Vec<Vec<u8>>,
}
impl<'a> MessageRead<'a> for PeerInfo {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.id = Some(r.read_bytes(bytes)?.to_owned()),
Ok(18) => msg.addrs.push(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for PeerInfo {
fn get_size(&self) -> usize {
0
+ self.id.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.addrs.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.id { w.write_with_tag(10, |w| w.write_bytes(&**s))?; }
for s in &self.addrs { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Dial {
pub peer: Option<structs::mod_Message::PeerInfo>,
}
impl<'a> MessageRead<'a> for Dial {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.peer = Some(r.read_message::<structs::mod_Message::PeerInfo>(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Dial {
fn get_size(&self) -> usize {
0
+ self.peer.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.peer { w.write_with_tag(10, |w| w.write_message(s))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct DialResponse {
pub status: Option<structs::mod_Message::ResponseStatus>,
pub statusText: Option<String>,
pub addr: Option<Vec<u8>>,
}
impl<'a> MessageRead<'a> for DialResponse {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.status = Some(r.read_enum(bytes)?),
Ok(18) => msg.statusText = Some(r.read_string(bytes)?.to_owned()),
Ok(26) => msg.addr = Some(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for DialResponse {
fn get_size(&self) -> usize {
0
+ self.status.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64))
+ self.statusText.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.addr.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.status { w.write_with_tag(8, |w| w.write_enum(*s as i32))?; }
if let Some(ref s) = self.statusText { w.write_with_tag(18, |w| w.write_string(&**s))?; }
if let Some(ref s) = self.addr { w.write_with_tag(26, |w| w.write_bytes(&**s))?; }
Ok(())
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MessageType {
DIAL = 0,
DIAL_RESPONSE = 1,
}
impl Default for MessageType {
fn default() -> Self {
MessageType::DIAL
}
}
impl From<i32> for MessageType {
fn from(i: i32) -> Self {
match i {
0 => MessageType::DIAL,
1 => MessageType::DIAL_RESPONSE,
_ => Self::default(),
}
}
}
impl<'a> From<&'a str> for MessageType {
fn from(s: &'a str) -> Self {
match s {
"DIAL" => MessageType::DIAL,
"DIAL_RESPONSE" => MessageType::DIAL_RESPONSE,
_ => Self::default(),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ResponseStatus {
OK = 0,
E_DIAL_ERROR = 100,
E_DIAL_REFUSED = 101,
E_BAD_REQUEST = 200,
E_INTERNAL_ERROR = 300,
}
impl Default for ResponseStatus {
fn default() -> Self {
ResponseStatus::OK
}
}
impl From<i32> for ResponseStatus {
fn from(i: i32) -> Self {
match i {
0 => ResponseStatus::OK,
100 => ResponseStatus::E_DIAL_ERROR,
101 => ResponseStatus::E_DIAL_REFUSED,
200 => ResponseStatus::E_BAD_REQUEST,
300 => ResponseStatus::E_INTERNAL_ERROR,
_ => Self::default(),
}
}
}
impl<'a> From<&'a str> for ResponseStatus {
fn from(s: &'a str) -> Self {
match s {
"OK" => ResponseStatus::OK,
"E_DIAL_ERROR" => ResponseStatus::E_DIAL_ERROR,
"E_DIAL_REFUSED" => ResponseStatus::E_DIAL_REFUSED,
"E_BAD_REQUEST" => ResponseStatus::E_BAD_REQUEST,
"E_INTERNAL_ERROR" => ResponseStatus::E_INTERNAL_ERROR,
_ => Self::default(),
}
}
}
}

View File

@ -34,7 +34,7 @@ pub use self::{
}; };
pub use libp2p_request_response::{InboundFailure, OutboundFailure}; pub use libp2p_request_response::{InboundFailure, OutboundFailure};
#[allow(clippy::derive_partial_eq_without_eq)] mod proto {
mod structs_proto { include!("generated/mod.rs");
include!(concat!(env!("OUT_DIR"), "/structs.rs")); pub use self::structs::{mod_Message::*, Message};
} }

View File

@ -18,12 +18,12 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::structs_proto; use crate::proto;
use async_trait::async_trait; use async_trait::async_trait;
use futures::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; use futures::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
use libp2p_core::{upgrade, Multiaddr, PeerId}; use libp2p_core::{upgrade, Multiaddr, PeerId};
use libp2p_request_response::{self as request_response, ProtocolName}; use libp2p_request_response::{self as request_response, ProtocolName};
use prost::Message; use quick_protobuf::{BytesReader, Writer};
use std::{convert::TryFrom, io}; use std::{convert::TryFrom, io};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -108,14 +108,17 @@ pub struct DialRequest {
impl DialRequest { impl DialRequest {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, io::Error> { pub fn from_bytes(bytes: &[u8]) -> Result<Self, io::Error> {
let msg = structs_proto::Message::decode(bytes) use quick_protobuf::MessageRead;
let mut reader = BytesReader::from_bytes(bytes);
let msg = proto::Message::from_reader(&mut reader, bytes)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
if msg.r#type != Some(structs_proto::message::MessageType::Dial as _) { if msg.type_pb != Some(proto::MessageType::DIAL) {
return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid type")); return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid type"));
} }
let (peer_id, addrs) = if let Some(structs_proto::message::Dial { let (peer_id, addrs) = if let Some(proto::Dial {
peer: peer:
Some(structs_proto::message::PeerInfo { Some(proto::PeerInfo {
id: Some(peer_id), id: Some(peer_id),
addrs, addrs,
}), }),
@ -131,12 +134,13 @@ impl DialRequest {
}; };
let peer_id = { let peer_id = {
PeerId::try_from(peer_id) PeerId::try_from(peer_id.to_vec())
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid peer id"))? .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid peer id"))?
}; };
let addrs = addrs let addrs = addrs
.into_iter() .into_iter()
.filter_map(|a| match Multiaddr::try_from(a) { .filter_map(|a| match Multiaddr::try_from(a.to_vec()) {
Ok(a) => Some(a), Ok(a) => Some(a),
Err(e) => { Err(e) => {
log::debug!("Unable to parse multiaddr: {e}"); log::debug!("Unable to parse multiaddr: {e}");
@ -151,6 +155,8 @@ impl DialRequest {
} }
pub fn into_bytes(self) -> Vec<u8> { pub fn into_bytes(self) -> Vec<u8> {
use quick_protobuf::MessageWrite;
let peer_id = self.peer_id.to_bytes(); let peer_id = self.peer_id.to_bytes();
let addrs = self let addrs = self
.addresses .addresses
@ -158,21 +164,21 @@ impl DialRequest {
.map(|addr| addr.to_vec()) .map(|addr| addr.to_vec())
.collect(); .collect();
let msg = structs_proto::Message { let msg = proto::Message {
r#type: Some(structs_proto::message::MessageType::Dial as _), type_pb: Some(proto::MessageType::DIAL),
dial: Some(structs_proto::message::Dial { dial: Some(proto::Dial {
peer: Some(structs_proto::message::PeerInfo { peer: Some(proto::PeerInfo {
id: Some(peer_id), id: Some(peer_id.to_vec()),
addrs, addrs,
}), }),
}), }),
dial_response: None, dialResponse: None,
}; };
let mut bytes = Vec::with_capacity(msg.encoded_len()); let mut buf = Vec::with_capacity(msg.get_size());
msg.encode(&mut bytes) let mut writer = Writer::new(&mut buf);
.expect("Vec<u8> provides capacity as needed"); msg.write_message(&mut writer).expect("Encoding to succeed");
bytes buf
} }
} }
@ -184,29 +190,27 @@ pub enum ResponseError {
InternalError, InternalError,
} }
impl From<ResponseError> for i32 { impl From<ResponseError> for proto::ResponseStatus {
fn from(t: ResponseError) -> Self { fn from(t: ResponseError) -> Self {
match t { match t {
ResponseError::DialError => 100, ResponseError::DialError => proto::ResponseStatus::E_DIAL_ERROR,
ResponseError::DialRefused => 101, ResponseError::DialRefused => proto::ResponseStatus::E_DIAL_REFUSED,
ResponseError::BadRequest => 200, ResponseError::BadRequest => proto::ResponseStatus::E_BAD_REQUEST,
ResponseError::InternalError => 300, ResponseError::InternalError => proto::ResponseStatus::E_INTERNAL_ERROR,
} }
} }
} }
impl TryFrom<structs_proto::message::ResponseStatus> for ResponseError { impl TryFrom<proto::ResponseStatus> for ResponseError {
type Error = io::Error; type Error = io::Error;
fn try_from(value: structs_proto::message::ResponseStatus) -> Result<Self, Self::Error> { fn try_from(value: proto::ResponseStatus) -> Result<Self, Self::Error> {
match value { match value {
structs_proto::message::ResponseStatus::EDialError => Ok(ResponseError::DialError), proto::ResponseStatus::E_DIAL_ERROR => Ok(ResponseError::DialError),
structs_proto::message::ResponseStatus::EDialRefused => Ok(ResponseError::DialRefused), proto::ResponseStatus::E_DIAL_REFUSED => Ok(ResponseError::DialRefused),
structs_proto::message::ResponseStatus::EBadRequest => Ok(ResponseError::BadRequest), proto::ResponseStatus::E_BAD_REQUEST => Ok(ResponseError::BadRequest),
structs_proto::message::ResponseStatus::EInternalError => { proto::ResponseStatus::E_INTERNAL_ERROR => Ok(ResponseError::InternalError),
Ok(ResponseError::InternalError) proto::ResponseStatus::OK => {
}
structs_proto::message::ResponseStatus::Ok => {
log::debug!("Received response with status code OK but expected error."); log::debug!("Received response with status code OK but expected error.");
Err(io::Error::new( Err(io::Error::new(
io::ErrorKind::InvalidData, io::ErrorKind::InvalidData,
@ -225,38 +229,35 @@ pub struct DialResponse {
impl DialResponse { impl DialResponse {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, io::Error> { pub fn from_bytes(bytes: &[u8]) -> Result<Self, io::Error> {
let msg = structs_proto::Message::decode(bytes) use quick_protobuf::MessageRead;
let mut reader = BytesReader::from_bytes(bytes);
let msg = proto::Message::from_reader(&mut reader, bytes)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
if msg.r#type != Some(structs_proto::message::MessageType::DialResponse as _) { if msg.type_pb != Some(proto::MessageType::DIAL_RESPONSE) {
return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid type")); return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid type"));
} }
Ok(match msg.dial_response { Ok(match msg.dialResponse {
Some(structs_proto::message::DialResponse { Some(proto::DialResponse {
status: Some(status), status: Some(proto::ResponseStatus::OK),
status_text, statusText,
addr: Some(addr), addr: Some(addr),
}) if structs_proto::message::ResponseStatus::from_i32(status) }) => {
== Some(structs_proto::message::ResponseStatus::Ok) => let addr = Multiaddr::try_from(addr.to_vec())
{
let addr = Multiaddr::try_from(addr)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
Self { Self {
status_text, status_text: statusText,
result: Ok(addr), result: Ok(addr),
} }
} }
Some(structs_proto::message::DialResponse { Some(proto::DialResponse {
status: Some(status), status: Some(status),
status_text, statusText,
addr: None, addr: None,
}) => Self { }) => Self {
status_text, status_text: statusText,
result: Err(ResponseError::try_from( result: Err(ResponseError::try_from(status)?),
structs_proto::message::ResponseStatus::from_i32(status).ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidData, "invalid response status code")
})?,
)?),
}, },
_ => { _ => {
log::debug!("Received malformed response message."); log::debug!("Received malformed response message.");
@ -269,35 +270,38 @@ impl DialResponse {
} }
pub fn into_bytes(self) -> Vec<u8> { pub fn into_bytes(self) -> Vec<u8> {
use quick_protobuf::MessageWrite;
let dial_response = match self.result { let dial_response = match self.result {
Ok(addr) => structs_proto::message::DialResponse { Ok(addr) => proto::DialResponse {
status: Some(0), status: Some(proto::ResponseStatus::OK),
status_text: self.status_text, statusText: self.status_text,
addr: Some(addr.to_vec()), addr: Some(addr.to_vec()),
}, },
Err(error) => structs_proto::message::DialResponse { Err(error) => proto::DialResponse {
status: Some(error.into()), status: Some(error.into()),
status_text: self.status_text, statusText: self.status_text,
addr: None, addr: None,
}, },
}; };
let msg = structs_proto::Message { let msg = proto::Message {
r#type: Some(structs_proto::message::MessageType::DialResponse as _), type_pb: Some(proto::MessageType::DIAL_RESPONSE),
dial: None, dial: None,
dial_response: Some(dial_response), dialResponse: Some(dial_response),
}; };
let mut bytes = Vec::with_capacity(msg.encoded_len()); let mut buf = Vec::with_capacity(msg.get_size());
msg.encode(&mut bytes) let mut writer = Writer::new(&mut buf);
.expect("Vec<u8> provides capacity as needed"); msg.write_message(&mut writer).expect("Encoding to succeed");
bytes buf
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use quick_protobuf::MessageWrite;
#[test] #[test]
fn test_request_encode_decode() { fn test_request_encode_decode() {
@ -346,20 +350,20 @@ mod tests {
a a
}; };
let msg = structs_proto::Message { let msg = proto::Message {
r#type: Some(structs_proto::message::MessageType::Dial.into()), type_pb: Some(proto::MessageType::DIAL),
dial: Some(structs_proto::message::Dial { dial: Some(proto::Dial {
peer: Some(structs_proto::message::PeerInfo { peer: Some(proto::PeerInfo {
id: Some(PeerId::random().to_bytes()), id: Some(PeerId::random().to_bytes()),
addrs: vec![valid_multiaddr_bytes, invalid_multiaddr], addrs: vec![valid_multiaddr_bytes, invalid_multiaddr],
}), }),
}), }),
dial_response: None, dialResponse: None,
}; };
let mut bytes = Vec::with_capacity(msg.encoded_len()); let mut bytes = Vec::with_capacity(msg.get_size());
msg.encode(&mut bytes) let mut writer = Writer::new(&mut bytes);
.expect("Vec<u8> provides capacity as needed"); msg.write_message(&mut writer).expect("Encoding to succeed");
let request = DialRequest::from_bytes(&bytes).expect("not to fail"); let request = DialRequest::from_bytes(&bytes).expect("not to fail");

View File

@ -11,10 +11,13 @@
- Rename types in public API to follow naming conventions defined in [issue 2217]. See [PR 3214]. - Rename types in public API to follow naming conventions defined in [issue 2217]. See [PR 3214].
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[PR 3213]: https://github.com/libp2p/rust-libp2p/pull/3213 [PR 3213]: https://github.com/libp2p/rust-libp2p/pull/3213
[PR 3153]: https://github.com/libp2p/rust-libp2p/pull/3153 [PR 3153]: https://github.com/libp2p/rust-libp2p/pull/3153
[issue 2217]: https://github.com/libp2p/rust-libp2p/issues/2217 [issue 2217]: https://github.com/libp2p/rust-libp2p/issues/2217
[PR 3214]: https://github.com/libp2p/rust-libp2p/pull/3214 [PR 3214]: https://github.com/libp2p/rust-libp2p/pull/3214
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
# 0.8.1 # 0.8.1

View File

@ -19,14 +19,11 @@ instant = "0.1.11"
libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-core = { version = "0.39.0", path = "../../core" }
libp2p-swarm = { version = "0.42.0", path = "../../swarm" } libp2p-swarm = { version = "0.42.0", path = "../../swarm" }
log = "0.4" log = "0.4"
prost-codec = { version = "0.3", path = "../../misc/prost-codec" } quick-protobuf = "0.8"
prost = "0.11" quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" }
thiserror = "1.0" thiserror = "1.0"
void = "1" void = "1"
[build-dependencies]
prost-build = "0.11"
[dev-dependencies] [dev-dependencies]
clap = { version = "4.1.6", features = ["derive"] } clap = { version = "4.1.6", features = ["derive"] }
env_logger = "0.10.0" env_logger = "0.10.0"

View File

@ -1,23 +0,0 @@
// Copyright 2021 Protocol Labs.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
fn main() {
prost_build::compile_protos(&["src/message.proto"], &["src"]).unwrap();
}

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod pb;

View File

@ -0,0 +1,88 @@
// Automatically generated rust module for 'message.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct HolePunch {
pub type_pb: holepunch::pb::mod_HolePunch::Type,
pub ObsAddrs: Vec<Vec<u8>>,
}
impl<'a> MessageRead<'a> for HolePunch {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.type_pb = r.read_enum(bytes)?,
Ok(18) => msg.ObsAddrs.push(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for HolePunch {
fn get_size(&self) -> usize {
0
+ 1 + sizeof_varint(*(&self.type_pb) as u64)
+ self.ObsAddrs.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
w.write_with_tag(8, |w| w.write_enum(*&self.type_pb as i32))?;
for s in &self.ObsAddrs { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
Ok(())
}
}
pub mod mod_HolePunch {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Type {
CONNECT = 100,
SYNC = 300,
}
impl Default for Type {
fn default() -> Self {
Type::CONNECT
}
}
impl From<i32> for Type {
fn from(i: i32) -> Self {
match i {
100 => Type::CONNECT,
300 => Type::SYNC,
_ => Self::default(),
}
}
}
impl<'a> From<&'a str> for Type {
fn from(s: &'a str) -> Self {
match s {
"CONNECT" => Type::CONNECT,
"SYNC" => Type::SYNC,
_ => Self::default(),
}
}
}
}

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod holepunch;

View File

@ -26,9 +26,10 @@
mod behaviour_impl; // TODO: Rename back `behaviour` once deprecation symbols are removed. mod behaviour_impl; // TODO: Rename back `behaviour` once deprecation symbols are removed.
mod handler; mod handler;
mod protocol; mod protocol;
#[allow(clippy::derive_partial_eq_without_eq)]
mod message_proto { mod proto {
include!(concat!(env!("OUT_DIR"), "/holepunch.pb.rs")); include!("generated/mod.rs");
pub use self::holepunch::pb::{mod_HolePunch::*, HolePunch};
} }
pub use behaviour_impl::Behaviour; pub use behaviour_impl::Behaviour;

View File

@ -18,7 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::message_proto::{hole_punch, HolePunch}; use crate::proto;
use asynchronous_codec::Framed; use asynchronous_codec::Framed;
use futures::{future::BoxFuture, prelude::*}; use futures::{future::BoxFuture, prelude::*};
use libp2p_core::{multiaddr::Protocol, upgrade, Multiaddr}; use libp2p_core::{multiaddr::Protocol, upgrade, Multiaddr};
@ -46,19 +46,19 @@ impl upgrade::InboundUpgrade<NegotiatedSubstream> for Upgrade {
fn upgrade_inbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future { fn upgrade_inbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future {
let mut substream = Framed::new( let mut substream = Framed::new(
substream, substream,
prost_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES), quick_protobuf_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES),
); );
async move { async move {
let HolePunch { r#type, obs_addrs } = let proto::HolePunch { type_pb, ObsAddrs } =
substream.next().await.ok_or(UpgradeError::StreamClosed)??; substream.next().await.ok_or(UpgradeError::StreamClosed)??;
let obs_addrs = if obs_addrs.is_empty() { let obs_addrs = if ObsAddrs.is_empty() {
return Err(UpgradeError::NoAddresses); return Err(UpgradeError::NoAddresses);
} else { } else {
obs_addrs ObsAddrs
.into_iter() .into_iter()
.filter_map(|a| match Multiaddr::try_from(a) { .filter_map(|a| match Multiaddr::try_from(a.to_vec()) {
Ok(a) => Some(a), Ok(a) => Some(a),
Err(e) => { Err(e) => {
log::debug!("Unable to parse multiaddr: {e}"); log::debug!("Unable to parse multiaddr: {e}");
@ -77,11 +77,9 @@ impl upgrade::InboundUpgrade<NegotiatedSubstream> for Upgrade {
.collect::<Vec<Multiaddr>>() .collect::<Vec<Multiaddr>>()
}; };
let r#type = hole_punch::Type::from_i32(r#type).ok_or(UpgradeError::ParseTypeField)?; match type_pb {
proto::Type::CONNECT => {}
match r#type { proto::Type::SYNC => return Err(UpgradeError::UnexpectedTypeSync),
hole_punch::Type::Connect => {}
hole_punch::Type::Sync => return Err(UpgradeError::UnexpectedTypeSync),
} }
Ok(PendingConnect { Ok(PendingConnect {
@ -94,7 +92,7 @@ impl upgrade::InboundUpgrade<NegotiatedSubstream> for Upgrade {
} }
pub struct PendingConnect { pub struct PendingConnect {
substream: Framed<NegotiatedSubstream, prost_codec::Codec<HolePunch>>, substream: Framed<NegotiatedSubstream, quick_protobuf_codec::Codec<proto::HolePunch>>,
remote_obs_addrs: Vec<Multiaddr>, remote_obs_addrs: Vec<Multiaddr>,
} }
@ -103,22 +101,21 @@ impl PendingConnect {
mut self, mut self,
local_obs_addrs: Vec<Multiaddr>, local_obs_addrs: Vec<Multiaddr>,
) -> Result<Vec<Multiaddr>, UpgradeError> { ) -> Result<Vec<Multiaddr>, UpgradeError> {
let msg = HolePunch { let msg = proto::HolePunch {
r#type: hole_punch::Type::Connect.into(), type_pb: proto::Type::CONNECT,
obs_addrs: local_obs_addrs.into_iter().map(|a| a.to_vec()).collect(), ObsAddrs: local_obs_addrs.into_iter().map(|a| a.to_vec()).collect(),
}; };
self.substream.send(msg).await?; self.substream.send(msg).await?;
let HolePunch { r#type, .. } = self let proto::HolePunch { type_pb, .. } = self
.substream .substream
.next() .next()
.await .await
.ok_or(UpgradeError::StreamClosed)??; .ok_or(UpgradeError::StreamClosed)??;
let r#type = hole_punch::Type::from_i32(r#type).ok_or(UpgradeError::ParseTypeField)?; match type_pb {
match r#type { proto::Type::CONNECT => return Err(UpgradeError::UnexpectedTypeConnect),
hole_punch::Type::Connect => return Err(UpgradeError::UnexpectedTypeConnect), proto::Type::SYNC => {}
hole_punch::Type::Sync => {}
} }
Ok(self.remote_obs_addrs) Ok(self.remote_obs_addrs)
@ -128,7 +125,7 @@ impl PendingConnect {
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum UpgradeError { pub enum UpgradeError {
#[error(transparent)] #[error(transparent)]
Codec(#[from] prost_codec::Error), Codec(#[from] quick_protobuf_codec::Error),
#[error("Stream closed")] #[error("Stream closed")]
StreamClosed, StreamClosed,
#[error("Expected at least one address in reservation.")] #[error("Expected at least one address in reservation.")]

View File

@ -18,7 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::message_proto::{hole_punch, HolePunch}; use crate::proto;
use asynchronous_codec::Framed; use asynchronous_codec::Framed;
use futures::{future::BoxFuture, prelude::*}; use futures::{future::BoxFuture, prelude::*};
use futures_timer::Delay; use futures_timer::Delay;
@ -56,12 +56,12 @@ impl upgrade::OutboundUpgrade<NegotiatedSubstream> for Upgrade {
fn upgrade_outbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future { fn upgrade_outbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future {
let mut substream = Framed::new( let mut substream = Framed::new(
substream, substream,
prost_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES), quick_protobuf_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES),
); );
let msg = HolePunch { let msg = proto::HolePunch {
r#type: hole_punch::Type::Connect.into(), type_pb: proto::Type::CONNECT,
obs_addrs: self.obs_addrs.into_iter().map(|a| a.to_vec()).collect(), ObsAddrs: self.obs_addrs.into_iter().map(|a| a.to_vec()).collect(),
}; };
async move { async move {
@ -69,23 +69,22 @@ impl upgrade::OutboundUpgrade<NegotiatedSubstream> for Upgrade {
let sent_time = Instant::now(); let sent_time = Instant::now();
let HolePunch { r#type, obs_addrs } = let proto::HolePunch { type_pb, ObsAddrs } =
substream.next().await.ok_or(UpgradeError::StreamClosed)??; substream.next().await.ok_or(UpgradeError::StreamClosed)??;
let rtt = sent_time.elapsed(); let rtt = sent_time.elapsed();
let r#type = hole_punch::Type::from_i32(r#type).ok_or(UpgradeError::ParseTypeField)?; match type_pb {
match r#type { proto::Type::CONNECT => {}
hole_punch::Type::Connect => {} proto::Type::SYNC => return Err(UpgradeError::UnexpectedTypeSync),
hole_punch::Type::Sync => return Err(UpgradeError::UnexpectedTypeSync),
} }
let obs_addrs = if obs_addrs.is_empty() { let obs_addrs = if ObsAddrs.is_empty() {
return Err(UpgradeError::NoAddresses); return Err(UpgradeError::NoAddresses);
} else { } else {
obs_addrs ObsAddrs
.into_iter() .into_iter()
.filter_map(|a| match Multiaddr::try_from(a) { .filter_map(|a| match Multiaddr::try_from(a.to_vec()) {
Ok(a) => Some(a), Ok(a) => Some(a),
Err(e) => { Err(e) => {
log::debug!("Unable to parse multiaddr: {e}"); log::debug!("Unable to parse multiaddr: {e}");
@ -104,9 +103,9 @@ impl upgrade::OutboundUpgrade<NegotiatedSubstream> for Upgrade {
.collect::<Vec<Multiaddr>>() .collect::<Vec<Multiaddr>>()
}; };
let msg = HolePunch { let msg = proto::HolePunch {
r#type: hole_punch::Type::Sync.into(), type_pb: proto::Type::SYNC,
obs_addrs: vec![], ObsAddrs: vec![],
}; };
substream.send(msg).await?; substream.send(msg).await?;
@ -126,7 +125,7 @@ pub struct Connect {
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum UpgradeError { pub enum UpgradeError {
#[error(transparent)] #[error(transparent)]
Codec(#[from] prost_codec::Error), Codec(#[from] quick_protobuf_codec::Error),
#[error("Stream closed")] #[error("Stream closed")]
StreamClosed, StreamClosed,
#[error("Expected 'status' field to be set.")] #[error("Expected 'status' field to be set.")]

View File

@ -4,9 +4,9 @@
- Update to `libp2p-swarm` `v0.42.0`. - Update to `libp2p-swarm` `v0.42.0`.
- Read and write protocols messages via `prost-codec`. See [PR 3224]. - Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[pr 3224]: https://github.com/libp2p/rust-libp2p/pull/3224 [PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
# 0.41.0 # 0.41.0

View File

@ -18,15 +18,12 @@ futures = "0.3.26"
libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-core = { version = "0.39.0", path = "../../core" }
libp2p-swarm = { version = "0.42.0", path = "../../swarm" } libp2p-swarm = { version = "0.42.0", path = "../../swarm" }
log = "0.4" log = "0.4"
prost = "0.11" quick-protobuf = "0.8"
prost-codec = { version = "0.3", path = "../../misc/prost-codec" } quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" }
rand = "0.8" rand = "0.8"
smallvec = "1.6.1" smallvec = "1.6.1"
thiserror = "1.0.37" thiserror = "1.0.37"
[build-dependencies]
prost-build = "0.11"
# Passing arguments to the docsrs builder in order to properly document cfg's. # Passing arguments to the docsrs builder in order to properly document cfg's.
# More information: https://docs.rs/about/builds#cross-compiling # More information: https://docs.rs/about/builds#cross-compiling
[package.metadata.docs.rs] [package.metadata.docs.rs]

View File

@ -1,23 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
fn main() {
prost_build::compile_protos(&["src/rpc.proto"], &["src"]).unwrap();
}

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod pb;

View File

@ -0,0 +1,137 @@
// Automatically generated rust module for 'rpc.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct RPC {
pub subscriptions: Vec<floodsub::pb::mod_RPC::SubOpts>,
pub publish: Vec<floodsub::pb::Message>,
}
impl<'a> MessageRead<'a> for RPC {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.subscriptions.push(r.read_message::<floodsub::pb::mod_RPC::SubOpts>(bytes)?),
Ok(18) => msg.publish.push(r.read_message::<floodsub::pb::Message>(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for RPC {
fn get_size(&self) -> usize {
0
+ self.subscriptions.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
+ self.publish.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
for s in &self.subscriptions { w.write_with_tag(10, |w| w.write_message(s))?; }
for s in &self.publish { w.write_with_tag(18, |w| w.write_message(s))?; }
Ok(())
}
}
pub mod mod_RPC {
use super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct SubOpts {
pub subscribe: Option<bool>,
pub topic_id: Option<String>,
}
impl<'a> MessageRead<'a> for SubOpts {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.subscribe = Some(r.read_bool(bytes)?),
Ok(18) => msg.topic_id = Some(r.read_string(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for SubOpts {
fn get_size(&self) -> usize {
0
+ self.subscribe.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64))
+ self.topic_id.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.subscribe { w.write_with_tag(8, |w| w.write_bool(*s))?; }
if let Some(ref s) = self.topic_id { w.write_with_tag(18, |w| w.write_string(&**s))?; }
Ok(())
}
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Message {
pub from: Option<Vec<u8>>,
pub data: Option<Vec<u8>>,
pub seqno: Option<Vec<u8>>,
pub topic_ids: Vec<String>,
}
impl<'a> MessageRead<'a> for Message {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.from = Some(r.read_bytes(bytes)?.to_owned()),
Ok(18) => msg.data = Some(r.read_bytes(bytes)?.to_owned()),
Ok(26) => msg.seqno = Some(r.read_bytes(bytes)?.to_owned()),
Ok(34) => msg.topic_ids.push(r.read_string(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Message {
fn get_size(&self) -> usize {
0
+ self.from.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.data.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.seqno.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.topic_ids.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.from { w.write_with_tag(10, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.data { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.seqno { w.write_with_tag(26, |w| w.write_bytes(&**s))?; }
for s in &self.topic_ids { w.write_with_tag(34, |w| w.write_string(&**s))?; }
Ok(())
}
}

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod floodsub;

View File

@ -29,9 +29,9 @@ pub mod protocol;
mod layer; mod layer;
mod topic; mod topic;
#[allow(clippy::derive_partial_eq_without_eq)] mod proto {
mod rpc_proto { include!("generated/mod.rs");
include!(concat!(env!("OUT_DIR"), "/floodsub.pb.rs")); pub use self::floodsub::pb::{mod_RPC::SubOpts, Message, RPC};
} }
pub use self::layer::{Floodsub, FloodsubEvent}; pub use self::layer::{Floodsub, FloodsubEvent};

View File

@ -18,7 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::rpc_proto; use crate::proto;
use crate::topic::Topic; use crate::topic::Topic;
use asynchronous_codec::Framed; use asynchronous_codec::Framed;
use futures::{ use futures::{
@ -65,7 +65,7 @@ where
Box::pin(async move { Box::pin(async move {
let mut framed = Framed::new( let mut framed = Framed::new(
socket, socket,
prost_codec::Codec::<rpc_proto::Rpc>::new(MAX_MESSAGE_LEN_BYTES), quick_protobuf_codec::Codec::<proto::RPC>::new(MAX_MESSAGE_LEN_BYTES),
); );
let rpc = framed let rpc = framed
@ -120,7 +120,7 @@ pub enum FloodsubError {
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
#[error(transparent)] #[error(transparent)]
pub struct CodecError(#[from] prost_codec::Error); pub struct CodecError(#[from] quick_protobuf_codec::Error);
/// An RPC received by the floodsub system. /// An RPC received by the floodsub system.
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -152,7 +152,7 @@ where
Box::pin(async move { Box::pin(async move {
let mut framed = Framed::new( let mut framed = Framed::new(
socket, socket,
prost_codec::Codec::<rpc_proto::Rpc>::new(MAX_MESSAGE_LEN_BYTES), quick_protobuf_codec::Codec::<proto::RPC>::new(MAX_MESSAGE_LEN_BYTES),
); );
framed.send(self.into_rpc()).await?; framed.send(self.into_rpc()).await?;
framed.close().await?; framed.close().await?;
@ -163,12 +163,12 @@ where
impl FloodsubRpc { impl FloodsubRpc {
/// Turns this `FloodsubRpc` into a message that can be sent to a substream. /// Turns this `FloodsubRpc` into a message that can be sent to a substream.
fn into_rpc(self) -> rpc_proto::Rpc { fn into_rpc(self) -> proto::RPC {
rpc_proto::Rpc { proto::RPC {
publish: self publish: self
.messages .messages
.into_iter() .into_iter()
.map(|msg| rpc_proto::Message { .map(|msg| proto::Message {
from: Some(msg.source.to_bytes()), from: Some(msg.source.to_bytes()),
data: Some(msg.data), data: Some(msg.data),
seqno: Some(msg.sequence_number), seqno: Some(msg.sequence_number),
@ -179,7 +179,7 @@ impl FloodsubRpc {
subscriptions: self subscriptions: self
.subscriptions .subscriptions
.into_iter() .into_iter()
.map(|topic| rpc_proto::rpc::SubOpts { .map(|topic| proto::SubOpts {
subscribe: Some(topic.action == FloodsubSubscriptionAction::Subscribe), subscribe: Some(topic.action == FloodsubSubscriptionAction::Subscribe),
topic_id: Some(topic.topic.into()), topic_id: Some(topic.topic.into()),
}) })

View File

@ -14,10 +14,13 @@
It is preferred to import the gossipsub protocol as a module (`use libp2p::gossipsub;`), and refer to its types via `gossipsub::`. It is preferred to import the gossipsub protocol as a module (`use libp2p::gossipsub;`), and refer to its types via `gossipsub::`.
For example: `gossipsub::Behaviour` or `gossipsub::RawMessage`. See [PR 3303]. For example: `gossipsub::Behaviour` or `gossipsub::RawMessage`. See [PR 3303].
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[PR 3207]: https://github.com/libp2p/rust-libp2p/pull/3207/ [PR 3207]: https://github.com/libp2p/rust-libp2p/pull/3207/
[PR 3303]: https://github.com/libp2p/rust-libp2p/pull/3303/ [PR 3303]: https://github.com/libp2p/rust-libp2p/pull/3303/
[PR 3381]: https://github.com/libp2p/rust-libp2p/pull/3381/ [PR 3381]: https://github.com/libp2p/rust-libp2p/pull/3381/
[discussion 2174]: https://github.com/libp2p/rust-libp2p/discussions/2174 [discussion 2174]: https://github.com/libp2p/rust-libp2p/discussions/2174
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
# 0.43.0 # 0.43.0

View File

@ -24,8 +24,8 @@ log = "0.4.11"
sha2 = "0.10.0" sha2 = "0.10.0"
base64 = "0.21.0" base64 = "0.21.0"
smallvec = "1.6.1" smallvec = "1.6.1"
prost = "0.11" quick-protobuf = "0.8"
prost-codec = { version = "0.3", path = "../../misc/prost-codec" } quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" }
hex_fmt = "0.3.0" hex_fmt = "0.3.0"
regex = "1.5.5" regex = "1.5.5"
serde = { version = "1", optional = true, features = ["derive"] } serde = { version = "1", optional = true, features = ["derive"] }
@ -46,9 +46,6 @@ libp2p-swarm = { path = "../../swarm" }
libp2p-yamux = { path = "../../muxers/yamux" } libp2p-yamux = { path = "../../muxers/yamux" }
quickcheck = { package = "quickcheck-ext", path = "../../misc/quickcheck-ext" } quickcheck = { package = "quickcheck-ext", path = "../../misc/quickcheck-ext" }
[build-dependencies]
prost-build = "0.11"
# Passing arguments to the docsrs builder in order to properly document cfg's. # Passing arguments to the docsrs builder in order to properly document cfg's.
# More information: https://docs.rs/about/builds#cross-compiling # More information: https://docs.rs/about/builds#cross-compiling
[package.metadata.docs.rs] [package.metadata.docs.rs]

View File

@ -1,23 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
fn main() {
prost_build::compile_protos(&["src/rpc.proto", "src/compat.proto"], &["src"]).unwrap();
}

View File

@ -32,7 +32,6 @@ use std::{
use futures::StreamExt; use futures::StreamExt;
use log::{debug, error, trace, warn}; use log::{debug, error, trace, warn};
use prometheus_client::registry::Registry; use prometheus_client::registry::Registry;
use prost::Message as _;
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
use libp2p_core::{ use libp2p_core::{
@ -64,8 +63,9 @@ use crate::types::{
Subscription, SubscriptionAction, Subscription, SubscriptionAction,
}; };
use crate::types::{PeerConnections, PeerKind, Rpc}; use crate::types::{PeerConnections, PeerKind, Rpc};
use crate::{rpc_proto, TopicScoreParams}; use crate::{rpc_proto::proto, TopicScoreParams};
use crate::{PublishError, SubscriptionError, ValidationError}; use crate::{PublishError, SubscriptionError, ValidationError};
use quick_protobuf::{MessageWrite, Writer};
use std::{cmp::Ordering::Equal, fmt::Debug}; use std::{cmp::Ordering::Equal, fmt::Debug};
use wasm_timer::Interval; use wasm_timer::Interval;
@ -179,8 +179,8 @@ impl From<MessageAuthenticity> for PublishConfig {
let public_key = keypair.public(); let public_key = keypair.public();
let key_enc = public_key.to_protobuf_encoding(); let key_enc = public_key.to_protobuf_encoding();
let key = if key_enc.len() <= 42 { let key = if key_enc.len() <= 42 {
// The public key can be inlined in [`rpc_proto::Message::from`], so we don't include it // The public key can be inlined in [`rpc_proto::proto::::Message::from`], so we don't include it
// specifically in the [`rpc_proto::Message::key`] field. // specifically in the [`rpc_proto::proto::Message::key`] field.
None None
} else { } else {
// Include the protobuf encoding of the public key in the message. // Include the protobuf encoding of the public key in the message.
@ -610,7 +610,7 @@ where
.into_protobuf(); .into_protobuf();
// check that the size doesn't exceed the max transmission size // check that the size doesn't exceed the max transmission size
if event.encoded_len() > self.config.max_transmit_size() { if event.get_size() > self.config.max_transmit_size() {
return Err(PublishError::MessageTooLarge); return Err(PublishError::MessageTooLarge);
} }
@ -721,7 +721,7 @@ where
} }
// Send to peers we know are subscribed to the topic. // Send to peers we know are subscribed to the topic.
let msg_bytes = event.encoded_len(); let msg_bytes = event.get_size();
for peer_id in recipient_peers.iter() { for peer_id in recipient_peers.iter() {
trace!("Sending message to peer: {:?}", peer_id); trace!("Sending message to peer: {:?}", peer_id);
self.send_message(*peer_id, event.clone())?; self.send_message(*peer_id, event.clone())?;
@ -1338,7 +1338,7 @@ where
} }
.into_protobuf(); .into_protobuf();
let msg_bytes = message.encoded_len(); let msg_bytes = message.get_size();
if self.send_message(*peer_id, message).is_err() { if self.send_message(*peer_id, message).is_err() {
error!("Failed to send cached messages. Messages too large"); error!("Failed to send cached messages. Messages too large");
@ -2733,7 +2733,7 @@ where
} }
.into_protobuf(); .into_protobuf();
let msg_bytes = event.encoded_len(); let msg_bytes = event.get_size();
for peer in recipient_peers.iter() { for peer in recipient_peers.iter() {
debug!("Sending message: {:?} to peer {:?}", msg_id, peer); debug!("Sending message: {:?} to peer {:?}", msg_id, peer);
self.send_message(*peer, event.clone())?; self.send_message(*peer, event.clone())?;
@ -2764,7 +2764,7 @@ where
let sequence_number: u64 = rand::random(); let sequence_number: u64 = rand::random();
let signature = { let signature = {
let message = rpc_proto::Message { let message = proto::Message {
from: Some(author.clone().to_bytes()), from: Some(author.clone().to_bytes()),
data: Some(data.clone()), data: Some(data.clone()),
seqno: Some(sequence_number.to_be_bytes().to_vec()), seqno: Some(sequence_number.to_be_bytes().to_vec()),
@ -2773,10 +2773,12 @@ where
key: None, key: None,
}; };
let mut buf = Vec::with_capacity(message.encoded_len()); let mut buf = Vec::with_capacity(message.get_size());
let mut writer = Writer::new(&mut buf);
message message
.encode(&mut buf) .write_message(&mut writer)
.expect("Buffer has sufficient capacity"); .expect("Encoding to succeed");
// the signature is over the bytes "libp2p-pubsub:<protobuf-message>" // the signature is over the bytes "libp2p-pubsub:<protobuf-message>"
let mut signature_bytes = SIGNING_PREFIX.to_vec(); let mut signature_bytes = SIGNING_PREFIX.to_vec();
@ -2875,11 +2877,7 @@ where
/// Send a [`Rpc`] message to a peer. This will wrap the message in an arc if it /// Send a [`Rpc`] message to a peer. This will wrap the message in an arc if it
/// is not already an arc. /// is not already an arc.
fn send_message( fn send_message(&mut self, peer_id: PeerId, message: proto::RPC) -> Result<(), PublishError> {
&mut self,
peer_id: PeerId,
message: rpc_proto::Rpc,
) -> Result<(), PublishError> {
// If the message is oversized, try and fragment it. If it cannot be fragmented, log an // If the message is oversized, try and fragment it. If it cannot be fragmented, log an
// error and drop the message (all individual messages should be small enough to fit in the // error and drop the message (all individual messages should be small enough to fit in the
// max_transmit_size) // max_transmit_size)
@ -2899,12 +2897,12 @@ where
// If a message is too large to be sent as-is, this attempts to fragment it into smaller RPC // If a message is too large to be sent as-is, this attempts to fragment it into smaller RPC
// messages to be sent. // messages to be sent.
fn fragment_message(&self, rpc: rpc_proto::Rpc) -> Result<Vec<rpc_proto::Rpc>, PublishError> { fn fragment_message(&self, rpc: proto::RPC) -> Result<Vec<proto::RPC>, PublishError> {
if rpc.encoded_len() < self.config.max_transmit_size() { if rpc.get_size() < self.config.max_transmit_size() {
return Ok(vec![rpc]); return Ok(vec![rpc]);
} }
let new_rpc = rpc_proto::Rpc { let new_rpc = proto::RPC {
subscriptions: Vec::new(), subscriptions: Vec::new(),
publish: Vec::new(), publish: Vec::new(),
control: None, control: None,
@ -2920,7 +2918,7 @@ where
// create a new RPC if the new object plus 5% of its size (for length prefix // create a new RPC if the new object plus 5% of its size (for length prefix
// buffers) exceeds the max transmit size. // buffers) exceeds the max transmit size.
if rpc_list[list_index].encoded_len() + (($object_size as f64) * 1.05) as usize if rpc_list[list_index].get_size() + (($object_size as f64) * 1.05) as usize
> self.config.max_transmit_size() > self.config.max_transmit_size()
&& rpc_list[list_index] != new_rpc && rpc_list[list_index] != new_rpc
{ {
@ -2932,7 +2930,7 @@ where
macro_rules! add_item { macro_rules! add_item {
($object: ident, $type: ident ) => { ($object: ident, $type: ident ) => {
let object_size = $object.encoded_len(); let object_size = $object.get_size();
if object_size + 2 > self.config.max_transmit_size() { if object_size + 2 > self.config.max_transmit_size() {
// This should not be possible. All received and published messages have already // This should not be possible. All received and published messages have already
@ -2960,12 +2958,12 @@ where
// handle the control messages. If all are within the max_transmit_size, send them without // handle the control messages. If all are within the max_transmit_size, send them without
// fragmenting, otherwise, fragment the control messages // fragmenting, otherwise, fragment the control messages
let empty_control = rpc_proto::ControlMessage::default(); let empty_control = proto::ControlMessage::default();
if let Some(control) = rpc.control.as_ref() { if let Some(control) = rpc.control.as_ref() {
if control.encoded_len() + 2 > self.config.max_transmit_size() { if control.get_size() + 2 > self.config.max_transmit_size() {
// fragment the RPC // fragment the RPC
for ihave in &control.ihave { for ihave in &control.ihave {
let len = ihave.encoded_len(); let len = ihave.get_size();
create_or_add_rpc!(len); create_or_add_rpc!(len);
rpc_list rpc_list
.last_mut() .last_mut()
@ -2976,7 +2974,7 @@ where
.push(ihave.clone()); .push(ihave.clone());
} }
for iwant in &control.iwant { for iwant in &control.iwant {
let len = iwant.encoded_len(); let len = iwant.get_size();
create_or_add_rpc!(len); create_or_add_rpc!(len);
rpc_list rpc_list
.last_mut() .last_mut()
@ -2987,7 +2985,7 @@ where
.push(iwant.clone()); .push(iwant.clone());
} }
for graft in &control.graft { for graft in &control.graft {
let len = graft.encoded_len(); let len = graft.get_size();
create_or_add_rpc!(len); create_or_add_rpc!(len);
rpc_list rpc_list
.last_mut() .last_mut()
@ -2998,7 +2996,7 @@ where
.push(graft.clone()); .push(graft.clone());
} }
for prune in &control.prune { for prune in &control.prune {
let len = prune.encoded_len(); let len = prune.get_size();
create_or_add_rpc!(len); create_or_add_rpc!(len);
rpc_list rpc_list
.last_mut() .last_mut()
@ -3009,7 +3007,7 @@ where
.push(prune.clone()); .push(prune.clone());
} }
} else { } else {
let len = control.encoded_len(); let len = control.get_size();
create_or_add_rpc!(len); create_or_add_rpc!(len);
rpc_list.last_mut().expect("Always an element").control = Some(control.clone()); rpc_list.last_mut().expect("Always an element").control = Some(control.clone());
} }
@ -3769,7 +3767,7 @@ mod local_test {
// Messages over the limit should be split // Messages over the limit should be split
while rpc_proto.encoded_len() < max_transmit_size { while rpc_proto.get_size() < max_transmit_size {
rpc.messages.push(test_message()); rpc.messages.push(test_message());
rpc_proto = rpc.clone().into_protobuf(); rpc_proto = rpc.clone().into_protobuf();
} }
@ -3786,7 +3784,7 @@ mod local_test {
// all fragmented messages should be under the limit // all fragmented messages should be under the limit
for message in fragmented_messages { for message in fragmented_messages {
assert!( assert!(
message.encoded_len() < max_transmit_size, message.get_size() < max_transmit_size,
"all messages should be less than the transmission size" "all messages should be less than the transmission size"
); );
} }
@ -3813,7 +3811,7 @@ mod local_test {
.fragment_message(rpc_proto.clone()) .fragment_message(rpc_proto.clone())
.expect("Messages must be valid"); .expect("Messages must be valid");
if rpc_proto.encoded_len() < max_transmit_size { if rpc_proto.get_size() < max_transmit_size {
assert_eq!( assert_eq!(
fragmented_messages.len(), fragmented_messages.len(),
1, 1,
@ -3829,12 +3827,12 @@ mod local_test {
// all fragmented messages should be under the limit // all fragmented messages should be under the limit
for message in fragmented_messages { for message in fragmented_messages {
assert!( assert!(
message.encoded_len() < max_transmit_size, message.get_size() < max_transmit_size,
"all messages should be less than the transmission size: list size {} max size{}", message.encoded_len(), max_transmit_size "all messages should be less than the transmission size: list size {} max size{}", message.get_size(), max_transmit_size
); );
// ensure they can all be encoded // ensure they can all be encoded
let mut buf = bytes::BytesMut::with_capacity(message.encoded_len()); let mut buf = bytes::BytesMut::with_capacity(message.get_size());
codec.encode(message, &mut buf).unwrap() codec.encode(message, &mut buf).unwrap()
} }
} }

View File

@ -284,7 +284,7 @@ where
} }
// Converts a protobuf message into a gossipsub message for reading the Gossipsub event queue. // Converts a protobuf message into a gossipsub message for reading the Gossipsub event queue.
fn proto_to_message(rpc: &crate::rpc_proto::Rpc) -> Rpc { fn proto_to_message(rpc: &proto::RPC) -> Rpc {
// Store valid messages. // Store valid messages.
let mut messages = Vec::with_capacity(rpc.publish.len()); let mut messages = Vec::with_capacity(rpc.publish.len());
let rpc = rpc.clone(); let rpc = rpc.clone();

View File

@ -100,7 +100,7 @@ pub enum HandlerError {
#[error("Protocol negotiation failed.")] #[error("Protocol negotiation failed.")]
NegotiationProtocolError(ProtocolError), NegotiationProtocolError(ProtocolError),
#[error("Failed to encode or decode")] #[error("Failed to encode or decode")]
Codec(#[from] prost_codec::Error), Codec(#[from] quick_protobuf_codec::Error),
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -136,7 +136,7 @@ impl std::error::Error for ValidationError {}
impl From<std::io::Error> for HandlerError { impl From<std::io::Error> for HandlerError {
fn from(error: std::io::Error) -> HandlerError { fn from(error: std::io::Error) -> HandlerError {
HandlerError::Codec(prost_codec::Error::from(error)) HandlerError::Codec(quick_protobuf_codec::Error::from(error))
} }
} }

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod pb;

View File

@ -0,0 +1,67 @@
// Automatically generated rust module for 'compat.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Message {
pub from: Option<Vec<u8>>,
pub data: Option<Vec<u8>>,
pub seqno: Option<Vec<u8>>,
pub topic_ids: Vec<String>,
pub signature: Option<Vec<u8>>,
pub key: Option<Vec<u8>>,
}
impl<'a> MessageRead<'a> for Message {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.from = Some(r.read_bytes(bytes)?.to_owned()),
Ok(18) => msg.data = Some(r.read_bytes(bytes)?.to_owned()),
Ok(26) => msg.seqno = Some(r.read_bytes(bytes)?.to_owned()),
Ok(34) => msg.topic_ids.push(r.read_string(bytes)?.to_owned()),
Ok(42) => msg.signature = Some(r.read_bytes(bytes)?.to_owned()),
Ok(50) => msg.key = Some(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Message {
fn get_size(&self) -> usize {
0
+ self.from.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.data.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.seqno.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.topic_ids.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
+ self.signature.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.key.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.from { w.write_with_tag(10, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.data { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.seqno { w.write_with_tag(26, |w| w.write_bytes(&**s))?; }
for s in &self.topic_ids { w.write_with_tag(34, |w| w.write_string(&**s))?; }
if let Some(ref s) = self.signature { w.write_with_tag(42, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.key { w.write_with_tag(50, |w| w.write_bytes(&**s))?; }
Ok(())
}
}

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod pb;

View File

@ -0,0 +1,567 @@
// Automatically generated rust module for 'rpc.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct RPC {
pub subscriptions: Vec<gossipsub::pb::mod_RPC::SubOpts>,
pub publish: Vec<gossipsub::pb::Message>,
pub control: Option<gossipsub::pb::ControlMessage>,
}
impl<'a> MessageRead<'a> for RPC {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.subscriptions.push(r.read_message::<gossipsub::pb::mod_RPC::SubOpts>(bytes)?),
Ok(18) => msg.publish.push(r.read_message::<gossipsub::pb::Message>(bytes)?),
Ok(26) => msg.control = Some(r.read_message::<gossipsub::pb::ControlMessage>(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for RPC {
fn get_size(&self) -> usize {
0
+ self.subscriptions.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
+ self.publish.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
+ self.control.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
for s in &self.subscriptions { w.write_with_tag(10, |w| w.write_message(s))?; }
for s in &self.publish { w.write_with_tag(18, |w| w.write_message(s))?; }
if let Some(ref s) = self.control { w.write_with_tag(26, |w| w.write_message(s))?; }
Ok(())
}
}
pub mod mod_RPC {
use super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct SubOpts {
pub subscribe: Option<bool>,
pub topic_id: Option<String>,
}
impl<'a> MessageRead<'a> for SubOpts {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.subscribe = Some(r.read_bool(bytes)?),
Ok(18) => msg.topic_id = Some(r.read_string(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for SubOpts {
fn get_size(&self) -> usize {
0
+ self.subscribe.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64))
+ self.topic_id.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.subscribe { w.write_with_tag(8, |w| w.write_bool(*s))?; }
if let Some(ref s) = self.topic_id { w.write_with_tag(18, |w| w.write_string(&**s))?; }
Ok(())
}
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Message {
pub from: Option<Vec<u8>>,
pub data: Option<Vec<u8>>,
pub seqno: Option<Vec<u8>>,
pub topic: String,
pub signature: Option<Vec<u8>>,
pub key: Option<Vec<u8>>,
}
impl<'a> MessageRead<'a> for Message {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.from = Some(r.read_bytes(bytes)?.to_owned()),
Ok(18) => msg.data = Some(r.read_bytes(bytes)?.to_owned()),
Ok(26) => msg.seqno = Some(r.read_bytes(bytes)?.to_owned()),
Ok(34) => msg.topic = r.read_string(bytes)?.to_owned(),
Ok(42) => msg.signature = Some(r.read_bytes(bytes)?.to_owned()),
Ok(50) => msg.key = Some(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Message {
fn get_size(&self) -> usize {
0
+ self.from.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.data.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.seqno.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ 1 + sizeof_len((&self.topic).len())
+ self.signature.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.key.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.from { w.write_with_tag(10, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.data { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.seqno { w.write_with_tag(26, |w| w.write_bytes(&**s))?; }
w.write_with_tag(34, |w| w.write_string(&**&self.topic))?;
if let Some(ref s) = self.signature { w.write_with_tag(42, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.key { w.write_with_tag(50, |w| w.write_bytes(&**s))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct ControlMessage {
pub ihave: Vec<gossipsub::pb::ControlIHave>,
pub iwant: Vec<gossipsub::pb::ControlIWant>,
pub graft: Vec<gossipsub::pb::ControlGraft>,
pub prune: Vec<gossipsub::pb::ControlPrune>,
}
impl<'a> MessageRead<'a> for ControlMessage {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.ihave.push(r.read_message::<gossipsub::pb::ControlIHave>(bytes)?),
Ok(18) => msg.iwant.push(r.read_message::<gossipsub::pb::ControlIWant>(bytes)?),
Ok(26) => msg.graft.push(r.read_message::<gossipsub::pb::ControlGraft>(bytes)?),
Ok(34) => msg.prune.push(r.read_message::<gossipsub::pb::ControlPrune>(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for ControlMessage {
fn get_size(&self) -> usize {
0
+ self.ihave.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
+ self.iwant.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
+ self.graft.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
+ self.prune.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
for s in &self.ihave { w.write_with_tag(10, |w| w.write_message(s))?; }
for s in &self.iwant { w.write_with_tag(18, |w| w.write_message(s))?; }
for s in &self.graft { w.write_with_tag(26, |w| w.write_message(s))?; }
for s in &self.prune { w.write_with_tag(34, |w| w.write_message(s))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct ControlIHave {
pub topic_id: Option<String>,
pub message_ids: Vec<Vec<u8>>,
}
impl<'a> MessageRead<'a> for ControlIHave {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.topic_id = Some(r.read_string(bytes)?.to_owned()),
Ok(18) => msg.message_ids.push(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for ControlIHave {
fn get_size(&self) -> usize {
0
+ self.topic_id.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.message_ids.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.topic_id { w.write_with_tag(10, |w| w.write_string(&**s))?; }
for s in &self.message_ids { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct ControlIWant {
pub message_ids: Vec<Vec<u8>>,
}
impl<'a> MessageRead<'a> for ControlIWant {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.message_ids.push(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for ControlIWant {
fn get_size(&self) -> usize {
0
+ self.message_ids.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
for s in &self.message_ids { w.write_with_tag(10, |w| w.write_bytes(&**s))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct ControlGraft {
pub topic_id: Option<String>,
}
impl<'a> MessageRead<'a> for ControlGraft {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.topic_id = Some(r.read_string(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for ControlGraft {
fn get_size(&self) -> usize {
0
+ self.topic_id.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.topic_id { w.write_with_tag(10, |w| w.write_string(&**s))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct ControlPrune {
pub topic_id: Option<String>,
pub peers: Vec<gossipsub::pb::PeerInfo>,
pub backoff: Option<u64>,
}
impl<'a> MessageRead<'a> for ControlPrune {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.topic_id = Some(r.read_string(bytes)?.to_owned()),
Ok(18) => msg.peers.push(r.read_message::<gossipsub::pb::PeerInfo>(bytes)?),
Ok(24) => msg.backoff = Some(r.read_uint64(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for ControlPrune {
fn get_size(&self) -> usize {
0
+ self.topic_id.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.peers.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
+ self.backoff.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.topic_id { w.write_with_tag(10, |w| w.write_string(&**s))?; }
for s in &self.peers { w.write_with_tag(18, |w| w.write_message(s))?; }
if let Some(ref s) = self.backoff { w.write_with_tag(24, |w| w.write_uint64(*s))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct PeerInfo {
pub peer_id: Option<Vec<u8>>,
pub signed_peer_record: Option<Vec<u8>>,
}
impl<'a> MessageRead<'a> for PeerInfo {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.peer_id = Some(r.read_bytes(bytes)?.to_owned()),
Ok(18) => msg.signed_peer_record = Some(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for PeerInfo {
fn get_size(&self) -> usize {
0
+ self.peer_id.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.signed_peer_record.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.peer_id { w.write_with_tag(10, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.signed_peer_record { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct TopicDescriptor {
pub name: Option<String>,
pub auth: Option<gossipsub::pb::mod_TopicDescriptor::AuthOpts>,
pub enc: Option<gossipsub::pb::mod_TopicDescriptor::EncOpts>,
}
impl<'a> MessageRead<'a> for TopicDescriptor {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.name = Some(r.read_string(bytes)?.to_owned()),
Ok(18) => msg.auth = Some(r.read_message::<gossipsub::pb::mod_TopicDescriptor::AuthOpts>(bytes)?),
Ok(26) => msg.enc = Some(r.read_message::<gossipsub::pb::mod_TopicDescriptor::EncOpts>(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for TopicDescriptor {
fn get_size(&self) -> usize {
0
+ self.name.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.auth.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
+ self.enc.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.name { w.write_with_tag(10, |w| w.write_string(&**s))?; }
if let Some(ref s) = self.auth { w.write_with_tag(18, |w| w.write_message(s))?; }
if let Some(ref s) = self.enc { w.write_with_tag(26, |w| w.write_message(s))?; }
Ok(())
}
}
pub mod mod_TopicDescriptor {
use super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct AuthOpts {
pub mode: Option<gossipsub::pb::mod_TopicDescriptor::mod_AuthOpts::AuthMode>,
pub keys: Vec<Vec<u8>>,
}
impl<'a> MessageRead<'a> for AuthOpts {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.mode = Some(r.read_enum(bytes)?),
Ok(18) => msg.keys.push(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for AuthOpts {
fn get_size(&self) -> usize {
0
+ self.mode.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64))
+ self.keys.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.mode { w.write_with_tag(8, |w| w.write_enum(*s as i32))?; }
for s in &self.keys { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
Ok(())
}
}
pub mod mod_AuthOpts {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum AuthMode {
NONE = 0,
KEY = 1,
WOT = 2,
}
impl Default for AuthMode {
fn default() -> Self {
AuthMode::NONE
}
}
impl From<i32> for AuthMode {
fn from(i: i32) -> Self {
match i {
0 => AuthMode::NONE,
1 => AuthMode::KEY,
2 => AuthMode::WOT,
_ => Self::default(),
}
}
}
impl<'a> From<&'a str> for AuthMode {
fn from(s: &'a str) -> Self {
match s {
"NONE" => AuthMode::NONE,
"KEY" => AuthMode::KEY,
"WOT" => AuthMode::WOT,
_ => Self::default(),
}
}
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct EncOpts {
pub mode: Option<gossipsub::pb::mod_TopicDescriptor::mod_EncOpts::EncMode>,
pub key_hashes: Vec<Vec<u8>>,
}
impl<'a> MessageRead<'a> for EncOpts {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.mode = Some(r.read_enum(bytes)?),
Ok(18) => msg.key_hashes.push(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for EncOpts {
fn get_size(&self) -> usize {
0
+ self.mode.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64))
+ self.key_hashes.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.mode { w.write_with_tag(8, |w| w.write_enum(*s as i32))?; }
for s in &self.key_hashes { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
Ok(())
}
}
pub mod mod_EncOpts {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum EncMode {
NONE = 0,
SHAREDKEY = 1,
WOT = 2,
}
impl Default for EncMode {
fn default() -> Self {
EncMode::NONE
}
}
impl From<i32> for EncMode {
fn from(i: i32) -> Self {
match i {
0 => EncMode::NONE,
1 => EncMode::SHAREDKEY,
2 => EncMode::WOT,
_ => Self::default(),
}
}
}
impl<'a> From<&'a str> for EncMode {
fn from(s: &'a str) -> Self {
match s {
"NONE" => EncMode::NONE,
"SHAREDKEY" => EncMode::SHAREDKEY,
"WOT" => EncMode::WOT,
_ => Self::default(),
}
}
}
}
}

View File

@ -0,0 +1,3 @@
// Automatically generated mod.rs
pub mod compat;
pub mod gossipsub;

View File

@ -19,6 +19,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::protocol::{GossipsubCodec, ProtocolConfig}; use crate::protocol::{GossipsubCodec, ProtocolConfig};
use crate::rpc_proto::proto;
use crate::types::{PeerKind, RawMessage, Rpc}; use crate::types::{PeerKind, RawMessage, Rpc};
use crate::{HandlerError, ValidationError}; use crate::{HandlerError, ValidationError};
use asynchronous_codec::Framed; use asynchronous_codec::Framed;
@ -67,7 +68,7 @@ pub enum HandlerEvent {
#[derive(Debug)] #[derive(Debug)]
pub enum HandlerIn { pub enum HandlerIn {
/// A gossipsub message to send. /// A gossipsub message to send.
Message(crate::rpc_proto::Rpc), Message(proto::RPC),
/// The peer has joined the mesh. /// The peer has joined the mesh.
JoinedMesh, JoinedMesh,
/// The peer has left the mesh. /// The peer has left the mesh.
@ -93,7 +94,7 @@ pub struct Handler {
inbound_substream: Option<InboundSubstreamState>, inbound_substream: Option<InboundSubstreamState>,
/// Queue of values that we want to send to the remote. /// Queue of values that we want to send to the remote.
send_queue: SmallVec<[crate::rpc_proto::Rpc; 16]>, send_queue: SmallVec<[proto::RPC; 16]>,
/// Flag indicating that an outbound substream is being established to prevent duplicate /// Flag indicating that an outbound substream is being established to prevent duplicate
/// requests. /// requests.
@ -149,10 +150,7 @@ enum OutboundSubstreamState {
/// Waiting for the user to send a message. The idle state for an outbound substream. /// Waiting for the user to send a message. The idle state for an outbound substream.
WaitingOutput(Framed<NegotiatedSubstream, GossipsubCodec>), WaitingOutput(Framed<NegotiatedSubstream, GossipsubCodec>),
/// Waiting to send a message to the remote. /// Waiting to send a message to the remote.
PendingSend( PendingSend(Framed<NegotiatedSubstream, GossipsubCodec>, proto::RPC),
Framed<NegotiatedSubstream, GossipsubCodec>,
crate::rpc_proto::Rpc,
),
/// Waiting to flush the substream so that the data arrives to the remote. /// Waiting to flush the substream so that the data arrives to the remote.
PendingFlush(Framed<NegotiatedSubstream, GossipsubCodec>), PendingFlush(Framed<NegotiatedSubstream, GossipsubCodec>),
/// The substream is being closed. Used by either substream. /// The substream is being closed. Used by either substream.
@ -251,7 +249,7 @@ impl ConnectionHandler for Handler {
type Error = HandlerError; type Error = HandlerError;
type InboundOpenInfo = (); type InboundOpenInfo = ();
type InboundProtocol = ProtocolConfig; type InboundProtocol = ProtocolConfig;
type OutboundOpenInfo = crate::rpc_proto::Rpc; type OutboundOpenInfo = proto::RPC;
type OutboundProtocol = ProtocolConfig; type OutboundProtocol = ProtocolConfig;
fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, Self::InboundOpenInfo> { fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, Self::InboundOpenInfo> {

View File

@ -24,7 +24,7 @@ use crate::topic::TopicHash;
use crate::types::{ use crate::types::{
ControlAction, MessageId, PeerInfo, PeerKind, RawMessage, Rpc, Subscription, SubscriptionAction, ControlAction, MessageId, PeerInfo, PeerKind, RawMessage, Rpc, Subscription, SubscriptionAction,
}; };
use crate::{rpc_proto, Config}; use crate::{rpc_proto::proto, Config};
use crate::{HandlerError, ValidationError}; use crate::{HandlerError, ValidationError};
use asynchronous_codec::{Decoder, Encoder, Framed}; use asynchronous_codec::{Decoder, Encoder, Framed};
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
@ -35,7 +35,7 @@ use libp2p_core::{
identity::PublicKey, InboundUpgrade, OutboundUpgrade, PeerId, ProtocolName, UpgradeInfo, identity::PublicKey, InboundUpgrade, OutboundUpgrade, PeerId, ProtocolName, UpgradeInfo,
}; };
use log::{debug, warn}; use log::{debug, warn};
use prost::Message as _; use quick_protobuf::Writer;
use std::pin::Pin; use std::pin::Pin;
use unsigned_varint::codec; use unsigned_varint::codec;
@ -191,12 +191,12 @@ pub struct GossipsubCodec {
/// Determines the level of validation performed on incoming messages. /// Determines the level of validation performed on incoming messages.
validation_mode: ValidationMode, validation_mode: ValidationMode,
/// The codec to handle common encoding/decoding of protobuf messages /// The codec to handle common encoding/decoding of protobuf messages
codec: prost_codec::Codec<rpc_proto::Rpc>, codec: quick_protobuf_codec::Codec<proto::RPC>,
} }
impl GossipsubCodec { impl GossipsubCodec {
pub fn new(length_codec: codec::UviBytes, validation_mode: ValidationMode) -> GossipsubCodec { pub fn new(length_codec: codec::UviBytes, validation_mode: ValidationMode) -> GossipsubCodec {
let codec = prost_codec::Codec::new(length_codec.max_len()); let codec = quick_protobuf_codec::Codec::new(length_codec.max_len());
GossipsubCodec { GossipsubCodec {
validation_mode, validation_mode,
codec, codec,
@ -206,7 +206,9 @@ impl GossipsubCodec {
/// Verifies a gossipsub message. This returns either a success or failure. All errors /// Verifies a gossipsub message. This returns either a success or failure. All errors
/// are logged, which prevents error handling in the codec and handler. We simply drop invalid /// are logged, which prevents error handling in the codec and handler. We simply drop invalid
/// messages and log warnings, rather than propagating errors through the codec. /// messages and log warnings, rather than propagating errors through the codec.
fn verify_signature(message: &rpc_proto::Message) -> bool { fn verify_signature(message: &proto::Message) -> bool {
use quick_protobuf::MessageWrite;
let from = match message.from.as_ref() { let from = match message.from.as_ref() {
Some(v) => v, Some(v) => v,
None => { None => {
@ -258,10 +260,11 @@ impl GossipsubCodec {
let mut message_sig = message.clone(); let mut message_sig = message.clone();
message_sig.signature = None; message_sig.signature = None;
message_sig.key = None; message_sig.key = None;
let mut buf = Vec::with_capacity(message_sig.encoded_len()); let mut buf = Vec::with_capacity(message_sig.get_size());
let mut writer = Writer::new(&mut buf);
message_sig message_sig
.encode(&mut buf) .write_message(&mut writer)
.expect("Buffer has sufficient capacity"); .expect("Encoding to succeed");
let mut signature_bytes = SIGNING_PREFIX.to_vec(); let mut signature_bytes = SIGNING_PREFIX.to_vec();
signature_bytes.extend_from_slice(&buf); signature_bytes.extend_from_slice(&buf);
public_key.verify(&signature_bytes, signature) public_key.verify(&signature_bytes, signature)
@ -269,7 +272,7 @@ impl GossipsubCodec {
} }
impl Encoder for GossipsubCodec { impl Encoder for GossipsubCodec {
type Item = rpc_proto::Rpc; type Item = proto::RPC;
type Error = HandlerError; type Error = HandlerError;
fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), HandlerError> { fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), HandlerError> {

View File

@ -17,27 +17,26 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#![allow(clippy::derive_partial_eq_without_eq)]
include!(concat!(env!("OUT_DIR"), "/gossipsub.pb.rs")); pub mod proto {
include!("generated/mod.rs");
pub use self::gossipsub::pb::{mod_RPC::SubOpts, *};
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::rpc_proto::proto::compat;
use crate::IdentTopic as Topic; use crate::IdentTopic as Topic;
use libp2p_core::PeerId; use libp2p_core::PeerId;
use prost::Message; use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
use rand::Rng; use rand::Rng;
mod compat_proto {
include!(concat!(env!("OUT_DIR"), "/compat.pb.rs"));
}
#[test] #[test]
fn test_multi_topic_message_compatibility() { fn test_multi_topic_message_compatibility() {
let topic1 = Topic::new("t1").hash(); let topic1 = Topic::new("t1").hash();
let topic2 = Topic::new("t2").hash(); let topic2 = Topic::new("t2").hash();
let new_message1 = super::Message { let new_message1 = super::proto::Message {
from: Some(PeerId::random().to_bytes()), from: Some(PeerId::random().to_bytes()),
data: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), data: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()),
seqno: Some(rand::thread_rng().gen::<[u8; 8]>().to_vec()), seqno: Some(rand::thread_rng().gen::<[u8; 8]>().to_vec()),
@ -45,7 +44,7 @@ mod test {
signature: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), signature: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()),
key: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), key: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()),
}; };
let old_message1 = compat_proto::Message { let old_message1 = compat::pb::Message {
from: Some(PeerId::random().to_bytes()), from: Some(PeerId::random().to_bytes()),
data: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), data: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()),
seqno: Some(rand::thread_rng().gen::<[u8; 8]>().to_vec()), seqno: Some(rand::thread_rng().gen::<[u8; 8]>().to_vec()),
@ -53,7 +52,7 @@ mod test {
signature: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), signature: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()),
key: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), key: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()),
}; };
let old_message2 = compat_proto::Message { let old_message2 = compat::pb::Message {
from: Some(PeerId::random().to_bytes()), from: Some(PeerId::random().to_bytes()),
data: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), data: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()),
seqno: Some(rand::thread_rng().gen::<[u8; 8]>().to_vec()), seqno: Some(rand::thread_rng().gen::<[u8; 8]>().to_vec()),
@ -62,22 +61,31 @@ mod test {
key: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), key: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()),
}; };
let mut new_message1b = Vec::with_capacity(new_message1.encoded_len()); let mut new_message1b = Vec::with_capacity(new_message1.get_size());
new_message1.encode(&mut new_message1b).unwrap(); let mut writer = Writer::new(&mut new_message1b);
new_message1.write_message(&mut writer).unwrap();
let mut old_message1b = Vec::with_capacity(old_message1.encoded_len()); let mut old_message1b = Vec::with_capacity(old_message1.get_size());
old_message1.encode(&mut old_message1b).unwrap(); let mut writer = Writer::new(&mut old_message1b);
old_message1.write_message(&mut writer).unwrap();
let mut old_message2b = Vec::with_capacity(old_message2.encoded_len()); let mut old_message2b = Vec::with_capacity(old_message2.get_size());
old_message2.encode(&mut old_message2b).unwrap(); let mut writer = Writer::new(&mut old_message2b);
old_message2.write_message(&mut writer).unwrap();
let new_message = super::Message::decode(&old_message1b[..]).unwrap(); let mut reader = BytesReader::from_bytes(&old_message1b[..]);
let new_message =
super::proto::Message::from_reader(&mut reader, &old_message1b[..]).unwrap();
assert_eq!(new_message.topic, topic1.clone().into_string()); assert_eq!(new_message.topic, topic1.clone().into_string());
let new_message = super::Message::decode(&old_message2b[..]).unwrap(); let mut reader = BytesReader::from_bytes(&old_message2b[..]);
let new_message =
super::proto::Message::from_reader(&mut reader, &old_message2b[..]).unwrap();
assert_eq!(new_message.topic, topic2.into_string()); assert_eq!(new_message.topic, topic2.into_string());
let old_message = compat_proto::Message::decode(&new_message1b[..]).unwrap(); let mut reader = BytesReader::from_bytes(&new_message1b[..]);
let old_message =
compat::pb::Message::from_reader(&mut reader, &new_message1b[..]).unwrap();
assert_eq!(old_message.topic_ids, vec![topic1.into_string()]); assert_eq!(old_message.topic_ids, vec![topic1.into_string()]);
} }
} }

View File

@ -18,10 +18,10 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::rpc_proto; use crate::rpc_proto::proto;
use base64::prelude::*; use base64::prelude::*;
use prometheus_client::encoding::EncodeLabelSet; use prometheus_client::encoding::EncodeLabelSet;
use prost::Message; use quick_protobuf::Writer;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::fmt; use std::fmt;
@ -47,15 +47,18 @@ impl Hasher for Sha256Hash {
/// Creates a [`TopicHash`] by SHA256 hashing the topic then base64 encoding the /// Creates a [`TopicHash`] by SHA256 hashing the topic then base64 encoding the
/// hash. /// hash.
fn hash(topic_string: String) -> TopicHash { fn hash(topic_string: String) -> TopicHash {
let topic_descripter = rpc_proto::TopicDescriptor { use quick_protobuf::MessageWrite;
let topic_descripter = proto::TopicDescriptor {
name: Some(topic_string), name: Some(topic_string),
auth: None, auth: None,
enc: None, enc: None,
}; };
let mut bytes = Vec::with_capacity(topic_descripter.encoded_len()); let mut bytes = Vec::with_capacity(topic_descripter.get_size());
let mut writer = Writer::new(&mut bytes);
topic_descripter topic_descripter
.encode(&mut bytes) .write_message(&mut writer)
.expect("buffer is large enough"); .expect("Encoding to succeed");
let hash = BASE64_STANDARD.encode(Sha256::digest(&bytes)); let hash = BASE64_STANDARD.encode(Sha256::digest(&bytes));
TopicHash { hash } TopicHash { hash }
} }

View File

@ -19,15 +19,15 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
//! A collection of types using the Gossipsub system. //! A collection of types using the Gossipsub system.
use crate::rpc_proto;
use crate::TopicHash; use crate::TopicHash;
use libp2p_core::PeerId; use libp2p_core::PeerId;
use libp2p_swarm::ConnectionId; use libp2p_swarm::ConnectionId;
use prometheus_client::encoding::EncodeLabelValue; use prometheus_client::encoding::EncodeLabelValue;
use prost::Message as _; use quick_protobuf::MessageWrite;
use std::fmt; use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
use crate::rpc_proto::proto;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -136,7 +136,7 @@ pub struct RawMessage {
impl RawMessage { impl RawMessage {
/// Calculates the encoded length of this message (used for calculating metrics). /// Calculates the encoded length of this message (used for calculating metrics).
pub fn raw_protobuf_len(&self) -> usize { pub fn raw_protobuf_len(&self) -> usize {
let message = rpc_proto::Message { let message = proto::Message {
from: self.source.map(|m| m.to_bytes()), from: self.source.map(|m| m.to_bytes()),
data: Some(self.data.clone()), data: Some(self.data.clone()),
seqno: self.sequence_number.map(|s| s.to_be_bytes().to_vec()), seqno: self.sequence_number.map(|s| s.to_be_bytes().to_vec()),
@ -144,7 +144,7 @@ impl RawMessage {
signature: self.signature.clone(), signature: self.signature.clone(),
key: self.key.clone(), key: self.key.clone(),
}; };
message.encoded_len() message.get_size()
} }
} }
@ -250,19 +250,19 @@ pub struct Rpc {
impl Rpc { impl Rpc {
/// Converts the GossipsubRPC into its protobuf format. /// Converts the GossipsubRPC into its protobuf format.
// A convenience function to avoid explicitly specifying types. // A convenience function to avoid explicitly specifying types.
pub fn into_protobuf(self) -> rpc_proto::Rpc { pub fn into_protobuf(self) -> proto::RPC {
self.into() self.into()
} }
} }
impl From<Rpc> for rpc_proto::Rpc { impl From<Rpc> for proto::RPC {
/// Converts the RPC into protobuf format. /// Converts the RPC into protobuf format.
fn from(rpc: Rpc) -> Self { fn from(rpc: Rpc) -> Self {
// Messages // Messages
let mut publish = Vec::new(); let mut publish = Vec::new();
for message in rpc.messages.into_iter() { for message in rpc.messages.into_iter() {
let message = rpc_proto::Message { let message = proto::Message {
from: message.source.map(|m| m.to_bytes()), from: message.source.map(|m| m.to_bytes()),
data: Some(message.data), data: Some(message.data),
seqno: message.sequence_number.map(|s| s.to_be_bytes().to_vec()), seqno: message.sequence_number.map(|s| s.to_be_bytes().to_vec()),
@ -278,14 +278,14 @@ impl From<Rpc> for rpc_proto::Rpc {
let subscriptions = rpc let subscriptions = rpc
.subscriptions .subscriptions
.into_iter() .into_iter()
.map(|sub| rpc_proto::rpc::SubOpts { .map(|sub| proto::SubOpts {
subscribe: Some(sub.action == SubscriptionAction::Subscribe), subscribe: Some(sub.action == SubscriptionAction::Subscribe),
topic_id: Some(sub.topic_hash.into_string()), topic_id: Some(sub.topic_hash.into_string()),
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// control messages // control messages
let mut control = rpc_proto::ControlMessage { let mut control = proto::ControlMessage {
ihave: Vec::new(), ihave: Vec::new(),
iwant: Vec::new(), iwant: Vec::new(),
graft: Vec::new(), graft: Vec::new(),
@ -301,20 +301,20 @@ impl From<Rpc> for rpc_proto::Rpc {
topic_hash, topic_hash,
message_ids, message_ids,
} => { } => {
let rpc_ihave = rpc_proto::ControlIHave { let rpc_ihave = proto::ControlIHave {
topic_id: Some(topic_hash.into_string()), topic_id: Some(topic_hash.into_string()),
message_ids: message_ids.into_iter().map(|msg_id| msg_id.0).collect(), message_ids: message_ids.into_iter().map(|msg_id| msg_id.0).collect(),
}; };
control.ihave.push(rpc_ihave); control.ihave.push(rpc_ihave);
} }
ControlAction::IWant { message_ids } => { ControlAction::IWant { message_ids } => {
let rpc_iwant = rpc_proto::ControlIWant { let rpc_iwant = proto::ControlIWant {
message_ids: message_ids.into_iter().map(|msg_id| msg_id.0).collect(), message_ids: message_ids.into_iter().map(|msg_id| msg_id.0).collect(),
}; };
control.iwant.push(rpc_iwant); control.iwant.push(rpc_iwant);
} }
ControlAction::Graft { topic_hash } => { ControlAction::Graft { topic_hash } => {
let rpc_graft = rpc_proto::ControlGraft { let rpc_graft = proto::ControlGraft {
topic_id: Some(topic_hash.into_string()), topic_id: Some(topic_hash.into_string()),
}; };
control.graft.push(rpc_graft); control.graft.push(rpc_graft);
@ -324,11 +324,11 @@ impl From<Rpc> for rpc_proto::Rpc {
peers, peers,
backoff, backoff,
} => { } => {
let rpc_prune = rpc_proto::ControlPrune { let rpc_prune = proto::ControlPrune {
topic_id: Some(topic_hash.into_string()), topic_id: Some(topic_hash.into_string()),
peers: peers peers: peers
.into_iter() .into_iter()
.map(|info| rpc_proto::PeerInfo { .map(|info| proto::PeerInfo {
peer_id: info.peer_id.map(|id| id.to_bytes()), peer_id: info.peer_id.map(|id| id.to_bytes()),
/// TODO, see https://github.com/libp2p/specs/pull/217 /// TODO, see https://github.com/libp2p/specs/pull/217
signed_peer_record: None, signed_peer_record: None,
@ -341,7 +341,7 @@ impl From<Rpc> for rpc_proto::Rpc {
} }
} }
rpc_proto::Rpc { proto::RPC {
subscriptions, subscriptions,
publish, publish,
control: if empty_control_msg { control: if empty_control_msg {

View File

@ -9,8 +9,11 @@
- Don't close the stream when reading the identify info in `protocol::recv`. See [PR 3344]. - Don't close the stream when reading the identify info in `protocol::recv`. See [PR 3344].
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[PR 3208]: https://github.com/libp2p/rust-libp2p/pull/3208 [PR 3208]: https://github.com/libp2p/rust-libp2p/pull/3208
[PR 3344]: https://github.com/libp2p/rust-libp2p/pull/3344 [PR 3344]: https://github.com/libp2p/rust-libp2p/pull/3344
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
# 0.41.1 # 0.41.1

View File

@ -18,8 +18,8 @@ libp2p-core = { version = "0.39.0", path = "../../core" }
libp2p-swarm = { version = "0.42.0", path = "../../swarm" } libp2p-swarm = { version = "0.42.0", path = "../../swarm" }
log = "0.4.1" log = "0.4.1"
lru = "0.9.0" lru = "0.9.0"
prost-codec = { version = "0.3", path = "../../misc/prost-codec" } quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" }
prost = "0.11" quick-protobuf = "0.8"
smallvec = "1.6.1" smallvec = "1.6.1"
thiserror = "1.0" thiserror = "1.0"
void = "1.0" void = "1.0"
@ -34,9 +34,6 @@ libp2p-noise = { path = "../../transports/noise" }
libp2p-swarm = { path = "../../swarm", features = ["async-std"] } libp2p-swarm = { path = "../../swarm", features = ["async-std"] }
libp2p-tcp = { path = "../../transports/tcp", features = ["async-io"] } libp2p-tcp = { path = "../../transports/tcp", features = ["async-io"] }
[build-dependencies]
prost-build = "0.11"
# Passing arguments to the docsrs builder in order to properly document cfg's. # Passing arguments to the docsrs builder in order to properly document cfg's.
# More information: https://docs.rs/about/builds#cross-compiling # More information: https://docs.rs/about/builds#cross-compiling
[package.metadata.docs.rs] [package.metadata.docs.rs]

View File

@ -1,23 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
fn main() {
prost_build::compile_protos(&["src/structs.proto"], &["src"]).unwrap();
}

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod structs;

View File

@ -0,0 +1,67 @@
// Automatically generated rust module for 'structs.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Identify {
pub protocolVersion: Option<String>,
pub agentVersion: Option<String>,
pub publicKey: Option<Vec<u8>>,
pub listenAddrs: Vec<Vec<u8>>,
pub observedAddr: Option<Vec<u8>>,
pub protocols: Vec<String>,
}
impl<'a> MessageRead<'a> for Identify {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(42) => msg.protocolVersion = Some(r.read_string(bytes)?.to_owned()),
Ok(50) => msg.agentVersion = Some(r.read_string(bytes)?.to_owned()),
Ok(10) => msg.publicKey = Some(r.read_bytes(bytes)?.to_owned()),
Ok(18) => msg.listenAddrs.push(r.read_bytes(bytes)?.to_owned()),
Ok(34) => msg.observedAddr = Some(r.read_bytes(bytes)?.to_owned()),
Ok(26) => msg.protocols.push(r.read_string(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Identify {
fn get_size(&self) -> usize {
0
+ self.protocolVersion.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.agentVersion.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.publicKey.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.listenAddrs.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
+ self.observedAddr.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.protocols.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.protocolVersion { w.write_with_tag(42, |w| w.write_string(&**s))?; }
if let Some(ref s) = self.agentVersion { w.write_with_tag(50, |w| w.write_string(&**s))?; }
if let Some(ref s) = self.publicKey { w.write_with_tag(10, |w| w.write_bytes(&**s))?; }
for s in &self.listenAddrs { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.observedAddr { w.write_with_tag(34, |w| w.write_bytes(&**s))?; }
for s in &self.protocols { w.write_with_tag(26, |w| w.write_string(&**s))?; }
Ok(())
}
}

View File

@ -69,7 +69,7 @@ mod behaviour;
mod handler; mod handler;
mod protocol; mod protocol;
#[allow(clippy::derive_partial_eq_without_eq)] mod proto {
mod structs_proto { include!("generated/mod.rs");
include!(concat!(env!("OUT_DIR"), "/structs.rs")); pub use self::structs::Identify;
} }

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod structs;

View File

@ -18,7 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::structs_proto; use crate::proto;
use asynchronous_codec::{FramedRead, FramedWrite}; use asynchronous_codec::{FramedRead, FramedWrite};
use futures::{future::BoxFuture, prelude::*}; use futures::{future::BoxFuture, prelude::*};
use libp2p_core::{ use libp2p_core::{
@ -169,18 +169,18 @@ where
let pubkey_bytes = info.public_key.to_protobuf_encoding(); let pubkey_bytes = info.public_key.to_protobuf_encoding();
let message = structs_proto::Identify { let message = proto::Identify {
agent_version: Some(info.agent_version), agentVersion: Some(info.agent_version),
protocol_version: Some(info.protocol_version), protocolVersion: Some(info.protocol_version),
public_key: Some(pubkey_bytes), publicKey: Some(pubkey_bytes),
listen_addrs, listenAddrs: listen_addrs,
observed_addr: Some(info.observed_addr.to_vec()), observedAddr: Some(info.observed_addr.to_vec()),
protocols: info.protocols, protocols: info.protocols,
}; };
let mut framed_io = FramedWrite::new( let mut framed_io = FramedWrite::new(
io, io,
prost_codec::Codec::<structs_proto::Identify>::new(MAX_MESSAGE_SIZE_BYTES), quick_protobuf_codec::Codec::<proto::Identify>::new(MAX_MESSAGE_SIZE_BYTES),
); );
framed_io.send(message).await?; framed_io.send(message).await?;
@ -200,7 +200,7 @@ where
let info = FramedRead::new( let info = FramedRead::new(
socket, socket,
prost_codec::Codec::<structs_proto::Identify>::new(MAX_MESSAGE_SIZE_BYTES), quick_protobuf_codec::Codec::<proto::Identify>::new(MAX_MESSAGE_SIZE_BYTES),
) )
.next() .next()
.await .await
@ -212,17 +212,17 @@ where
Ok(info) Ok(info)
} }
impl TryFrom<structs_proto::Identify> for Info { impl TryFrom<proto::Identify> for Info {
type Error = UpgradeError; type Error = UpgradeError;
fn try_from(msg: structs_proto::Identify) -> Result<Self, Self::Error> { fn try_from(msg: proto::Identify) -> Result<Self, Self::Error> {
fn parse_multiaddr(bytes: Vec<u8>) -> Result<Multiaddr, multiaddr::Error> { fn parse_multiaddr(bytes: Vec<u8>) -> Result<Multiaddr, multiaddr::Error> {
Multiaddr::try_from(bytes) Multiaddr::try_from(bytes)
} }
let listen_addrs = { let listen_addrs = {
let mut addrs = Vec::new(); let mut addrs = Vec::new();
for addr in msg.listen_addrs.into_iter() { for addr in msg.listenAddrs.into_iter() {
match parse_multiaddr(addr) { match parse_multiaddr(addr) {
Ok(a) => addrs.push(a), Ok(a) => addrs.push(a),
Err(e) => { Err(e) => {
@ -233,9 +233,9 @@ impl TryFrom<structs_proto::Identify> for Info {
addrs addrs
}; };
let public_key = PublicKey::from_protobuf_encoding(&msg.public_key.unwrap_or_default())?; let public_key = PublicKey::from_protobuf_encoding(&msg.publicKey.unwrap_or_default())?;
let observed_addr = match parse_multiaddr(msg.observed_addr.unwrap_or_default()) { let observed_addr = match parse_multiaddr(msg.observedAddr.unwrap_or_default()) {
Ok(a) => a, Ok(a) => a,
Err(e) => { Err(e) => {
debug!("Unable to parse multiaddr: {e:?}"); debug!("Unable to parse multiaddr: {e:?}");
@ -244,8 +244,8 @@ impl TryFrom<structs_proto::Identify> for Info {
}; };
let info = Info { let info = Info {
public_key, public_key,
protocol_version: msg.protocol_version.unwrap_or_default(), protocol_version: msg.protocolVersion.unwrap_or_default(),
agent_version: msg.agent_version.unwrap_or_default(), agent_version: msg.agentVersion.unwrap_or_default(),
listen_addrs, listen_addrs,
protocols: msg.protocols, protocols: msg.protocols,
observed_addr, observed_addr,
@ -258,7 +258,7 @@ impl TryFrom<structs_proto::Identify> for Info {
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum UpgradeError { pub enum UpgradeError {
#[error(transparent)] #[error(transparent)]
Codec(#[from] prost_codec::Error), Codec(#[from] quick_protobuf_codec::Error),
#[error("I/O interaction failed")] #[error("I/O interaction failed")]
Io(#[from] io::Error), Io(#[from] io::Error),
#[error("Stream closed")] #[error("Stream closed")]
@ -375,13 +375,13 @@ mod tests {
a a
}; };
let payload = structs_proto::Identify { let payload = proto::Identify {
agent_version: None, agentVersion: None,
listen_addrs: vec![valid_multiaddr_bytes, invalid_multiaddr], listenAddrs: vec![valid_multiaddr_bytes, invalid_multiaddr],
observed_addr: None, observedAddr: None,
protocol_version: None, protocolVersion: None,
protocols: vec![], protocols: vec![],
public_key: Some( publicKey: Some(
identity::Keypair::generate_ed25519() identity::Keypair::generate_ed25519()
.public() .public()
.to_protobuf_encoding(), .to_protobuf_encoding(),

View File

@ -0,0 +1,67 @@
// Automatically generated rust module for 'structs.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Identify {
pub protocolVersion: Option<String>,
pub agentVersion: Option<String>,
pub publicKey: Option<Vec<u8>>,
pub listenAddrs: Vec<Vec<u8>>,
pub observedAddr: Option<Vec<u8>>,
pub protocols: Vec<String>,
}
impl<'a> MessageRead<'a> for Identify {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(42) => msg.protocolVersion = Some(r.read_string(bytes)?.to_owned()),
Ok(50) => msg.agentVersion = Some(r.read_string(bytes)?.to_owned()),
Ok(10) => msg.publicKey = Some(r.read_bytes(bytes)?.to_owned()),
Ok(18) => msg.listenAddrs.push(r.read_bytes(bytes)?.to_owned()),
Ok(34) => msg.observedAddr = Some(r.read_bytes(bytes)?.to_owned()),
Ok(26) => msg.protocols.push(r.read_string(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Identify {
fn get_size(&self) -> usize {
0
+ self.protocolVersion.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.agentVersion.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.publicKey.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.listenAddrs.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
+ self.observedAddr.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
+ self.protocols.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.protocolVersion { w.write_with_tag(42, |w| w.write_string(&**s))?; }
if let Some(ref s) = self.agentVersion { w.write_with_tag(50, |w| w.write_string(&**s))?; }
if let Some(ref s) = self.publicKey { w.write_with_tag(10, |w| w.write_bytes(&**s))?; }
for s in &self.listenAddrs { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.observedAddr { w.write_with_tag(34, |w| w.write_bytes(&**s))?; }
for s in &self.protocols { w.write_with_tag(26, |w| w.write_string(&**s))?; }
Ok(())
}
}

View File

@ -10,8 +10,11 @@
- Bump MSRV to 1.65.0. - Bump MSRV to 1.65.0.
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[PR 3239]: https://github.com/libp2p/rust-libp2p/pull/3239 [PR 3239]: https://github.com/libp2p/rust-libp2p/pull/3239
[PR 3287]: https://github.com/libp2p/rust-libp2p/pull/3287 [PR 3287]: https://github.com/libp2p/rust-libp2p/pull/3287
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
# 0.42.1 # 0.42.1

View File

@ -20,7 +20,7 @@ futures = "0.3.26"
log = "0.4" log = "0.4"
libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-core = { version = "0.39.0", path = "../../core" }
libp2p-swarm = { version = "0.42.0", path = "../../swarm" } libp2p-swarm = { version = "0.42.0", path = "../../swarm" }
prost = "0.11" quick-protobuf = "0.8"
rand = "0.8" rand = "0.8"
sha2 = "0.10.0" sha2 = "0.10.0"
smallvec = "1.6.1" smallvec = "1.6.1"
@ -39,9 +39,6 @@ libp2p-noise = { path = "../../transports/noise" }
libp2p-yamux = { path = "../../muxers/yamux" } libp2p-yamux = { path = "../../muxers/yamux" }
quickcheck = { package = "quickcheck-ext", path = "../../misc/quickcheck-ext" } quickcheck = { package = "quickcheck-ext", path = "../../misc/quickcheck-ext" }
[build-dependencies]
prost-build = "0.11"
[features] [features]
serde = ["dep:serde", "bytes/serde"] serde = ["dep:serde", "bytes/serde"]

View File

@ -1,23 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
fn main() {
prost_build::compile_protos(&["src/dht.proto"], &["src"]).unwrap();
}

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod pb;

View File

@ -0,0 +1,243 @@
// Automatically generated rust module for 'dht.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Record {
pub key: Vec<u8>,
pub value: Vec<u8>,
pub timeReceived: String,
pub publisher: Vec<u8>,
pub ttl: u32,
}
impl<'a> MessageRead<'a> for Record {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.key = r.read_bytes(bytes)?.to_owned(),
Ok(18) => msg.value = r.read_bytes(bytes)?.to_owned(),
Ok(42) => msg.timeReceived = r.read_string(bytes)?.to_owned(),
Ok(5330) => msg.publisher = r.read_bytes(bytes)?.to_owned(),
Ok(6216) => msg.ttl = r.read_uint32(bytes)?,
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Record {
fn get_size(&self) -> usize {
0
+ if self.key.is_empty() { 0 } else { 1 + sizeof_len((&self.key).len()) }
+ if self.value.is_empty() { 0 } else { 1 + sizeof_len((&self.value).len()) }
+ if self.timeReceived == String::default() { 0 } else { 1 + sizeof_len((&self.timeReceived).len()) }
+ if self.publisher.is_empty() { 0 } else { 2 + sizeof_len((&self.publisher).len()) }
+ if self.ttl == 0u32 { 0 } else { 2 + sizeof_varint(*(&self.ttl) as u64) }
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if !self.key.is_empty() { w.write_with_tag(10, |w| w.write_bytes(&**&self.key))?; }
if !self.value.is_empty() { w.write_with_tag(18, |w| w.write_bytes(&**&self.value))?; }
if self.timeReceived != String::default() { w.write_with_tag(42, |w| w.write_string(&**&self.timeReceived))?; }
if !self.publisher.is_empty() { w.write_with_tag(5330, |w| w.write_bytes(&**&self.publisher))?; }
if self.ttl != 0u32 { w.write_with_tag(6216, |w| w.write_uint32(*&self.ttl))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Message {
pub type_pb: dht::pb::mod_Message::MessageType,
pub clusterLevelRaw: i32,
pub key: Vec<u8>,
pub record: Option<dht::pb::Record>,
pub closerPeers: Vec<dht::pb::mod_Message::Peer>,
pub providerPeers: Vec<dht::pb::mod_Message::Peer>,
}
impl<'a> MessageRead<'a> for Message {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.type_pb = r.read_enum(bytes)?,
Ok(80) => msg.clusterLevelRaw = r.read_int32(bytes)?,
Ok(18) => msg.key = r.read_bytes(bytes)?.to_owned(),
Ok(26) => msg.record = Some(r.read_message::<dht::pb::Record>(bytes)?),
Ok(66) => msg.closerPeers.push(r.read_message::<dht::pb::mod_Message::Peer>(bytes)?),
Ok(74) => msg.providerPeers.push(r.read_message::<dht::pb::mod_Message::Peer>(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Message {
fn get_size(&self) -> usize {
0
+ if self.type_pb == dht::pb::mod_Message::MessageType::PUT_VALUE { 0 } else { 1 + sizeof_varint(*(&self.type_pb) as u64) }
+ if self.clusterLevelRaw == 0i32 { 0 } else { 1 + sizeof_varint(*(&self.clusterLevelRaw) as u64) }
+ if self.key.is_empty() { 0 } else { 1 + sizeof_len((&self.key).len()) }
+ self.record.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
+ self.closerPeers.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
+ self.providerPeers.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if self.type_pb != dht::pb::mod_Message::MessageType::PUT_VALUE { w.write_with_tag(8, |w| w.write_enum(*&self.type_pb as i32))?; }
if self.clusterLevelRaw != 0i32 { w.write_with_tag(80, |w| w.write_int32(*&self.clusterLevelRaw))?; }
if !self.key.is_empty() { w.write_with_tag(18, |w| w.write_bytes(&**&self.key))?; }
if let Some(ref s) = self.record { w.write_with_tag(26, |w| w.write_message(s))?; }
for s in &self.closerPeers { w.write_with_tag(66, |w| w.write_message(s))?; }
for s in &self.providerPeers { w.write_with_tag(74, |w| w.write_message(s))?; }
Ok(())
}
}
pub mod mod_Message {
use super::*;
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Peer {
pub id: Vec<u8>,
pub addrs: Vec<Vec<u8>>,
pub connection: dht::pb::mod_Message::ConnectionType,
}
impl<'a> MessageRead<'a> for Peer {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.id = r.read_bytes(bytes)?.to_owned(),
Ok(18) => msg.addrs.push(r.read_bytes(bytes)?.to_owned()),
Ok(24) => msg.connection = r.read_enum(bytes)?,
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Peer {
fn get_size(&self) -> usize {
0
+ if self.id.is_empty() { 0 } else { 1 + sizeof_len((&self.id).len()) }
+ self.addrs.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
+ if self.connection == dht::pb::mod_Message::ConnectionType::NOT_CONNECTED { 0 } else { 1 + sizeof_varint(*(&self.connection) as u64) }
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if !self.id.is_empty() { w.write_with_tag(10, |w| w.write_bytes(&**&self.id))?; }
for s in &self.addrs { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
if self.connection != dht::pb::mod_Message::ConnectionType::NOT_CONNECTED { w.write_with_tag(24, |w| w.write_enum(*&self.connection as i32))?; }
Ok(())
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MessageType {
PUT_VALUE = 0,
GET_VALUE = 1,
ADD_PROVIDER = 2,
GET_PROVIDERS = 3,
FIND_NODE = 4,
PING = 5,
}
impl Default for MessageType {
fn default() -> Self {
MessageType::PUT_VALUE
}
}
impl From<i32> for MessageType {
fn from(i: i32) -> Self {
match i {
0 => MessageType::PUT_VALUE,
1 => MessageType::GET_VALUE,
2 => MessageType::ADD_PROVIDER,
3 => MessageType::GET_PROVIDERS,
4 => MessageType::FIND_NODE,
5 => MessageType::PING,
_ => Self::default(),
}
}
}
impl<'a> From<&'a str> for MessageType {
fn from(s: &'a str) -> Self {
match s {
"PUT_VALUE" => MessageType::PUT_VALUE,
"GET_VALUE" => MessageType::GET_VALUE,
"ADD_PROVIDER" => MessageType::ADD_PROVIDER,
"GET_PROVIDERS" => MessageType::GET_PROVIDERS,
"FIND_NODE" => MessageType::FIND_NODE,
"PING" => MessageType::PING,
_ => Self::default(),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ConnectionType {
NOT_CONNECTED = 0,
CONNECTED = 1,
CAN_CONNECT = 2,
CANNOT_CONNECT = 3,
}
impl Default for ConnectionType {
fn default() -> Self {
ConnectionType::NOT_CONNECTED
}
}
impl From<i32> for ConnectionType {
fn from(i: i32) -> Self {
match i {
0 => ConnectionType::NOT_CONNECTED,
1 => ConnectionType::CONNECTED,
2 => ConnectionType::CAN_CONNECT,
3 => ConnectionType::CANNOT_CONNECT,
_ => Self::default(),
}
}
}
impl<'a> From<&'a str> for ConnectionType {
fn from(s: &'a str) -> Self {
match s {
"NOT_CONNECTED" => ConnectionType::NOT_CONNECTED,
"CONNECTED" => ConnectionType::CONNECTED,
"CAN_CONNECT" => ConnectionType::CAN_CONNECT,
"CANNOT_CONNECT" => ConnectionType::CANNOT_CONNECT,
_ => Self::default(),
}
}
}
}

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod dht;

View File

@ -48,9 +48,12 @@ mod behaviour;
mod jobs; mod jobs;
mod query; mod query;
#[allow(clippy::derive_partial_eq_without_eq)] mod proto {
mod dht_proto { include!("generated/mod.rs");
include!(concat!(env!("OUT_DIR"), "/dht.pb.rs")); pub use self::dht::pb::{
mod_Message::{ConnectionType, MessageType, Peer},
Message, Record,
};
} }
pub use addresses::Addresses; pub use addresses::Addresses;

View File

@ -26,7 +26,7 @@
//! to poll the underlying transport for incoming messages, and the `Sink` component //! to poll the underlying transport for incoming messages, and the `Sink` component
//! is used to send messages to remote peers. //! is used to send messages to remote peers.
use crate::dht_proto as proto; use crate::proto;
use crate::record::{self, Record}; use crate::record::{self, Record};
use asynchronous_codec::Framed; use asynchronous_codec::Framed;
use bytes::BytesMut; use bytes::BytesMut;
@ -35,7 +35,7 @@ use futures::prelude::*;
use instant::Instant; use instant::Instant;
use libp2p_core::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use libp2p_core::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
use libp2p_core::{Multiaddr, PeerId}; use libp2p_core::{Multiaddr, PeerId};
use prost::Message; use quick_protobuf::{BytesReader, Writer};
use std::{borrow::Cow, convert::TryFrom, time::Duration}; use std::{borrow::Cow, convert::TryFrom, time::Duration};
use std::{io, iter}; use std::{io, iter};
use unsigned_varint::codec; use unsigned_varint::codec;
@ -59,26 +59,26 @@ pub enum KadConnectionType {
CannotConnect = 3, CannotConnect = 3,
} }
impl From<proto::message::ConnectionType> for KadConnectionType { impl From<proto::ConnectionType> for KadConnectionType {
fn from(raw: proto::message::ConnectionType) -> KadConnectionType { fn from(raw: proto::ConnectionType) -> KadConnectionType {
use proto::message::ConnectionType::*; use proto::ConnectionType::*;
match raw { match raw {
NotConnected => KadConnectionType::NotConnected, NOT_CONNECTED => KadConnectionType::NotConnected,
Connected => KadConnectionType::Connected, CONNECTED => KadConnectionType::Connected,
CanConnect => KadConnectionType::CanConnect, CAN_CONNECT => KadConnectionType::CanConnect,
CannotConnect => KadConnectionType::CannotConnect, CANNOT_CONNECT => KadConnectionType::CannotConnect,
} }
} }
} }
impl From<KadConnectionType> for proto::message::ConnectionType { impl From<KadConnectionType> for proto::ConnectionType {
fn from(val: KadConnectionType) -> Self { fn from(val: KadConnectionType) -> Self {
use proto::message::ConnectionType::*; use proto::ConnectionType::*;
match val { match val {
KadConnectionType::NotConnected => NotConnected, KadConnectionType::NotConnected => NOT_CONNECTED,
KadConnectionType::Connected => Connected, KadConnectionType::Connected => CONNECTED,
KadConnectionType::CanConnect => CanConnect, KadConnectionType::CanConnect => CAN_CONNECT,
KadConnectionType::CannotConnect => CannotConnect, KadConnectionType::CannotConnect => CANNOT_CONNECT,
} }
} }
} }
@ -95,10 +95,10 @@ pub struct KadPeer {
} }
// Builds a `KadPeer` from a corresponding protobuf message. // Builds a `KadPeer` from a corresponding protobuf message.
impl TryFrom<proto::message::Peer> for KadPeer { impl TryFrom<proto::Peer> for KadPeer {
type Error = io::Error; type Error = io::Error;
fn try_from(peer: proto::message::Peer) -> Result<KadPeer, Self::Error> { fn try_from(peer: proto::Peer) -> Result<KadPeer, Self::Error> {
// TODO: this is in fact a CID; not sure if this should be handled in `from_bytes` or // TODO: this is in fact a CID; not sure if this should be handled in `from_bytes` or
// as a special case here // as a special case here
let node_id = PeerId::from_bytes(&peer.id).map_err(|_| invalid_data("invalid peer id"))?; let node_id = PeerId::from_bytes(&peer.id).map_err(|_| invalid_data("invalid peer id"))?;
@ -113,27 +113,20 @@ impl TryFrom<proto::message::Peer> for KadPeer {
}; };
} }
let connection_ty = proto::message::ConnectionType::from_i32(peer.connection)
.ok_or_else(|| invalid_data("unknown connection type"))?
.into();
Ok(KadPeer { Ok(KadPeer {
node_id, node_id,
multiaddrs: addrs, multiaddrs: addrs,
connection_ty, connection_ty: peer.connection.into(),
}) })
} }
} }
impl From<KadPeer> for proto::message::Peer { impl From<KadPeer> for proto::Peer {
fn from(peer: KadPeer) -> Self { fn from(peer: KadPeer) -> Self {
proto::message::Peer { proto::Peer {
id: peer.node_id.to_bytes(), id: peer.node_id.to_bytes(),
addrs: peer.multiaddrs.into_iter().map(|a| a.to_vec()).collect(), addrs: peer.multiaddrs.into_iter().map(|a| a.to_vec()).collect(),
connection: { connection: peer.connection_ty.into(),
let ct: proto::message::ConnectionType = peer.connection_ty.into();
ct as i32
},
} }
} }
} }
@ -195,6 +188,8 @@ where
type Error = io::Error; type Error = io::Error;
fn upgrade_inbound(self, incoming: C, _: Self::Info) -> Self::Future { fn upgrade_inbound(self, incoming: C, _: Self::Info) -> Self::Future {
use quick_protobuf::{MessageRead, MessageWrite};
let mut codec = UviBytes::default(); let mut codec = UviBytes::default();
codec.set_max_len(self.max_packet_size); codec.set_max_len(self.max_packet_size);
@ -203,14 +198,16 @@ where
.err_into() .err_into()
.with::<_, _, fn(_) -> _, _>(|response| { .with::<_, _, fn(_) -> _, _>(|response| {
let proto_struct = resp_msg_to_proto(response); let proto_struct = resp_msg_to_proto(response);
let mut buf = Vec::with_capacity(proto_struct.encoded_len()); let mut buf = Vec::with_capacity(proto_struct.get_size());
let mut writer = Writer::new(&mut buf);
proto_struct proto_struct
.encode(&mut buf) .write_message(&mut writer)
.expect("Vec<u8> provides capacity as needed"); .expect("Encoding to succeed");
future::ready(Ok(io::Cursor::new(buf))) future::ready(Ok(io::Cursor::new(buf)))
}) })
.and_then::<_, fn(_) -> _>(|bytes| { .and_then::<_, fn(_) -> _>(|bytes| {
let request = match proto::Message::decode(bytes) { let mut reader = BytesReader::from_bytes(&bytes);
let request = match proto::Message::from_reader(&mut reader, &bytes) {
Ok(r) => r, Ok(r) => r,
Err(err) => return future::ready(Err(err.into())), Err(err) => return future::ready(Err(err.into())),
}; };
@ -229,6 +226,8 @@ where
type Error = io::Error; type Error = io::Error;
fn upgrade_outbound(self, incoming: C, _: Self::Info) -> Self::Future { fn upgrade_outbound(self, incoming: C, _: Self::Info) -> Self::Future {
use quick_protobuf::{MessageRead, MessageWrite};
let mut codec = UviBytes::default(); let mut codec = UviBytes::default();
codec.set_max_len(self.max_packet_size); codec.set_max_len(self.max_packet_size);
@ -237,14 +236,16 @@ where
.err_into() .err_into()
.with::<_, _, fn(_) -> _, _>(|request| { .with::<_, _, fn(_) -> _, _>(|request| {
let proto_struct = req_msg_to_proto(request); let proto_struct = req_msg_to_proto(request);
let mut buf = Vec::with_capacity(proto_struct.encoded_len()); let mut buf = Vec::with_capacity(proto_struct.get_size());
let mut writer = Writer::new(&mut buf);
proto_struct proto_struct
.encode(&mut buf) .write_message(&mut writer)
.expect("Vec<u8> provides capacity as needed"); .expect("Encoding to succeed");
future::ready(Ok(io::Cursor::new(buf))) future::ready(Ok(io::Cursor::new(buf)))
}) })
.and_then::<_, fn(_) -> _>(|bytes| { .and_then::<_, fn(_) -> _>(|bytes| {
let response = match proto::Message::decode(bytes) { let mut reader = BytesReader::from_bytes(&bytes);
let response = match proto::Message::from_reader(&mut reader, &bytes) {
Ok(r) => r, Ok(r) => r,
Err(err) => return future::ready(Err(err.into())), Err(err) => return future::ready(Err(err.into())),
}; };
@ -351,36 +352,36 @@ pub enum KadResponseMsg {
fn req_msg_to_proto(kad_msg: KadRequestMsg) -> proto::Message { fn req_msg_to_proto(kad_msg: KadRequestMsg) -> proto::Message {
match kad_msg { match kad_msg {
KadRequestMsg::Ping => proto::Message { KadRequestMsg::Ping => proto::Message {
r#type: proto::message::MessageType::Ping as i32, type_pb: proto::MessageType::PING,
..proto::Message::default() ..proto::Message::default()
}, },
KadRequestMsg::FindNode { key } => proto::Message { KadRequestMsg::FindNode { key } => proto::Message {
r#type: proto::message::MessageType::FindNode as i32, type_pb: proto::MessageType::FIND_NODE,
key, key,
cluster_level_raw: 10, clusterLevelRaw: 10,
..proto::Message::default() ..proto::Message::default()
}, },
KadRequestMsg::GetProviders { key } => proto::Message { KadRequestMsg::GetProviders { key } => proto::Message {
r#type: proto::message::MessageType::GetProviders as i32, type_pb: proto::MessageType::GET_PROVIDERS,
key: key.to_vec(), key: key.to_vec(),
cluster_level_raw: 10, clusterLevelRaw: 10,
..proto::Message::default() ..proto::Message::default()
}, },
KadRequestMsg::AddProvider { key, provider } => proto::Message { KadRequestMsg::AddProvider { key, provider } => proto::Message {
r#type: proto::message::MessageType::AddProvider as i32, type_pb: proto::MessageType::ADD_PROVIDER,
cluster_level_raw: 10, clusterLevelRaw: 10,
key: key.to_vec(), key: key.to_vec(),
provider_peers: vec![provider.into()], providerPeers: vec![provider.into()],
..proto::Message::default() ..proto::Message::default()
}, },
KadRequestMsg::GetValue { key } => proto::Message { KadRequestMsg::GetValue { key } => proto::Message {
r#type: proto::message::MessageType::GetValue as i32, type_pb: proto::MessageType::GET_VALUE,
cluster_level_raw: 10, clusterLevelRaw: 10,
key: key.to_vec(), key: key.to_vec(),
..proto::Message::default() ..proto::Message::default()
}, },
KadRequestMsg::PutValue { record } => proto::Message { KadRequestMsg::PutValue { record } => proto::Message {
r#type: proto::message::MessageType::PutValue as i32, type_pb: proto::MessageType::PUT_VALUE,
key: record.key.to_vec(), key: record.key.to_vec(),
record: Some(record_to_proto(record)), record: Some(record_to_proto(record)),
..proto::Message::default() ..proto::Message::default()
@ -392,37 +393,37 @@ fn req_msg_to_proto(kad_msg: KadRequestMsg) -> proto::Message {
fn resp_msg_to_proto(kad_msg: KadResponseMsg) -> proto::Message { fn resp_msg_to_proto(kad_msg: KadResponseMsg) -> proto::Message {
match kad_msg { match kad_msg {
KadResponseMsg::Pong => proto::Message { KadResponseMsg::Pong => proto::Message {
r#type: proto::message::MessageType::Ping as i32, type_pb: proto::MessageType::PING,
..proto::Message::default() ..proto::Message::default()
}, },
KadResponseMsg::FindNode { closer_peers } => proto::Message { KadResponseMsg::FindNode { closer_peers } => proto::Message {
r#type: proto::message::MessageType::FindNode as i32, type_pb: proto::MessageType::FIND_NODE,
cluster_level_raw: 9, clusterLevelRaw: 9,
closer_peers: closer_peers.into_iter().map(KadPeer::into).collect(), closerPeers: closer_peers.into_iter().map(KadPeer::into).collect(),
..proto::Message::default() ..proto::Message::default()
}, },
KadResponseMsg::GetProviders { KadResponseMsg::GetProviders {
closer_peers, closer_peers,
provider_peers, provider_peers,
} => proto::Message { } => proto::Message {
r#type: proto::message::MessageType::GetProviders as i32, type_pb: proto::MessageType::GET_PROVIDERS,
cluster_level_raw: 9, clusterLevelRaw: 9,
closer_peers: closer_peers.into_iter().map(KadPeer::into).collect(), closerPeers: closer_peers.into_iter().map(KadPeer::into).collect(),
provider_peers: provider_peers.into_iter().map(KadPeer::into).collect(), providerPeers: provider_peers.into_iter().map(KadPeer::into).collect(),
..proto::Message::default() ..proto::Message::default()
}, },
KadResponseMsg::GetValue { KadResponseMsg::GetValue {
record, record,
closer_peers, closer_peers,
} => proto::Message { } => proto::Message {
r#type: proto::message::MessageType::GetValue as i32, type_pb: proto::MessageType::GET_VALUE,
cluster_level_raw: 9, clusterLevelRaw: 9,
closer_peers: closer_peers.into_iter().map(KadPeer::into).collect(), closerPeers: closer_peers.into_iter().map(KadPeer::into).collect(),
record: record.map(record_to_proto), record: record.map(record_to_proto),
..proto::Message::default() ..proto::Message::default()
}, },
KadResponseMsg::PutValue { key, value } => proto::Message { KadResponseMsg::PutValue { key, value } => proto::Message {
r#type: proto::message::MessageType::PutValue as i32, type_pb: proto::MessageType::PUT_VALUE,
key: key.to_vec(), key: key.to_vec(),
record: Some(proto::Record { record: Some(proto::Record {
key: key.to_vec(), key: key.to_vec(),
@ -438,28 +439,25 @@ fn resp_msg_to_proto(kad_msg: KadResponseMsg) -> proto::Message {
/// ///
/// Fails if the protobuf message is not a valid and supported Kademlia request message. /// Fails if the protobuf message is not a valid and supported Kademlia request message.
fn proto_to_req_msg(message: proto::Message) -> Result<KadRequestMsg, io::Error> { fn proto_to_req_msg(message: proto::Message) -> Result<KadRequestMsg, io::Error> {
let msg_type = proto::message::MessageType::from_i32(message.r#type) match message.type_pb {
.ok_or_else(|| invalid_data(format!("unknown message type: {}", message.r#type)))?; proto::MessageType::PING => Ok(KadRequestMsg::Ping),
proto::MessageType::PUT_VALUE => {
match msg_type {
proto::message::MessageType::Ping => Ok(KadRequestMsg::Ping),
proto::message::MessageType::PutValue => {
let record = record_from_proto(message.record.unwrap_or_default())?; let record = record_from_proto(message.record.unwrap_or_default())?;
Ok(KadRequestMsg::PutValue { record }) Ok(KadRequestMsg::PutValue { record })
} }
proto::message::MessageType::GetValue => Ok(KadRequestMsg::GetValue { proto::MessageType::GET_VALUE => Ok(KadRequestMsg::GetValue {
key: record::Key::from(message.key), key: record::Key::from(message.key),
}), }),
proto::message::MessageType::FindNode => Ok(KadRequestMsg::FindNode { key: message.key }), proto::MessageType::FIND_NODE => Ok(KadRequestMsg::FindNode { key: message.key }),
proto::message::MessageType::GetProviders => Ok(KadRequestMsg::GetProviders { proto::MessageType::GET_PROVIDERS => Ok(KadRequestMsg::GetProviders {
key: record::Key::from(message.key), key: record::Key::from(message.key),
}), }),
proto::message::MessageType::AddProvider => { proto::MessageType::ADD_PROVIDER => {
// TODO: for now we don't parse the peer properly, so it is possible that we get // TODO: for now we don't parse the peer properly, so it is possible that we get
// parsing errors for peers even when they are valid; we ignore these // parsing errors for peers even when they are valid; we ignore these
// errors for now, but ultimately we should just error altogether // errors for now, but ultimately we should just error altogether
let provider = message let provider = message
.provider_peers .providerPeers
.into_iter() .into_iter()
.find_map(|peer| KadPeer::try_from(peer).ok()); .find_map(|peer| KadPeer::try_from(peer).ok());
@ -477,12 +475,9 @@ fn proto_to_req_msg(message: proto::Message) -> Result<KadRequestMsg, io::Error>
/// ///
/// Fails if the protobuf message is not a valid and supported Kademlia response message. /// Fails if the protobuf message is not a valid and supported Kademlia response message.
fn proto_to_resp_msg(message: proto::Message) -> Result<KadResponseMsg, io::Error> { fn proto_to_resp_msg(message: proto::Message) -> Result<KadResponseMsg, io::Error> {
let msg_type = proto::message::MessageType::from_i32(message.r#type) match message.type_pb {
.ok_or_else(|| invalid_data(format!("unknown message type: {}", message.r#type)))?; proto::MessageType::PING => Ok(KadResponseMsg::Pong),
proto::MessageType::GET_VALUE => {
match msg_type {
proto::message::MessageType::Ping => Ok(KadResponseMsg::Pong),
proto::message::MessageType::GetValue => {
let record = if let Some(r) = message.record { let record = if let Some(r) = message.record {
Some(record_from_proto(r)?) Some(record_from_proto(r)?)
} else { } else {
@ -490,7 +485,7 @@ fn proto_to_resp_msg(message: proto::Message) -> Result<KadResponseMsg, io::Erro
}; };
let closer_peers = message let closer_peers = message
.closer_peers .closerPeers
.into_iter() .into_iter()
.filter_map(|peer| KadPeer::try_from(peer).ok()) .filter_map(|peer| KadPeer::try_from(peer).ok())
.collect(); .collect();
@ -501,9 +496,9 @@ fn proto_to_resp_msg(message: proto::Message) -> Result<KadResponseMsg, io::Erro
}) })
} }
proto::message::MessageType::FindNode => { proto::MessageType::FIND_NODE => {
let closer_peers = message let closer_peers = message
.closer_peers .closerPeers
.into_iter() .into_iter()
.filter_map(|peer| KadPeer::try_from(peer).ok()) .filter_map(|peer| KadPeer::try_from(peer).ok())
.collect(); .collect();
@ -511,15 +506,15 @@ fn proto_to_resp_msg(message: proto::Message) -> Result<KadResponseMsg, io::Erro
Ok(KadResponseMsg::FindNode { closer_peers }) Ok(KadResponseMsg::FindNode { closer_peers })
} }
proto::message::MessageType::GetProviders => { proto::MessageType::GET_PROVIDERS => {
let closer_peers = message let closer_peers = message
.closer_peers .closerPeers
.into_iter() .into_iter()
.filter_map(|peer| KadPeer::try_from(peer).ok()) .filter_map(|peer| KadPeer::try_from(peer).ok())
.collect(); .collect();
let provider_peers = message let provider_peers = message
.provider_peers .providerPeers
.into_iter() .into_iter()
.filter_map(|peer| KadPeer::try_from(peer).ok()) .filter_map(|peer| KadPeer::try_from(peer).ok())
.collect(); .collect();
@ -530,7 +525,7 @@ fn proto_to_resp_msg(message: proto::Message) -> Result<KadResponseMsg, io::Erro
}) })
} }
proto::message::MessageType::PutValue => { proto::MessageType::PUT_VALUE => {
let key = record::Key::from(message.key); let key = record::Key::from(message.key);
let rec = message let rec = message
.record .record
@ -542,7 +537,7 @@ fn proto_to_resp_msg(message: proto::Message) -> Result<KadResponseMsg, io::Erro
}) })
} }
proto::message::MessageType::AddProvider => { proto::MessageType::ADD_PROVIDER => {
Err(invalid_data("received an unexpected AddProvider message")) Err(invalid_data("received an unexpected AddProvider message"))
} }
} }
@ -590,7 +585,7 @@ fn record_to_proto(record: Record) -> proto::Record {
} }
}) })
.unwrap_or(0), .unwrap_or(0),
time_received: String::new(), timeReceived: String::new(),
} }
} }
@ -617,10 +612,10 @@ mod tests {
a a
}; };
let payload = proto::message::Peer { let payload = proto::Peer {
id: PeerId::random().to_bytes(), id: PeerId::random().to_bytes(),
addrs: vec![valid_multiaddr_bytes, invalid_multiaddr], addrs: vec![valid_multiaddr_bytes, invalid_multiaddr],
connection: proto::message::ConnectionType::CanConnect.into(), connection: proto::ConnectionType::CAN_CONNECT,
}; };
let peer = KadPeer::try_from(payload).expect("not to fail"); let peer = KadPeer::try_from(payload).expect("not to fail");

View File

@ -11,8 +11,11 @@
- Update to `libp2p-swarm` `v0.42.0`. - Update to `libp2p-swarm` `v0.42.0`.
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[PR 3238]: https://github.com/libp2p/rust-libp2p/pull/3238 [PR 3238]: https://github.com/libp2p/rust-libp2p/pull/3238
[discussion 2174]: https://github.com/libp2p/rust-libp2p/issues/2174 [discussion 2174]: https://github.com/libp2p/rust-libp2p/issues/2174
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
# 0.14.0 # 0.14.0

View File

@ -20,16 +20,13 @@ instant = "0.1.11"
libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-core = { version = "0.39.0", path = "../../core" }
libp2p-swarm = { version = "0.42.0", path = "../../swarm" } libp2p-swarm = { version = "0.42.0", path = "../../swarm" }
log = "0.4" log = "0.4"
prost-codec = { version = "0.3", path = "../../misc/prost-codec" } quick-protobuf = "0.8"
prost = "0.11" quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" }
rand = "0.8.4" rand = "0.8.4"
static_assertions = "1" static_assertions = "1"
thiserror = "1.0" thiserror = "1.0"
void = "1" void = "1"
[build-dependencies]
prost-build = "0.11"
[dev-dependencies] [dev-dependencies]
clap = { version = "4.1.6", features = ["derive"] } clap = { version = "4.1.6", features = ["derive"] }
env_logger = "0.10.0" env_logger = "0.10.0"

View File

@ -1,23 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
fn main() {
prost_build::compile_protos(&["src/message.proto"], &["src/"]).unwrap();
}

View File

@ -24,8 +24,8 @@ mod handler;
pub mod rate_limiter; pub mod rate_limiter;
use crate::behaviour::handler::Handler; use crate::behaviour::handler::Handler;
use crate::message_proto;
use crate::multiaddr_ext::MultiaddrExt; use crate::multiaddr_ext::MultiaddrExt;
use crate::proto;
use crate::protocol::{inbound_hop, outbound_stop}; use crate::protocol::{inbound_hop, outbound_stop};
use either::Either; use either::Either;
use instant::Instant; use instant::Instant;
@ -381,7 +381,7 @@ impl NetworkBehaviour for Behaviour {
peer_id: event_source, peer_id: event_source,
event: Either::Left(handler::In::DenyReservationReq { event: Either::Left(handler::In::DenyReservationReq {
inbound_reservation_req, inbound_reservation_req,
status: message_proto::Status::ResourceLimitExceeded, status: proto::Status::RESOURCE_LIMIT_EXCEEDED,
}), }),
} }
.into() .into()
@ -496,7 +496,7 @@ impl NetworkBehaviour for Behaviour {
event: Either::Left(handler::In::DenyCircuitReq { event: Either::Left(handler::In::DenyCircuitReq {
circuit_id: None, circuit_id: None,
inbound_circuit_req, inbound_circuit_req,
status: message_proto::Status::ResourceLimitExceeded, status: proto::Status::RESOURCE_LIMIT_EXCEEDED,
}), }),
} }
} else if let Some(dst_conn) = self } else if let Some(dst_conn) = self
@ -532,7 +532,7 @@ impl NetworkBehaviour for Behaviour {
event: Either::Left(handler::In::DenyCircuitReq { event: Either::Left(handler::In::DenyCircuitReq {
circuit_id: None, circuit_id: None,
inbound_circuit_req, inbound_circuit_req,
status: message_proto::Status::NoReservation, status: proto::Status::NO_RESERVATION,
}), }),
} }
}; };

View File

@ -20,7 +20,7 @@
use crate::behaviour::CircuitId; use crate::behaviour::CircuitId;
use crate::copy_future::CopyFuture; use crate::copy_future::CopyFuture;
use crate::message_proto::Status; use crate::proto;
use crate::protocol::{inbound_hop, outbound_stop}; use crate::protocol::{inbound_hop, outbound_stop};
use bytes::Bytes; use bytes::Bytes;
use either::Either; use either::Either;
@ -58,12 +58,12 @@ pub enum In {
}, },
DenyReservationReq { DenyReservationReq {
inbound_reservation_req: inbound_hop::ReservationReq, inbound_reservation_req: inbound_hop::ReservationReq,
status: Status, status: proto::Status,
}, },
DenyCircuitReq { DenyCircuitReq {
circuit_id: Option<CircuitId>, circuit_id: Option<CircuitId>,
inbound_circuit_req: inbound_hop::CircuitReq, inbound_circuit_req: inbound_hop::CircuitReq,
status: Status, status: proto::Status,
}, },
NegotiateOutboundConnect { NegotiateOutboundConnect {
circuit_id: CircuitId, circuit_id: CircuitId,
@ -208,7 +208,7 @@ pub enum Event {
src_peer_id: PeerId, src_peer_id: PeerId,
src_connection_id: ConnectionId, src_connection_id: ConnectionId,
inbound_circuit_req: inbound_hop::CircuitReq, inbound_circuit_req: inbound_hop::CircuitReq,
status: Status, status: proto::Status,
error: ConnectionHandlerUpgrErr<outbound_stop::CircuitFailedReason>, error: ConnectionHandlerUpgrErr<outbound_stop::CircuitFailedReason>,
}, },
/// An inbound circuit has closed. /// An inbound circuit has closed.
@ -522,12 +522,14 @@ impl Handler {
>, >,
) { ) {
let (non_fatal_error, status) = match error { let (non_fatal_error, status) = match error {
ConnectionHandlerUpgrErr::Timeout => { ConnectionHandlerUpgrErr::Timeout => (
(ConnectionHandlerUpgrErr::Timeout, Status::ConnectionFailed) ConnectionHandlerUpgrErr::Timeout,
} proto::Status::CONNECTION_FAILED,
ConnectionHandlerUpgrErr::Timer => { ),
(ConnectionHandlerUpgrErr::Timer, Status::ConnectionFailed) ConnectionHandlerUpgrErr::Timer => (
} ConnectionHandlerUpgrErr::Timer,
proto::Status::CONNECTION_FAILED,
),
ConnectionHandlerUpgrErr::Upgrade(upgrade::UpgradeError::Select( ConnectionHandlerUpgrErr::Upgrade(upgrade::UpgradeError::Select(
upgrade::NegotiationError::Failed, upgrade::NegotiationError::Failed,
)) => { )) => {
@ -556,10 +558,10 @@ impl Handler {
outbound_stop::UpgradeError::CircuitFailed(error) => { outbound_stop::UpgradeError::CircuitFailed(error) => {
let status = match error { let status = match error {
outbound_stop::CircuitFailedReason::ResourceLimitExceeded => { outbound_stop::CircuitFailedReason::ResourceLimitExceeded => {
Status::ResourceLimitExceeded proto::Status::RESOURCE_LIMIT_EXCEEDED
} }
outbound_stop::CircuitFailedReason::PermissionDenied => { outbound_stop::CircuitFailedReason::PermissionDenied => {
Status::PermissionDenied proto::Status::PERMISSION_DENIED
} }
}; };
( (

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod pb;

View File

@ -0,0 +1,346 @@
// Automatically generated rust module for 'message.proto' file
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt_skip)]
use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
use quick_protobuf::sizeofs::*;
use super::super::*;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Status {
OK = 100,
RESERVATION_REFUSED = 200,
RESOURCE_LIMIT_EXCEEDED = 201,
PERMISSION_DENIED = 202,
CONNECTION_FAILED = 203,
NO_RESERVATION = 204,
MALFORMED_MESSAGE = 400,
UNEXPECTED_MESSAGE = 401,
}
impl Default for Status {
fn default() -> Self {
Status::OK
}
}
impl From<i32> for Status {
fn from(i: i32) -> Self {
match i {
100 => Status::OK,
200 => Status::RESERVATION_REFUSED,
201 => Status::RESOURCE_LIMIT_EXCEEDED,
202 => Status::PERMISSION_DENIED,
203 => Status::CONNECTION_FAILED,
204 => Status::NO_RESERVATION,
400 => Status::MALFORMED_MESSAGE,
401 => Status::UNEXPECTED_MESSAGE,
_ => Self::default(),
}
}
}
impl<'a> From<&'a str> for Status {
fn from(s: &'a str) -> Self {
match s {
"OK" => Status::OK,
"RESERVATION_REFUSED" => Status::RESERVATION_REFUSED,
"RESOURCE_LIMIT_EXCEEDED" => Status::RESOURCE_LIMIT_EXCEEDED,
"PERMISSION_DENIED" => Status::PERMISSION_DENIED,
"CONNECTION_FAILED" => Status::CONNECTION_FAILED,
"NO_RESERVATION" => Status::NO_RESERVATION,
"MALFORMED_MESSAGE" => Status::MALFORMED_MESSAGE,
"UNEXPECTED_MESSAGE" => Status::UNEXPECTED_MESSAGE,
_ => Self::default(),
}
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct HopMessage {
pub type_pb: message_v2::pb::mod_HopMessage::Type,
pub peer: Option<message_v2::pb::Peer>,
pub reservation: Option<message_v2::pb::Reservation>,
pub limit: Option<message_v2::pb::Limit>,
pub status: Option<message_v2::pb::Status>,
}
impl<'a> MessageRead<'a> for HopMessage {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.type_pb = r.read_enum(bytes)?,
Ok(18) => msg.peer = Some(r.read_message::<message_v2::pb::Peer>(bytes)?),
Ok(26) => msg.reservation = Some(r.read_message::<message_v2::pb::Reservation>(bytes)?),
Ok(34) => msg.limit = Some(r.read_message::<message_v2::pb::Limit>(bytes)?),
Ok(40) => msg.status = Some(r.read_enum(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for HopMessage {
fn get_size(&self) -> usize {
0
+ 1 + sizeof_varint(*(&self.type_pb) as u64)
+ self.peer.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
+ self.reservation.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
+ self.limit.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
+ self.status.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
w.write_with_tag(8, |w| w.write_enum(*&self.type_pb as i32))?;
if let Some(ref s) = self.peer { w.write_with_tag(18, |w| w.write_message(s))?; }
if let Some(ref s) = self.reservation { w.write_with_tag(26, |w| w.write_message(s))?; }
if let Some(ref s) = self.limit { w.write_with_tag(34, |w| w.write_message(s))?; }
if let Some(ref s) = self.status { w.write_with_tag(40, |w| w.write_enum(*s as i32))?; }
Ok(())
}
}
pub mod mod_HopMessage {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Type {
RESERVE = 0,
CONNECT = 1,
STATUS = 2,
}
impl Default for Type {
fn default() -> Self {
Type::RESERVE
}
}
impl From<i32> for Type {
fn from(i: i32) -> Self {
match i {
0 => Type::RESERVE,
1 => Type::CONNECT,
2 => Type::STATUS,
_ => Self::default(),
}
}
}
impl<'a> From<&'a str> for Type {
fn from(s: &'a str) -> Self {
match s {
"RESERVE" => Type::RESERVE,
"CONNECT" => Type::CONNECT,
"STATUS" => Type::STATUS,
_ => Self::default(),
}
}
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct StopMessage {
pub type_pb: message_v2::pb::mod_StopMessage::Type,
pub peer: Option<message_v2::pb::Peer>,
pub limit: Option<message_v2::pb::Limit>,
pub status: Option<message_v2::pb::Status>,
}
impl<'a> MessageRead<'a> for StopMessage {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.type_pb = r.read_enum(bytes)?,
Ok(18) => msg.peer = Some(r.read_message::<message_v2::pb::Peer>(bytes)?),
Ok(26) => msg.limit = Some(r.read_message::<message_v2::pb::Limit>(bytes)?),
Ok(32) => msg.status = Some(r.read_enum(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for StopMessage {
fn get_size(&self) -> usize {
0
+ 1 + sizeof_varint(*(&self.type_pb) as u64)
+ self.peer.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
+ self.limit.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
+ self.status.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
w.write_with_tag(8, |w| w.write_enum(*&self.type_pb as i32))?;
if let Some(ref s) = self.peer { w.write_with_tag(18, |w| w.write_message(s))?; }
if let Some(ref s) = self.limit { w.write_with_tag(26, |w| w.write_message(s))?; }
if let Some(ref s) = self.status { w.write_with_tag(32, |w| w.write_enum(*s as i32))?; }
Ok(())
}
}
pub mod mod_StopMessage {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Type {
CONNECT = 0,
STATUS = 1,
}
impl Default for Type {
fn default() -> Self {
Type::CONNECT
}
}
impl From<i32> for Type {
fn from(i: i32) -> Self {
match i {
0 => Type::CONNECT,
1 => Type::STATUS,
_ => Self::default(),
}
}
}
impl<'a> From<&'a str> for Type {
fn from(s: &'a str) -> Self {
match s {
"CONNECT" => Type::CONNECT,
"STATUS" => Type::STATUS,
_ => Self::default(),
}
}
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Peer {
pub id: Vec<u8>,
pub addrs: Vec<Vec<u8>>,
}
impl<'a> MessageRead<'a> for Peer {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(10) => msg.id = r.read_bytes(bytes)?.to_owned(),
Ok(18) => msg.addrs.push(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Peer {
fn get_size(&self) -> usize {
0
+ 1 + sizeof_len((&self.id).len())
+ self.addrs.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
w.write_with_tag(10, |w| w.write_bytes(&**&self.id))?;
for s in &self.addrs { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Reservation {
pub expire: u64,
pub addrs: Vec<Vec<u8>>,
pub voucher: Option<Vec<u8>>,
}
impl<'a> MessageRead<'a> for Reservation {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.expire = r.read_uint64(bytes)?,
Ok(18) => msg.addrs.push(r.read_bytes(bytes)?.to_owned()),
Ok(26) => msg.voucher = Some(r.read_bytes(bytes)?.to_owned()),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Reservation {
fn get_size(&self) -> usize {
0
+ 1 + sizeof_varint(*(&self.expire) as u64)
+ self.addrs.iter().map(|s| 1 + sizeof_len((s).len())).sum::<usize>()
+ self.voucher.as_ref().map_or(0, |m| 1 + sizeof_len((m).len()))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
w.write_with_tag(8, |w| w.write_uint64(*&self.expire))?;
for s in &self.addrs { w.write_with_tag(18, |w| w.write_bytes(&**s))?; }
if let Some(ref s) = self.voucher { w.write_with_tag(26, |w| w.write_bytes(&**s))?; }
Ok(())
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Limit {
pub duration: Option<u32>,
pub data: Option<u64>,
}
impl<'a> MessageRead<'a> for Limit {
fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
let mut msg = Self::default();
while !r.is_eof() {
match r.next_tag(bytes) {
Ok(8) => msg.duration = Some(r.read_uint32(bytes)?),
Ok(16) => msg.data = Some(r.read_uint64(bytes)?),
Ok(t) => { r.read_unknown(bytes, t)?; }
Err(e) => return Err(e),
}
}
Ok(msg)
}
}
impl MessageWrite for Limit {
fn get_size(&self) -> usize {
0
+ self.duration.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64))
+ self.data.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64))
}
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
if let Some(ref s) = self.duration { w.write_with_tag(8, |w| w.write_uint32(*s))?; }
if let Some(ref s) = self.data { w.write_with_tag(16, |w| w.write_uint64(*s))?; }
Ok(())
}
}

View File

@ -0,0 +1,2 @@
// Automatically generated mod.rs
pub mod message_v2;

View File

@ -30,9 +30,11 @@ mod priv_client;
mod protocol; mod protocol;
pub mod v2; pub mod v2;
#[allow(clippy::derive_partial_eq_without_eq)] mod proto {
mod message_proto { include!("generated/mod.rs");
include!(concat!(env!("OUT_DIR"), "/message_v2.pb.rs")); pub use self::message_v2::pb::mod_HopMessage::Type as HopMessageType;
pub use self::message_v2::pb::mod_StopMessage::Type as StopMessageType;
pub use self::message_v2::pb::{HopMessage, Limit, Peer, Reservation, Status, StopMessage};
} }
pub use behaviour::{Behaviour, CircuitId, Config, Event}; pub use behaviour::{Behaviour, CircuitId, Config, Event};

View File

@ -18,8 +18,8 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::message_proto::Status;
use crate::priv_client::transport; use crate::priv_client::transport;
use crate::proto;
use crate::protocol::{self, inbound_stop, outbound_hop}; use crate::protocol::{self, inbound_stop, outbound_hop};
use either::Either; use either::Either;
use futures::channel::{mpsc, oneshot}; use futures::channel::{mpsc, oneshot};
@ -218,7 +218,7 @@ impl Handler {
.circuit_deny_futs .circuit_deny_futs
.insert( .insert(
src_peer_id, src_peer_id,
inbound_circuit.deny(Status::NoReservation).boxed(), inbound_circuit.deny(proto::Status::NO_RESERVATION).boxed(),
) )
.is_some() .is_some()
{ {

View File

@ -18,7 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::message_proto; use crate::proto;
use std::time::Duration; use std::time::Duration;
pub mod inbound_hop; pub mod inbound_hop;
@ -37,8 +37,8 @@ pub struct Limit {
data_in_bytes: Option<u64>, data_in_bytes: Option<u64>,
} }
impl From<message_proto::Limit> for Limit { impl From<proto::Limit> for Limit {
fn from(limit: message_proto::Limit) -> Self { fn from(limit: proto::Limit) -> Self {
Limit { Limit {
duration: limit.duration.map(|d| Duration::from_secs(d.into())), duration: limit.duration.map(|d| Duration::from_secs(d.into())),
data_in_bytes: limit.data, data_in_bytes: limit.data,

View File

@ -18,7 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::message_proto::{hop_message, HopMessage, Limit, Reservation, Status}; use crate::proto;
use crate::protocol::{HOP_PROTOCOL_NAME, MAX_MESSAGE_SIZE}; use crate::protocol::{HOP_PROTOCOL_NAME, MAX_MESSAGE_SIZE};
use asynchronous_codec::{Framed, FramedParts}; use asynchronous_codec::{Framed, FramedParts};
use bytes::Bytes; use bytes::Bytes;
@ -51,11 +51,14 @@ impl upgrade::InboundUpgrade<NegotiatedSubstream> for Upgrade {
type Future = BoxFuture<'static, Result<Self::Output, Self::Error>>; type Future = BoxFuture<'static, Result<Self::Output, Self::Error>>;
fn upgrade_inbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future { fn upgrade_inbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future {
let mut substream = Framed::new(substream, prost_codec::Codec::new(MAX_MESSAGE_SIZE)); let mut substream = Framed::new(
substream,
quick_protobuf_codec::Codec::new(MAX_MESSAGE_SIZE),
);
async move { async move {
let HopMessage { let proto::HopMessage {
r#type, type_pb,
peer, peer,
reservation: _, reservation: _,
limit: _, limit: _,
@ -65,21 +68,19 @@ impl upgrade::InboundUpgrade<NegotiatedSubstream> for Upgrade {
.await .await
.ok_or(FatalUpgradeError::StreamClosed)??; .ok_or(FatalUpgradeError::StreamClosed)??;
let r#type = let req = match type_pb {
hop_message::Type::from_i32(r#type).ok_or(FatalUpgradeError::ParseTypeField)?; proto::HopMessageType::RESERVE => Req::Reserve(ReservationReq {
let req = match r#type {
hop_message::Type::Reserve => Req::Reserve(ReservationReq {
substream, substream,
reservation_duration: self.reservation_duration, reservation_duration: self.reservation_duration,
max_circuit_duration: self.max_circuit_duration, max_circuit_duration: self.max_circuit_duration,
max_circuit_bytes: self.max_circuit_bytes, max_circuit_bytes: self.max_circuit_bytes,
}), }),
hop_message::Type::Connect => { proto::HopMessageType::CONNECT => {
let dst = PeerId::from_bytes(&peer.ok_or(FatalUpgradeError::MissingPeer)?.id) let dst = PeerId::from_bytes(&peer.ok_or(FatalUpgradeError::MissingPeer)?.id)
.map_err(|_| FatalUpgradeError::ParsePeerId)?; .map_err(|_| FatalUpgradeError::ParsePeerId)?;
Req::Connect(CircuitReq { dst, substream }) Req::Connect(CircuitReq { dst, substream })
} }
hop_message::Type::Status => { proto::HopMessageType::STATUS => {
return Err(FatalUpgradeError::UnexpectedTypeStatus.into()) return Err(FatalUpgradeError::UnexpectedTypeStatus.into())
} }
}; };
@ -96,8 +97,8 @@ pub enum UpgradeError {
Fatal(#[from] FatalUpgradeError), Fatal(#[from] FatalUpgradeError),
} }
impl From<prost_codec::Error> for UpgradeError { impl From<quick_protobuf_codec::Error> for UpgradeError {
fn from(error: prost_codec::Error) -> Self { fn from(error: quick_protobuf_codec::Error) -> Self {
Self::Fatal(error.into()) Self::Fatal(error.into())
} }
} }
@ -105,7 +106,7 @@ impl From<prost_codec::Error> for UpgradeError {
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum FatalUpgradeError { pub enum FatalUpgradeError {
#[error(transparent)] #[error(transparent)]
Codec(#[from] prost_codec::Error), Codec(#[from] quick_protobuf_codec::Error),
#[error("Stream closed")] #[error("Stream closed")]
StreamClosed, StreamClosed,
#[error("Failed to parse response type field.")] #[error("Failed to parse response type field.")]
@ -124,7 +125,7 @@ pub enum Req {
} }
pub struct ReservationReq { pub struct ReservationReq {
substream: Framed<NegotiatedSubstream, prost_codec::Codec<HopMessage>>, substream: Framed<NegotiatedSubstream, quick_protobuf_codec::Codec<proto::HopMessage>>,
reservation_duration: Duration, reservation_duration: Duration,
max_circuit_duration: Duration, max_circuit_duration: Duration,
max_circuit_bytes: u64, max_circuit_bytes: u64,
@ -132,10 +133,10 @@ pub struct ReservationReq {
impl ReservationReq { impl ReservationReq {
pub async fn accept(self, addrs: Vec<Multiaddr>) -> Result<(), UpgradeError> { pub async fn accept(self, addrs: Vec<Multiaddr>) -> Result<(), UpgradeError> {
let msg = HopMessage { let msg = proto::HopMessage {
r#type: hop_message::Type::Status.into(), type_pb: proto::HopMessageType::STATUS,
peer: None, peer: None,
reservation: Some(Reservation { reservation: Some(proto::Reservation {
addrs: addrs.into_iter().map(|a| a.to_vec()).collect(), addrs: addrs.into_iter().map(|a| a.to_vec()).collect(),
expire: (SystemTime::now() + self.reservation_duration) expire: (SystemTime::now() + self.reservation_duration)
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
@ -143,7 +144,7 @@ impl ReservationReq {
.as_secs(), .as_secs(),
voucher: None, voucher: None,
}), }),
limit: Some(Limit { limit: Some(proto::Limit {
duration: Some( duration: Some(
self.max_circuit_duration self.max_circuit_duration
.as_secs() .as_secs()
@ -152,25 +153,25 @@ impl ReservationReq {
), ),
data: Some(self.max_circuit_bytes), data: Some(self.max_circuit_bytes),
}), }),
status: Some(Status::Ok.into()), status: Some(proto::Status::OK),
}; };
self.send(msg).await self.send(msg).await
} }
pub async fn deny(self, status: Status) -> Result<(), UpgradeError> { pub async fn deny(self, status: proto::Status) -> Result<(), UpgradeError> {
let msg = HopMessage { let msg = proto::HopMessage {
r#type: hop_message::Type::Status.into(), type_pb: proto::HopMessageType::STATUS,
peer: None, peer: None,
reservation: None, reservation: None,
limit: None, limit: None,
status: Some(status.into()), status: Some(status),
}; };
self.send(msg).await self.send(msg).await
} }
async fn send(mut self, msg: HopMessage) -> Result<(), UpgradeError> { async fn send(mut self, msg: proto::HopMessage) -> Result<(), UpgradeError> {
self.substream.send(msg).await?; self.substream.send(msg).await?;
self.substream.flush().await?; self.substream.flush().await?;
self.substream.close().await?; self.substream.close().await?;
@ -181,7 +182,7 @@ impl ReservationReq {
pub struct CircuitReq { pub struct CircuitReq {
dst: PeerId, dst: PeerId,
substream: Framed<NegotiatedSubstream, prost_codec::Codec<HopMessage>>, substream: Framed<NegotiatedSubstream, quick_protobuf_codec::Codec<proto::HopMessage>>,
} }
impl CircuitReq { impl CircuitReq {
@ -190,12 +191,12 @@ impl CircuitReq {
} }
pub async fn accept(mut self) -> Result<(NegotiatedSubstream, Bytes), UpgradeError> { pub async fn accept(mut self) -> Result<(NegotiatedSubstream, Bytes), UpgradeError> {
let msg = HopMessage { let msg = proto::HopMessage {
r#type: hop_message::Type::Status.into(), type_pb: proto::HopMessageType::STATUS,
peer: None, peer: None,
reservation: None, reservation: None,
limit: None, limit: None,
status: Some(Status::Ok.into()), status: Some(proto::Status::OK),
}; };
self.send(msg).await?; self.send(msg).await?;
@ -214,19 +215,19 @@ impl CircuitReq {
Ok((io, read_buffer.freeze())) Ok((io, read_buffer.freeze()))
} }
pub async fn deny(mut self, status: Status) -> Result<(), UpgradeError> { pub async fn deny(mut self, status: proto::Status) -> Result<(), UpgradeError> {
let msg = HopMessage { let msg = proto::HopMessage {
r#type: hop_message::Type::Status.into(), type_pb: proto::HopMessageType::STATUS,
peer: None, peer: None,
reservation: None, reservation: None,
limit: None, limit: None,
status: Some(status.into()), status: Some(status),
}; };
self.send(msg).await?; self.send(msg).await?;
self.substream.close().await.map_err(Into::into) self.substream.close().await.map_err(Into::into)
} }
async fn send(&mut self, msg: HopMessage) -> Result<(), prost_codec::Error> { async fn send(&mut self, msg: proto::HopMessage) -> Result<(), quick_protobuf_codec::Error> {
self.substream.send(msg).await?; self.substream.send(msg).await?;
self.substream.flush().await?; self.substream.flush().await?;

Some files were not shown because too many files have changed in this diff Show More