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)"
exit 1
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",
]
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flate2"
version = "1.0.25"
@ -2177,8 +2171,7 @@ dependencies = [
"libp2p-tcp",
"libp2p-yamux",
"log",
"prost",
"prost-build",
"quick-protobuf",
"rand 0.8.5",
]
@ -2208,8 +2201,7 @@ dependencies = [
"p256 0.12.0",
"parking_lot 0.12.1",
"pin-project",
"prost",
"prost-build",
"quick-protobuf",
"quickcheck-ext",
"rand 0.8.5",
"ring",
@ -2248,9 +2240,8 @@ dependencies = [
"libp2p-tcp",
"libp2p-yamux",
"log",
"prost",
"prost-build",
"prost-codec",
"quick-protobuf",
"quick-protobuf-codec",
"rand 0.8.5",
"thiserror",
"void",
@ -2296,9 +2287,8 @@ dependencies = [
"libp2p-core",
"libp2p-swarm",
"log",
"prost",
"prost-build",
"prost-codec",
"quick-protobuf",
"quick-protobuf-codec",
"rand 0.8.5",
"smallvec",
"thiserror",
@ -2327,9 +2317,8 @@ dependencies = [
"libp2p-yamux",
"log",
"prometheus-client",
"prost",
"prost-build",
"prost-codec",
"quick-protobuf",
"quick-protobuf-codec",
"quickcheck-ext",
"rand 0.8.5",
"regex",
@ -2359,9 +2348,8 @@ dependencies = [
"libp2p-yamux",
"log",
"lru",
"prost",
"prost-build",
"prost-codec",
"quick-protobuf",
"quick-protobuf-codec",
"smallvec",
"thiserror",
"void",
@ -2385,8 +2373,7 @@ dependencies = [
"libp2p-swarm",
"libp2p-yamux",
"log",
"prost",
"prost-build",
"quick-protobuf",
"quickcheck-ext",
"rand 0.8.5",
"serde",
@ -2493,8 +2480,7 @@ dependencies = [
"libsodium-sys-stable",
"log",
"once_cell",
"prost",
"prost-build",
"quick-protobuf",
"quickcheck-ext",
"rand 0.8.5",
"sha2 0.10.6",
@ -2536,8 +2522,7 @@ dependencies = [
"futures",
"libp2p-core",
"log",
"prost",
"prost-build",
"quick-protobuf",
"quickcheck-ext",
"rand 0.8.5",
"unsigned-varint",
@ -2611,9 +2596,8 @@ dependencies = [
"libp2p-tcp",
"libp2p-yamux",
"log",
"prost",
"prost-build",
"prost-codec",
"quick-protobuf",
"quick-protobuf-codec",
"quickcheck-ext",
"rand 0.8.5",
"static_assertions",
@ -2641,9 +2625,8 @@ dependencies = [
"libp2p-tcp",
"libp2p-yamux",
"log",
"prost",
"prost-build",
"prost-codec",
"quick-protobuf",
"quick-protobuf-codec",
"rand 0.8.5",
"thiserror",
"tokio",
@ -2787,9 +2770,8 @@ dependencies = [
"libp2p-swarm",
"log",
"multihash",
"prost",
"prost-build",
"prost-codec",
"quick-protobuf",
"quick-protobuf-codec",
"quickcheck",
"rand 0.8.5",
"rcgen 0.9.3",
@ -3103,12 +3085,6 @@ dependencies = [
"synstructure",
]
[[package]]
name = "multimap"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]]
name = "multistream-select"
version = "0.12.1"
@ -3441,16 +3417,6 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "pin-project"
version = "1.0.12"
@ -3593,16 +3559,6 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "primeorder"
version = "0.12.1"
@ -3678,78 +3634,32 @@ dependencies = [
"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]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "quickcheck"
version = "1.0.3"
@ -5374,17 +5284,6 @@ dependencies = [
"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]]
name = "widestring"
version = "0.5.1"

View File

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

View File

@ -2,7 +2,9 @@
- Move `ConnectionId` to `libp2p-swarm`. 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
# 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 }
parking_lot = "0.12.0"
pin-project = "1.0.0"
prost = "0.11"
quick-protobuf = "0.8"
once_cell = "1.17.1"
rand = "0.8"
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"
serde_json = "1.0"
[build-dependencies]
prost-build = "0.11"
[features]
secp256k1 = [ "libsecp256k1" ]
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;
use self::error::*;
use crate::{keys_proto, PeerId};
use crate::{proto, PeerId};
use quick_protobuf::{BytesReader, Writer};
use std::convert::{TryFrom, TryInto};
/// Identity keypair of a node.
@ -147,12 +148,12 @@ impl Keypair {
/// Encode a private key as protobuf structure.
pub fn to_protobuf_encoding(&self) -> Result<Vec<u8>, DecodingError> {
use prost::Message;
use quick_protobuf::MessageWrite;
let pk = match self {
Self::Ed25519(data) => keys_proto::PrivateKey {
r#type: keys_proto::KeyType::Ed25519.into(),
data: data.encode().into(),
Self::Ed25519(data) => proto::PrivateKey {
Type: proto::KeyType::Ed25519,
Data: data.encode().to_vec(),
},
#[cfg(all(feature = "rsa", not(target_arch = "wasm32")))]
Self::Rsa(_) => return Err(DecodingError::encoding_unsupported("RSA")),
@ -162,35 +163,38 @@ impl Keypair {
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`].
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(zeroize::Zeroizing::new)?;
let key_type = keys_proto::KeyType::from_i32(private_key.r#type)
.ok_or_else(|| DecodingError::unknown_key_type(private_key.r#type))?;
match key_type {
keys_proto::KeyType::Ed25519 => {
ed25519::Keypair::decode(&mut private_key.data).map(Keypair::Ed25519)
match private_key.Type {
proto::KeyType::Ed25519 => {
ed25519::Keypair::decode(&mut private_key.Data).map(Keypair::Ed25519)
}
keys_proto::KeyType::Rsa => Err(DecodingError::decoding_unsupported("RSA")),
keys_proto::KeyType::Secp256k1 => Err(DecodingError::decoding_unsupported("secp256k1")),
keys_proto::KeyType::Ecdsa => Err(DecodingError::decoding_unsupported("ECDSA")),
proto::KeyType::RSA => Err(DecodingError::decoding_unsupported("RSA")),
proto::KeyType::Secp256k1 => Err(DecodingError::decoding_unsupported("secp256k1")),
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) {
self.r#type.zeroize();
self.data.zeroize();
// KeyType cannot be zeroized.
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
/// exchange with other nodes.
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
.encode(&mut buf)
.expect("Vec<u8> provides capacity as needed");
.write_message(&mut writer)
.expect("Encoding to succeed");
buf
}
/// Decode a public key from a protobuf structure, e.g. read from storage
/// or received from another node.
pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<PublicKey, DecodingError> {
use prost::Message;
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))?;
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 {
match key {
PublicKey::Ed25519(key) => keys_proto::PublicKey {
r#type: keys_proto::KeyType::Ed25519 as i32,
data: key.encode().to_vec(),
PublicKey::Ed25519(key) => proto::PublicKey {
Type: proto::KeyType::Ed25519,
Data: key.encode().to_vec(),
},
#[cfg(all(feature = "rsa", not(target_arch = "wasm32")))]
PublicKey::Rsa(key) => keys_proto::PublicKey {
r#type: keys_proto::KeyType::Rsa as i32,
data: key.encode_x509(),
PublicKey::Rsa(key) => proto::PublicKey {
Type: proto::KeyType::RSA,
Data: key.encode_x509(),
},
#[cfg(feature = "secp256k1")]
PublicKey::Secp256k1(key) => keys_proto::PublicKey {
r#type: keys_proto::KeyType::Secp256k1 as i32,
data: key.encode().to_vec(),
PublicKey::Secp256k1(key) => proto::PublicKey {
Type: proto::KeyType::Secp256k1,
Data: key.encode().to_vec(),
},
#[cfg(feature = "ecdsa")]
PublicKey::Ecdsa(key) => keys_proto::PublicKey {
r#type: keys_proto::KeyType::Ecdsa as i32,
data: key.encode_der(),
PublicKey::Ecdsa(key) => proto::PublicKey {
Type: proto::KeyType::ECDSA,
Data: key.encode_der(),
},
}
}
}
impl TryFrom<keys_proto::PublicKey> for PublicKey {
impl TryFrom<proto::PublicKey> for PublicKey {
type Error = DecodingError;
fn try_from(pubkey: keys_proto::PublicKey) -> Result<Self, Self::Error> {
let key_type = keys_proto::KeyType::from_i32(pubkey.r#type)
.ok_or_else(|| DecodingError::unknown_key_type(pubkey.r#type))?;
match key_type {
keys_proto::KeyType::Ed25519 => {
ed25519::PublicKey::decode(&pubkey.data).map(PublicKey::Ed25519)
fn try_from(pubkey: proto::PublicKey) -> Result<Self, Self::Error> {
match pubkey.Type {
proto::KeyType::Ed25519 => {
ed25519::PublicKey::decode(&pubkey.Data).map(PublicKey::Ed25519)
}
#[cfg(all(feature = "rsa", not(target_arch = "wasm32")))]
keys_proto::KeyType::Rsa => {
rsa::PublicKey::decode_x509(&pubkey.data).map(PublicKey::Rsa)
}
proto::KeyType::RSA => rsa::PublicKey::decode_x509(&pubkey.Data).map(PublicKey::Rsa),
#[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");
Err(DecodingError::missing_feature("rsa"))
}
#[cfg(feature = "secp256k1")]
keys_proto::KeyType::Secp256k1 => {
secp256k1::PublicKey::decode(&pubkey.data).map(PublicKey::Secp256k1)
proto::KeyType::Secp256k1 => {
secp256k1::PublicKey::decode(&pubkey.Data).map(PublicKey::Secp256k1)
}
#[cfg(not(feature = "secp256k1"))]
keys_proto::KeyType::Secp256k1 => {
proto::KeyType::Secp256k1 => {
log::debug!("support for secp256k1 was disabled at compile-time");
Err(DecodingError::missing_feature("secp256k1"))
}
#[cfg(feature = "ecdsa")]
keys_proto::KeyType::Ecdsa => {
ecdsa::PublicKey::decode_der(&pubkey.data).map(PublicKey::Ecdsa)
proto::KeyType::ECDSA => {
ecdsa::PublicKey::decode_der(&pubkey.Data).map(PublicKey::Ecdsa)
}
#[cfg(not(feature = "ecdsa"))]
keys_proto::KeyType::Ecdsa => {
proto::KeyType::ECDSA => {
log::debug!("support for ECDSA was disabled at compile-time");
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 {
Self {
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))]
#[allow(clippy::derive_partial_eq_without_eq)]
mod keys_proto {
include!(concat!(env!("OUT_DIR"), "/keys_proto.rs"));
}
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"));
mod proto {
include!("generated/mod.rs");
pub use self::{
envelope_proto::*, keys_proto::*, peer_record_proto::mod_PeerRecord::*,
peer_record_proto::PeerRecord,
};
}
/// Multi-address re-export.
pub use multiaddr;
use std::fmt;
use std::fmt::Formatter;
pub type Negotiated<T> = multistream_select::Negotiated<T>;
mod peer_id;
@ -80,6 +76,17 @@ pub use translation::address_translation;
pub use transport::Transport;
pub use upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeError, UpgradeInfo};
#[derive(thiserror::Error, Debug)]
#[error(transparent)]
pub struct DecodeError(prost::DecodeError);
#[derive(Debug, thiserror::Error)]
pub struct DecodeError(String);
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::Keypair;
use crate::proto;
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 quick_protobuf::{BytesReader, Writer};
use std::convert::TryInto;
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.
pub fn from_signed_envelope(envelope: SignedEnvelope) -> Result<Self, FromEnvelopeError> {
use prost::Message;
use quick_protobuf::MessageRead;
let (payload, signing_key) =
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)?;
@ -45,7 +49,7 @@ impl PeerRecord {
let addresses = record
.addresses
.into_iter()
.map(|a| a.multiaddr.try_into())
.map(|a| a.multiaddr.to_vec().try_into())
.collect::<Result<Vec<_>, _>>()?;
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`].
pub fn new(key: &Keypair, addresses: Vec<Multiaddr>) -> Result<Self, SigningError> {
use prost::Message;
use quick_protobuf::MessageWrite;
let seq = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
@ -69,21 +73,23 @@ impl PeerRecord {
let peer_id = key.public().to_peer_id();
let payload = {
let record = peer_record_proto::PeerRecord {
let record = proto::PeerRecord {
peer_id: peer_id.to_bytes(),
seq,
addresses: addresses
.iter()
.map(|m| peer_record_proto::peer_record::AddressInfo {
.map(|m| proto::AddressInfo {
multiaddr: m.to_vec(),
})
.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
.encode(&mut buf)
.expect("Vec<u8> provides capacity as needed");
.write_message(&mut writer)
.expect("Encoding to succeed");
buf
};
@ -162,7 +168,7 @@ mod tests {
#[test]
fn mismatched_signature() {
use prost::Message;
use quick_protobuf::MessageWrite;
let addr: Multiaddr = HOME.parse().unwrap();
@ -171,18 +177,20 @@ mod tests {
let identity_b = Keypair::generate_ed25519();
let payload = {
let record = peer_record_proto::PeerRecord {
let record = proto::PeerRecord {
peer_id: identity_a.public().to_peer_id().to_bytes(),
seq: 0,
addresses: vec![peer_record_proto::peer_record::AddressInfo {
addresses: vec![proto::AddressInfo {
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
.encode(&mut buf)
.expect("Vec<u8> provides capacity as needed");
.write_message(&mut writer)
.expect("Encoding to succeed");
buf
};

View File

@ -1,6 +1,7 @@
use crate::identity::error::SigningError;
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::fmt;
use unsigned_varint::encode::usize_buffer;
@ -73,37 +74,41 @@ impl SignedEnvelope {
/// Encode this [`SignedEnvelope`] using the protobuf encoding specified in the RFC.
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()),
payload_type: self.payload_type,
payload: self.payload,
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
.encode(&mut buf)
.expect("Vec<u8> provides capacity as needed");
.write_message(&mut writer)
.expect("Encoding to succeed");
buf
}
/// Decode a [`SignedEnvelope`] using the protobuf encoding specified in the RFC.
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 {
key: envelope
.public_key
.ok_or(DecodingError::MissingPublicKey)?
.try_into()?,
payload_type: envelope.payload_type,
payload: envelope.payload,
signature: envelope.signature,
payload_type: envelope.payload_type.to_vec(),
payload: envelope.payload.to_vec(),
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.
# In the future protobuf generated files will be checked in, so we can remove this
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
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]
name = "prost-codec"
name = "quick-protobuf-codec"
edition = "2021"
rust-version = "1.60.0"
description = "Asynchronous de-/encoding of Protobuf structs using asynchronous-codec, unsigned-varint and prost."
version = "0.3.0"
description = "Asynchronous de-/encoding of Protobuf structs using asynchronous-codec, unsigned-varint and quick-protobuf."
version = "0.1.0"
authors = ["Max Inden <mail@max-inden.de>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
@ -13,12 +13,9 @@ categories = ["asynchronous"]
[dependencies]
asynchronous-codec = { version = "0.6" }
bytes = { version = "1" }
prost = "0.11"
thiserror = "1.0"
unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] }
[dev-dependencies]
prost-build = "0.11"
quick-protobuf = "0.8"
# Passing arguments to the docsrs builder in order to properly document cfg's.
# More information: https://docs.rs/about/builds#cross-compiling

View File

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

View File

@ -8,6 +8,9 @@
- 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
# 0.9.1

View File

@ -10,9 +10,6 @@ repository = "https://github.com/libp2p/rust-libp2p"
keywords = ["peer-to-peer", "libp2p", "networking"]
categories = ["network-programming", "asynchronous"]
[build-dependencies]
prost-build = "0.11"
[dependencies]
async-trait = "0.1"
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" }
log = "0.4"
rand = "0.8"
prost = "0.11"
quick-protobuf = "0.8"
[dev-dependencies]
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};
#[allow(clippy::derive_partial_eq_without_eq)]
mod structs_proto {
include!(concat!(env!("OUT_DIR"), "/structs.rs"));
mod proto {
include!("generated/mod.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
// DEALINGS IN THE SOFTWARE.
use crate::structs_proto;
use crate::proto;
use async_trait::async_trait;
use futures::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
use libp2p_core::{upgrade, Multiaddr, PeerId};
use libp2p_request_response::{self as request_response, ProtocolName};
use prost::Message;
use quick_protobuf::{BytesReader, Writer};
use std::{convert::TryFrom, io};
#[derive(Clone, Debug)]
@ -108,14 +108,17 @@ pub struct DialRequest {
impl DialRequest {
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))?;
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"));
}
let (peer_id, addrs) = if let Some(structs_proto::message::Dial {
let (peer_id, addrs) = if let Some(proto::Dial {
peer:
Some(structs_proto::message::PeerInfo {
Some(proto::PeerInfo {
id: Some(peer_id),
addrs,
}),
@ -131,12 +134,13 @@ impl DialRequest {
};
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"))?
};
let addrs = addrs
.into_iter()
.filter_map(|a| match Multiaddr::try_from(a) {
.filter_map(|a| match Multiaddr::try_from(a.to_vec()) {
Ok(a) => Some(a),
Err(e) => {
log::debug!("Unable to parse multiaddr: {e}");
@ -151,6 +155,8 @@ impl DialRequest {
}
pub fn into_bytes(self) -> Vec<u8> {
use quick_protobuf::MessageWrite;
let peer_id = self.peer_id.to_bytes();
let addrs = self
.addresses
@ -158,21 +164,21 @@ impl DialRequest {
.map(|addr| addr.to_vec())
.collect();
let msg = structs_proto::Message {
r#type: Some(structs_proto::message::MessageType::Dial as _),
dial: Some(structs_proto::message::Dial {
peer: Some(structs_proto::message::PeerInfo {
id: Some(peer_id),
let msg = proto::Message {
type_pb: Some(proto::MessageType::DIAL),
dial: Some(proto::Dial {
peer: Some(proto::PeerInfo {
id: Some(peer_id.to_vec()),
addrs,
}),
}),
dial_response: None,
dialResponse: None,
};
let mut bytes = Vec::with_capacity(msg.encoded_len());
msg.encode(&mut bytes)
.expect("Vec<u8> provides capacity as needed");
bytes
let mut buf = Vec::with_capacity(msg.get_size());
let mut writer = Writer::new(&mut buf);
msg.write_message(&mut writer).expect("Encoding to succeed");
buf
}
}
@ -184,29 +190,27 @@ pub enum ResponseError {
InternalError,
}
impl From<ResponseError> for i32 {
impl From<ResponseError> for proto::ResponseStatus {
fn from(t: ResponseError) -> Self {
match t {
ResponseError::DialError => 100,
ResponseError::DialRefused => 101,
ResponseError::BadRequest => 200,
ResponseError::InternalError => 300,
ResponseError::DialError => proto::ResponseStatus::E_DIAL_ERROR,
ResponseError::DialRefused => proto::ResponseStatus::E_DIAL_REFUSED,
ResponseError::BadRequest => proto::ResponseStatus::E_BAD_REQUEST,
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;
fn try_from(value: structs_proto::message::ResponseStatus) -> Result<Self, Self::Error> {
fn try_from(value: proto::ResponseStatus) -> Result<Self, Self::Error> {
match value {
structs_proto::message::ResponseStatus::EDialError => Ok(ResponseError::DialError),
structs_proto::message::ResponseStatus::EDialRefused => Ok(ResponseError::DialRefused),
structs_proto::message::ResponseStatus::EBadRequest => Ok(ResponseError::BadRequest),
structs_proto::message::ResponseStatus::EInternalError => {
Ok(ResponseError::InternalError)
}
structs_proto::message::ResponseStatus::Ok => {
proto::ResponseStatus::E_DIAL_ERROR => Ok(ResponseError::DialError),
proto::ResponseStatus::E_DIAL_REFUSED => Ok(ResponseError::DialRefused),
proto::ResponseStatus::E_BAD_REQUEST => Ok(ResponseError::BadRequest),
proto::ResponseStatus::E_INTERNAL_ERROR => Ok(ResponseError::InternalError),
proto::ResponseStatus::OK => {
log::debug!("Received response with status code OK but expected error.");
Err(io::Error::new(
io::ErrorKind::InvalidData,
@ -225,38 +229,35 @@ pub struct DialResponse {
impl DialResponse {
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))?;
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"));
}
Ok(match msg.dial_response {
Some(structs_proto::message::DialResponse {
status: Some(status),
status_text,
Ok(match msg.dialResponse {
Some(proto::DialResponse {
status: Some(proto::ResponseStatus::OK),
statusText,
addr: Some(addr),
}) if structs_proto::message::ResponseStatus::from_i32(status)
== Some(structs_proto::message::ResponseStatus::Ok) =>
{
let addr = Multiaddr::try_from(addr)
}) => {
let addr = Multiaddr::try_from(addr.to_vec())
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
Self {
status_text,
status_text: statusText,
result: Ok(addr),
}
}
Some(structs_proto::message::DialResponse {
Some(proto::DialResponse {
status: Some(status),
status_text,
statusText,
addr: None,
}) => Self {
status_text,
result: Err(ResponseError::try_from(
structs_proto::message::ResponseStatus::from_i32(status).ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidData, "invalid response status code")
})?,
)?),
status_text: statusText,
result: Err(ResponseError::try_from(status)?),
},
_ => {
log::debug!("Received malformed response message.");
@ -269,35 +270,38 @@ impl DialResponse {
}
pub fn into_bytes(self) -> Vec<u8> {
use quick_protobuf::MessageWrite;
let dial_response = match self.result {
Ok(addr) => structs_proto::message::DialResponse {
status: Some(0),
status_text: self.status_text,
Ok(addr) => proto::DialResponse {
status: Some(proto::ResponseStatus::OK),
statusText: self.status_text,
addr: Some(addr.to_vec()),
},
Err(error) => structs_proto::message::DialResponse {
Err(error) => proto::DialResponse {
status: Some(error.into()),
status_text: self.status_text,
statusText: self.status_text,
addr: None,
},
};
let msg = structs_proto::Message {
r#type: Some(structs_proto::message::MessageType::DialResponse as _),
let msg = proto::Message {
type_pb: Some(proto::MessageType::DIAL_RESPONSE),
dial: None,
dial_response: Some(dial_response),
dialResponse: Some(dial_response),
};
let mut bytes = Vec::with_capacity(msg.encoded_len());
msg.encode(&mut bytes)
.expect("Vec<u8> provides capacity as needed");
bytes
let mut buf = Vec::with_capacity(msg.get_size());
let mut writer = Writer::new(&mut buf);
msg.write_message(&mut writer).expect("Encoding to succeed");
buf
}
}
#[cfg(test)]
mod tests {
use super::*;
use quick_protobuf::MessageWrite;
#[test]
fn test_request_encode_decode() {
@ -346,20 +350,20 @@ mod tests {
a
};
let msg = structs_proto::Message {
r#type: Some(structs_proto::message::MessageType::Dial.into()),
dial: Some(structs_proto::message::Dial {
peer: Some(structs_proto::message::PeerInfo {
let msg = proto::Message {
type_pb: Some(proto::MessageType::DIAL),
dial: Some(proto::Dial {
peer: Some(proto::PeerInfo {
id: Some(PeerId::random().to_bytes()),
addrs: vec![valid_multiaddr_bytes, invalid_multiaddr],
}),
}),
dial_response: None,
dialResponse: None,
};
let mut bytes = Vec::with_capacity(msg.encoded_len());
msg.encode(&mut bytes)
.expect("Vec<u8> provides capacity as needed");
let mut bytes = Vec::with_capacity(msg.get_size());
let mut writer = Writer::new(&mut bytes);
msg.write_message(&mut writer).expect("Encoding to succeed");
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].
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[PR 3213]: https://github.com/libp2p/rust-libp2p/pull/3213
[PR 3153]: https://github.com/libp2p/rust-libp2p/pull/3153
[issue 2217]: https://github.com/libp2p/rust-libp2p/issues/2217
[PR 3214]: https://github.com/libp2p/rust-libp2p/pull/3214
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
# 0.8.1

View File

@ -19,14 +19,11 @@ instant = "0.1.11"
libp2p-core = { version = "0.39.0", path = "../../core" }
libp2p-swarm = { version = "0.42.0", path = "../../swarm" }
log = "0.4"
prost-codec = { version = "0.3", path = "../../misc/prost-codec" }
prost = "0.11"
quick-protobuf = "0.8"
quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" }
thiserror = "1.0"
void = "1"
[build-dependencies]
prost-build = "0.11"
[dev-dependencies]
clap = { version = "4.1.6", features = ["derive"] }
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 handler;
mod protocol;
#[allow(clippy::derive_partial_eq_without_eq)]
mod message_proto {
include!(concat!(env!("OUT_DIR"), "/holepunch.pb.rs"));
mod proto {
include!("generated/mod.rs");
pub use self::holepunch::pb::{mod_HolePunch::*, HolePunch};
}
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
// DEALINGS IN THE SOFTWARE.
use crate::message_proto::{hole_punch, HolePunch};
use crate::proto;
use asynchronous_codec::Framed;
use futures::{future::BoxFuture, prelude::*};
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 {
let mut substream = Framed::new(
substream,
prost_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES),
quick_protobuf_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES),
);
async move {
let HolePunch { r#type, obs_addrs } =
let proto::HolePunch { type_pb, ObsAddrs } =
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);
} else {
obs_addrs
ObsAddrs
.into_iter()
.filter_map(|a| match Multiaddr::try_from(a) {
.filter_map(|a| match Multiaddr::try_from(a.to_vec()) {
Ok(a) => Some(a),
Err(e) => {
log::debug!("Unable to parse multiaddr: {e}");
@ -77,11 +77,9 @@ impl upgrade::InboundUpgrade<NegotiatedSubstream> for Upgrade {
.collect::<Vec<Multiaddr>>()
};
let r#type = hole_punch::Type::from_i32(r#type).ok_or(UpgradeError::ParseTypeField)?;
match r#type {
hole_punch::Type::Connect => {}
hole_punch::Type::Sync => return Err(UpgradeError::UnexpectedTypeSync),
match type_pb {
proto::Type::CONNECT => {}
proto::Type::SYNC => return Err(UpgradeError::UnexpectedTypeSync),
}
Ok(PendingConnect {
@ -94,7 +92,7 @@ impl upgrade::InboundUpgrade<NegotiatedSubstream> for Upgrade {
}
pub struct PendingConnect {
substream: Framed<NegotiatedSubstream, prost_codec::Codec<HolePunch>>,
substream: Framed<NegotiatedSubstream, quick_protobuf_codec::Codec<proto::HolePunch>>,
remote_obs_addrs: Vec<Multiaddr>,
}
@ -103,22 +101,21 @@ impl PendingConnect {
mut self,
local_obs_addrs: Vec<Multiaddr>,
) -> Result<Vec<Multiaddr>, UpgradeError> {
let msg = HolePunch {
r#type: hole_punch::Type::Connect.into(),
obs_addrs: local_obs_addrs.into_iter().map(|a| a.to_vec()).collect(),
let msg = proto::HolePunch {
type_pb: proto::Type::CONNECT,
ObsAddrs: local_obs_addrs.into_iter().map(|a| a.to_vec()).collect(),
};
self.substream.send(msg).await?;
let HolePunch { r#type, .. } = self
let proto::HolePunch { type_pb, .. } = self
.substream
.next()
.await
.ok_or(UpgradeError::StreamClosed)??;
let r#type = hole_punch::Type::from_i32(r#type).ok_or(UpgradeError::ParseTypeField)?;
match r#type {
hole_punch::Type::Connect => return Err(UpgradeError::UnexpectedTypeConnect),
hole_punch::Type::Sync => {}
match type_pb {
proto::Type::CONNECT => return Err(UpgradeError::UnexpectedTypeConnect),
proto::Type::SYNC => {}
}
Ok(self.remote_obs_addrs)
@ -128,7 +125,7 @@ impl PendingConnect {
#[derive(Debug, Error)]
pub enum UpgradeError {
#[error(transparent)]
Codec(#[from] prost_codec::Error),
Codec(#[from] quick_protobuf_codec::Error),
#[error("Stream closed")]
StreamClosed,
#[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
// DEALINGS IN THE SOFTWARE.
use crate::message_proto::{hole_punch, HolePunch};
use crate::proto;
use asynchronous_codec::Framed;
use futures::{future::BoxFuture, prelude::*};
use futures_timer::Delay;
@ -56,12 +56,12 @@ impl upgrade::OutboundUpgrade<NegotiatedSubstream> for Upgrade {
fn upgrade_outbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future {
let mut substream = Framed::new(
substream,
prost_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES),
quick_protobuf_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES),
);
let msg = HolePunch {
r#type: hole_punch::Type::Connect.into(),
obs_addrs: self.obs_addrs.into_iter().map(|a| a.to_vec()).collect(),
let msg = proto::HolePunch {
type_pb: proto::Type::CONNECT,
ObsAddrs: self.obs_addrs.into_iter().map(|a| a.to_vec()).collect(),
};
async move {
@ -69,23 +69,22 @@ impl upgrade::OutboundUpgrade<NegotiatedSubstream> for Upgrade {
let sent_time = Instant::now();
let HolePunch { r#type, obs_addrs } =
let proto::HolePunch { type_pb, ObsAddrs } =
substream.next().await.ok_or(UpgradeError::StreamClosed)??;
let rtt = sent_time.elapsed();
let r#type = hole_punch::Type::from_i32(r#type).ok_or(UpgradeError::ParseTypeField)?;
match r#type {
hole_punch::Type::Connect => {}
hole_punch::Type::Sync => return Err(UpgradeError::UnexpectedTypeSync),
match type_pb {
proto::Type::CONNECT => {}
proto::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);
} else {
obs_addrs
ObsAddrs
.into_iter()
.filter_map(|a| match Multiaddr::try_from(a) {
.filter_map(|a| match Multiaddr::try_from(a.to_vec()) {
Ok(a) => Some(a),
Err(e) => {
log::debug!("Unable to parse multiaddr: {e}");
@ -104,9 +103,9 @@ impl upgrade::OutboundUpgrade<NegotiatedSubstream> for Upgrade {
.collect::<Vec<Multiaddr>>()
};
let msg = HolePunch {
r#type: hole_punch::Type::Sync.into(),
obs_addrs: vec![],
let msg = proto::HolePunch {
type_pb: proto::Type::SYNC,
ObsAddrs: vec![],
};
substream.send(msg).await?;
@ -126,7 +125,7 @@ pub struct Connect {
#[derive(Debug, Error)]
pub enum UpgradeError {
#[error(transparent)]
Codec(#[from] prost_codec::Error),
Codec(#[from] quick_protobuf_codec::Error),
#[error("Stream closed")]
StreamClosed,
#[error("Expected 'status' field to be set.")]

View File

@ -4,9 +4,9 @@
- 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

View File

@ -18,15 +18,12 @@ futures = "0.3.26"
libp2p-core = { version = "0.39.0", path = "../../core" }
libp2p-swarm = { version = "0.42.0", path = "../../swarm" }
log = "0.4"
prost = "0.11"
prost-codec = { version = "0.3", path = "../../misc/prost-codec" }
quick-protobuf = "0.8"
quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" }
rand = "0.8"
smallvec = "1.6.1"
thiserror = "1.0.37"
[build-dependencies]
prost-build = "0.11"
# Passing arguments to the docsrs builder in order to properly document cfg's.
# More information: https://docs.rs/about/builds#cross-compiling
[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 topic;
#[allow(clippy::derive_partial_eq_without_eq)]
mod rpc_proto {
include!(concat!(env!("OUT_DIR"), "/floodsub.pb.rs"));
mod proto {
include!("generated/mod.rs");
pub use self::floodsub::pb::{mod_RPC::SubOpts, Message, RPC};
}
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
// DEALINGS IN THE SOFTWARE.
use crate::rpc_proto;
use crate::proto;
use crate::topic::Topic;
use asynchronous_codec::Framed;
use futures::{
@ -65,7 +65,7 @@ where
Box::pin(async move {
let mut framed = Framed::new(
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
@ -120,7 +120,7 @@ pub enum FloodsubError {
#[derive(thiserror::Error, Debug)]
#[error(transparent)]
pub struct CodecError(#[from] prost_codec::Error);
pub struct CodecError(#[from] quick_protobuf_codec::Error);
/// An RPC received by the floodsub system.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -152,7 +152,7 @@ where
Box::pin(async move {
let mut framed = Framed::new(
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.close().await?;
@ -163,12 +163,12 @@ where
impl FloodsubRpc {
/// Turns this `FloodsubRpc` into a message that can be sent to a substream.
fn into_rpc(self) -> rpc_proto::Rpc {
rpc_proto::Rpc {
fn into_rpc(self) -> proto::RPC {
proto::RPC {
publish: self
.messages
.into_iter()
.map(|msg| rpc_proto::Message {
.map(|msg| proto::Message {
from: Some(msg.source.to_bytes()),
data: Some(msg.data),
seqno: Some(msg.sequence_number),
@ -179,7 +179,7 @@ impl FloodsubRpc {
subscriptions: self
.subscriptions
.into_iter()
.map(|topic| rpc_proto::rpc::SubOpts {
.map(|topic| proto::SubOpts {
subscribe: Some(topic.action == FloodsubSubscriptionAction::Subscribe),
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::`.
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 3303]: https://github.com/libp2p/rust-libp2p/pull/3303/
[PR 3381]: https://github.com/libp2p/rust-libp2p/pull/3381/
[discussion 2174]: https://github.com/libp2p/rust-libp2p/discussions/2174
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
# 0.43.0

View File

@ -24,8 +24,8 @@ log = "0.4.11"
sha2 = "0.10.0"
base64 = "0.21.0"
smallvec = "1.6.1"
prost = "0.11"
prost-codec = { version = "0.3", path = "../../misc/prost-codec" }
quick-protobuf = "0.8"
quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" }
hex_fmt = "0.3.0"
regex = "1.5.5"
serde = { version = "1", optional = true, features = ["derive"] }
@ -46,9 +46,6 @@ libp2p-swarm = { path = "../../swarm" }
libp2p-yamux = { path = "../../muxers/yamux" }
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.
# More information: https://docs.rs/about/builds#cross-compiling
[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 log::{debug, error, trace, warn};
use prometheus_client::registry::Registry;
use prost::Message as _;
use rand::{seq::SliceRandom, thread_rng};
use libp2p_core::{
@ -64,8 +63,9 @@ use crate::types::{
Subscription, SubscriptionAction,
};
use crate::types::{PeerConnections, PeerKind, Rpc};
use crate::{rpc_proto, TopicScoreParams};
use crate::{rpc_proto::proto, TopicScoreParams};
use crate::{PublishError, SubscriptionError, ValidationError};
use quick_protobuf::{MessageWrite, Writer};
use std::{cmp::Ordering::Equal, fmt::Debug};
use wasm_timer::Interval;
@ -179,8 +179,8 @@ impl From<MessageAuthenticity> for PublishConfig {
let public_key = keypair.public();
let key_enc = public_key.to_protobuf_encoding();
let key = if key_enc.len() <= 42 {
// The public key can be inlined in [`rpc_proto::Message::from`], so we don't include it
// specifically in the [`rpc_proto::Message::key`] field.
// The public key can be inlined in [`rpc_proto::proto::::Message::from`], so we don't include it
// specifically in the [`rpc_proto::proto::Message::key`] field.
None
} else {
// Include the protobuf encoding of the public key in the message.
@ -610,7 +610,7 @@ where
.into_protobuf();
// 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);
}
@ -721,7 +721,7 @@ where
}
// 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() {
trace!("Sending message to peer: {:?}", peer_id);
self.send_message(*peer_id, event.clone())?;
@ -1338,7 +1338,7 @@ where
}
.into_protobuf();
let msg_bytes = message.encoded_len();
let msg_bytes = message.get_size();
if self.send_message(*peer_id, message).is_err() {
error!("Failed to send cached messages. Messages too large");
@ -2733,7 +2733,7 @@ where
}
.into_protobuf();
let msg_bytes = event.encoded_len();
let msg_bytes = event.get_size();
for peer in recipient_peers.iter() {
debug!("Sending message: {:?} to peer {:?}", msg_id, peer);
self.send_message(*peer, event.clone())?;
@ -2764,7 +2764,7 @@ where
let sequence_number: u64 = rand::random();
let signature = {
let message = rpc_proto::Message {
let message = proto::Message {
from: Some(author.clone().to_bytes()),
data: Some(data.clone()),
seqno: Some(sequence_number.to_be_bytes().to_vec()),
@ -2773,10 +2773,12 @@ where
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
.encode(&mut buf)
.expect("Buffer has sufficient capacity");
.write_message(&mut writer)
.expect("Encoding to succeed");
// the signature is over the bytes "libp2p-pubsub:<protobuf-message>"
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
/// is not already an arc.
fn send_message(
&mut self,
peer_id: PeerId,
message: rpc_proto::Rpc,
) -> Result<(), PublishError> {
fn send_message(&mut self, peer_id: PeerId, message: proto::RPC) -> Result<(), PublishError> {
// 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
// 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
// messages to be sent.
fn fragment_message(&self, rpc: rpc_proto::Rpc) -> Result<Vec<rpc_proto::Rpc>, PublishError> {
if rpc.encoded_len() < self.config.max_transmit_size() {
fn fragment_message(&self, rpc: proto::RPC) -> Result<Vec<proto::RPC>, PublishError> {
if rpc.get_size() < self.config.max_transmit_size() {
return Ok(vec![rpc]);
}
let new_rpc = rpc_proto::Rpc {
let new_rpc = proto::RPC {
subscriptions: Vec::new(),
publish: Vec::new(),
control: None,
@ -2920,7 +2918,7 @@ where
// create a new RPC if the new object plus 5% of its size (for length prefix
// 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()
&& rpc_list[list_index] != new_rpc
{
@ -2932,7 +2930,7 @@ where
macro_rules! add_item {
($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() {
// 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
// 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 control.encoded_len() + 2 > self.config.max_transmit_size() {
if control.get_size() + 2 > self.config.max_transmit_size() {
// fragment the RPC
for ihave in &control.ihave {
let len = ihave.encoded_len();
let len = ihave.get_size();
create_or_add_rpc!(len);
rpc_list
.last_mut()
@ -2976,7 +2974,7 @@ where
.push(ihave.clone());
}
for iwant in &control.iwant {
let len = iwant.encoded_len();
let len = iwant.get_size();
create_or_add_rpc!(len);
rpc_list
.last_mut()
@ -2987,7 +2985,7 @@ where
.push(iwant.clone());
}
for graft in &control.graft {
let len = graft.encoded_len();
let len = graft.get_size();
create_or_add_rpc!(len);
rpc_list
.last_mut()
@ -2998,7 +2996,7 @@ where
.push(graft.clone());
}
for prune in &control.prune {
let len = prune.encoded_len();
let len = prune.get_size();
create_or_add_rpc!(len);
rpc_list
.last_mut()
@ -3009,7 +3007,7 @@ where
.push(prune.clone());
}
} else {
let len = control.encoded_len();
let len = control.get_size();
create_or_add_rpc!(len);
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
while rpc_proto.encoded_len() < max_transmit_size {
while rpc_proto.get_size() < max_transmit_size {
rpc.messages.push(test_message());
rpc_proto = rpc.clone().into_protobuf();
}
@ -3786,7 +3784,7 @@ mod local_test {
// all fragmented messages should be under the limit
for message in fragmented_messages {
assert!(
message.encoded_len() < max_transmit_size,
message.get_size() < max_transmit_size,
"all messages should be less than the transmission size"
);
}
@ -3813,7 +3811,7 @@ mod local_test {
.fragment_message(rpc_proto.clone())
.expect("Messages must be valid");
if rpc_proto.encoded_len() < max_transmit_size {
if rpc_proto.get_size() < max_transmit_size {
assert_eq!(
fragmented_messages.len(),
1,
@ -3829,12 +3827,12 @@ mod local_test {
// all fragmented messages should be under the limit
for message in fragmented_messages {
assert!(
message.encoded_len() < max_transmit_size,
"all messages should be less than the transmission size: list size {} max size{}", 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.get_size(), max_transmit_size
);
// 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()
}
}

View File

@ -284,7 +284,7 @@ where
}
// 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.
let mut messages = Vec::with_capacity(rpc.publish.len());
let rpc = rpc.clone();

View File

@ -100,7 +100,7 @@ pub enum HandlerError {
#[error("Protocol negotiation failed.")]
NegotiationProtocolError(ProtocolError),
#[error("Failed to encode or decode")]
Codec(#[from] prost_codec::Error),
Codec(#[from] quick_protobuf_codec::Error),
}
#[derive(Debug, Clone, Copy)]
@ -136,7 +136,7 @@ impl std::error::Error for ValidationError {}
impl From<std::io::Error> for 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.
use crate::protocol::{GossipsubCodec, ProtocolConfig};
use crate::rpc_proto::proto;
use crate::types::{PeerKind, RawMessage, Rpc};
use crate::{HandlerError, ValidationError};
use asynchronous_codec::Framed;
@ -67,7 +68,7 @@ pub enum HandlerEvent {
#[derive(Debug)]
pub enum HandlerIn {
/// A gossipsub message to send.
Message(crate::rpc_proto::Rpc),
Message(proto::RPC),
/// The peer has joined the mesh.
JoinedMesh,
/// The peer has left the mesh.
@ -93,7 +94,7 @@ pub struct Handler {
inbound_substream: Option<InboundSubstreamState>,
/// 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
/// requests.
@ -149,10 +150,7 @@ enum OutboundSubstreamState {
/// Waiting for the user to send a message. The idle state for an outbound substream.
WaitingOutput(Framed<NegotiatedSubstream, GossipsubCodec>),
/// Waiting to send a message to the remote.
PendingSend(
Framed<NegotiatedSubstream, GossipsubCodec>,
crate::rpc_proto::Rpc,
),
PendingSend(Framed<NegotiatedSubstream, GossipsubCodec>, proto::RPC),
/// Waiting to flush the substream so that the data arrives to the remote.
PendingFlush(Framed<NegotiatedSubstream, GossipsubCodec>),
/// The substream is being closed. Used by either substream.
@ -251,7 +249,7 @@ impl ConnectionHandler for Handler {
type Error = HandlerError;
type InboundOpenInfo = ();
type InboundProtocol = ProtocolConfig;
type OutboundOpenInfo = crate::rpc_proto::Rpc;
type OutboundOpenInfo = proto::RPC;
type OutboundProtocol = ProtocolConfig;
fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, Self::InboundOpenInfo> {

View File

@ -24,7 +24,7 @@ use crate::topic::TopicHash;
use crate::types::{
ControlAction, MessageId, PeerInfo, PeerKind, RawMessage, Rpc, Subscription, SubscriptionAction,
};
use crate::{rpc_proto, Config};
use crate::{rpc_proto::proto, Config};
use crate::{HandlerError, ValidationError};
use asynchronous_codec::{Decoder, Encoder, Framed};
use byteorder::{BigEndian, ByteOrder};
@ -35,7 +35,7 @@ use libp2p_core::{
identity::PublicKey, InboundUpgrade, OutboundUpgrade, PeerId, ProtocolName, UpgradeInfo,
};
use log::{debug, warn};
use prost::Message as _;
use quick_protobuf::Writer;
use std::pin::Pin;
use unsigned_varint::codec;
@ -191,12 +191,12 @@ pub struct GossipsubCodec {
/// Determines the level of validation performed on incoming messages.
validation_mode: ValidationMode,
/// 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 {
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 {
validation_mode,
codec,
@ -206,7 +206,9 @@ impl GossipsubCodec {
/// 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
/// 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() {
Some(v) => v,
None => {
@ -258,10 +260,11 @@ impl GossipsubCodec {
let mut message_sig = message.clone();
message_sig.signature = 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
.encode(&mut buf)
.expect("Buffer has sufficient capacity");
.write_message(&mut writer)
.expect("Encoding to succeed");
let mut signature_bytes = SIGNING_PREFIX.to_vec();
signature_bytes.extend_from_slice(&buf);
public_key.verify(&signature_bytes, signature)
@ -269,7 +272,7 @@ impl GossipsubCodec {
}
impl Encoder for GossipsubCodec {
type Item = rpc_proto::Rpc;
type Item = proto::RPC;
type Error = 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
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// 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)]
mod test {
use crate::rpc_proto::proto::compat;
use crate::IdentTopic as Topic;
use libp2p_core::PeerId;
use prost::Message;
use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
use rand::Rng;
mod compat_proto {
include!(concat!(env!("OUT_DIR"), "/compat.pb.rs"));
}
#[test]
fn test_multi_topic_message_compatibility() {
let topic1 = Topic::new("t1").hash();
let topic2 = Topic::new("t2").hash();
let new_message1 = super::Message {
let new_message1 = super::proto::Message {
from: Some(PeerId::random().to_bytes()),
data: Some(rand::thread_rng().gen::<[u8; 32]>().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()),
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()),
data: Some(rand::thread_rng().gen::<[u8; 32]>().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()),
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()),
data: Some(rand::thread_rng().gen::<[u8; 32]>().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()),
};
let mut new_message1b = Vec::with_capacity(new_message1.encoded_len());
new_message1.encode(&mut new_message1b).unwrap();
let mut new_message1b = Vec::with_capacity(new_message1.get_size());
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());
old_message1.encode(&mut old_message1b).unwrap();
let mut old_message1b = Vec::with_capacity(old_message1.get_size());
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());
old_message2.encode(&mut old_message2b).unwrap();
let mut old_message2b = Vec::with_capacity(old_message2.get_size());
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());
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());
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()]);
}
}

View File

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

View File

@ -19,15 +19,15 @@
// DEALINGS IN THE SOFTWARE.
//! A collection of types using the Gossipsub system.
use crate::rpc_proto;
use crate::TopicHash;
use libp2p_core::PeerId;
use libp2p_swarm::ConnectionId;
use prometheus_client::encoding::EncodeLabelValue;
use prost::Message as _;
use quick_protobuf::MessageWrite;
use std::fmt;
use std::fmt::Debug;
use crate::rpc_proto::proto;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
@ -136,7 +136,7 @@ pub struct RawMessage {
impl RawMessage {
/// Calculates the encoded length of this message (used for calculating metrics).
pub fn raw_protobuf_len(&self) -> usize {
let message = rpc_proto::Message {
let message = proto::Message {
from: self.source.map(|m| m.to_bytes()),
data: Some(self.data.clone()),
seqno: self.sequence_number.map(|s| s.to_be_bytes().to_vec()),
@ -144,7 +144,7 @@ impl RawMessage {
signature: self.signature.clone(),
key: self.key.clone(),
};
message.encoded_len()
message.get_size()
}
}
@ -250,19 +250,19 @@ pub struct Rpc {
impl Rpc {
/// Converts the GossipsubRPC into its protobuf format.
// 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()
}
}
impl From<Rpc> for rpc_proto::Rpc {
impl From<Rpc> for proto::RPC {
/// Converts the RPC into protobuf format.
fn from(rpc: Rpc) -> Self {
// Messages
let mut publish = Vec::new();
for message in rpc.messages.into_iter() {
let message = rpc_proto::Message {
let message = proto::Message {
from: message.source.map(|m| m.to_bytes()),
data: Some(message.data),
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
.subscriptions
.into_iter()
.map(|sub| rpc_proto::rpc::SubOpts {
.map(|sub| proto::SubOpts {
subscribe: Some(sub.action == SubscriptionAction::Subscribe),
topic_id: Some(sub.topic_hash.into_string()),
})
.collect::<Vec<_>>();
// control messages
let mut control = rpc_proto::ControlMessage {
let mut control = proto::ControlMessage {
ihave: Vec::new(),
iwant: Vec::new(),
graft: Vec::new(),
@ -301,20 +301,20 @@ impl From<Rpc> for rpc_proto::Rpc {
topic_hash,
message_ids,
} => {
let rpc_ihave = rpc_proto::ControlIHave {
let rpc_ihave = proto::ControlIHave {
topic_id: Some(topic_hash.into_string()),
message_ids: message_ids.into_iter().map(|msg_id| msg_id.0).collect(),
};
control.ihave.push(rpc_ihave);
}
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(),
};
control.iwant.push(rpc_iwant);
}
ControlAction::Graft { topic_hash } => {
let rpc_graft = rpc_proto::ControlGraft {
let rpc_graft = proto::ControlGraft {
topic_id: Some(topic_hash.into_string()),
};
control.graft.push(rpc_graft);
@ -324,11 +324,11 @@ impl From<Rpc> for rpc_proto::Rpc {
peers,
backoff,
} => {
let rpc_prune = rpc_proto::ControlPrune {
let rpc_prune = proto::ControlPrune {
topic_id: Some(topic_hash.into_string()),
peers: peers
.into_iter()
.map(|info| rpc_proto::PeerInfo {
.map(|info| proto::PeerInfo {
peer_id: info.peer_id.map(|id| id.to_bytes()),
/// TODO, see https://github.com/libp2p/specs/pull/217
signed_peer_record: None,
@ -341,7 +341,7 @@ impl From<Rpc> for rpc_proto::Rpc {
}
}
rpc_proto::Rpc {
proto::RPC {
subscriptions,
publish,
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].
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[PR 3208]: https://github.com/libp2p/rust-libp2p/pull/3208
[PR 3344]: https://github.com/libp2p/rust-libp2p/pull/3344
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
# 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" }
log = "0.4.1"
lru = "0.9.0"
prost-codec = { version = "0.3", path = "../../misc/prost-codec" }
prost = "0.11"
quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" }
quick-protobuf = "0.8"
smallvec = "1.6.1"
thiserror = "1.0"
void = "1.0"
@ -34,9 +34,6 @@ libp2p-noise = { path = "../../transports/noise" }
libp2p-swarm = { path = "../../swarm", features = ["async-std"] }
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.
# More information: https://docs.rs/about/builds#cross-compiling
[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 protocol;
#[allow(clippy::derive_partial_eq_without_eq)]
mod structs_proto {
include!(concat!(env!("OUT_DIR"), "/structs.rs"));
mod proto {
include!("generated/mod.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
// DEALINGS IN THE SOFTWARE.
use crate::structs_proto;
use crate::proto;
use asynchronous_codec::{FramedRead, FramedWrite};
use futures::{future::BoxFuture, prelude::*};
use libp2p_core::{
@ -169,18 +169,18 @@ where
let pubkey_bytes = info.public_key.to_protobuf_encoding();
let message = structs_proto::Identify {
agent_version: Some(info.agent_version),
protocol_version: Some(info.protocol_version),
public_key: Some(pubkey_bytes),
listen_addrs,
observed_addr: Some(info.observed_addr.to_vec()),
let message = proto::Identify {
agentVersion: Some(info.agent_version),
protocolVersion: Some(info.protocol_version),
publicKey: Some(pubkey_bytes),
listenAddrs: listen_addrs,
observedAddr: Some(info.observed_addr.to_vec()),
protocols: info.protocols,
};
let mut framed_io = FramedWrite::new(
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?;
@ -200,7 +200,7 @@ where
let info = FramedRead::new(
socket,
prost_codec::Codec::<structs_proto::Identify>::new(MAX_MESSAGE_SIZE_BYTES),
quick_protobuf_codec::Codec::<proto::Identify>::new(MAX_MESSAGE_SIZE_BYTES),
)
.next()
.await
@ -212,17 +212,17 @@ where
Ok(info)
}
impl TryFrom<structs_proto::Identify> for Info {
impl TryFrom<proto::Identify> for Info {
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> {
Multiaddr::try_from(bytes)
}
let listen_addrs = {
let mut addrs = Vec::new();
for addr in msg.listen_addrs.into_iter() {
for addr in msg.listenAddrs.into_iter() {
match parse_multiaddr(addr) {
Ok(a) => addrs.push(a),
Err(e) => {
@ -233,9 +233,9 @@ impl TryFrom<structs_proto::Identify> for Info {
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,
Err(e) => {
debug!("Unable to parse multiaddr: {e:?}");
@ -244,8 +244,8 @@ impl TryFrom<structs_proto::Identify> for Info {
};
let info = Info {
public_key,
protocol_version: msg.protocol_version.unwrap_or_default(),
agent_version: msg.agent_version.unwrap_or_default(),
protocol_version: msg.protocolVersion.unwrap_or_default(),
agent_version: msg.agentVersion.unwrap_or_default(),
listen_addrs,
protocols: msg.protocols,
observed_addr,
@ -258,7 +258,7 @@ impl TryFrom<structs_proto::Identify> for Info {
#[derive(Debug, Error)]
pub enum UpgradeError {
#[error(transparent)]
Codec(#[from] prost_codec::Error),
Codec(#[from] quick_protobuf_codec::Error),
#[error("I/O interaction failed")]
Io(#[from] io::Error),
#[error("Stream closed")]
@ -375,13 +375,13 @@ mod tests {
a
};
let payload = structs_proto::Identify {
agent_version: None,
listen_addrs: vec![valid_multiaddr_bytes, invalid_multiaddr],
observed_addr: None,
protocol_version: None,
let payload = proto::Identify {
agentVersion: None,
listenAddrs: vec![valid_multiaddr_bytes, invalid_multiaddr],
observedAddr: None,
protocolVersion: None,
protocols: vec![],
public_key: Some(
publicKey: Some(
identity::Keypair::generate_ed25519()
.public()
.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.
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
[PR 3239]: https://github.com/libp2p/rust-libp2p/pull/3239
[PR 3287]: https://github.com/libp2p/rust-libp2p/pull/3287
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
# 0.42.1

View File

@ -20,7 +20,7 @@ futures = "0.3.26"
log = "0.4"
libp2p-core = { version = "0.39.0", path = "../../core" }
libp2p-swarm = { version = "0.42.0", path = "../../swarm" }
prost = "0.11"
quick-protobuf = "0.8"
rand = "0.8"
sha2 = "0.10.0"
smallvec = "1.6.1"
@ -39,9 +39,6 @@ libp2p-noise = { path = "../../transports/noise" }
libp2p-yamux = { path = "../../muxers/yamux" }
quickcheck = { package = "quickcheck-ext", path = "../../misc/quickcheck-ext" }
[build-dependencies]
prost-build = "0.11"
[features]
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 query;
#[allow(clippy::derive_partial_eq_without_eq)]
mod dht_proto {
include!(concat!(env!("OUT_DIR"), "/dht.pb.rs"));
mod proto {
include!("generated/mod.rs");
pub use self::dht::pb::{
mod_Message::{ConnectionType, MessageType, Peer},
Message, Record,
};
}
pub use addresses::Addresses;

View File

@ -26,7 +26,7 @@
//! to poll the underlying transport for incoming messages, and the `Sink` component
//! is used to send messages to remote peers.
use crate::dht_proto as proto;
use crate::proto;
use crate::record::{self, Record};
use asynchronous_codec::Framed;
use bytes::BytesMut;
@ -35,7 +35,7 @@ use futures::prelude::*;
use instant::Instant;
use libp2p_core::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
use libp2p_core::{Multiaddr, PeerId};
use prost::Message;
use quick_protobuf::{BytesReader, Writer};
use std::{borrow::Cow, convert::TryFrom, time::Duration};
use std::{io, iter};
use unsigned_varint::codec;
@ -59,26 +59,26 @@ pub enum KadConnectionType {
CannotConnect = 3,
}
impl From<proto::message::ConnectionType> for KadConnectionType {
fn from(raw: proto::message::ConnectionType) -> KadConnectionType {
use proto::message::ConnectionType::*;
impl From<proto::ConnectionType> for KadConnectionType {
fn from(raw: proto::ConnectionType) -> KadConnectionType {
use proto::ConnectionType::*;
match raw {
NotConnected => KadConnectionType::NotConnected,
Connected => KadConnectionType::Connected,
CanConnect => KadConnectionType::CanConnect,
CannotConnect => KadConnectionType::CannotConnect,
NOT_CONNECTED => KadConnectionType::NotConnected,
CONNECTED => KadConnectionType::Connected,
CAN_CONNECT => KadConnectionType::CanConnect,
CANNOT_CONNECT => KadConnectionType::CannotConnect,
}
}
}
impl From<KadConnectionType> for proto::message::ConnectionType {
impl From<KadConnectionType> for proto::ConnectionType {
fn from(val: KadConnectionType) -> Self {
use proto::message::ConnectionType::*;
use proto::ConnectionType::*;
match val {
KadConnectionType::NotConnected => NotConnected,
KadConnectionType::Connected => Connected,
KadConnectionType::CanConnect => CanConnect,
KadConnectionType::CannotConnect => CannotConnect,
KadConnectionType::NotConnected => NOT_CONNECTED,
KadConnectionType::Connected => CONNECTED,
KadConnectionType::CanConnect => CAN_CONNECT,
KadConnectionType::CannotConnect => CANNOT_CONNECT,
}
}
}
@ -95,10 +95,10 @@ pub struct KadPeer {
}
// 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;
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
// as a special case here
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 {
node_id,
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 {
proto::message::Peer {
proto::Peer {
id: peer.node_id.to_bytes(),
addrs: peer.multiaddrs.into_iter().map(|a| a.to_vec()).collect(),
connection: {
let ct: proto::message::ConnectionType = peer.connection_ty.into();
ct as i32
},
connection: peer.connection_ty.into(),
}
}
}
@ -195,6 +188,8 @@ where
type Error = io::Error;
fn upgrade_inbound(self, incoming: C, _: Self::Info) -> Self::Future {
use quick_protobuf::{MessageRead, MessageWrite};
let mut codec = UviBytes::default();
codec.set_max_len(self.max_packet_size);
@ -203,14 +198,16 @@ where
.err_into()
.with::<_, _, fn(_) -> _, _>(|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
.encode(&mut buf)
.expect("Vec<u8> provides capacity as needed");
.write_message(&mut writer)
.expect("Encoding to succeed");
future::ready(Ok(io::Cursor::new(buf)))
})
.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,
Err(err) => return future::ready(Err(err.into())),
};
@ -229,6 +226,8 @@ where
type Error = io::Error;
fn upgrade_outbound(self, incoming: C, _: Self::Info) -> Self::Future {
use quick_protobuf::{MessageRead, MessageWrite};
let mut codec = UviBytes::default();
codec.set_max_len(self.max_packet_size);
@ -237,14 +236,16 @@ where
.err_into()
.with::<_, _, fn(_) -> _, _>(|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
.encode(&mut buf)
.expect("Vec<u8> provides capacity as needed");
.write_message(&mut writer)
.expect("Encoding to succeed");
future::ready(Ok(io::Cursor::new(buf)))
})
.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,
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 {
match kad_msg {
KadRequestMsg::Ping => proto::Message {
r#type: proto::message::MessageType::Ping as i32,
type_pb: proto::MessageType::PING,
..proto::Message::default()
},
KadRequestMsg::FindNode { key } => proto::Message {
r#type: proto::message::MessageType::FindNode as i32,
type_pb: proto::MessageType::FIND_NODE,
key,
cluster_level_raw: 10,
clusterLevelRaw: 10,
..proto::Message::default()
},
KadRequestMsg::GetProviders { key } => proto::Message {
r#type: proto::message::MessageType::GetProviders as i32,
type_pb: proto::MessageType::GET_PROVIDERS,
key: key.to_vec(),
cluster_level_raw: 10,
clusterLevelRaw: 10,
..proto::Message::default()
},
KadRequestMsg::AddProvider { key, provider } => proto::Message {
r#type: proto::message::MessageType::AddProvider as i32,
cluster_level_raw: 10,
type_pb: proto::MessageType::ADD_PROVIDER,
clusterLevelRaw: 10,
key: key.to_vec(),
provider_peers: vec![provider.into()],
providerPeers: vec![provider.into()],
..proto::Message::default()
},
KadRequestMsg::GetValue { key } => proto::Message {
r#type: proto::message::MessageType::GetValue as i32,
cluster_level_raw: 10,
type_pb: proto::MessageType::GET_VALUE,
clusterLevelRaw: 10,
key: key.to_vec(),
..proto::Message::default()
},
KadRequestMsg::PutValue { record } => proto::Message {
r#type: proto::message::MessageType::PutValue as i32,
type_pb: proto::MessageType::PUT_VALUE,
key: record.key.to_vec(),
record: Some(record_to_proto(record)),
..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 {
match kad_msg {
KadResponseMsg::Pong => proto::Message {
r#type: proto::message::MessageType::Ping as i32,
type_pb: proto::MessageType::PING,
..proto::Message::default()
},
KadResponseMsg::FindNode { closer_peers } => proto::Message {
r#type: proto::message::MessageType::FindNode as i32,
cluster_level_raw: 9,
closer_peers: closer_peers.into_iter().map(KadPeer::into).collect(),
type_pb: proto::MessageType::FIND_NODE,
clusterLevelRaw: 9,
closerPeers: closer_peers.into_iter().map(KadPeer::into).collect(),
..proto::Message::default()
},
KadResponseMsg::GetProviders {
closer_peers,
provider_peers,
} => proto::Message {
r#type: proto::message::MessageType::GetProviders as i32,
cluster_level_raw: 9,
closer_peers: closer_peers.into_iter().map(KadPeer::into).collect(),
provider_peers: provider_peers.into_iter().map(KadPeer::into).collect(),
type_pb: proto::MessageType::GET_PROVIDERS,
clusterLevelRaw: 9,
closerPeers: closer_peers.into_iter().map(KadPeer::into).collect(),
providerPeers: provider_peers.into_iter().map(KadPeer::into).collect(),
..proto::Message::default()
},
KadResponseMsg::GetValue {
record,
closer_peers,
} => proto::Message {
r#type: proto::message::MessageType::GetValue as i32,
cluster_level_raw: 9,
closer_peers: closer_peers.into_iter().map(KadPeer::into).collect(),
type_pb: proto::MessageType::GET_VALUE,
clusterLevelRaw: 9,
closerPeers: closer_peers.into_iter().map(KadPeer::into).collect(),
record: record.map(record_to_proto),
..proto::Message::default()
},
KadResponseMsg::PutValue { key, value } => proto::Message {
r#type: proto::message::MessageType::PutValue as i32,
type_pb: proto::MessageType::PUT_VALUE,
key: key.to_vec(),
record: Some(proto::Record {
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.
fn proto_to_req_msg(message: proto::Message) -> Result<KadRequestMsg, io::Error> {
let msg_type = proto::message::MessageType::from_i32(message.r#type)
.ok_or_else(|| invalid_data(format!("unknown message type: {}", message.r#type)))?;
match msg_type {
proto::message::MessageType::Ping => Ok(KadRequestMsg::Ping),
proto::message::MessageType::PutValue => {
match message.type_pb {
proto::MessageType::PING => Ok(KadRequestMsg::Ping),
proto::MessageType::PUT_VALUE => {
let record = record_from_proto(message.record.unwrap_or_default())?;
Ok(KadRequestMsg::PutValue { record })
}
proto::message::MessageType::GetValue => Ok(KadRequestMsg::GetValue {
proto::MessageType::GET_VALUE => Ok(KadRequestMsg::GetValue {
key: record::Key::from(message.key),
}),
proto::message::MessageType::FindNode => Ok(KadRequestMsg::FindNode { key: message.key }),
proto::message::MessageType::GetProviders => Ok(KadRequestMsg::GetProviders {
proto::MessageType::FIND_NODE => Ok(KadRequestMsg::FindNode { key: message.key }),
proto::MessageType::GET_PROVIDERS => Ok(KadRequestMsg::GetProviders {
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
// parsing errors for peers even when they are valid; we ignore these
// errors for now, but ultimately we should just error altogether
let provider = message
.provider_peers
.providerPeers
.into_iter()
.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.
fn proto_to_resp_msg(message: proto::Message) -> Result<KadResponseMsg, io::Error> {
let msg_type = proto::message::MessageType::from_i32(message.r#type)
.ok_or_else(|| invalid_data(format!("unknown message type: {}", message.r#type)))?;
match msg_type {
proto::message::MessageType::Ping => Ok(KadResponseMsg::Pong),
proto::message::MessageType::GetValue => {
match message.type_pb {
proto::MessageType::PING => Ok(KadResponseMsg::Pong),
proto::MessageType::GET_VALUE => {
let record = if let Some(r) = message.record {
Some(record_from_proto(r)?)
} else {
@ -490,7 +485,7 @@ fn proto_to_resp_msg(message: proto::Message) -> Result<KadResponseMsg, io::Erro
};
let closer_peers = message
.closer_peers
.closerPeers
.into_iter()
.filter_map(|peer| KadPeer::try_from(peer).ok())
.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
.closer_peers
.closerPeers
.into_iter()
.filter_map(|peer| KadPeer::try_from(peer).ok())
.collect();
@ -511,15 +506,15 @@ fn proto_to_resp_msg(message: proto::Message) -> Result<KadResponseMsg, io::Erro
Ok(KadResponseMsg::FindNode { closer_peers })
}
proto::message::MessageType::GetProviders => {
proto::MessageType::GET_PROVIDERS => {
let closer_peers = message
.closer_peers
.closerPeers
.into_iter()
.filter_map(|peer| KadPeer::try_from(peer).ok())
.collect();
let provider_peers = message
.provider_peers
.providerPeers
.into_iter()
.filter_map(|peer| KadPeer::try_from(peer).ok())
.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 rec = message
.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"))
}
}
@ -590,7 +585,7 @@ fn record_to_proto(record: Record) -> proto::Record {
}
})
.unwrap_or(0),
time_received: String::new(),
timeReceived: String::new(),
}
}
@ -617,10 +612,10 @@ mod tests {
a
};
let payload = proto::message::Peer {
let payload = proto::Peer {
id: PeerId::random().to_bytes(),
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");

View File

@ -11,8 +11,11 @@
- 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
[discussion 2174]: https://github.com/libp2p/rust-libp2p/issues/2174
[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312
# 0.14.0

View File

@ -20,16 +20,13 @@ instant = "0.1.11"
libp2p-core = { version = "0.39.0", path = "../../core" }
libp2p-swarm = { version = "0.42.0", path = "../../swarm" }
log = "0.4"
prost-codec = { version = "0.3", path = "../../misc/prost-codec" }
prost = "0.11"
quick-protobuf = "0.8"
quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" }
rand = "0.8.4"
static_assertions = "1"
thiserror = "1.0"
void = "1"
[build-dependencies]
prost-build = "0.11"
[dev-dependencies]
clap = { version = "4.1.6", features = ["derive"] }
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;
use crate::behaviour::handler::Handler;
use crate::message_proto;
use crate::multiaddr_ext::MultiaddrExt;
use crate::proto;
use crate::protocol::{inbound_hop, outbound_stop};
use either::Either;
use instant::Instant;
@ -381,7 +381,7 @@ impl NetworkBehaviour for Behaviour {
peer_id: event_source,
event: Either::Left(handler::In::DenyReservationReq {
inbound_reservation_req,
status: message_proto::Status::ResourceLimitExceeded,
status: proto::Status::RESOURCE_LIMIT_EXCEEDED,
}),
}
.into()
@ -496,7 +496,7 @@ impl NetworkBehaviour for Behaviour {
event: Either::Left(handler::In::DenyCircuitReq {
circuit_id: None,
inbound_circuit_req,
status: message_proto::Status::ResourceLimitExceeded,
status: proto::Status::RESOURCE_LIMIT_EXCEEDED,
}),
}
} else if let Some(dst_conn) = self
@ -532,7 +532,7 @@ impl NetworkBehaviour for Behaviour {
event: Either::Left(handler::In::DenyCircuitReq {
circuit_id: None,
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::copy_future::CopyFuture;
use crate::message_proto::Status;
use crate::proto;
use crate::protocol::{inbound_hop, outbound_stop};
use bytes::Bytes;
use either::Either;
@ -58,12 +58,12 @@ pub enum In {
},
DenyReservationReq {
inbound_reservation_req: inbound_hop::ReservationReq,
status: Status,
status: proto::Status,
},
DenyCircuitReq {
circuit_id: Option<CircuitId>,
inbound_circuit_req: inbound_hop::CircuitReq,
status: Status,
status: proto::Status,
},
NegotiateOutboundConnect {
circuit_id: CircuitId,
@ -208,7 +208,7 @@ pub enum Event {
src_peer_id: PeerId,
src_connection_id: ConnectionId,
inbound_circuit_req: inbound_hop::CircuitReq,
status: Status,
status: proto::Status,
error: ConnectionHandlerUpgrErr<outbound_stop::CircuitFailedReason>,
},
/// An inbound circuit has closed.
@ -522,12 +522,14 @@ impl Handler {
>,
) {
let (non_fatal_error, status) = match error {
ConnectionHandlerUpgrErr::Timeout => {
(ConnectionHandlerUpgrErr::Timeout, Status::ConnectionFailed)
}
ConnectionHandlerUpgrErr::Timer => {
(ConnectionHandlerUpgrErr::Timer, Status::ConnectionFailed)
}
ConnectionHandlerUpgrErr::Timeout => (
ConnectionHandlerUpgrErr::Timeout,
proto::Status::CONNECTION_FAILED,
),
ConnectionHandlerUpgrErr::Timer => (
ConnectionHandlerUpgrErr::Timer,
proto::Status::CONNECTION_FAILED,
),
ConnectionHandlerUpgrErr::Upgrade(upgrade::UpgradeError::Select(
upgrade::NegotiationError::Failed,
)) => {
@ -556,10 +558,10 @@ impl Handler {
outbound_stop::UpgradeError::CircuitFailed(error) => {
let status = match error {
outbound_stop::CircuitFailedReason::ResourceLimitExceeded => {
Status::ResourceLimitExceeded
proto::Status::RESOURCE_LIMIT_EXCEEDED
}
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;
pub mod v2;
#[allow(clippy::derive_partial_eq_without_eq)]
mod message_proto {
include!(concat!(env!("OUT_DIR"), "/message_v2.pb.rs"));
mod proto {
include!("generated/mod.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};

View File

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

View File

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

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