diff --git a/Cargo.lock b/Cargo.lock index 541353dc08d..d6efa3b5db9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2530,8 +2530,8 @@ dependencies = [ "libp2p-request-response", "libp2p-swarm", "libp2p-swarm-test", - "quick-protobuf", - "quick-protobuf-codec", + "prost 0.14.3", + "prost-codec", "rand 0.8.5", "rand_core 0.6.4", "thiserror 2.0.18", @@ -2573,7 +2573,7 @@ dependencies = [ "multistream-select", "parking_lot", "pin-project", - "quick-protobuf", + "prost 0.14.3", "rand 0.8.5", "rw-stream-sink", "thiserror 2.0.18", @@ -2602,8 +2602,8 @@ dependencies = [ "libp2p-swarm-test", "libp2p-tcp", "libp2p-yamux", - "quick-protobuf", - "quick-protobuf-codec", + "prost 0.14.3", + "prost-codec", "thiserror 2.0.18", "tokio", "tracing", @@ -2638,8 +2638,8 @@ dependencies = [ "libp2p-core", "libp2p-identity", "libp2p-swarm", - "quick-protobuf", - "quick-protobuf-codec", + "prost 0.14.3", + "prost-codec", "rand 0.8.5", "smallvec", "thiserror 2.0.18", @@ -2667,8 +2667,8 @@ dependencies = [ "libp2p-swarm", "libp2p-swarm-test", "prometheus-client", - "quick-protobuf", - "quick-protobuf-codec", + "prost 0.14.3", + "prost-codec", "quickcheck-ext", "rand 0.8.5", "regex", @@ -2693,8 +2693,8 @@ dependencies = [ "libp2p-identity", "libp2p-swarm", "libp2p-swarm-test", - "quick-protobuf", - "quick-protobuf-codec", + "prost 0.14.3", + "prost-codec", "smallvec", "thiserror 2.0.18", "tokio", @@ -2704,7 +2704,7 @@ dependencies = [ [[package]] name = "libp2p-identity" -version = "0.2.13" +version = "0.2.14" dependencies = [ "asn1_der", "bs58", @@ -2715,7 +2715,7 @@ dependencies = [ "k256", "multihash", "p256", - "quick-protobuf", + "prost 0.14.3", "quickcheck-ext", "rand 0.8.5", "ring", @@ -2747,8 +2747,8 @@ dependencies = [ "libp2p-swarm", "libp2p-swarm-test", "libp2p-yamux", - "quick-protobuf", - "quick-protobuf-codec", + "prost 0.14.3", + "prost-codec", "quickcheck-ext", "rand 0.8.5", "serde", @@ -2863,7 +2863,7 @@ dependencies = [ "libp2p-identity", "multiaddr", "multihash", - "quick-protobuf", + "prost 0.14.3", "quickcheck-ext", "rand 0.8.5", "snow", @@ -2942,8 +2942,8 @@ dependencies = [ "futures_ringbuf", "libp2p-core", "libp2p-identity", - "quick-protobuf", - "quick-protobuf-codec", + "prost 0.14.3", + "prost-codec", "quickcheck-ext", "tracing", "tracing-subscriber", @@ -3013,8 +3013,8 @@ dependencies = [ "libp2p-swarm", "libp2p-swarm-test", "libp2p-yamux", - "quick-protobuf", - "quick-protobuf-codec", + "prost 0.14.3", + "prost-codec", "quickcheck-ext", "rand 0.8.5", "static_assertions", @@ -3039,8 +3039,8 @@ dependencies = [ "libp2p-request-response", "libp2p-swarm", "libp2p-swarm-test", - "quick-protobuf", - "quick-protobuf-codec", + "prost 0.14.3", + "prost-codec", "rand 0.8.5", "thiserror 2.0.18", "tokio", @@ -3249,7 +3249,7 @@ dependencies = [ [[package]] name = "libp2p-webrtc-utils" -version = "0.5.0" +version = "0.6.0" dependencies = [ "asynchronous-codec", "bytes", @@ -3259,8 +3259,8 @@ dependencies = [ "libp2p-core", "libp2p-identity", "libp2p-noise", - "quick-protobuf", - "quick-protobuf-codec", + "prost 0.14.3", + "prost-codec", "rand 0.8.5", "serde", "sha2", @@ -3916,7 +3916,7 @@ dependencies = [ "opentelemetry", "opentelemetry-proto", "opentelemetry_sdk", - "prost", + "prost 0.13.5", "thiserror 1.0.69", "tokio", "tonic", @@ -3931,7 +3931,7 @@ checksum = "a6e05acbfada5ec79023c85368af14abd0b307c015e9064d249b2a950ef459a6" dependencies = [ "opentelemetry", "opentelemetry_sdk", - "prost", + "prost 0.13.5", "tonic", ] @@ -4258,7 +4258,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.13.5", +] + +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive 0.14.3", +] + +[[package]] +name = "prost-codec" +version = "0.4.0" +dependencies = [ + "asynchronous-codec", + "bytes", + "futures", + "prost 0.14.3", + "quickcheck-ext", + "thiserror 2.0.18", + "unsigned-varint", ] [[package]] @@ -4275,26 +4298,16 @@ dependencies = [ ] [[package]] -name = "quick-protobuf" -version = "0.8.1" +name = "prost-derive" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" -dependencies = [ - "byteorder", -] - -[[package]] -name = "quick-protobuf-codec" -version = "0.4.0" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ - "asynchronous-codec", - "bytes", - "criterion", - "futures", - "quick-protobuf", - "quickcheck-ext", - "thiserror 2.0.18", - "unsigned-varint", + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -5776,7 +5789,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "prost", + "prost 0.13.5", "socket2 0.5.9", "tokio", "tokio-stream", diff --git a/Cargo.toml b/Cargo.toml index aafbd1c0ceb..f3e5c7e2ce6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ members = [ "misc/metrics", "misc/multistream-select", "misc/peer-store", - "misc/quick-protobuf-codec", + "misc/prost-codec", "misc/quickcheck-ext", "misc/rw-stream-sink", "misc/server", @@ -84,7 +84,7 @@ libp2p-dns = { version = "0.45.0", path = "transports/dns" } libp2p-floodsub = { version = "0.48.0", path = "protocols/floodsub" } libp2p-gossipsub = { version = "0.50.0", path = "protocols/gossipsub" } libp2p-identify = { version = "0.48.0", path = "protocols/identify" } -libp2p-identity = { version = "0.2.13" } +libp2p-identity = { version = "0.2.14" } libp2p-kad = { version = "0.49.0", path = "protocols/kad" } libp2p-mdns = { version = "0.49.0", path = "protocols/mdns" } libp2p-memory-connection-limits = { version = "0.6.0", path = "misc/memory-connection-limits" } @@ -110,7 +110,7 @@ libp2p-tls = { version = "0.7.0", path = "transports/tls" } libp2p-uds = { version = "0.44.0", path = "transports/uds" } libp2p-upnp = { version = "0.7.0", path = "protocols/upnp" } libp2p-webrtc = { version = "0.10.0-alpha", path = "transports/webrtc" } -libp2p-webrtc-utils = { version = "0.5.0", path = "misc/webrtc-utils" } +libp2p-webrtc-utils = { version = "0.6.0", path = "misc/webrtc-utils" } libp2p-webrtc-websys = { version = "0.5.0", path = "transports/webrtc-websys" } libp2p-websocket = { version = "0.46.0", path = "transports/websocket" } libp2p-websocket-websys = { version = "0.6.0", path = "transports/websocket-websys" } @@ -133,7 +133,8 @@ multiaddr = "0.18.1" multihash = "0.19.4" multistream-select = { version = "0.14.0", path = "misc/multistream-select" } prometheus-client = "0.24" -quick-protobuf-codec = { version = "0.4.0", path = "misc/quick-protobuf-codec" } +prost-codec = { version = "0.4.0", path = "misc/prost-codec" } +prost = "0.14" quickcheck = { package = "quickcheck-ext", path = "misc/quickcheck-ext" } rcgen = "0.13" ring = "0.17.12" diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 474dccafe8a..6e68bc4d235 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -2,6 +2,8 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). ## 0.43.2 diff --git a/core/Cargo.toml b/core/Cargo.toml index 25f9b6a7c30..5db219b1347 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -22,7 +22,7 @@ multihash = { workspace = true } multistream-select = { workspace = true } parking_lot = "0.12.5" pin-project = "1.1.11" -quick-protobuf = "0.8" +prost = { workspace = true } rand = "0.8" rw-stream-sink = { workspace = true } thiserror = { workspace = true } diff --git a/core/src/generated/envelope_proto.rs b/core/src/generated/envelope_proto.rs index 0f342f05413..167c2baab07 100644 --- a/core/src/generated/envelope_proto.rs +++ b/core/src/generated/envelope_proto.rs @@ -1,59 +1,27 @@ -// 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)] +// This file is @generated by prost-build. +/// Envelope encloses a signed payload produced by a peer, along with the public +/// key of the keypair it was signed with so that it can be statelessly validated +/// by the receiver. +/// +/// The payload is prefixed with a byte string that determines the type, so it +/// can be deserialized deterministically. Often, this byte string is a +/// multicodec. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Envelope { - pub public_key: Vec, - pub payload_type: Vec, - pub payload: Vec, - pub signature: Vec, + /// public_key is the public key of the keypair the enclosed payload was + /// signed with. + #[prost(bytes = "vec", tag = "1")] + pub public_key: ::prost::alloc::vec::Vec, + /// payload_type encodes the type of payload, so that it can be deserialized + /// deterministically. + #[prost(bytes = "vec", tag = "2")] + pub payload_type: ::prost::alloc::vec::Vec, + /// payload is the actual payload carried inside this envelope. + #[prost(bytes = "vec", tag = "3")] + pub payload: ::prost::alloc::vec::Vec, + /// signature is the signature produced by the private key corresponding to + /// the enclosed public key, over the payload, prefixing a domain string for + /// additional security. + #[prost(bytes = "vec", tag = "5")] + pub signature: ::prost::alloc::vec::Vec, } - -impl<'a> MessageRead<'a> for Envelope { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.public_key = r.read_bytes(bytes)?.to_owned(), - 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 - + if self.public_key.is_empty() { 0 } else { 1 + sizeof_len((&self.public_key).len()) } - + 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(&self, w: &mut Writer) -> Result<()> { - if !self.public_key.is_empty() { w.write_with_tag(10, |w| w.write_bytes(&**&self.public_key))?; } - 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(()) - } -} - diff --git a/core/src/generated/mod.rs b/core/src/generated/mod.rs index 950f42ed128..2b7f9848042 100644 --- a/core/src/generated/mod.rs +++ b/core/src/generated/mod.rs @@ -1,3 +1,3 @@ -// Automatically generated mod.rs +// Automatically generated by gen-proto. DO NOT EDIT. pub mod envelope_proto; pub mod peer_record_proto; diff --git a/core/src/generated/peer_record_proto.rs b/core/src/generated/peer_record_proto.rs index c771caacd2e..d7064e7ab16 100644 --- a/core/src/generated/peer_record_proto.rs +++ b/core/src/generated/peer_record_proto.rs @@ -1,93 +1,29 @@ -// 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)] +// This file is @generated by prost-build. +/// PeerRecord messages contain information that is useful to share with other peers. +/// Currently, a PeerRecord contains the public listen addresses for a peer, but this +/// is expected to expand to include other information in the future. +/// +/// PeerRecords are designed to be serialized to bytes and placed inside of +/// SignedEnvelopes before sharing with other peers. +#[derive(Clone, PartialEq, ::prost::Message)] pub struct PeerRecord { - pub peer_id: Vec, + /// peer_id contains a libp2p peer id in its binary representation. + #[prost(bytes = "vec", tag = "1")] + pub peer_id: ::prost::alloc::vec::Vec, + /// seq contains a monotonically-increasing sequence counter to order PeerRecords in time. + #[prost(uint64, tag = "2")] pub seq: u64, - pub addresses: Vec, + /// addresses is a list of public listen addresses for the peer. + #[prost(message, repeated, tag = "3")] + pub addresses: ::prost::alloc::vec::Vec, } - -impl<'a> MessageRead<'a> for PeerRecord { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::(bytes)?), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) +/// Nested message and enum types in `PeerRecord`. +pub mod peer_record { + /// AddressInfo is a wrapper around a binary multiaddr. It is defined as a + /// separate message to allow us to add per-address metadata in the future. + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct AddressInfo { + #[prost(bytes = "vec", tag = "1")] + pub multiaddr: ::prost::alloc::vec::Vec, } } - -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::() - } - - fn write_message(&self, w: &mut Writer) -> 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, -} - -impl<'a> MessageRead<'a> for AddressInfo { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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(&self, w: &mut Writer) -> Result<()> { - if !self.multiaddr.is_empty() { w.write_with_tag(10, |w| w.write_bytes(&**&self.multiaddr))?; } - Ok(()) - } -} - -} - diff --git a/core/src/lib.rs b/core/src/lib.rs index a1e05207720..61c4bd1303c 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -36,7 +36,7 @@ mod proto { include!("generated/mod.rs"); pub use self::{ envelope_proto::*, - peer_record_proto::{PeerRecord, mod_PeerRecord::*}, + peer_record_proto::{PeerRecord, peer_record::*}, }; } @@ -64,7 +64,7 @@ pub use upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}; #[derive(Debug, thiserror::Error)] #[error(transparent)] -pub struct DecodeError(quick_protobuf::Error); +pub struct DecodeError(prost::DecodeError); pub mod util { use std::convert::Infallible; diff --git a/core/src/peer_record.rs b/core/src/peer_record.rs index b9c2d350e73..7d358df47aa 100644 --- a/core/src/peer_record.rs +++ b/core/src/peer_record.rs @@ -1,5 +1,5 @@ use libp2p_identity::{Keypair, PeerId, SigningError}; -use quick_protobuf::{BytesReader, Writer}; +use prost::Message; use web_time::SystemTime; use crate::{DecodeError, Multiaddr, proto, signed_envelope, signed_envelope::SignedEnvelope}; @@ -75,12 +75,9 @@ impl PeerRecord { domain: &str, payload_type: &[u8], ) -> Result { - use quick_protobuf::MessageRead; - let (payload, signing_key) = envelope.payload_and_signing_key(String::from(domain), payload_type)?; - let mut reader = BytesReader::from_bytes(payload); - let record = proto::PeerRecord::from_reader(&mut reader, payload).map_err(DecodeError)?; + let record = proto::PeerRecord::decode(payload).map_err(DecodeError)?; let peer_id = PeerId::from_bytes(&record.peer_id)?; @@ -92,7 +89,7 @@ impl PeerRecord { let addresses = record .addresses .into_iter() - .map(|a| a.multiaddr.to_vec().try_into()) + .map(|a| a.multiaddr.try_into()) .collect::, _>>()?; Ok(Self { @@ -140,8 +137,6 @@ impl PeerRecord { domain: &str, payload_type: &[u8], ) -> Result { - use quick_protobuf::MessageWrite; - let seq = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .expect("now() is never before UNIX_EPOCH") @@ -160,13 +155,7 @@ impl PeerRecord { .collect(), }; - let mut buf = Vec::with_capacity(record.get_size()); - let mut writer = Writer::new(&mut buf); - record - .write_message(&mut writer) - .expect("Encoding to succeed"); - - buf + record.encode_to_vec() }; let envelope = @@ -252,8 +241,6 @@ mod tests { #[test] fn mismatched_signature_legacy() { - use quick_protobuf::MessageWrite; - let addr: Multiaddr = HOME.parse().unwrap(); let envelope = { @@ -269,13 +256,7 @@ mod tests { }], }; - let mut buf = Vec::with_capacity(record.get_size()); - let mut writer = Writer::new(&mut buf); - record - .write_message(&mut writer) - .expect("Encoding to succeed"); - - buf + record.encode_to_vec() }; SignedEnvelope::new( @@ -295,8 +276,6 @@ mod tests { #[test] fn mismatched_signature_interop() { - use quick_protobuf::MessageWrite; - let addr: Multiaddr = HOME.parse().unwrap(); let envelope = { @@ -312,13 +291,7 @@ mod tests { }], }; - let mut buf = Vec::with_capacity(record.get_size()); - let mut writer = Writer::new(&mut buf); - record - .write_message(&mut writer) - .expect("Encoding to succeed"); - - buf + record.encode_to_vec() }; SignedEnvelope::new( diff --git a/core/src/signed_envelope.rs b/core/src/signed_envelope.rs index 08808e4cad0..75d0ae66787 100644 --- a/core/src/signed_envelope.rs +++ b/core/src/signed_envelope.rs @@ -1,7 +1,7 @@ use std::fmt; use libp2p_identity::{Keypair, PublicKey, SigningError}; -use quick_protobuf::{BytesReader, Writer}; +use prost::Message; use unsigned_varint::encode::usize_buffer; use crate::{DecodeError, proto}; @@ -76,8 +76,6 @@ impl SignedEnvelope { /// Encode this [`SignedEnvelope`] using the protobuf encoding specified in the RFC. pub fn into_protobuf_encoding(self) -> Vec { - use quick_protobuf::MessageWrite; - let envelope = proto::Envelope { public_key: self.key.encode_protobuf(), payload_type: self.payload_type, @@ -85,28 +83,18 @@ impl SignedEnvelope { signature: self.signature, }; - let mut buf = Vec::with_capacity(envelope.get_size()); - let mut writer = Writer::new(&mut buf); - - envelope - .write_message(&mut writer) - .expect("Encoding to succeed"); - - buf + envelope.encode_to_vec() } /// Decode a [`SignedEnvelope`] using the protobuf encoding specified in the RFC. pub fn from_protobuf_encoding(bytes: &[u8]) -> Result { - use quick_protobuf::MessageRead; - - let mut reader = BytesReader::from_bytes(bytes); - let envelope = proto::Envelope::from_reader(&mut reader, bytes).map_err(DecodeError)?; + let envelope = proto::Envelope::decode(bytes).map_err(DecodeError)?; Ok(Self { key: PublicKey::try_decode_protobuf(&envelope.public_key)?, - payload_type: envelope.payload_type.to_vec(), - payload: envelope.payload.to_vec(), - signature: envelope.signature.to_vec(), + payload_type: envelope.payload_type, + payload: envelope.payload, + signature: envelope.signature, }) } } diff --git a/identity/CHANGELOG.md b/identity/CHANGELOG.md index 430d8263e7a..5d4842b61c4 100644 --- a/identity/CHANGELOG.md +++ b/identity/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.2.14 + +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). + ## 0.2.13 - Turn the `quick-protobuf` dependency optional to only the features which require it. diff --git a/identity/Cargo.toml b/identity/Cargo.toml index 0b8a16e377f..b93ba77f201 100644 --- a/identity/Cargo.toml +++ b/identity/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libp2p-identity" -version = "0.2.13" +version = "0.2.14" edition = "2021" # MUST NOT inherit from workspace because we don't want to publish breaking changes to `libp2p-identity`. description = "Data structures and algorithms for identifying peers in libp2p." rust-version = "1.73.0" # MUST NOT inherit from workspace because we don't want to publish breaking changes to `libp2p-identity`. @@ -20,7 +20,7 @@ k256 = { version = "0.13.4", optional = true, features = ["ecdsa", "arithmetic"] tracing = { workspace = true } multihash = { version = "0.19.4", optional = true } p256 = { version = "0.13", default-features = false, features = ["ecdsa", "std", "pem"], optional = true } -quick-protobuf = { version = "0.8.1", optional = true } +prost = { workspace = true, optional = true } rand = { version = "0.8", optional = true } sec1 = { version = "0.7", default-features = false, optional = true } serde = { version = "1", optional = true, features = ["derive"] } @@ -32,10 +32,10 @@ zeroize = { version = "1.8", optional = true } ring = { workspace = true, features = ["alloc", "std"], optional = true } [features] -secp256k1 = ["dep:k256", "dep:asn1_der", "dep:sha2", "dep:hkdf", "dep:zeroize", "dep:quick-protobuf"] -ecdsa = ["dep:p256", "dep:zeroize", "dep:sec1", "dep:sha2", "dep:hkdf", "dep:quick-protobuf"] -rsa = ["dep:ring", "dep:asn1_der", "dep:rand", "dep:zeroize", "dep:quick-protobuf"] -ed25519 = ["dep:ed25519-dalek", "dep:zeroize", "dep:sha2", "dep:hkdf", "dep:quick-protobuf"] +secp256k1 = ["dep:k256", "dep:asn1_der", "dep:sha2", "dep:hkdf", "dep:zeroize", "dep:prost"] +ecdsa = ["dep:p256", "dep:zeroize", "dep:sec1", "dep:sha2", "dep:hkdf", "dep:prost"] +rsa = ["dep:ring", "dep:asn1_der", "dep:rand", "dep:zeroize", "dep:prost"] +ed25519 = ["dep:ed25519-dalek", "dep:zeroize", "dep:sha2", "dep:hkdf", "dep:prost"] peerid = ["dep:multihash", "dep:bs58", "dep:thiserror", "dep:sha2", "dep:hkdf"] rand = ["dep:rand"] diff --git a/identity/src/error.rs b/identity/src/error.rs index 6e8c4d02caa..80e11a659dd 100644 --- a/identity/src/error.rs +++ b/identity/src/error.rs @@ -76,6 +76,19 @@ impl DecodingError { } } + #[cfg(any( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa" + ))] + pub(crate) fn unknown_key_type(key_type: i32) -> Self { + Self { + msg: format!("unknown key type {key_type}"), + source: None, + } + } + #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] pub(crate) fn encoding_unsupported(key_type: &'static str) -> Self { Self { diff --git a/identity/src/generated/keys_proto.rs b/identity/src/generated/keys_proto.rs index ba15fed5004..cc973e4b817 100644 --- a/identity/src/generated/keys_proto.rs +++ b/identity/src/generated/keys_proto.rs @@ -1,125 +1,47 @@ -// 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 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)] +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct PublicKey { - pub Type: keys_proto::KeyType, - pub Data: Vec, + #[prost(enumeration = "KeyType", required, tag = "1")] + pub r#type: i32, + #[prost(bytes = "vec", required, tag = "2")] + pub data: ::prost::alloc::vec::Vec, } - -impl<'a> MessageRead<'a> for PublicKey { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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(&self, w: &mut Writer) -> 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)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct PrivateKey { - pub Type: keys_proto::KeyType, - pub Data: Vec, + #[prost(enumeration = "KeyType", required, tag = "1")] + pub r#type: i32, + #[prost(bytes = "vec", required, tag = "2")] + pub data: ::prost::alloc::vec::Vec, } - -impl<'a> MessageRead<'a> for PrivateKey { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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), - } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum KeyType { + Rsa = 0, + Ed25519 = 1, + Secp256k1 = 2, + Ecdsa = 3, +} +impl KeyType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Rsa => "RSA", + Self::Ed25519 => "Ed25519", + Self::Secp256k1 => "Secp256k1", + Self::Ecdsa => "ECDSA", } - 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(&self, w: &mut Writer) -> 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(()) + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "RSA" => Some(Self::Rsa), + "Ed25519" => Some(Self::Ed25519), + "Secp256k1" => Some(Self::Secp256k1), + "ECDSA" => Some(Self::Ecdsa), + _ => None, + } } } - diff --git a/identity/src/generated/mod.rs b/identity/src/generated/mod.rs index 9f9a104ac10..eedd2f5a46f 100644 --- a/identity/src/generated/mod.rs +++ b/identity/src/generated/mod.rs @@ -1,2 +1,2 @@ -// Automatically generated mod.rs +// Automatically generated by gen-proto. DO NOT EDIT. pub mod keys_proto; diff --git a/identity/src/keypair.rs b/identity/src/keypair.rs index a1bbba00fa9..03a780fecf9 100644 --- a/identity/src/keypair.rs +++ b/identity/src/keypair.rs @@ -24,7 +24,7 @@ feature = "ed25519", feature = "rsa" ))] -use quick_protobuf::{BytesReader, Writer}; +use prost::Message; #[cfg(feature = "ecdsa")] use crate::ecdsa; @@ -220,32 +220,27 @@ impl Keypair { feature = "rsa" ))] { - use quick_protobuf::MessageWrite; let pk: proto::PrivateKey = match self.keypair { #[cfg(feature = "ed25519")] KeyPairInner::Ed25519(ref data) => proto::PrivateKey { - Type: proto::KeyType::Ed25519, - Data: data.to_bytes().to_vec(), + r#type: proto::KeyType::Ed25519 as i32, + data: data.to_bytes().to_vec(), }, #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] KeyPairInner::Rsa(_) => return Err(DecodingError::encoding_unsupported("RSA")), #[cfg(feature = "secp256k1")] KeyPairInner::Secp256k1(ref data) => proto::PrivateKey { - Type: proto::KeyType::Secp256k1, - Data: data.secret().to_bytes().to_vec(), + r#type: proto::KeyType::Secp256k1 as i32, + data: data.secret().to_bytes().to_vec(), }, #[cfg(feature = "ecdsa")] KeyPairInner::Ecdsa(ref data) => proto::PrivateKey { - Type: proto::KeyType::ECDSA, - Data: data.secret().encode_der(), + r#type: proto::KeyType::Ecdsa as i32, + data: data.secret().encode_der(), }, }; - 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) + Ok(pk.encode_to_vec()) } #[cfg(not(any( @@ -267,27 +262,27 @@ impl Keypair { feature = "rsa" ))] { - use quick_protobuf::MessageRead; - - let mut reader = BytesReader::from_bytes(bytes); - let mut private_key = proto::PrivateKey::from_reader(&mut reader, bytes) + let mut private_key = proto::PrivateKey::decode(bytes) .map_err(|e| DecodingError::bad_protobuf("private key bytes", e)) .map(zeroize::Zeroizing::new)?; + let key_type = proto::KeyType::try_from(private_key.r#type) + .map_err(|_| DecodingError::unknown_key_type(private_key.r#type))?; + #[allow(unreachable_code)] - match private_key.Type { + match key_type { proto::KeyType::Ed25519 => { #[cfg(feature = "ed25519")] - return ed25519::Keypair::try_from_bytes(&mut private_key.Data).map(|sk| { + return ed25519::Keypair::try_from_bytes(&mut private_key.data).map(|sk| { Keypair { keypair: KeyPairInner::Ed25519(sk), } }); Err(DecodingError::missing_feature("ed25519")) } - proto::KeyType::RSA => { + proto::KeyType::Rsa => { #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - return rsa::Keypair::try_decode_pkcs1(&mut private_key.Data).map(|sk| { + return rsa::Keypair::try_decode_pkcs1(&mut private_key.data).map(|sk| { Keypair { keypair: KeyPairInner::Rsa(sk), } @@ -296,7 +291,7 @@ impl Keypair { } proto::KeyType::Secp256k1 => { #[cfg(feature = "secp256k1")] - return secp256k1::SecretKey::try_from_bytes(&mut private_key.Data).map( + return secp256k1::SecretKey::try_from_bytes(&mut private_key.data).map( |key| Keypair { keypair: KeyPairInner::Secp256k1(key.into()), }, @@ -304,9 +299,9 @@ impl Keypair { Err(DecodingError::missing_feature("secp256k1")) } - proto::KeyType::ECDSA => { + proto::KeyType::Ecdsa => { #[cfg(feature = "ecdsa")] - return ecdsa::SecretKey::try_decode_der(&mut private_key.Data).map(|key| { + return ecdsa::SecretKey::try_decode_der(&mut private_key.data).map(|key| { Keypair { keypair: KeyPairInner::Ecdsa(key.into()), } @@ -581,16 +576,9 @@ impl PublicKey { feature = "rsa" ))] { - use quick_protobuf::MessageWrite; let public_key = proto::PublicKey::from(self); - let mut buf = Vec::with_capacity(public_key.get_size()); - let mut writer = Writer::new(&mut buf); - public_key - .write_message(&mut writer) - .expect("Encoding to succeed"); - - buf + public_key.encode_to_vec() } #[cfg(not(any( @@ -613,10 +601,7 @@ impl PublicKey { feature = "rsa" ))] { - use quick_protobuf::MessageRead; - let mut reader = BytesReader::from_bytes(bytes); - - let pubkey = proto::PublicKey::from_reader(&mut reader, bytes) + let pubkey = proto::PublicKey::decode(bytes) .map_err(|e| DecodingError::bad_protobuf("public key bytes", e))?; pubkey.try_into() @@ -662,9 +647,12 @@ impl TryFrom for PublicKey { type Error = DecodingError; fn try_from(pubkey: proto::PublicKey) -> Result { - match pubkey.Type { + let key_type = proto::KeyType::try_from(pubkey.r#type) + .map_err(|_| DecodingError::unknown_key_type(pubkey.r#type))?; + + match key_type { #[cfg(feature = "ed25519")] - proto::KeyType::Ed25519 => Ok(ed25519::PublicKey::try_from_bytes(&pubkey.Data).map( + proto::KeyType::Ed25519 => Ok(ed25519::PublicKey::try_from_bytes(&pubkey.data).map( |kp| PublicKey { publickey: PublicKeyInner::Ed25519(kp), }, @@ -675,20 +663,20 @@ impl TryFrom for PublicKey { Err(DecodingError::missing_feature("ed25519")) } #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - proto::KeyType::RSA => { + proto::KeyType::Rsa => { Ok( - rsa::PublicKey::try_decode_x509(&pubkey.Data).map(|kp| PublicKey { + rsa::PublicKey::try_decode_x509(&pubkey.data).map(|kp| PublicKey { publickey: PublicKeyInner::Rsa(kp), })?, ) } #[cfg(any(not(feature = "rsa"), target_arch = "wasm32"))] - proto::KeyType::RSA => { + proto::KeyType::Rsa => { tracing::debug!("support for RSA was disabled at compile-time"); Err(DecodingError::missing_feature("rsa")) } #[cfg(feature = "secp256k1")] - proto::KeyType::Secp256k1 => Ok(secp256k1::PublicKey::try_from_bytes(&pubkey.Data) + proto::KeyType::Secp256k1 => Ok(secp256k1::PublicKey::try_from_bytes(&pubkey.data) .map(|kp| PublicKey { publickey: PublicKeyInner::Secp256k1(kp), })?), @@ -698,13 +686,13 @@ impl TryFrom for PublicKey { Err(DecodingError::missing_feature("secp256k1")) } #[cfg(feature = "ecdsa")] - proto::KeyType::ECDSA => Ok(ecdsa::PublicKey::try_decode_der(&pubkey.Data).map( + proto::KeyType::Ecdsa => Ok(ecdsa::PublicKey::try_decode_der(&pubkey.data).map( |kp| PublicKey { publickey: PublicKeyInner::Ecdsa(kp), }, )?), #[cfg(not(feature = "ecdsa"))] - proto::KeyType::ECDSA => { + proto::KeyType::Ecdsa => { tracing::debug!("support for ECDSA was disabled at compile-time"); Err(DecodingError::missing_feature("ecdsa")) } diff --git a/identity/src/lib.rs b/identity/src/lib.rs index 4f4313e8f17..58931161e1c 100644 --- a/identity/src/lib.rs +++ b/identity/src/lib.rs @@ -71,7 +71,7 @@ mod peer_id; ))] impl zeroize::Zeroize for proto::PrivateKey { fn zeroize(&mut self) { - self.Data.zeroize(); + self.data.zeroize(); } } @@ -86,23 +86,23 @@ impl From<&PublicKey> for proto::PublicKey { match &key.publickey { #[cfg(feature = "ed25519")] keypair::PublicKeyInner::Ed25519(key) => proto::PublicKey { - Type: proto::KeyType::Ed25519, - Data: key.to_bytes().to_vec(), + r#type: proto::KeyType::Ed25519 as i32, + data: key.to_bytes().to_vec(), }, #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] keypair::PublicKeyInner::Rsa(key) => proto::PublicKey { - Type: proto::KeyType::RSA, - Data: key.encode_x509(), + r#type: proto::KeyType::Rsa as i32, + data: key.encode_x509(), }, #[cfg(feature = "secp256k1")] keypair::PublicKeyInner::Secp256k1(key) => proto::PublicKey { - Type: proto::KeyType::Secp256k1, - Data: key.to_bytes().to_vec(), + r#type: proto::KeyType::Secp256k1 as i32, + data: key.to_bytes().to_vec(), }, #[cfg(feature = "ecdsa")] keypair::PublicKeyInner::Ecdsa(key) => proto::PublicKey { - Type: proto::KeyType::ECDSA, - Data: key.encode_der(), + r#type: proto::KeyType::Ecdsa as i32, + data: key.encode_der(), }, } } diff --git a/misc/gen-proto/Cargo.lock b/misc/gen-proto/Cargo.lock new file mode 100644 index 00000000000..cd382a1a586 --- /dev/null +++ b/misc/gen-proto/Cargo.lock @@ -0,0 +1,575 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "gen-proto" +version = "0.0.0" +dependencies = [ + "prost-build", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" +dependencies = [ + "heck", + "itertools", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +dependencies = [ + "prost", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/misc/gen-proto/Cargo.toml b/misc/gen-proto/Cargo.toml new file mode 100644 index 00000000000..6a4a859250f --- /dev/null +++ b/misc/gen-proto/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "gen-proto" +version = "0.0.0" +edition = "2024" +publish = false + +[workspace] + +[dependencies] +prost-build = "0.14" \ No newline at end of file diff --git a/misc/gen-proto/src/main.rs b/misc/gen-proto/src/main.rs new file mode 100644 index 00000000000..2450aca7544 --- /dev/null +++ b/misc/gen-proto/src/main.rs @@ -0,0 +1,104 @@ +use std::collections::{BTreeMap, BTreeSet}; +use std::path::PathBuf; + +/// All `.proto` files to compile, relative to the workspace root. +const PROTO_FILES: &[&str] = &[ + "misc/prost-codec/src/generated/test.proto", + "core/src/generated/envelope.proto", + "core/src/generated/peer_record.proto", + "identity/src/generated/keys.proto", + "misc/webrtc-utils/src/generated/message.proto", + "transports/noise/src/generated/payload.proto", + "transports/plaintext/src/generated/structs.proto", + "protocols/autonat/src/v1/generated/structs.proto", + "protocols/autonat/src/v2/generated/structs.proto", + "protocols/dcutr/src/generated/message.proto", + "protocols/floodsub/src/generated/rpc.proto", + "protocols/gossipsub/src/generated/rpc.proto", + "protocols/gossipsub/src/generated/compat.proto", + "protocols/identify/src/generated/structs.proto", + "protocols/kad/src/generated/dht.proto", + "protocols/relay/src/generated/message.proto", + "protocols/rendezvous/src/generated/rpc.proto", +]; + +fn main() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .ancestors() + .nth(2) + .expect("gen-proto must live two directories below the workspace root") + .to_path_buf(); + + assert!( + root.join("Cargo.toml").exists(), + "workspace root not found at {}", + root.display(), + ); + + // Group proto files by parent directory (= include dir = output dir). + let mut by_dir: BTreeMap<&str, Vec<&str>> = BTreeMap::new(); + for proto in PROTO_FILES { + let dir = proto + .rsplit_once('/') + .expect("proto path must contain '/'") + .0; + by_dir.entry(dir).or_default().push(proto); + } + + // Compile each group with prost-build. + for (dir, protos) in &by_dir { + let abs_dir = root.join(dir); + let abs_protos: Vec = protos.iter().map(|p| root.join(p)).collect(); + + println!(" {} file(s) in {dir}", protos.len()); + + prost_build::Config::new() + .out_dir(&abs_dir) + .compile_protos( + &abs_protos + .iter() + .map(|p| p.as_path()) + .collect::>(), + &[abs_dir.as_path()], + ) + .unwrap_or_else(|e| panic!("failed to compile protos in {dir}: {e}")); + } + + // Generate a `mod.rs` in every output directory. + let dirs: BTreeSet<&str> = by_dir.keys().copied().collect(); + for dir in dirs { + write_mod_rs(&root.join(dir)); + } + + println!("Done."); +} + +/// Write a `mod.rs` that re-exports every generated `.rs` file in `dir`. +/// +/// Files whose stem contains dots (e.g. `gossipsub.pb.rs`) get a `#[path]` +/// attribute because dots are not valid in Rust identifiers. +fn write_mod_rs(dir: &std::path::Path) { + let mut files: Vec = std::fs::read_dir(dir) + .unwrap() + .filter_map(|entry| { + let name = entry.ok()?.file_name().into_string().ok()?; + (name.ends_with(".rs") && name != "mod.rs").then_some(name) + }) + .collect(); + files.sort(); + + let mut out = + String::from("// Automatically generated by gen-proto. DO NOT EDIT.\n"); + + for file in &files { + let stem = file.strip_suffix(".rs").unwrap(); + if stem.contains('.') { + let mod_name = stem.replace('.', "_"); + out.push_str(&format!("#[path = \"{file}\"]\npub mod {mod_name};\n")); + } else { + out.push_str(&format!("pub mod {stem};\n")); + } + } + + std::fs::write(dir.join("mod.rs"), &out).unwrap(); +} diff --git a/misc/prost-codec/CHANGELOG.md b/misc/prost-codec/CHANGELOG.md new file mode 100644 index 00000000000..8a5a803b782 --- /dev/null +++ b/misc/prost-codec/CHANGELOG.md @@ -0,0 +1,26 @@ +# 0.4.0 + +- Raise MSRV to 1.88.0. + See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Migrate from `prost` 0.11 to `prost` 0.14. +- Replace `UviBytes`-based framing with manual unsigned-varint encoding/decoding for improved performance. +- Use `#[error(transparent)]` on `Error` type for better error messages. +- Derive `Debug` and `Clone` on `Codec`. +- Add `From for io::Error` conversion. +- Add tests including QuickCheck-based roundtrip property test. + +# 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/ \ No newline at end of file diff --git a/misc/quick-protobuf-codec/Cargo.toml b/misc/prost-codec/Cargo.toml similarity index 79% rename from misc/quick-protobuf-codec/Cargo.toml rename to misc/prost-codec/Cargo.toml index 2afeb82ee31..0b21c0e7309 100644 --- a/misc/quick-protobuf-codec/Cargo.toml +++ b/misc/prost-codec/Cargo.toml @@ -1,8 +1,8 @@ [package] -name = "quick-protobuf-codec" +name = "prost-codec" edition.workspace = true rust-version = { workspace = true } -description = "Asynchronous de-/encoding of Protobuf structs using asynchronous-codec, unsigned-varint and quick-protobuf." +description = "Asynchronous de-/encoding of Protobuf structs using asynchronous-codec, unsigned-varint and prost." version = "0.4.0" authors = ["Max Inden "] license = "MIT" @@ -12,20 +12,15 @@ categories = ["asynchronous"] [dependencies] asynchronous-codec = { workspace = true } -bytes = { version = "1" } +bytes = "1" +prost = { workspace = true } thiserror = { workspace = true } unsigned-varint = { workspace = true, features = ["std"] } -quick-protobuf = "0.8" [dev-dependencies] -criterion = "0.5.1" futures = { workspace = true } quickcheck = { workspace = true } -[[bench]] -name = "codec" -harness = false - # 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] diff --git a/misc/prost-codec/src/generated/mod.rs b/misc/prost-codec/src/generated/mod.rs new file mode 100644 index 00000000000..8e1e816dae0 --- /dev/null +++ b/misc/prost-codec/src/generated/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated by gen-proto. DO NOT EDIT. +pub mod test; diff --git a/misc/quick-protobuf-codec/src/generated/test.proto b/misc/prost-codec/src/generated/test.proto similarity index 100% rename from misc/quick-protobuf-codec/src/generated/test.proto rename to misc/prost-codec/src/generated/test.proto diff --git a/misc/prost-codec/src/generated/test.rs b/misc/prost-codec/src/generated/test.rs new file mode 100644 index 00000000000..2d96aad8cf0 --- /dev/null +++ b/misc/prost-codec/src/generated/test.rs @@ -0,0 +1,6 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct Message { + #[prost(bytes = "vec", tag = "1")] + pub data: ::prost::alloc::vec::Vec, +} diff --git a/misc/quick-protobuf-codec/src/lib.rs b/misc/prost-codec/src/lib.rs similarity index 61% rename from misc/quick-protobuf-codec/src/lib.rs rename to misc/prost-codec/src/lib.rs index d492c517249..59bfa0ef0dd 100644 --- a/misc/quick-protobuf-codec/src/lib.rs +++ b/misc/prost-codec/src/lib.rs @@ -3,8 +3,8 @@ use std::{io, marker::PhantomData}; use asynchronous_codec::{Decoder, Encoder}; -use bytes::{Buf, BufMut, BytesMut}; -use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer, WriterBackend}; +use bytes::{Buf, BytesMut}; +use prost::Message; mod generated; @@ -13,8 +13,9 @@ pub use generated::test as proto; /// [`Codec`] implements [`Encoder`] and [`Decoder`], uses [`unsigned_varint`] /// -/// to prefix messages with their length and uses [`quick_protobuf`] and a provided -/// `struct` implementing [`MessageRead`] and [`MessageWrite`] to do the encoding. +/// to prefix messages with their length and uses [`prost`] and a provided +/// `struct` implementing [`prost::Message`] to do the encoding. +#[derive(Debug, Clone)] pub struct Codec { max_message_len_bytes: usize, phantom: PhantomData<(In, Out)>, @@ -34,39 +35,27 @@ impl Codec { } } -impl Encoder for Codec { +impl Encoder for Codec { type Item<'a> = In; type Error = Error; fn encode(&mut self, item: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> { - write_length(&item, dst); - write_message(&item, dst)?; + let message_length = item.encoded_len(); - Ok(()) - } -} - -/// Write the message's length (i.e. `size`) to `dst` as a variable-length integer. -fn write_length(message: &impl MessageWrite, dst: &mut BytesMut) { - let message_length = message.get_size(); + let mut uvi_buf = unsigned_varint::encode::usize_buffer(); + let encoded_length = unsigned_varint::encode::usize(message_length, &mut uvi_buf); + dst.reserve(encoded_length.len() + message_length); + dst.extend_from_slice(encoded_length); - let mut uvi_buf = unsigned_varint::encode::usize_buffer(); - let encoded_length = unsigned_varint::encode::usize(message_length, &mut uvi_buf); + item.encode(dst).map_err(io::Error::other)?; - dst.extend_from_slice(encoded_length); -} - -/// Write the message itself to `dst`. -fn write_message(item: &impl MessageWrite, dst: &mut BytesMut) -> io::Result<()> { - let mut writer = Writer::new(BytesMutWriterBackend::new(dst)); - item.write_message(&mut writer).map_err(io::Error::other)?; - - Ok(()) + Ok(()) + } } impl Decoder for Codec where - Out: for<'a> MessageRead<'a>, + Out: Message + Default, { type Item = Out; type Error = Error; @@ -80,7 +69,7 @@ where if message_length > self.max_message_len_bytes { return Err(Error(io::Error::new( - io::ErrorKind::PermissionDenied, + io::ErrorKind::InvalidData, format!( "message with {message_length}b exceeds maximum of {}b", self.max_message_len_bytes @@ -99,78 +88,17 @@ where // Safe to advance buffer now. src.advance(varint_length); - let message = src.split_to(message_length); + let message_bytes = src.split_to(message_length); - let mut reader = BytesReader::from_bytes(&message); - let message = Self::Item::from_reader(&mut reader, &message) + let message = Self::Item::decode(&message_bytes[..]) .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; Ok(Some(message)) } } -struct BytesMutWriterBackend<'a> { - dst: &'a mut BytesMut, -} - -impl<'a> BytesMutWriterBackend<'a> { - fn new(dst: &'a mut BytesMut) -> Self { - Self { dst } - } -} - -impl WriterBackend for BytesMutWriterBackend<'_> { - fn pb_write_u8(&mut self, x: u8) -> quick_protobuf::Result<()> { - self.dst.put_u8(x); - - Ok(()) - } - - fn pb_write_u32(&mut self, x: u32) -> quick_protobuf::Result<()> { - self.dst.put_u32_le(x); - - Ok(()) - } - - fn pb_write_i32(&mut self, x: i32) -> quick_protobuf::Result<()> { - self.dst.put_i32_le(x); - - Ok(()) - } - - fn pb_write_f32(&mut self, x: f32) -> quick_protobuf::Result<()> { - self.dst.put_f32_le(x); - - Ok(()) - } - - fn pb_write_u64(&mut self, x: u64) -> quick_protobuf::Result<()> { - self.dst.put_u64_le(x); - - Ok(()) - } - - fn pb_write_i64(&mut self, x: i64) -> quick_protobuf::Result<()> { - self.dst.put_i64_le(x); - - Ok(()) - } - - fn pb_write_f64(&mut self, x: f64) -> quick_protobuf::Result<()> { - self.dst.put_f64_le(x); - - Ok(()) - } - - fn pb_write_all(&mut self, buf: &[u8]) -> quick_protobuf::Result<()> { - self.dst.put_slice(buf); - - Ok(()) - } -} - #[derive(thiserror::Error, Debug)] -#[error("Failed to encode/decode message")] +#[error(transparent)] pub struct Error(#[from] io::Error); impl From for io::Error { @@ -181,8 +109,6 @@ impl From for io::Error { #[cfg(test)] mod tests { - use std::error::Error; - use asynchronous_codec::FramedRead; use futures::{FutureExt, StreamExt, io::Cursor}; use quickcheck::{Arbitrary, Gen, QuickCheck}; @@ -197,10 +123,7 @@ mod tests { let mut read = FramedRead::new(Cursor::new(&mut src), codec); let err = read.next().now_or_never().unwrap().unwrap().unwrap_err(); - assert_eq!( - err.source().unwrap().to_string(), - "message with 100b exceeds maximum of 1b" - ) + assert_eq!(err.to_string(), "message with 100b exceeds maximum of 1b") } #[test] @@ -263,11 +186,36 @@ mod tests { } } - #[derive(Debug)] + /// Dummy message type for tests that don't need real decoding. + #[derive(Debug, Default)] struct Dummy; - impl<'a> MessageRead<'a> for Dummy { - fn from_reader(_: &mut BytesReader, _: &'a [u8]) -> quick_protobuf::Result { + impl Message for Dummy { + fn encode_raw(&self, _buf: &mut impl bytes::BufMut) + where + Self: Sized, + { + todo!() + } + + fn merge_field( + &mut self, + _tag: u32, + _wire_type: prost::encoding::WireType, + _buf: &mut impl bytes::Buf, + _ctx: prost::encoding::DecodeContext, + ) -> Result<(), prost::DecodeError> + where + Self: Sized, + { + todo!() + } + + fn encoded_len(&self) -> usize { + todo!() + } + + fn clear(&mut self) { todo!() } } diff --git a/misc/quick-protobuf-codec/CHANGELOG.md b/misc/quick-protobuf-codec/CHANGELOG.md index 68fcfe98dfe..7f3fb54830f 100644 --- a/misc/quick-protobuf-codec/CHANGELOG.md +++ b/misc/quick-protobuf-codec/CHANGELOG.md @@ -2,6 +2,8 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). ## 0.3.1 diff --git a/misc/quick-protobuf-codec/src/generated/mod.rs b/misc/quick-protobuf-codec/src/generated/mod.rs deleted file mode 100644 index b9f982f8dfd..00000000000 --- a/misc/quick-protobuf-codec/src/generated/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Automatically generated mod.rs -pub mod test; diff --git a/misc/quick-protobuf-codec/src/generated/test.rs b/misc/quick-protobuf-codec/src/generated/test.rs deleted file mode 100644 index b353e6d9183..00000000000 --- a/misc/quick-protobuf-codec/src/generated/test.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Automatically generated rust module for 'test.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 data: Vec, -} - -impl<'a> MessageRead<'a> for Message { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => 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 Message { - fn get_size(&self) -> usize { - 0 - + if self.data.is_empty() { 0 } else { 1 + sizeof_len((&self.data).len()) } - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if !self.data.is_empty() { w.write_with_tag(10, |w| w.write_bytes(&**&self.data))?; } - Ok(()) - } -} - diff --git a/misc/webrtc-utils/CHANGELOG.md b/misc/webrtc-utils/CHANGELOG.md index d4f01297bdc..36c6cf33aa8 100644 --- a/misc/webrtc-utils/CHANGELOG.md +++ b/misc/webrtc-utils/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.6.0 + +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). + ## 0.5.0 - Raise MSRV to 1.88.0. diff --git a/misc/webrtc-utils/Cargo.toml b/misc/webrtc-utils/Cargo.toml index 4da6cb503f7..107224d0203 100644 --- a/misc/webrtc-utils/Cargo.toml +++ b/misc/webrtc-utils/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT" name = "libp2p-webrtc-utils" repository = "https://github.com/libp2p/rust-libp2p" rust-version = { workspace = true } -version = "0.5.0" +version = "0.6.0" publish = true [dependencies] @@ -18,8 +18,8 @@ hex = "0.4" libp2p-core = { workspace = true } libp2p-identity = { workspace = true } libp2p-noise = { workspace = true } -quick-protobuf = "0.8" -quick-protobuf-codec = { workspace = true } +prost = { workspace = true } +prost-codec = { workspace = true } rand = "0.8" serde = { version = "1.0", features = ["derive"] } sha2 = "0.10.8" diff --git a/misc/webrtc-utils/src/generated/mod.rs b/misc/webrtc-utils/src/generated/mod.rs index 5e9f6373b12..f40db89b00a 100644 --- a/misc/webrtc-utils/src/generated/mod.rs +++ b/misc/webrtc-utils/src/generated/mod.rs @@ -1,2 +1,3 @@ -// Automatically generated mod.rs -pub mod webrtc; +// Automatically generated by gen-proto. DO NOT EDIT. +#[path = "webrtc.pb.rs"] +pub mod webrtc_pb; diff --git a/misc/webrtc-utils/src/generated/webrtc.pb.rs b/misc/webrtc-utils/src/generated/webrtc.pb.rs new file mode 100644 index 00000000000..22c5235773c --- /dev/null +++ b/misc/webrtc-utils/src/generated/webrtc.pb.rs @@ -0,0 +1,55 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct Message { + #[prost(enumeration = "message::Flag", optional, tag = "1")] + pub flag: ::core::option::Option, + #[prost(bytes = "vec", optional, tag = "2")] + pub message: ::core::option::Option<::prost::alloc::vec::Vec>, +} +/// Nested message and enum types in `Message`. +pub mod message { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Flag { + /// The sender will no longer send messages on the stream. + Fin = 0, + /// The sender will no longer read messages on the stream. Incoming data is + /// being discarded on receipt. + StopSending = 1, + /// The sender abruptly terminates the sending part of the stream. The + /// receiver can discard any data that it already received on that stream. + Reset = 2, + } + impl Flag { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Fin => "FIN", + Self::StopSending => "STOP_SENDING", + Self::Reset => "RESET", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "FIN" => Some(Self::Fin), + "STOP_SENDING" => Some(Self::StopSending), + "RESET" => Some(Self::Reset), + _ => None, + } + } + } +} diff --git a/misc/webrtc-utils/src/generated/webrtc/mod.rs b/misc/webrtc-utils/src/generated/webrtc/mod.rs deleted file mode 100644 index aec6164c7ef..00000000000 --- a/misc/webrtc-utils/src/generated/webrtc/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Automatically generated mod.rs -pub mod pb; diff --git a/misc/webrtc-utils/src/generated/webrtc/pb.rs b/misc/webrtc-utils/src/generated/webrtc/pb.rs deleted file mode 100644 index 9e33e97188c..00000000000 --- a/misc/webrtc-utils/src/generated/webrtc/pb.rs +++ /dev/null @@ -1,91 +0,0 @@ -// 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 Message { - pub flag: Option, - pub message: Option>, -} - -impl<'a> MessageRead<'a> for Message { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(8) => msg.flag = Some(r.read_enum(bytes)?), - Ok(18) => msg.message = 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.flag.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64)) - + self.message.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if let Some(ref s) = self.flag { w.write_with_tag(8, |w| w.write_enum(*s as i32))?; } - if let Some(ref s) = self.message { w.write_with_tag(18, |w| w.write_bytes(&**s))?; } - Ok(()) - } -} - -pub mod mod_Message { - - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Flag { - FIN = 0, - STOP_SENDING = 1, - RESET = 2, -} - -impl Default for Flag { - fn default() -> Self { - Flag::FIN - } -} - -impl From for Flag { - fn from(i: i32) -> Self { - match i { - 0 => Flag::FIN, - 1 => Flag::STOP_SENDING, - 2 => Flag::RESET, - _ => Self::default(), - } - } -} - -impl<'a> From<&'a str> for Flag { - fn from(s: &'a str) -> Self { - match s { - "FIN" => Flag::FIN, - "STOP_SENDING" => Flag::STOP_SENDING, - "RESET" => Flag::RESET, - _ => Self::default(), - } - } -} - -} - diff --git a/misc/webrtc-utils/src/lib.rs b/misc/webrtc-utils/src/lib.rs index 060e69a299e..330cebee3b1 100644 --- a/misc/webrtc-utils/src/lib.rs +++ b/misc/webrtc-utils/src/lib.rs @@ -1,7 +1,7 @@ mod proto { #![allow(unreachable_pub)] include!("generated/mod.rs"); - pub use self::webrtc::pb::{Message, mod_Message::Flag}; + pub use self::webrtc_pb::{Message, message::Flag}; } mod fingerprint; diff --git a/misc/webrtc-utils/src/stream.rs b/misc/webrtc-utils/src/stream.rs index 0ec420a103a..b0074536ac4 100644 --- a/misc/webrtc-utils/src/stream.rs +++ b/misc/webrtc-utils/src/stream.rs @@ -95,7 +95,7 @@ where ready!(self.io.poll_ready_unpin(cx))?; self.io.start_send_unpin(Message { - flag: Some(Flag::STOP_SENDING), + flag: Some(Flag::StopSending as i32), message: None, })?; self.state.close_read_message_sent(); @@ -160,7 +160,7 @@ where } } None => { - state.handle_inbound_flag(Flag::FIN, read_buffer); + state.handle_inbound_flag(Flag::Fin, read_buffer); return Poll::Ready(Ok(0)); } } @@ -226,7 +226,7 @@ where ready!(self.io.poll_ready_unpin(cx))?; self.io.start_send_unpin(Message { - flag: Some(Flag::FIN), + flag: Some(Flag::Fin as i32), message: None, })?; self.state.close_write_message_sent(); @@ -262,7 +262,10 @@ where .transpose() .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))? { - Some(Message { flag, message }) => Poll::Ready(Ok(Some((flag, message)))), + Some(Message { flag, message }) => { + let flag = flag.and_then(|f| Flag::try_from(f).ok()); + Poll::Ready(Ok(Some((flag, message)))) + } None => Poll::Ready(Ok(None)), } } @@ -281,7 +284,7 @@ mod tests { let message = [0; MAX_DATA_LEN]; let protobuf = Message { - flag: Some(Flag::FIN), + flag: Some(Flag::Fin as i32), message: Some(message.to_vec()), }; diff --git a/misc/webrtc-utils/src/stream/drop_listener.rs b/misc/webrtc-utils/src/stream/drop_listener.rs index def6757b298..cd4c3a03d99 100644 --- a/misc/webrtc-utils/src/stream/drop_listener.rs +++ b/misc/webrtc-utils/src/stream/drop_listener.rs @@ -96,7 +96,7 @@ where State::SendingReset { mut stream } => match stream.poll_ready_unpin(cx)? { Poll::Ready(()) => { stream.start_send_unpin(Message { - flag: Some(Flag::RESET), + flag: Some(Flag::Reset as i32), message: None, })?; *state = State::Flushing { stream }; diff --git a/misc/webrtc-utils/src/stream/framed_dc.rs b/misc/webrtc-utils/src/stream/framed_dc.rs index a7b9b6214e0..f0bbda84ca8 100644 --- a/misc/webrtc-utils/src/stream/framed_dc.rs +++ b/misc/webrtc-utils/src/stream/framed_dc.rs @@ -26,7 +26,7 @@ use crate::{ stream::{MAX_DATA_LEN, MAX_MSG_LEN, VARINT_LEN}, }; -pub(crate) type FramedDc = Framed>; +pub(crate) type FramedDc = Framed>; pub(crate) fn new(inner: T) -> FramedDc where T: AsyncRead + AsyncWrite, @@ -38,6 +38,6 @@ where framed } -pub(crate) fn codec() -> quick_protobuf_codec::Codec { - quick_protobuf_codec::Codec::new(MAX_MSG_LEN - VARINT_LEN) +pub(crate) fn codec() -> prost_codec::Codec { + prost_codec::Codec::new(MAX_MSG_LEN - VARINT_LEN) } diff --git a/misc/webrtc-utils/src/stream/state.rs b/misc/webrtc-utils/src/stream/state.rs index 9b84989fb6b..05e0a1b37b9 100644 --- a/misc/webrtc-utils/src/stream/state.rs +++ b/misc/webrtc-utils/src/stream/state.rs @@ -60,19 +60,19 @@ impl State { let current = *self; match (current, flag) { - (Self::Open, Flag::FIN) => { + (Self::Open, Flag::Fin) => { *self = Self::ReadClosed; } - (Self::WriteClosed, Flag::FIN) => { + (Self::WriteClosed, Flag::Fin) => { *self = Self::BothClosed { reset: false }; } - (Self::Open, Flag::STOP_SENDING) => { + (Self::Open, Flag::StopSending) => { *self = Self::WriteClosed; } - (Self::ReadClosed, Flag::STOP_SENDING) => { + (Self::ReadClosed, Flag::StopSending) => { *self = Self::BothClosed { reset: false }; } - (_, Flag::RESET) => { + (_, Flag::Reset) => { buffer.clear(); *self = Self::BothClosed { reset: true }; } @@ -330,7 +330,7 @@ mod tests { fn cannot_read_after_receiving_fin() { let mut open = State::Open; - open.handle_inbound_flag(Flag::FIN, &mut Bytes::default()); + open.handle_inbound_flag(Flag::Fin, &mut Bytes::default()); let error = open.read_barrier().unwrap_err(); assert_eq!(error.kind(), ErrorKind::BrokenPipe) @@ -352,7 +352,7 @@ mod tests { fn cannot_write_after_receiving_stop_sending() { let mut open = State::Open; - open.handle_inbound_flag(Flag::STOP_SENDING, &mut Bytes::default()); + open.handle_inbound_flag(Flag::StopSending, &mut Bytes::default()); let error = open.write_barrier().unwrap_err(); assert_eq!(error.kind(), ErrorKind::BrokenPipe) @@ -374,7 +374,7 @@ mod tests { fn everything_broken_after_receiving_reset() { let mut open = State::Open; - open.handle_inbound_flag(Flag::RESET, &mut Bytes::default()); + open.handle_inbound_flag(Flag::Reset, &mut Bytes::default()); let error1 = open.read_barrier().unwrap_err(); let error2 = open.write_barrier().unwrap_err(); let error3 = open.close_write_barrier().unwrap_err(); @@ -390,7 +390,7 @@ mod tests { fn should_read_flags_in_async_write_after_read_closed() { let mut open = State::Open; - open.handle_inbound_flag(Flag::FIN, &mut Bytes::default()); + open.handle_inbound_flag(Flag::Fin, &mut Bytes::default()); assert!(open.read_flags_in_async_write()) } @@ -399,8 +399,8 @@ mod tests { fn cannot_read_or_write_after_receiving_fin_and_stop_sending() { let mut open = State::Open; - open.handle_inbound_flag(Flag::FIN, &mut Bytes::default()); - open.handle_inbound_flag(Flag::STOP_SENDING, &mut Bytes::default()); + open.handle_inbound_flag(Flag::Fin, &mut Bytes::default()); + open.handle_inbound_flag(Flag::StopSending, &mut Bytes::default()); let error1 = open.read_barrier().unwrap_err(); let error2 = open.write_barrier().unwrap_err(); @@ -500,7 +500,7 @@ mod tests { let mut open = State::Open; let mut buffer = Bytes::copy_from_slice(b"foobar"); - open.handle_inbound_flag(Flag::RESET, &mut buffer); + open.handle_inbound_flag(Flag::Reset, &mut buffer); assert!(buffer.is_empty()); } diff --git a/protocols/autonat/CHANGELOG.md b/protocols/autonat/CHANGELOG.md index 51e785f7f66..43684c299e6 100644 --- a/protocols/autonat/CHANGELOG.md +++ b/protocols/autonat/CHANGELOG.md @@ -5,6 +5,8 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). ## 0.15.0 diff --git a/protocols/autonat/Cargo.toml b/protocols/autonat/Cargo.toml index a5691d227f3..cd20ead2487 100644 --- a/protocols/autonat/Cargo.toml +++ b/protocols/autonat/Cargo.toml @@ -26,9 +26,9 @@ libp2p-core = { workspace = true } libp2p-identity = { workspace = true } libp2p-request-response = { workspace = true, optional = true } libp2p-swarm = { workspace = true } -quick-protobuf = "0.8" +prost = { workspace = true } tracing = { workspace = true } -quick-protobuf-codec = { workspace = true } +prost-codec = { workspace = true } rand = "0.8" rand_core = { version = "0.6", optional = true } thiserror = { workspace = true, optional = true } diff --git a/protocols/autonat/src/v1.rs b/protocols/autonat/src/v1.rs index 98d793f4d89..9350288ef6c 100644 --- a/protocols/autonat/src/v1.rs +++ b/protocols/autonat/src/v1.rs @@ -42,5 +42,5 @@ pub use self::{ pub(crate) mod proto { #![allow(unreachable_pub)] include!("v1/generated/mod.rs"); - pub(crate) use self::structs::{Message, mod_Message::*}; + pub(crate) use self::structs::{Message, message::*}; } diff --git a/protocols/autonat/src/v1/generated/mod.rs b/protocols/autonat/src/v1/generated/mod.rs index e52c5a80bc0..c271155936b 100644 --- a/protocols/autonat/src/v1/generated/mod.rs +++ b/protocols/autonat/src/v1/generated/mod.rs @@ -1,2 +1,2 @@ -// Automatically generated mod.rs +// Automatically generated by gen-proto. DO NOT EDIT. pub mod structs; diff --git a/protocols/autonat/src/v1/generated/structs.rs b/protocols/autonat/src/v1/generated/structs.rs index 3a6d416b2b1..c0f68fa2841 100644 --- a/protocols/autonat/src/v1/generated/structs.rs +++ b/protocols/autonat/src/v1/generated/structs.rs @@ -1,242 +1,115 @@ -// 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)] +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Message { - pub type_pb: Option, - pub dial: Option, - pub dialResponse: Option, -} - -impl<'a> MessageRead<'a> for Message { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::(bytes)?), - Ok(26) => msg.dialResponse = Some(r.read_message::(bytes)?), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), + #[prost(enumeration = "message::MessageType", optional, tag = "1")] + pub r#type: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub dial: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub dial_response: ::core::option::Option, +} +/// Nested message and enum types in `Message`. +pub mod message { + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct PeerInfo { + #[prost(bytes = "vec", optional, tag = "1")] + pub id: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", repeated, tag = "2")] + pub addrs: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + } + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct Dial { + #[prost(message, optional, tag = "1")] + pub peer: ::core::option::Option, + } + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct DialResponse { + #[prost(enumeration = "ResponseStatus", optional, tag = "1")] + pub status: ::core::option::Option, + #[prost(string, optional, tag = "2")] + pub status_text: ::core::option::Option<::prost::alloc::string::String>, + #[prost(bytes = "vec", optional, tag = "3")] + pub addr: ::core::option::Option<::prost::alloc::vec::Vec>, + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum MessageType { + Dial = 0, + DialResponse = 1, + } + impl MessageType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Dial => "DIAL", + Self::DialResponse => "DIAL_RESPONSE", } } - 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(&self, w: &mut Writer) -> 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>, - pub addrs: Vec>, -} - -impl<'a> MessageRead<'a> for PeerInfo { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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), + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "DIAL" => Some(Self::Dial), + "DIAL_RESPONSE" => Some(Self::DialResponse), + _ => None, } } - 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::() - } - - fn write_message(&self, w: &mut Writer) -> 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, -} - -impl<'a> MessageRead<'a> for Dial { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.peer = Some(r.read_message::(bytes)?), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum ResponseStatus { + Ok = 0, + EDialError = 100, + EDialRefused = 101, + EBadRequest = 200, + EInternalError = 300, + } + impl ResponseStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Ok => "OK", + Self::EDialError => "E_DIAL_ERROR", + Self::EDialRefused => "E_DIAL_REFUSED", + Self::EBadRequest => "E_BAD_REQUEST", + Self::EInternalError => "E_INTERNAL_ERROR", } } - 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(&self, w: &mut Writer) -> 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, - pub statusText: Option, - pub addr: Option>, -} - -impl<'a> MessageRead<'a> for DialResponse { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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), + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "OK" => Some(Self::Ok), + "E_DIAL_ERROR" => Some(Self::EDialError), + "E_DIAL_REFUSED" => Some(Self::EDialRefused), + "E_BAD_REQUEST" => Some(Self::EBadRequest), + "E_INTERNAL_ERROR" => Some(Self::EInternalError), + _ => None, } } - 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(&self, w: &mut Writer) -> 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 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 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(), - } - } -} - -} - diff --git a/protocols/autonat/src/v1/protocol.rs b/protocols/autonat/src/v1/protocol.rs index 2784c44fe03..988f12c5b1e 100644 --- a/protocols/autonat/src/v1/protocol.rs +++ b/protocols/autonat/src/v1/protocol.rs @@ -106,8 +106,8 @@ impl request_response::Codec for AutoNatCodec { } } -fn codec() -> quick_protobuf_codec::Codec { - quick_protobuf_codec::Codec::::new(1024) +fn codec() -> prost_codec::Codec { + prost_codec::Codec::::new(1024) } #[derive(Clone, Debug, Eq, PartialEq)] @@ -118,7 +118,7 @@ pub struct DialRequest { impl DialRequest { pub fn from_proto(msg: proto::Message) -> Result { - if msg.type_pb != Some(proto::MessageType::DIAL) { + if msg.r#type != Some(proto::MessageType::Dial as i32) { return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid type")); } @@ -160,14 +160,14 @@ impl DialRequest { .collect(); proto::Message { - type_pb: Some(proto::MessageType::DIAL), + r#type: Some(proto::MessageType::Dial as i32), dial: Some(proto::Dial { peer: Some(proto::PeerInfo { id: Some(peer_id.to_vec()), addrs, }), }), - dialResponse: None, + dial_response: None, } } } @@ -183,10 +183,10 @@ pub enum ResponseError { impl From for proto::ResponseStatus { fn from(t: ResponseError) -> Self { match t { - 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, + ResponseError::DialError => proto::ResponseStatus::EDialError, + ResponseError::DialRefused => proto::ResponseStatus::EDialRefused, + ResponseError::BadRequest => proto::ResponseStatus::EBadRequest, + ResponseError::InternalError => proto::ResponseStatus::EInternalError, } } } @@ -196,11 +196,11 @@ impl TryFrom for ResponseError { fn try_from(value: proto::ResponseStatus) -> Result { match value { - 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 => { + proto::ResponseStatus::EDialError => Ok(ResponseError::DialError), + proto::ResponseStatus::EDialRefused => Ok(ResponseError::DialRefused), + proto::ResponseStatus::EBadRequest => Ok(ResponseError::BadRequest), + proto::ResponseStatus::EInternalError => Ok(ResponseError::InternalError), + proto::ResponseStatus::Ok => { tracing::debug!("Received response with status code OK but expected error"); Err(io::Error::new( io::ErrorKind::InvalidData, @@ -219,31 +219,39 @@ pub struct DialResponse { impl DialResponse { pub fn from_proto(msg: proto::Message) -> Result { - if msg.type_pb != Some(proto::MessageType::DIAL_RESPONSE) { + if msg.r#type != Some(proto::MessageType::DialResponse as i32) { return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid type")); } - Ok(match msg.dialResponse { + Ok(match msg.dial_response { Some(proto::DialResponse { - status: Some(proto::ResponseStatus::OK), - statusText, - addr: Some(addr), + status, + status_text, + addr, }) => { - let addr = Multiaddr::try_from(addr.to_vec()) - .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; - Self { - status_text: statusText, - result: Ok(addr), + let status = status.and_then(|s| proto::ResponseStatus::try_from(s).ok()); + match (status, addr) { + (Some(proto::ResponseStatus::Ok), Some(addr)) => { + let addr = Multiaddr::try_from(addr.to_vec()) + .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; + Self { + status_text, + result: Ok(addr), + } + } + (Some(status), _) => Self { + status_text, + result: Err(ResponseError::try_from(status)?), + }, + _ => { + tracing::debug!("Received malformed response message"); + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "invalid dial response message", + )); + } } } - Some(proto::DialResponse { - status: Some(status), - statusText, - addr: None, - }) => Self { - status_text: statusText, - result: Err(ResponseError::try_from(status)?), - }, _ => { tracing::debug!("Received malformed response message"); return Err(io::Error::new( @@ -257,21 +265,21 @@ impl DialResponse { pub fn into_proto(self) -> proto::Message { let dial_response = match self.result { Ok(addr) => proto::DialResponse { - status: Some(proto::ResponseStatus::OK), - statusText: self.status_text, + status: Some(proto::ResponseStatus::Ok as i32), + status_text: self.status_text, addr: Some(addr.to_vec()), }, Err(error) => proto::DialResponse { - status: Some(error.into()), - statusText: self.status_text, + status: Some(proto::ResponseStatus::from(error) as i32), + status_text: self.status_text, addr: None, }, }; proto::Message { - type_pb: Some(proto::MessageType::DIAL_RESPONSE), + r#type: Some(proto::MessageType::DialResponse as i32), dial: None, - dialResponse: Some(dial_response), + dial_response: Some(dial_response), } } } @@ -328,14 +336,14 @@ mod tests { }; let msg = proto::Message { - type_pb: Some(proto::MessageType::DIAL), + r#type: Some(proto::MessageType::Dial as i32), dial: Some(proto::Dial { peer: Some(proto::PeerInfo { id: Some(PeerId::random().to_bytes()), addrs: vec![valid_multiaddr_bytes, invalid_multiaddr], }), }), - dialResponse: None, + dial_response: None, }; let request = DialRequest::from_proto(msg).expect("not to fail"); diff --git a/protocols/autonat/src/v2.rs b/protocols/autonat/src/v2.rs index 045c0c52546..a5aa4129bd8 100644 --- a/protocols/autonat/src/v2.rs +++ b/protocols/autonat/src/v2.rs @@ -25,7 +25,7 @@ pub(crate) mod protocol; pub mod server; pub(crate) mod generated { - #![allow(unreachable_pub)] + #![allow(unreachable_pub, clippy::enum_variant_names)] include!("v2/generated/mod.rs"); } diff --git a/protocols/autonat/src/v2/client/handler/dial_request.rs b/protocols/autonat/src/v2/client/handler/dial_request.rs index e14f5e19a44..79538e566fc 100644 --- a/protocols/autonat/src/v2/client/handler/dial_request.rs +++ b/protocols/autonat/src/v2/client/handler/dial_request.rs @@ -24,7 +24,7 @@ use libp2p_swarm::{ use crate::v2::{ DIAL_REQUEST_PROTOCOL, Nonce, - generated::structs::{DialStatus, mod_DialResponse::ResponseStatus}, + generated::structs::{DialStatus, dial_response::ResponseStatus}, protocol::{ Coder, DATA_FIELD_LEN_UPPER_BOUND, DATA_LEN_LOWER_BOUND, DATA_LEN_UPPER_BOUND, DialDataRequest, DialDataResponse, DialRequest, Response, @@ -268,18 +268,18 @@ async fn start_stream_handle( } match res.status { - ResponseStatus::E_REQUEST_REJECTED => { + ResponseStatus::ERequestRejected => { return Err(Error::Io(io::Error::other("server rejected request"))); } - ResponseStatus::E_DIAL_REFUSED => { + ResponseStatus::EDialRefused => { return Err(Error::Io(io::Error::other("server refused dial"))); } - ResponseStatus::E_INTERNAL_ERROR => { + ResponseStatus::EInternalError => { return Err(Error::Io(io::Error::other( "server encountered internal error", ))); } - ResponseStatus::OK => {} + ResponseStatus::Ok => {} } let tested_address = req @@ -289,27 +289,27 @@ async fn start_stream_handle( .clone(); match res.dial_status { - DialStatus::UNUSED => { + DialStatus::Unused => { return Err(Error::Io(io::Error::new( io::ErrorKind::InvalidInput, "unexpected message", ))); } - DialStatus::E_DIAL_ERROR => { + DialStatus::EDialError => { return Err(Error::AddressNotReachable { address: tested_address, bytes_sent, error: DialBackError::NoConnection, }); } - DialStatus::E_DIAL_BACK_ERROR => { + DialStatus::EDialBackError => { return Err(Error::AddressNotReachable { address: tested_address, bytes_sent, error: DialBackError::StreamFailed, }); } - DialStatus::OK => {} + DialStatus::Ok => {} } Ok((tested_address, bytes_sent)) diff --git a/protocols/autonat/src/v2/generated/mod.rs b/protocols/autonat/src/v2/generated/mod.rs index e52c5a80bc0..c271155936b 100644 --- a/protocols/autonat/src/v2/generated/mod.rs +++ b/protocols/autonat/src/v2/generated/mod.rs @@ -1,2 +1,2 @@ -// Automatically generated mod.rs +// Automatically generated by gen-proto. DO NOT EDIT. pub mod structs; diff --git a/protocols/autonat/src/v2/generated/structs.rs b/protocols/autonat/src/v2/generated/structs.rs index e188adb8a42..05e2c78753c 100644 --- a/protocols/autonat/src/v2/generated/structs.rs +++ b/protocols/autonat/src/v2/generated/structs.rs @@ -1,403 +1,171 @@ -// 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::*; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum DialStatus { - UNUSED = 0, - E_DIAL_ERROR = 100, - E_DIAL_BACK_ERROR = 101, - OK = 200, -} - -impl Default for DialStatus { - fn default() -> Self { - DialStatus::UNUSED - } -} - -impl From for DialStatus { - fn from(i: i32) -> Self { - match i { - 0 => DialStatus::UNUSED, - 100 => DialStatus::E_DIAL_ERROR, - 101 => DialStatus::E_DIAL_BACK_ERROR, - 200 => DialStatus::OK, - _ => Self::default(), - } - } -} - -impl<'a> From<&'a str> for DialStatus { - fn from(s: &'a str) -> Self { - match s { - "UNUSED" => DialStatus::UNUSED, - "E_DIAL_ERROR" => DialStatus::E_DIAL_ERROR, - "E_DIAL_BACK_ERROR" => DialStatus::E_DIAL_BACK_ERROR, - "OK" => DialStatus::OK, - _ => Self::default(), - } - } -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Message { - pub msg: structs::mod_Message::OneOfmsg, -} - -impl<'a> MessageRead<'a> for Message { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.msg = structs::mod_Message::OneOfmsg::dialRequest(r.read_message::(bytes)?), - Ok(18) => msg.msg = structs::mod_Message::OneOfmsg::dialResponse(r.read_message::(bytes)?), - Ok(26) => msg.msg = structs::mod_Message::OneOfmsg::dialDataRequest(r.read_message::(bytes)?), - Ok(34) => msg.msg = structs::mod_Message::OneOfmsg::dialDataResponse(r.read_message::(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 - + match self.msg { - structs::mod_Message::OneOfmsg::dialRequest(ref m) => 1 + sizeof_len((m).get_size()), - structs::mod_Message::OneOfmsg::dialResponse(ref m) => 1 + sizeof_len((m).get_size()), - structs::mod_Message::OneOfmsg::dialDataRequest(ref m) => 1 + sizeof_len((m).get_size()), - structs::mod_Message::OneOfmsg::dialDataResponse(ref m) => 1 + sizeof_len((m).get_size()), - structs::mod_Message::OneOfmsg::None => 0, - } } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - match self.msg { structs::mod_Message::OneOfmsg::dialRequest(ref m) => { w.write_with_tag(10, |w| w.write_message(m))? }, - structs::mod_Message::OneOfmsg::dialResponse(ref m) => { w.write_with_tag(18, |w| w.write_message(m))? }, - structs::mod_Message::OneOfmsg::dialDataRequest(ref m) => { w.write_with_tag(26, |w| w.write_message(m))? }, - structs::mod_Message::OneOfmsg::dialDataResponse(ref m) => { w.write_with_tag(34, |w| w.write_message(m))? }, - structs::mod_Message::OneOfmsg::None => {}, - } Ok(()) - } -} - -pub mod mod_Message { - -use super::*; - -#[derive(Debug, PartialEq, Clone)] -pub enum OneOfmsg { - dialRequest(structs::DialRequest), - dialResponse(structs::DialResponse), - dialDataRequest(structs::DialDataRequest), - dialDataResponse(structs::DialDataResponse), - None, -} - -impl Default for OneOfmsg { - fn default() -> Self { - OneOfmsg::None - } -} - -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] + #[prost(oneof = "message::Msg", tags = "1, 2, 3, 4")] + pub msg: ::core::option::Option, +} +/// Nested message and enum types in `Message`. +pub mod message { + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)] + pub enum Msg { + #[prost(message, tag = "1")] + DialRequest(super::DialRequest), + #[prost(message, tag = "2")] + DialResponse(super::DialResponse), + #[prost(message, tag = "3")] + DialDataRequest(super::DialDataRequest), + #[prost(message, tag = "4")] + DialDataResponse(super::DialDataResponse), + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct DialRequest { - pub addrs: Vec>, + #[prost(bytes = "vec", repeated, tag = "1")] + pub addrs: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + #[prost(fixed64, tag = "2")] pub nonce: u64, } - -impl<'a> MessageRead<'a> for DialRequest { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.addrs.push(r.read_bytes(bytes)?.to_owned()), - Ok(17) => msg.nonce = r.read_fixed64(bytes)?, - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for DialRequest { - fn get_size(&self) -> usize { - 0 - + self.addrs.iter().map(|s| 1 + sizeof_len((s).len())).sum::() - + if self.nonce == 0u64 { 0 } else { 1 + 8 } - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - for s in &self.addrs { w.write_with_tag(10, |w| w.write_bytes(&**s))?; } - if self.nonce != 0u64 { w.write_with_tag(17, |w| w.write_fixed64(*&self.nonce))?; } - Ok(()) - } -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct DialDataRequest { - pub addrIdx: u32, - pub numBytes: u64, + #[prost(uint32, tag = "1")] + pub addr_idx: u32, + #[prost(uint64, tag = "2")] + pub num_bytes: u64, } - -impl<'a> MessageRead<'a> for DialDataRequest { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(8) => msg.addrIdx = r.read_uint32(bytes)?, - Ok(16) => msg.numBytes = r.read_uint64(bytes)?, - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for DialDataRequest { - fn get_size(&self) -> usize { - 0 - + if self.addrIdx == 0u32 { 0 } else { 1 + sizeof_varint(*(&self.addrIdx) as u64) } - + if self.numBytes == 0u64 { 0 } else { 1 + sizeof_varint(*(&self.numBytes) as u64) } - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if self.addrIdx != 0u32 { w.write_with_tag(8, |w| w.write_uint32(*&self.addrIdx))?; } - if self.numBytes != 0u64 { w.write_with_tag(16, |w| w.write_uint64(*&self.numBytes))?; } - Ok(()) - } -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct DialResponse { - pub status: structs::mod_DialResponse::ResponseStatus, - pub addrIdx: u32, - pub dialStatus: structs::DialStatus, -} - -impl<'a> MessageRead<'a> for DialResponse { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(8) => msg.status = r.read_enum(bytes)?, - Ok(16) => msg.addrIdx = r.read_uint32(bytes)?, - Ok(24) => msg.dialStatus = r.read_enum(bytes)?, - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), + #[prost(enumeration = "dial_response::ResponseStatus", tag = "1")] + pub status: i32, + #[prost(uint32, tag = "2")] + pub addr_idx: u32, + #[prost(enumeration = "DialStatus", tag = "3")] + pub dial_status: i32, +} +/// Nested message and enum types in `DialResponse`. +pub mod dial_response { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum ResponseStatus { + EInternalError = 0, + ERequestRejected = 100, + EDialRefused = 101, + Ok = 200, + } + impl ResponseStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::EInternalError => "E_INTERNAL_ERROR", + Self::ERequestRejected => "E_REQUEST_REJECTED", + Self::EDialRefused => "E_DIAL_REFUSED", + Self::Ok => "OK", } } - Ok(msg) - } -} - -impl MessageWrite for DialResponse { - fn get_size(&self) -> usize { - 0 - + if self.status == structs::mod_DialResponse::ResponseStatus::E_INTERNAL_ERROR { 0 } else { 1 + sizeof_varint(*(&self.status) as u64) } - + if self.addrIdx == 0u32 { 0 } else { 1 + sizeof_varint(*(&self.addrIdx) as u64) } - + if self.dialStatus == structs::DialStatus::UNUSED { 0 } else { 1 + sizeof_varint(*(&self.dialStatus) as u64) } - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if self.status != structs::mod_DialResponse::ResponseStatus::E_INTERNAL_ERROR { w.write_with_tag(8, |w| w.write_enum(*&self.status as i32))?; } - if self.addrIdx != 0u32 { w.write_with_tag(16, |w| w.write_uint32(*&self.addrIdx))?; } - if self.dialStatus != structs::DialStatus::UNUSED { w.write_with_tag(24, |w| w.write_enum(*&self.dialStatus as i32))?; } - Ok(()) - } -} - -pub mod mod_DialResponse { - - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum ResponseStatus { - E_INTERNAL_ERROR = 0, - E_REQUEST_REJECTED = 100, - E_DIAL_REFUSED = 101, - OK = 200, -} - -impl Default for ResponseStatus { - fn default() -> Self { - ResponseStatus::E_INTERNAL_ERROR - } -} - -impl From for ResponseStatus { - fn from(i: i32) -> Self { - match i { - 0 => ResponseStatus::E_INTERNAL_ERROR, - 100 => ResponseStatus::E_REQUEST_REJECTED, - 101 => ResponseStatus::E_DIAL_REFUSED, - 200 => ResponseStatus::OK, - _ => Self::default(), - } - } -} - -impl<'a> From<&'a str> for ResponseStatus { - fn from(s: &'a str) -> Self { - match s { - "E_INTERNAL_ERROR" => ResponseStatus::E_INTERNAL_ERROR, - "E_REQUEST_REJECTED" => ResponseStatus::E_REQUEST_REJECTED, - "E_DIAL_REFUSED" => ResponseStatus::E_DIAL_REFUSED, - "OK" => ResponseStatus::OK, - _ => Self::default(), - } - } -} - -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] -pub struct DialDataResponse { - pub data: Vec, -} - -impl<'a> MessageRead<'a> for DialDataResponse { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.data = r.read_bytes(bytes)?.to_owned(), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "E_INTERNAL_ERROR" => Some(Self::EInternalError), + "E_REQUEST_REJECTED" => Some(Self::ERequestRejected), + "E_DIAL_REFUSED" => Some(Self::EDialRefused), + "OK" => Some(Self::Ok), + _ => None, } } - Ok(msg) } } - -impl MessageWrite for DialDataResponse { - fn get_size(&self) -> usize { - 0 - + if self.data.is_empty() { 0 } else { 1 + sizeof_len((&self.data).len()) } - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if !self.data.is_empty() { w.write_with_tag(10, |w| w.write_bytes(&**&self.data))?; } - Ok(()) - } +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct DialDataResponse { + #[prost(bytes = "vec", tag = "1")] + pub data: ::prost::alloc::vec::Vec, } - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct DialBack { + #[prost(fixed64, tag = "1")] pub nonce: u64, } - -impl<'a> MessageRead<'a> for DialBack { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(9) => msg.nonce = r.read_fixed64(bytes)?, - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct DialBackResponse { + #[prost(enumeration = "dial_back_response::DialBackStatus", tag = "1")] + pub status: i32, +} +/// Nested message and enum types in `DialBackResponse`. +pub mod dial_back_response { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum DialBackStatus { + Ok = 0, + } + impl DialBackStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Ok => "OK", } } - Ok(msg) - } -} - -impl MessageWrite for DialBack { - fn get_size(&self) -> usize { - 0 - + if self.nonce == 0u64 { 0 } else { 1 + 8 } - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if self.nonce != 0u64 { w.write_with_tag(9, |w| w.write_fixed64(*&self.nonce))?; } - Ok(()) - } -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] -pub struct DialBackResponse { - pub status: structs::mod_DialBackResponse::DialBackStatus, -} - -impl<'a> MessageRead<'a> for DialBackResponse { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(8) => msg.status = r.read_enum(bytes)?, - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "OK" => Some(Self::Ok), + _ => None, } } - Ok(msg) } } - -impl MessageWrite for DialBackResponse { - fn get_size(&self) -> usize { - 0 - + if self.status == structs::mod_DialBackResponse::DialBackStatus::OK { 0 } else { 1 + sizeof_varint(*(&self.status) as u64) } - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if self.status != structs::mod_DialBackResponse::DialBackStatus::OK { w.write_with_tag(8, |w| w.write_enum(*&self.status as i32))?; } - Ok(()) - } -} - -pub mod mod_DialBackResponse { - - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum DialBackStatus { - OK = 0, -} - -impl Default for DialBackStatus { - fn default() -> Self { - DialBackStatus::OK - } -} - -impl From for DialBackStatus { - fn from(i: i32) -> Self { - match i { - 0 => DialBackStatus::OK, - _ => Self::default(), +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum DialStatus { + Unused = 0, + EDialError = 100, + EDialBackError = 101, + Ok = 200, +} +impl DialStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unused => "UNUSED", + Self::EDialError => "E_DIAL_ERROR", + Self::EDialBackError => "E_DIAL_BACK_ERROR", + Self::Ok => "OK", } } -} - -impl<'a> From<&'a str> for DialBackStatus { - fn from(s: &'a str) -> Self { - match s { - "OK" => DialBackStatus::OK, - _ => Self::default(), + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNUSED" => Some(Self::Unused), + "E_DIAL_ERROR" => Some(Self::EDialError), + "E_DIAL_BACK_ERROR" => Some(Self::EDialBackError), + "OK" => Some(Self::Ok), + _ => None, } } } - -} - diff --git a/protocols/autonat/src/v2/protocol.rs b/protocols/autonat/src/v2/protocol.rs index e20235d1ca7..6afd93fc0af 100644 --- a/protocols/autonat/src/v2/protocol.rs +++ b/protocols/autonat/src/v2/protocol.rs @@ -1,16 +1,14 @@ -// change to quick-protobuf-codec - use std::{io, io::ErrorKind}; use asynchronous_codec::{Framed, FramedRead, FramedWrite}; use futures::{AsyncRead, AsyncWrite, SinkExt, StreamExt}; use libp2p_core::Multiaddr; -use quick_protobuf_codec::Codec; +use prost_codec::Codec; use rand::Rng; use crate::v2::{Nonce, generated::structs as proto}; -const REQUEST_MAX_SIZE: usize = 4104; +const REQUEST_MAX_SIZE: usize = 4102; pub(super) const DATA_LEN_LOWER_BOUND: usize = 30_000u32 as usize; pub(super) const DATA_LEN_UPPER_BOUND: usize = 100_000u32 as usize; pub(super) const DATA_FIELD_LEN_UPPER_BOUND: usize = 4096; @@ -87,7 +85,10 @@ impl From for proto::Message { let nonce = val.nonce; proto::Message { - msg: proto::mod_Message::OneOfmsg::dialRequest(proto::DialRequest { addrs, nonce }), + msg: Some(proto::message::Msg::DialRequest(proto::DialRequest { + addrs, + nonce, + })), } } } @@ -99,12 +100,14 @@ impl From for proto::Message { "data_count too large" ); proto::Message { - msg: proto::mod_Message::OneOfmsg::dialDataResponse(proto::DialDataResponse { - // One could use Cow::Borrowed here, but it will - // require a modification of the generated code - // and that will fail the CI - data: vec![0; val.data_count], - }), + msg: Some(proto::message::Msg::DialDataResponse( + proto::DialDataResponse { + // One could use Cow::Borrowed here, but it will + // require a modification of the generated code + // and that will fail the CI + data: vec![0; val.data_count], + }, + )), } } } @@ -139,7 +142,7 @@ impl TryFrom for Request { fn try_from(msg: proto::Message) -> Result { match msg.msg { - proto::mod_Message::OneOfmsg::dialRequest(proto::DialRequest { addrs, nonce }) => { + Some(proto::message::Msg::DialRequest(proto::DialRequest { addrs, nonce })) => { let addrs = addrs .into_iter() .map(|e| e.to_vec()) @@ -151,7 +154,7 @@ impl TryFrom for Request { .collect::, io::Error>>()?; Ok(Self::Dial(DialRequest { addrs, nonce })) } - proto::mod_Message::OneOfmsg::dialDataResponse(proto::DialDataResponse { data }) => { + Some(proto::message::Msg::DialDataResponse(proto::DialDataResponse { data })) => { let data_count = data.len(); Ok(Self::Data(DialDataResponse { data_count })) } @@ -176,7 +179,7 @@ pub(crate) struct DialDataRequest { #[derive(Debug, Clone)] pub(crate) struct DialResponse { - pub(crate) status: proto::mod_DialResponse::ResponseStatus, + pub(crate) status: proto::dial_response::ResponseStatus, pub(crate) addr_idx: usize, pub(crate) dial_status: proto::DialStatus, } @@ -186,21 +189,25 @@ impl TryFrom for Response { fn try_from(msg: proto::Message) -> Result { match msg.msg { - proto::mod_Message::OneOfmsg::dialResponse(proto::DialResponse { + Some(proto::message::Msg::DialResponse(proto::DialResponse { status, - addrIdx, - dialStatus, - }) => Ok(Response::Dial(DialResponse { - status, - addr_idx: addrIdx as usize, - dial_status: dialStatus, + addr_idx, + dial_status, + })) => Ok(Response::Dial(DialResponse { + status: proto::dial_response::ResponseStatus::try_from(status).map_err(|_| { + new_io_invalid_data_err(format!("unknown response status: {status}")) + })?, + addr_idx: addr_idx as usize, + dial_status: proto::DialStatus::try_from(dial_status).map_err(|_| { + new_io_invalid_data_err(format!("unknown dial status: {dial_status}")) + })?, })), - proto::mod_Message::OneOfmsg::dialDataRequest(proto::DialDataRequest { - addrIdx, - numBytes, - }) => Ok(Self::Data(DialDataRequest { - addr_idx: addrIdx as usize, - num_bytes: numBytes as usize, + Some(proto::message::Msg::DialDataRequest(proto::DialDataRequest { + addr_idx, + num_bytes, + })) => Ok(Self::Data(DialDataRequest { + addr_idx: addr_idx as usize, + num_bytes: num_bytes as usize, })), _ => Err(new_io_invalid_data_err( "invalid message type, expected dialResponse or dialDataRequest", @@ -217,20 +224,22 @@ impl From for proto::Message { addr_idx, dial_status, }) => proto::Message { - msg: proto::mod_Message::OneOfmsg::dialResponse(proto::DialResponse { - status, - addrIdx: addr_idx as u32, - dialStatus: dial_status, - }), + msg: Some(proto::message::Msg::DialResponse(proto::DialResponse { + status: status as i32, + addr_idx: addr_idx as u32, + dial_status: dial_status as i32, + })), }, Response::Data(DialDataRequest { addr_idx, num_bytes, }) => proto::Message { - msg: proto::mod_Message::OneOfmsg::dialDataRequest(proto::DialDataRequest { - addrIdx: addr_idx as u32, - numBytes: num_bytes as u64, - }), + msg: Some(proto::message::Msg::DialDataRequest( + proto::DialDataRequest { + addr_idx: addr_idx as u32, + num_bytes: num_bytes as u64, + }, + )), }, } } @@ -268,7 +277,7 @@ pub(crate) async fn recv_dial_back(stream: impl AsyncRead + Unpin) -> io::Result pub(crate) async fn dial_back_response(stream: impl AsyncWrite + Unpin) -> io::Result<()> { let msg = proto::DialBackResponse { - status: proto::mod_DialBackResponse::DialBackStatus::OK, + status: proto::dial_back_response::DialBackStatus::Ok as i32, }; let mut framed = FramedWrite::new( stream, @@ -291,7 +300,7 @@ pub(crate) async fn recv_dial_back_response( .await .ok_or(io::Error::from(io::ErrorKind::UnexpectedEof))??; - if proto::mod_DialBackResponse::DialBackStatus::OK == status { + if status == proto::dial_back_response::DialBackStatus::Ok as i32 { Ok(()) } else { Err(io::Error::new( @@ -303,29 +312,31 @@ pub(crate) async fn recv_dial_back_response( #[cfg(test)] mod tests { + use prost::Message as ProstMessage; + use crate::v2::generated::structs::{ - DialDataResponse as GenDialDataResponse, Message, mod_Message::OneOfmsg, + DialDataResponse as GenDialDataResponse, Message, message::Msg, }; #[test] fn message_correct_max_size() { - let message_bytes = quick_protobuf::serialize_into_vec(&Message { - msg: OneOfmsg::dialDataResponse(GenDialDataResponse { + let msg = Message { + msg: Some(Msg::DialDataResponse(GenDialDataResponse { data: vec![0; 4096], - }), - }) - .unwrap(); + })), + }; + let message_bytes = msg.encode_to_vec(); assert_eq!(message_bytes.len(), super::REQUEST_MAX_SIZE); } #[test] fn dial_back_correct_size() { let dial_back = super::proto::DialBack { nonce: 0 }; - let buf = quick_protobuf::serialize_into_vec(&dial_back).unwrap(); + let buf = dial_back.encode_to_vec(); assert!(buf.len() <= super::DIAL_BACK_MAX_SIZE); let dial_back_max_nonce = super::proto::DialBack { nonce: u64::MAX }; - let buf = quick_protobuf::serialize_into_vec(&dial_back_max_nonce).unwrap(); + let buf = dial_back_max_nonce.encode_to_vec(); assert!(buf.len() <= super::DIAL_BACK_MAX_SIZE); } } diff --git a/protocols/autonat/src/v2/server/handler/dial_request.rs b/protocols/autonat/src/v2/server/handler/dial_request.rs index fe4e1da69b0..a8a0e840147 100644 --- a/protocols/autonat/src/v2/server/handler/dial_request.rs +++ b/protocols/autonat/src/v2/server/handler/dial_request.rs @@ -24,7 +24,7 @@ use rand_core::RngCore; use crate::v2::{ DIAL_REQUEST_PROTOCOL, Nonce, - generated::structs::{DialStatus, mod_DialResponse::ResponseStatus}, + generated::structs::{DialStatus, dial_response::ResponseStatus}, protocol::{Coder, DialDataRequest, DialRequest, DialResponse, Request, Response}, server::behaviour::Event, }; @@ -163,27 +163,27 @@ impl From for DialResponse { fn from(value: HandleFail) -> Self { match value { HandleFail::InternalError(addr_idx) => Self { - status: ResponseStatus::E_INTERNAL_ERROR, + status: ResponseStatus::EInternalError, addr_idx, - dial_status: DialStatus::UNUSED, + dial_status: DialStatus::Unused, }, HandleFail::RequestRejected => Self { - status: ResponseStatus::E_REQUEST_REJECTED, + status: ResponseStatus::ERequestRejected, addr_idx: 0, - dial_status: DialStatus::UNUSED, + dial_status: DialStatus::Unused, }, HandleFail::DialRefused => Self { - status: ResponseStatus::E_DIAL_REFUSED, + status: ResponseStatus::EDialRefused, addr_idx: 0, - dial_status: DialStatus::UNUSED, + dial_status: DialStatus::Unused, }, HandleFail::DialBack { idx, result } => Self { - status: ResponseStatus::OK, + status: ResponseStatus::Ok, addr_idx: idx, dial_status: match result { - Err(DialBackStatus::DialErr) => DialStatus::E_DIAL_ERROR, - Err(DialBackStatus::DialBackErr) => DialStatus::E_DIAL_BACK_ERROR, - Ok(()) => DialStatus::OK, + Err(DialBackStatus::DialErr) => DialStatus::EDialError, + Err(DialBackStatus::DialBackErr) => DialStatus::EDialBackError, + Ok(()) => DialStatus::Ok, }, }, } @@ -322,8 +322,8 @@ where }); } Ok(DialResponse { - status: ResponseStatus::OK, + status: ResponseStatus::Ok, addr_idx: idx, - dial_status: DialStatus::OK, + dial_status: DialStatus::Ok, }) } diff --git a/protocols/dcutr/CHANGELOG.md b/protocols/dcutr/CHANGELOG.md index 72049ca3374..293dcc9fb8e 100644 --- a/protocols/dcutr/CHANGELOG.md +++ b/protocols/dcutr/CHANGELOG.md @@ -2,6 +2,8 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). ## 0.14.1 diff --git a/protocols/dcutr/Cargo.toml b/protocols/dcutr/Cargo.toml index dc771a1cd01..ace0976654e 100644 --- a/protocols/dcutr/Cargo.toml +++ b/protocols/dcutr/Cargo.toml @@ -19,8 +19,8 @@ web-time = { workspace = true } libp2p-core = { workspace = true } libp2p-swarm = { workspace = true } libp2p-identity = { workspace = true } -quick-protobuf = "0.8" -quick-protobuf-codec = { workspace = true } +prost = { workspace = true } +prost-codec = { workspace = true } thiserror = { workspace = true } tracing = { workspace = true } hashlink = { workspace = true } diff --git a/protocols/dcutr/src/generated/holepunch.pb.rs b/protocols/dcutr/src/generated/holepunch.pb.rs new file mode 100644 index 00000000000..4d1ea612618 --- /dev/null +++ b/protocols/dcutr/src/generated/holepunch.pb.rs @@ -0,0 +1,52 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct HolePunch { + #[prost(enumeration = "hole_punch::Type", required, tag = "1")] + pub r#type: i32, + /// For hole punching, we'll send some additional observed addresses to the remote peer + /// that could have been filtered by the Host address factory (for example: AutoRelay removes all public addresses if peer has private reachability). + /// This is a hack! + /// We plan to have a better address discovery and advertisement mechanism in the future. + /// See + #[prost(bytes = "vec", repeated, tag = "2")] + pub obs_addrs: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, +} +/// Nested message and enum types in `HolePunch`. +pub mod hole_punch { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Type { + Connect = 100, + Sync = 300, + } + impl Type { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Connect => "CONNECT", + Self::Sync => "SYNC", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "CONNECT" => Some(Self::Connect), + "SYNC" => Some(Self::Sync), + _ => None, + } + } + } +} diff --git a/protocols/dcutr/src/generated/holepunch/mod.rs b/protocols/dcutr/src/generated/holepunch/mod.rs deleted file mode 100644 index aec6164c7ef..00000000000 --- a/protocols/dcutr/src/generated/holepunch/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Automatically generated mod.rs -pub mod pb; diff --git a/protocols/dcutr/src/generated/holepunch/pb.rs b/protocols/dcutr/src/generated/holepunch/pb.rs deleted file mode 100644 index 59f37040f14..00000000000 --- a/protocols/dcutr/src/generated/holepunch/pb.rs +++ /dev/null @@ -1,88 +0,0 @@ -// 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>, -} - -impl<'a> MessageRead<'a> for HolePunch { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::() - } - - fn write_message(&self, w: &mut Writer) -> 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 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(), - } - } -} - -} - diff --git a/protocols/dcutr/src/generated/mod.rs b/protocols/dcutr/src/generated/mod.rs index 89023be5535..dbe0cdcc9be 100644 --- a/protocols/dcutr/src/generated/mod.rs +++ b/protocols/dcutr/src/generated/mod.rs @@ -1,2 +1,3 @@ -// Automatically generated mod.rs -pub mod holepunch; +// Automatically generated by gen-proto. DO NOT EDIT. +#[path = "holepunch.pb.rs"] +pub mod holepunch_pb; diff --git a/protocols/dcutr/src/lib.rs b/protocols/dcutr/src/lib.rs index a6911c1aeda..d23b7d84814 100644 --- a/protocols/dcutr/src/lib.rs +++ b/protocols/dcutr/src/lib.rs @@ -30,7 +30,7 @@ mod protocol; mod proto { #![allow(unreachable_pub)] include!("generated/mod.rs"); - pub(crate) use self::holepunch::pb::{HolePunch, mod_HolePunch::*}; + pub(crate) use self::holepunch_pb::{HolePunch, hole_punch::*}; } pub use behaviour::{Behaviour, Error, Event}; diff --git a/protocols/dcutr/src/protocol/inbound.rs b/protocols/dcutr/src/protocol/inbound.rs index 969212765c8..e81782aac40 100644 --- a/protocols/dcutr/src/protocol/inbound.rs +++ b/protocols/dcutr/src/protocol/inbound.rs @@ -34,19 +34,19 @@ pub(crate) async fn handshake( ) -> Result, Error> { let mut stream = Framed::new( stream, - quick_protobuf_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES), + prost_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES), ); - let proto::HolePunch { type_pb, ObsAddrs } = stream + let proto::HolePunch { r#type, obs_addrs } = stream .next() .await .ok_or(io::Error::from(io::ErrorKind::UnexpectedEof))??; - if ObsAddrs.is_empty() { + if obs_addrs.is_empty() { return Err(Error::Protocol(ProtocolViolation::NoAddresses)); }; - let obs_addrs = ObsAddrs + let obs_addrs = obs_addrs .into_iter() .filter_map(|a| match Multiaddr::try_from(a.to_vec()) { Ok(a) => Some(a), @@ -66,22 +66,22 @@ pub(crate) async fn handshake( }) .collect(); - if !matches!(type_pb, proto::Type::CONNECT) { + if r#type != proto::Type::Connect as i32 { return Err(Error::Protocol(ProtocolViolation::UnexpectedTypeSync)); } let msg = proto::HolePunch { - type_pb: proto::Type::CONNECT, - ObsAddrs: candidates.into_iter().map(|a| a.to_vec()).collect(), + r#type: proto::Type::Connect as i32, + obs_addrs: candidates.into_iter().map(|a| a.to_vec()).collect(), }; stream.send(msg).await?; - let proto::HolePunch { type_pb, .. } = stream + let proto::HolePunch { r#type, .. } = stream .next() .await .ok_or(io::Error::from(io::ErrorKind::UnexpectedEof))??; - if !matches!(type_pb, proto::Type::SYNC) { + if r#type != proto::Type::Sync as i32 { return Err(Error::Protocol(ProtocolViolation::UnexpectedTypeConnect)); } @@ -96,8 +96,8 @@ pub enum Error { Protocol(#[from] ProtocolViolation), } -impl From for Error { - fn from(e: quick_protobuf_codec::Error) -> Self { +impl From for Error { + fn from(e: prost_codec::Error) -> Self { Error::Protocol(ProtocolViolation::Codec(e)) } } @@ -105,7 +105,7 @@ impl From for Error { #[derive(Debug, Error)] pub enum ProtocolViolation { #[error(transparent)] - Codec(#[from] quick_protobuf_codec::Error), + Codec(#[from] prost_codec::Error), #[error("Expected at least one address in reservation.")] NoAddresses, #[error("Failed to parse response type field.")] diff --git a/protocols/dcutr/src/protocol/outbound.rs b/protocols/dcutr/src/protocol/outbound.rs index 5c45ca97156..d184b011d82 100644 --- a/protocols/dcutr/src/protocol/outbound.rs +++ b/protocols/dcutr/src/protocol/outbound.rs @@ -36,34 +36,34 @@ pub(crate) async fn handshake( ) -> Result, Error> { let mut stream = Framed::new( stream, - quick_protobuf_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES), + prost_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES), ); let msg = proto::HolePunch { - type_pb: proto::Type::CONNECT, - ObsAddrs: candidates.into_iter().map(|a| a.to_vec()).collect(), + r#type: proto::Type::Connect as i32, + obs_addrs: candidates.into_iter().map(|a| a.to_vec()).collect(), }; stream.send(msg).await?; let sent_time = Instant::now(); - let proto::HolePunch { type_pb, ObsAddrs } = stream + let proto::HolePunch { r#type, obs_addrs } = stream .next() .await .ok_or(io::Error::from(io::ErrorKind::UnexpectedEof))??; let rtt = sent_time.elapsed(); - if !matches!(type_pb, proto::Type::CONNECT) { + if r#type != proto::Type::Connect as i32 { return Err(Error::Protocol(ProtocolViolation::UnexpectedTypeSync)); } - if ObsAddrs.is_empty() { + if obs_addrs.is_empty() { return Err(Error::Protocol(ProtocolViolation::NoAddresses)); } - let obs_addrs = ObsAddrs + let obs_addrs = obs_addrs .into_iter() .filter_map(|a| match Multiaddr::try_from(a.to_vec()) { Ok(a) => Some(a), @@ -84,8 +84,8 @@ pub(crate) async fn handshake( .collect(); let msg = proto::HolePunch { - type_pb: proto::Type::SYNC, - ObsAddrs: vec![], + r#type: proto::Type::Sync as i32, + obs_addrs: vec![], }; stream.send(msg).await?; @@ -105,8 +105,8 @@ pub enum Error { Protocol(#[from] ProtocolViolation), } -impl From for Error { - fn from(e: quick_protobuf_codec::Error) -> Self { +impl From for Error { + fn from(e: prost_codec::Error) -> Self { Error::Protocol(ProtocolViolation::Codec(e)) } } @@ -114,7 +114,7 @@ impl From for Error { #[derive(Debug, Error)] pub enum ProtocolViolation { #[error(transparent)] - Codec(#[from] quick_protobuf_codec::Error), + Codec(#[from] prost_codec::Error), #[error("Expected 'status' field to be set.")] MissingStatusField, #[error("Expected 'reservation' field to be set.")] diff --git a/protocols/floodsub/CHANGELOG.md b/protocols/floodsub/CHANGELOG.md index a44c2dcc29c..fe2d82051f0 100644 --- a/protocols/floodsub/CHANGELOG.md +++ b/protocols/floodsub/CHANGELOG.md @@ -2,6 +2,8 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). ## 0.47.0 diff --git a/protocols/floodsub/Cargo.toml b/protocols/floodsub/Cargo.toml index 4746cc90bf2..5218db1b3d1 100644 --- a/protocols/floodsub/Cargo.toml +++ b/protocols/floodsub/Cargo.toml @@ -19,8 +19,8 @@ futures = { workspace = true } libp2p-core = { workspace = true } libp2p-swarm = { workspace = true } libp2p-identity = { workspace = true } -quick-protobuf = "0.8" -quick-protobuf-codec = { workspace = true } +prost = { workspace = true } +prost-codec = { workspace = true } rand = "0.8" smallvec = "1.15.1" thiserror = { workspace = true } diff --git a/protocols/floodsub/src/generated/floodsub.pb.rs b/protocols/floodsub/src/generated/floodsub.pb.rs new file mode 100644 index 00000000000..d18d6278de1 --- /dev/null +++ b/protocols/floodsub/src/generated/floodsub.pb.rs @@ -0,0 +1,30 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Rpc { + #[prost(message, repeated, tag = "1")] + pub subscriptions: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "2")] + pub publish: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `RPC`. +pub mod rpc { + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct SubOpts { + /// subscribe or unsubscribe + #[prost(bool, optional, tag = "1")] + pub subscribe: ::core::option::Option, + #[prost(string, optional, tag = "2")] + pub topic_id: ::core::option::Option<::prost::alloc::string::String>, + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct Message { + #[prost(bytes = "vec", optional, tag = "1")] + pub from: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", optional, tag = "2")] + pub data: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", optional, tag = "3")] + pub seqno: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(string, repeated, tag = "4")] + pub topic_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} diff --git a/protocols/floodsub/src/generated/floodsub/mod.rs b/protocols/floodsub/src/generated/floodsub/mod.rs deleted file mode 100644 index aec6164c7ef..00000000000 --- a/protocols/floodsub/src/generated/floodsub/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Automatically generated mod.rs -pub mod pb; diff --git a/protocols/floodsub/src/generated/floodsub/pb.rs b/protocols/floodsub/src/generated/floodsub/pb.rs deleted file mode 100644 index a11135ad053..00000000000 --- a/protocols/floodsub/src/generated/floodsub/pb.rs +++ /dev/null @@ -1,137 +0,0 @@ -// 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, - pub publish: Vec, -} - -impl<'a> MessageRead<'a> for RPC { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.subscriptions.push(r.read_message::(bytes)?), - Ok(18) => msg.publish.push(r.read_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::() - + self.publish.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::() - } - - fn write_message(&self, w: &mut Writer) -> 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, - pub topic_id: Option, -} - -impl<'a> MessageRead<'a> for SubOpts { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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(&self, w: &mut Writer) -> 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>, - pub data: Option>, - pub seqno: Option>, - pub topic_ids: Vec, -} - -impl<'a> MessageRead<'a> for Message { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::() - } - - fn write_message(&self, w: &mut Writer) -> 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(()) - } -} - diff --git a/protocols/floodsub/src/generated/mod.rs b/protocols/floodsub/src/generated/mod.rs index 1cef0041eb6..eee010b08fc 100644 --- a/protocols/floodsub/src/generated/mod.rs +++ b/protocols/floodsub/src/generated/mod.rs @@ -1,2 +1,3 @@ -// Automatically generated mod.rs -pub mod floodsub; +// Automatically generated by gen-proto. DO NOT EDIT. +#[path = "floodsub.pb.rs"] +pub mod floodsub_pb; diff --git a/protocols/floodsub/src/lib.rs b/protocols/floodsub/src/lib.rs index 2a527dbfbbd..cc1a01f0250 100644 --- a/protocols/floodsub/src/lib.rs +++ b/protocols/floodsub/src/lib.rs @@ -32,7 +32,7 @@ mod topic; mod proto { #![allow(unreachable_pub)] include!("generated/mod.rs"); - pub(crate) use self::floodsub::pb::{Message, RPC, mod_RPC::SubOpts}; + pub(crate) use self::floodsub_pb::{Message, Rpc as RPC, rpc::SubOpts}; } #[allow(deprecated)] diff --git a/protocols/floodsub/src/protocol.rs b/protocols/floodsub/src/protocol.rs index 58a93fcb2ce..12f429dd66f 100644 --- a/protocols/floodsub/src/protocol.rs +++ b/protocols/floodsub/src/protocol.rs @@ -68,7 +68,7 @@ where Box::pin(async move { let mut framed = Framed::new( socket, - quick_protobuf_codec::Codec::::new(MAX_MESSAGE_LEN_BYTES), + prost_codec::Codec::::new(MAX_MESSAGE_LEN_BYTES), ); let rpc = framed @@ -123,7 +123,7 @@ pub enum FloodsubError { #[derive(thiserror::Error, Debug)] #[error(transparent)] -pub struct CodecError(#[from] quick_protobuf_codec::Error); +pub struct CodecError(#[from] prost_codec::Error); /// An RPC received by the floodsub system. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -155,7 +155,7 @@ where Box::pin(async move { let mut framed = Framed::new( socket, - quick_protobuf_codec::Codec::::new(MAX_MESSAGE_LEN_BYTES), + prost_codec::Codec::::new(MAX_MESSAGE_LEN_BYTES), ); framed.send(self.into_rpc()).await?; framed.close().await?; diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index 191e4132f20..aee52716c17 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -4,6 +4,9 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). + - Optimize IDONTWANT sending by avoiding broadcasts for already-seen messages and deduplicating recipient peers. See [PR 6356](https://github.com/libp2p/rust-libp2p/pull/6356) diff --git a/protocols/gossipsub/Cargo.toml b/protocols/gossipsub/Cargo.toml index c0c50732408..6be89b6df7c 100644 --- a/protocols/gossipsub/Cargo.toml +++ b/protocols/gossipsub/Cargo.toml @@ -30,8 +30,8 @@ web-time = { workspace = true } libp2p-core = { workspace = true } libp2p-identity = { workspace = true, features = ["rand"] } libp2p-swarm = { workspace = true } -quick-protobuf = "0.8" -quick-protobuf-codec = { workspace = true } +prost = { workspace = true } +prost-codec = { workspace = true } rand = "0.8" regex = "1.12.3" serde = { version = "1", optional = true, features = ["derive"] } diff --git a/protocols/gossipsub/src/behaviour.rs b/protocols/gossipsub/src/behaviour.rs index 16009d89099..d97b8bc88ef 100644 --- a/protocols/gossipsub/src/behaviour.rs +++ b/protocols/gossipsub/src/behaviour.rs @@ -47,7 +47,7 @@ use libp2p_swarm::{ }; #[cfg(feature = "metrics")] use prometheus_client::registry::Registry; -use quick_protobuf::{MessageWrite, Writer}; +use prost::Message as _; use rand::{ seq::{IteratorRandom, SliceRandom}, thread_rng, @@ -3054,12 +3054,7 @@ where key: None, }; - let mut buf = Vec::with_capacity(message.get_size()); - let mut writer = Writer::new(&mut buf); - - message - .write_message(&mut writer) - .expect("Encoding to succeed"); + let buf = message.encode_to_vec(); // the signature is over the bytes "libp2p-pubsub:" let mut signature_bytes = SIGNING_PREFIX.to_vec(); diff --git a/protocols/gossipsub/src/behaviour/tests/mod.rs b/protocols/gossipsub/src/behaviour/tests/mod.rs index 92135198467..cdb2524eb28 100644 --- a/protocols/gossipsub/src/behaviour/tests/mod.rs +++ b/protocols/gossipsub/src/behaviour/tests/mod.rs @@ -442,7 +442,7 @@ where /// This is useful for simulating incoming RPC messages from peers in tests. /// It parses all message types: publish messages, subscriptions, and control /// messages (IHAVE, IWANT, GRAFT, PRUNE). -pub(super) fn proto_to_message(rpc: &proto::RPC) -> RpcIn { +pub(super) fn proto_to_message(rpc: &proto::Rpc) -> RpcIn { // Store valid messages. let mut messages = Vec::with_capacity(rpc.publish.len()); let rpc = rpc.clone(); diff --git a/protocols/gossipsub/src/behaviour/tests/topic_config.rs b/protocols/gossipsub/src/behaviour/tests/topic_config.rs index 0a3fa2cc57f..ae1170ab6b8 100644 --- a/protocols/gossipsub/src/behaviour/tests/topic_config.rs +++ b/protocols/gossipsub/src/behaviour/tests/topic_config.rs @@ -671,7 +671,7 @@ fn test_validation_error_message_size_too_large_topic_specific() { max_transmit_size_map, ); let mut buf = BytesMut::new(); - let rpc = proto::RPC { + let rpc = proto::Rpc { publish: vec![proto::Message { from: Some(peers[0].to_bytes()), data: Some(vec![0u8; max_size + 1]), @@ -778,7 +778,7 @@ fn test_validation_message_size_within_topic_specific() { max_transmit_size_map, ); let mut buf = BytesMut::new(); - let rpc = proto::RPC { + let rpc = proto::Rpc { publish: vec![proto::Message { from: Some(peers[0].to_bytes()), data: Some(vec![0u8; max_size - 100]), diff --git a/protocols/gossipsub/src/generated/compat.pb.rs b/protocols/gossipsub/src/generated/compat.pb.rs new file mode 100644 index 00000000000..75cab99c306 --- /dev/null +++ b/protocols/gossipsub/src/generated/compat.pb.rs @@ -0,0 +1,16 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct Message { + #[prost(bytes = "vec", optional, tag = "1")] + pub from: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", optional, tag = "2")] + pub data: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", optional, tag = "3")] + pub seqno: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(string, repeated, tag = "4")] + pub topic_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(bytes = "vec", optional, tag = "5")] + pub signature: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", optional, tag = "6")] + pub key: ::core::option::Option<::prost::alloc::vec::Vec>, +} diff --git a/protocols/gossipsub/src/generated/compat/mod.rs b/protocols/gossipsub/src/generated/compat/mod.rs deleted file mode 100644 index aec6164c7ef..00000000000 --- a/protocols/gossipsub/src/generated/compat/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Automatically generated mod.rs -pub mod pb; diff --git a/protocols/gossipsub/src/generated/compat/pb.rs b/protocols/gossipsub/src/generated/compat/pb.rs deleted file mode 100644 index fd59c38e2b4..00000000000 --- a/protocols/gossipsub/src/generated/compat/pb.rs +++ /dev/null @@ -1,67 +0,0 @@ -// 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>, - pub data: Option>, - pub seqno: Option>, - pub topic_ids: Vec, - pub signature: Option>, - pub key: Option>, -} - -impl<'a> MessageRead<'a> for Message { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::() - + 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(&self, w: &mut Writer) -> 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(()) - } -} - diff --git a/protocols/gossipsub/src/generated/gossipsub.pb.rs b/protocols/gossipsub/src/generated/gossipsub.pb.rs new file mode 100644 index 00000000000..1035332c26b --- /dev/null +++ b/protocols/gossipsub/src/generated/gossipsub.pb.rs @@ -0,0 +1,241 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Rpc { + #[prost(message, repeated, tag = "1")] + pub subscriptions: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "2")] + pub publish: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "3")] + pub control: ::core::option::Option, + /// Canonical Extensions should register their messages here. + #[prost(message, optional, tag = "10")] + pub partial: ::core::option::Option, +} +/// Nested message and enum types in `RPC`. +pub mod rpc { + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct SubOpts { + /// subscribe or unsubscribe + #[prost(bool, optional, tag = "1")] + pub subscribe: ::core::option::Option, + #[prost(string, optional, tag = "2")] + pub topic_id: ::core::option::Option<::prost::alloc::string::String>, + /// Used with Partial Messages extension. + /// If set to true, signals to the receiver that the sender prefers partialMessage + /// messages. + #[prost(bool, optional, tag = "3")] + pub requests_partial: ::core::option::Option, + /// If set to true, signals to the receiver that the sender supports sending + /// partial messages on this topic. If requestsPartial is true, this is + /// assumed to be true. + #[prost(bool, optional, tag = "4")] + pub supports_partial: ::core::option::Option, + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct Message { + #[prost(bytes = "vec", optional, tag = "1")] + pub from: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", optional, tag = "2")] + pub data: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", optional, tag = "3")] + pub seqno: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(string, required, tag = "4")] + pub topic: ::prost::alloc::string::String, + #[prost(bytes = "vec", optional, tag = "5")] + pub signature: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", optional, tag = "6")] + pub key: ::core::option::Option<::prost::alloc::vec::Vec>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ControlMessage { + #[prost(message, repeated, tag = "1")] + pub ihave: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "2")] + pub iwant: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "3")] + pub graft: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "4")] + pub prune: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "5")] + pub idontwant: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "6")] + pub extensions: ::core::option::Option, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ControlIHave { + #[prost(string, optional, tag = "1")] + pub topic_id: ::core::option::Option<::prost::alloc::string::String>, + #[prost(bytes = "vec", repeated, tag = "2")] + pub message_ids: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ControlIWant { + #[prost(bytes = "vec", repeated, tag = "1")] + pub message_ids: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ControlGraft { + #[prost(string, optional, tag = "1")] + pub topic_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ControlPrune { + #[prost(string, optional, tag = "1")] + pub topic_id: ::core::option::Option<::prost::alloc::string::String>, + /// gossipsub v1.1 PX + #[prost(message, repeated, tag = "2")] + pub peers: ::prost::alloc::vec::Vec, + /// gossipsub v1.1 backoff time (in seconds) + #[prost(uint64, optional, tag = "3")] + pub backoff: ::core::option::Option, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ControlIDontWant { + #[prost(bytes = "vec", repeated, tag = "1")] + pub message_ids: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ControlExtensions { + #[prost(bool, optional, tag = "10")] + pub partial_messages: ::core::option::Option, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct PeerInfo { + #[prost(bytes = "vec", optional, tag = "1")] + pub peer_id: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", optional, tag = "2")] + pub signed_peer_record: ::core::option::Option<::prost::alloc::vec::Vec>, +} +/// topicID = hash(topicDescriptor); (not the topic.name) +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct TopicDescriptor { + #[prost(string, optional, tag = "1")] + pub name: ::core::option::Option<::prost::alloc::string::String>, + #[prost(message, optional, tag = "2")] + pub auth: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub enc: ::core::option::Option, +} +/// Nested message and enum types in `TopicDescriptor`. +pub mod topic_descriptor { + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct AuthOpts { + #[prost(enumeration = "auth_opts::AuthMode", optional, tag = "1")] + pub mode: ::core::option::Option, + /// root keys to trust + #[prost(bytes = "vec", repeated, tag = "2")] + pub keys: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + } + /// Nested message and enum types in `AuthOpts`. + pub mod auth_opts { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum AuthMode { + /// no authentication, anyone can publish + None = 0, + /// only messages signed by keys in the topic descriptor are accepted + Key = 1, + /// web of trust, certificates can allow publisher set to grow + Wot = 2, + } + impl AuthMode { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::None => "NONE", + Self::Key => "KEY", + Self::Wot => "WOT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "NONE" => Some(Self::None), + "KEY" => Some(Self::Key), + "WOT" => Some(Self::Wot), + _ => None, + } + } + } + } + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct EncOpts { + #[prost(enumeration = "enc_opts::EncMode", optional, tag = "1")] + pub mode: ::core::option::Option, + /// the hashes of the shared keys used (salted) + #[prost(bytes = "vec", repeated, tag = "2")] + pub key_hashes: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + } + /// Nested message and enum types in `EncOpts`. + pub mod enc_opts { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum EncMode { + /// no encryption, anyone can read + None = 0, + /// messages are encrypted with shared key + Sharedkey = 1, + /// web of trust, certificates can allow publisher set to grow + Wot = 2, + } + impl EncMode { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::None => "NONE", + Self::Sharedkey => "SHAREDKEY", + Self::Wot => "WOT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "NONE" => Some(Self::None), + "SHAREDKEY" => Some(Self::Sharedkey), + "WOT" => Some(Self::Wot), + _ => None, + } + } + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct PartialMessagesExtension { + #[prost(bytes = "vec", optional, tag = "1")] + pub topic_id: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", optional, tag = "2")] + pub group_id: ::core::option::Option<::prost::alloc::vec::Vec>, + /// An encoded partial message + #[prost(bytes = "vec", optional, tag = "3")] + pub partial_message: ::core::option::Option<::prost::alloc::vec::Vec>, + /// An encoded representation of the parts a peer has and wants. + #[prost(bytes = "vec", optional, tag = "4")] + pub parts_metadata: ::core::option::Option<::prost::alloc::vec::Vec>, +} diff --git a/protocols/gossipsub/src/generated/gossipsub/mod.rs b/protocols/gossipsub/src/generated/gossipsub/mod.rs deleted file mode 100644 index aec6164c7ef..00000000000 --- a/protocols/gossipsub/src/generated/gossipsub/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Automatically generated mod.rs -pub mod pb; diff --git a/protocols/gossipsub/src/generated/gossipsub/pb.rs b/protocols/gossipsub/src/generated/gossipsub/pb.rs deleted file mode 100644 index 8df235966a7..00000000000 --- a/protocols/gossipsub/src/generated/gossipsub/pb.rs +++ /dev/null @@ -1,695 +0,0 @@ -// 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, - pub publish: Vec, - pub control: Option, - pub partial: Option, -} - -impl<'a> MessageRead<'a> for RPC { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.subscriptions.push(r.read_message::(bytes)?), - Ok(18) => msg.publish.push(r.read_message::(bytes)?), - Ok(26) => msg.control = Some(r.read_message::(bytes)?), - Ok(82) => msg.partial = Some(r.read_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::() - + self.publish.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::() - + self.control.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size())) - + self.partial.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size())) - } - - fn write_message(&self, w: &mut Writer) -> 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))?; } - if let Some(ref s) = self.partial { w.write_with_tag(82, |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, - pub topic_id: Option, - pub requestsPartial: Option, - pub supportsPartial: Option, -} - -impl<'a> MessageRead<'a> for SubOpts { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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(24) => msg.requestsPartial = Some(r.read_bool(bytes)?), - Ok(32) => msg.supportsPartial = Some(r.read_bool(bytes)?), - 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())) - + self.requestsPartial.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64)) - + self.supportsPartial.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64)) - } - - fn write_message(&self, w: &mut Writer) -> 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))?; } - if let Some(ref s) = self.requestsPartial { w.write_with_tag(24, |w| w.write_bool(*s))?; } - if let Some(ref s) = self.supportsPartial { w.write_with_tag(32, |w| w.write_bool(*s))?; } - Ok(()) - } -} - -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] -pub struct Message { - pub from: Option>, - pub data: Option>, - pub seqno: Option>, - pub topic: String, - pub signature: Option>, - pub key: Option>, -} - -impl<'a> MessageRead<'a> for Message { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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(&self, w: &mut Writer) -> 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, - pub iwant: Vec, - pub graft: Vec, - pub prune: Vec, - pub idontwant: Vec, - pub extensions: Option, -} - -impl<'a> MessageRead<'a> for ControlMessage { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.ihave.push(r.read_message::(bytes)?), - Ok(18) => msg.iwant.push(r.read_message::(bytes)?), - Ok(26) => msg.graft.push(r.read_message::(bytes)?), - Ok(34) => msg.prune.push(r.read_message::(bytes)?), - Ok(42) => msg.idontwant.push(r.read_message::(bytes)?), - Ok(50) => msg.extensions = Some(r.read_message::(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::() - + self.iwant.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::() - + self.graft.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::() - + self.prune.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::() - + self.idontwant.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::() - + self.extensions.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size())) - } - - fn write_message(&self, w: &mut Writer) -> 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))?; } - for s in &self.idontwant { w.write_with_tag(42, |w| w.write_message(s))?; } - if let Some(ref s) = self.extensions { w.write_with_tag(50, |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, - pub message_ids: Vec>, -} - -impl<'a> MessageRead<'a> for ControlIHave { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::() - } - - fn write_message(&self, w: &mut Writer) -> 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>, -} - -impl<'a> MessageRead<'a> for ControlIWant { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::() - } - - fn write_message(&self, w: &mut Writer) -> 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, -} - -impl<'a> MessageRead<'a> for ControlGraft { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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(&self, w: &mut Writer) -> 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, - pub peers: Vec, - pub backoff: Option, -} - -impl<'a> MessageRead<'a> for ControlPrune { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::(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::() - + self.backoff.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64)) - } - - fn write_message(&self, w: &mut Writer) -> 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 ControlIDontWant { - pub message_ids: Vec>, -} - -impl<'a> MessageRead<'a> for ControlIDontWant { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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 ControlIDontWant { - fn get_size(&self) -> usize { - 0 - + self.message_ids.iter().map(|s| 1 + sizeof_len((s).len())).sum::() - } - - fn write_message(&self, w: &mut Writer) -> 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 ControlExtensions { - pub partialMessages: Option, -} - -impl<'a> MessageRead<'a> for ControlExtensions { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(80) => msg.partialMessages = Some(r.read_bool(bytes)?), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for ControlExtensions { - fn get_size(&self) -> usize { - 0 - + self.partialMessages.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64)) - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if let Some(ref s) = self.partialMessages { w.write_with_tag(80, |w| w.write_bool(*s))?; } - Ok(()) - } -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] -pub struct PeerInfo { - pub peer_id: Option>, - pub signed_peer_record: Option>, -} - -impl<'a> MessageRead<'a> for PeerInfo { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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(&self, w: &mut Writer) -> 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, - pub auth: Option, - pub enc: Option, -} - -impl<'a> MessageRead<'a> for TopicDescriptor { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::(bytes)?), - Ok(26) => msg.enc = Some(r.read_message::(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(&self, w: &mut Writer) -> 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, - pub keys: Vec>, -} - -impl<'a> MessageRead<'a> for AuthOpts { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::() - } - - fn write_message(&self, w: &mut Writer) -> 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 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, - pub key_hashes: Vec>, -} - -impl<'a> MessageRead<'a> for EncOpts { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::() - } - - fn write_message(&self, w: &mut Writer) -> 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 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(), - } - } -} - -} - -} - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Debug, Default, PartialEq, Clone)] -pub struct PartialMessagesExtension { - pub topicID: Option>, - pub groupID: Option>, - pub partialMessage: Option>, - pub partsMetadata: Option>, -} - -impl<'a> MessageRead<'a> for PartialMessagesExtension { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.topicID = Some(r.read_bytes(bytes)?.to_owned()), - Ok(18) => msg.groupID = Some(r.read_bytes(bytes)?.to_owned()), - Ok(26) => msg.partialMessage = Some(r.read_bytes(bytes)?.to_owned()), - Ok(34) => msg.partsMetadata = Some(r.read_bytes(bytes)?.to_owned()), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for PartialMessagesExtension { - fn get_size(&self) -> usize { - 0 - + self.topicID.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - + self.groupID.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - + self.partialMessage.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - + self.partsMetadata.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if let Some(ref s) = self.topicID { w.write_with_tag(10, |w| w.write_bytes(&**s))?; } - if let Some(ref s) = self.groupID { w.write_with_tag(18, |w| w.write_bytes(&**s))?; } - if let Some(ref s) = self.partialMessage { w.write_with_tag(26, |w| w.write_bytes(&**s))?; } - if let Some(ref s) = self.partsMetadata { w.write_with_tag(34, |w| w.write_bytes(&**s))?; } - Ok(()) - } -} - diff --git a/protocols/gossipsub/src/generated/mod.rs b/protocols/gossipsub/src/generated/mod.rs index 7ac564f3c36..005eea5dce3 100644 --- a/protocols/gossipsub/src/generated/mod.rs +++ b/protocols/gossipsub/src/generated/mod.rs @@ -1,3 +1,5 @@ -// Automatically generated mod.rs -pub mod compat; -pub mod gossipsub; +// Automatically generated by gen-proto. DO NOT EDIT. +#[path = "compat.pb.rs"] +pub mod compat_pb; +#[path = "gossipsub.pb.rs"] +pub mod gossipsub_pb; diff --git a/protocols/gossipsub/src/handler.rs b/protocols/gossipsub/src/handler.rs index 82befaed377..6a8a9915bd0 100644 --- a/protocols/gossipsub/src/handler.rs +++ b/protocols/gossipsub/src/handler.rs @@ -156,7 +156,7 @@ enum OutboundSubstreamState { /// Waiting for the user to send a message. The idle state for an outbound substream. WaitingOutput(Framed), /// Waiting to send a message to the remote. - PendingSend(Framed, Box), + PendingSend(Framed, Box), /// Waiting to flush the substream so that the data arrives to the remote. PendingFlush(Framed), /// An error occurred during processing. diff --git a/protocols/gossipsub/src/protocol.rs b/protocols/gossipsub/src/protocol.rs index e23f478c91a..37b1ade66df 100644 --- a/protocols/gossipsub/src/protocol.rs +++ b/protocols/gossipsub/src/protocol.rs @@ -27,7 +27,7 @@ use futures::prelude::*; use libp2p_core::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use libp2p_identity::{PeerId, PublicKey}; use libp2p_swarm::StreamProtocol; -use quick_protobuf::{MessageWrite, Writer}; +use prost::Message; #[cfg(feature = "partial_messages")] use crate::extensions::partial_messages::PartialMessage; @@ -183,7 +183,7 @@ 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: quick_protobuf_codec::Codec, + codec: prost_codec::Codec, /// Maximum transmit sizes per topic, with a default if not specified. max_transmit_sizes: HashMap, } @@ -194,7 +194,7 @@ impl GossipsubCodec { validation_mode: ValidationMode, max_transmit_sizes: HashMap, ) -> GossipsubCodec { - let codec = quick_protobuf_codec::Codec::new(max_length); + let codec = prost_codec::Codec::new(max_length); GossipsubCodec { validation_mode, codec, @@ -211,7 +211,7 @@ impl GossipsubCodec { /// 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: &proto::Message) -> bool { - use quick_protobuf::MessageWrite; + use prost::Message; let Some(from) = message.from.as_ref() else { tracing::debug!("Signature verification failed: No source id given"); @@ -253,11 +253,7 @@ impl GossipsubCodec { let mut message_sig = message.clone(); message_sig.signature = None; message_sig.key = None; - let mut buf = Vec::with_capacity(message_sig.get_size()); - let mut writer = Writer::new(&mut buf); - message_sig - .write_message(&mut writer) - .expect("Encoding to succeed"); + let buf = message_sig.encode_to_vec(); let mut signature_bytes = SIGNING_PREFIX.to_vec(); signature_bytes.extend_from_slice(&buf); public_key.verify(&signature_bytes, signature) @@ -265,8 +261,8 @@ impl GossipsubCodec { } impl Encoder for GossipsubCodec { - type Item<'a> = proto::RPC; - type Error = quick_protobuf_codec::Error; + type Item<'a> = proto::Rpc; + type Error = prost_codec::Error; fn encode(&mut self, item: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> { self.codec.encode(item, dst) @@ -275,7 +271,7 @@ impl Encoder for GossipsubCodec { impl Decoder for GossipsubCodec { type Item = HandlerEvent; - type Error = quick_protobuf_codec::Error; + type Error = prost_codec::Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { let Some(rpc) = self.codec.decode(src)? else { @@ -292,7 +288,7 @@ impl Decoder for GossipsubCodec { // Check the message size to ensure it doesn't bypass the configured max. if self .max_transmit_size_for_topic(&topic) - .is_some_and(|max| message.get_size() > max) + .is_some_and(|max| message.encoded_len() > max) { let message = RawMessage { source: None, // don't bother inform the application @@ -567,7 +563,7 @@ impl Decoder for GossipsubCodec { .collect(); let extensions_msg = rpc_control.extensions.map(|extensions| Extensions { - partial_messages: extensions.partialMessages, + partial_messages: extensions.partial_messages, }); control_msgs.extend(ihave_msgs); @@ -580,13 +576,13 @@ impl Decoder for GossipsubCodec { #[cfg(feature = "partial_messages")] let partial_message = rpc.partial.and_then(|partial_proto| { - let Some(topic_id_bytes) = partial_proto.topicID else { + let Some(topic_id_bytes) = partial_proto.topic_id else { tracing::debug!("Partial message without topic_id, discarding"); return None; }; let topic_hash = TopicHash::from_raw(String::from_utf8_lossy(&topic_id_bytes)); - let Some(group_id) = partial_proto.groupID else { + let Some(group_id) = partial_proto.group_id else { tracing::debug!("Partial message without group_id, discarding"); return None; }; @@ -594,8 +590,8 @@ impl Decoder for GossipsubCodec { Some(PartialMessage { topic_hash, group_id, - metadata: partial_proto.partsMetadata, - body: partial_proto.partialMessage, + metadata: partial_proto.parts_metadata, + body: partial_proto.partial_message, }) }); @@ -613,8 +609,8 @@ impl Decoder for GossipsubCodec { }, topic_hash: TopicHash::from_raw(sub.topic_id.unwrap_or_default()), options: SubscriptionOpts { - requests_partial: sub.requestsPartial.unwrap_or_default(), - supports_partial: sub.supportsPartial.unwrap_or_default(), + requests_partial: sub.requests_partial.unwrap_or_default(), + supports_partial: sub.supports_partial.unwrap_or_default(), }, }) .collect(), diff --git a/protocols/gossipsub/src/rpc.rs b/protocols/gossipsub/src/rpc.rs new file mode 100644 index 00000000000..93df7b57213 --- /dev/null +++ b/protocols/gossipsub/src/rpc.rs @@ -0,0 +1,199 @@ +// Copyright 2020 Sigma Prime Pty 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. + +use std::{ + future::Future, + pin::Pin, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, + }, + task::{Context, Poll}, +}; + +use futures::{stream::Peekable, Stream, StreamExt}; + +use crate::types::RpcOut; + +/// `RpcOut` sender that is priority aware. +#[derive(Debug)] +pub(crate) struct Sender { + /// Capacity of the priority channel for `Publish` messages. + priority_cap: usize, + len: Arc, + pub(crate) priority_sender: async_channel::Sender, + pub(crate) non_priority_sender: async_channel::Sender, + priority_receiver: async_channel::Receiver, + non_priority_receiver: async_channel::Receiver, +} + +impl Sender { + /// Create a RpcSender. + pub(crate) fn new(cap: usize) -> Sender { + // We intentionally do not bound the channel, as we still need to send control messages + // such as `GRAFT`, `PRUNE`, `SUBSCRIBE`, and `UNSUBSCRIBE`. + // That's also why we define `cap` and divide it by two, + // to ensure there is capacity for both priority and non_priority messages. + let (priority_sender, priority_receiver) = async_channel::unbounded(); + let (non_priority_sender, non_priority_receiver) = async_channel::bounded(cap / 2); + let len = Arc::new(AtomicUsize::new(0)); + Sender { + priority_cap: cap / 2, + len, + priority_sender, + non_priority_sender, + priority_receiver, + non_priority_receiver, + } + } + + /// Create a new Receiver to the sender. + pub(crate) fn new_receiver(&self) -> Receiver { + Receiver { + priority_queue_len: self.len.clone(), + priority: Box::pin(self.priority_receiver.clone().peekable()), + non_priority: Box::pin(self.non_priority_receiver.clone().peekable()), + } + } + + #[allow(clippy::result_large_err)] + pub(crate) fn send_message(&self, rpc: RpcOut) -> Result<(), RpcOut> { + if let RpcOut::Publish { .. } = rpc { + // Update number of publish message in queue. + let len = self.len.load(Ordering::Relaxed); + if len >= self.priority_cap { + return Err(rpc); + } + self.len.store(len + 1, Ordering::Relaxed); + } + let sender = match rpc { + RpcOut::Publish { .. } + | RpcOut::Graft(_) + | RpcOut::Prune(_) + | RpcOut::Extensions(_) + | RpcOut::Subscribe { .. } + | RpcOut::Unsubscribe(_) => &self.priority_sender, + RpcOut::Forward { .. } + | RpcOut::IHave(_) + | RpcOut::IWant(_) + | RpcOut::IDontWant(_) + | RpcOut::TestExtension + | RpcOut::PartialMessage { .. } => &self.non_priority_sender, + }; + sender.try_send(rpc).map_err(|err| err.into_inner()) + } + + /// Returns the current size of the priority queue. + #[cfg(feature = "metrics")] + pub(crate) fn priority_queue_len(&self) -> usize { + self.len.load(Ordering::Relaxed) + } + + /// Returns the current size of the non-priority queue. + #[cfg(feature = "metrics")] + pub(crate) fn non_priority_queue_len(&self) -> usize { + self.non_priority_sender.len() + } +} + +/// `RpcOut` sender that is priority aware. +#[derive(Debug)] +pub struct Receiver { + /// The maximum length of the priority queue. + pub(crate) priority_queue_len: Arc, + /// The priority queue receiver. + pub(crate) priority: Pin>>>, + /// The non priority queue receiver. + pub(crate) non_priority: Pin>>>, +} + +impl Receiver { + // Peek the next message in the queues and return it if its timeout has elapsed. + // Returns `None` if there aren't any more messages on the stream or none is stale. + pub(crate) fn poll_stale(&mut self, cx: &mut Context<'_>) -> Poll> { + // Peek priority queue. + let priority = match self.priority.as_mut().poll_peek_mut(cx) { + Poll::Ready(Some(RpcOut::Publish { + message: _, + ref mut timeout, + })) => { + if Pin::new(timeout).poll(cx).is_ready() { + // Return the message. + let dropped = futures::ready!(self.priority.poll_next_unpin(cx)) + .expect("There should be a message"); + return Poll::Ready(Some(dropped)); + } + Poll::Ready(None) + } + poll => poll, + }; + + let non_priority = match self.non_priority.as_mut().poll_peek_mut(cx) { + Poll::Ready(Some(RpcOut::Forward { + message: _, + ref mut timeout, + })) => { + if Pin::new(timeout).poll(cx).is_ready() { + // Return the message. + let dropped = futures::ready!(self.non_priority.poll_next_unpin(cx)) + .expect("There should be a message"); + return Poll::Ready(Some(dropped)); + } + Poll::Ready(None) + } + poll => poll, + }; + + match (priority, non_priority) { + (Poll::Ready(None), Poll::Ready(None)) => Poll::Ready(None), + _ => Poll::Pending, + } + } + + /// Poll queues and return true if both are empty. + pub(crate) fn poll_is_empty(&mut self, cx: &mut Context<'_>) -> bool { + matches!( + ( + self.priority.as_mut().poll_peek(cx), + self.non_priority.as_mut().poll_peek(cx), + ), + (Poll::Ready(None), Poll::Ready(None)) + ) + } +} + +impl Stream for Receiver { + type Item = RpcOut; + + fn poll_next( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + // The priority queue is first polled. + if let Poll::Ready(rpc) = Pin::new(&mut self.priority).poll_next(cx) { + if let Some(RpcOut::Publish { .. }) = rpc { + self.priority_queue_len.fetch_sub(1, Ordering::Relaxed); + } + return Poll::Ready(rpc); + } + // Then we poll the non priority. + Pin::new(&mut self.non_priority).poll_next(cx) + } +} diff --git a/protocols/gossipsub/src/rpc_proto.rs b/protocols/gossipsub/src/rpc_proto.rs index 53f5ef6ec92..f25cc60ab67 100644 --- a/protocols/gossipsub/src/rpc_proto.rs +++ b/protocols/gossipsub/src/rpc_proto.rs @@ -21,16 +21,16 @@ pub(crate) mod proto { #![allow(unreachable_pub, dead_code)] include!("generated/mod.rs"); - pub use self::gossipsub::pb::{mod_RPC::SubOpts, *}; + pub use self::gossipsub_pb::{rpc::SubOpts, *}; } #[cfg(test)] mod test { use libp2p_identity::PeerId; - use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer}; + use prost::Message; use rand::Rng; - use crate::{IdentTopic as Topic, rpc_proto::proto::compat}; + use crate::{IdentTopic as Topic, rpc_proto::proto::compat_pb}; #[test] fn test_multi_topic_message_compatibility() { @@ -45,7 +45,7 @@ mod test { signature: Some(rand::thread_rng().r#gen::<[u8; 32]>().to_vec()), key: Some(rand::thread_rng().r#gen::<[u8; 32]>().to_vec()), }; - let old_message1 = compat::pb::Message { + let old_message1 = compat_pb::Message { from: Some(PeerId::random().to_bytes()), data: Some(rand::thread_rng().r#gen::<[u8; 32]>().to_vec()), seqno: Some(rand::thread_rng().r#gen::<[u8; 8]>().to_vec()), @@ -53,7 +53,7 @@ mod test { signature: Some(rand::thread_rng().r#gen::<[u8; 32]>().to_vec()), key: Some(rand::thread_rng().r#gen::<[u8; 32]>().to_vec()), }; - let old_message2 = compat::pb::Message { + let old_message2 = compat_pb::Message { from: Some(PeerId::random().to_bytes()), data: Some(rand::thread_rng().r#gen::<[u8; 32]>().to_vec()), seqno: Some(rand::thread_rng().r#gen::<[u8; 8]>().to_vec()), @@ -62,31 +62,17 @@ mod test { key: Some(rand::thread_rng().r#gen::<[u8; 32]>().to_vec()), }; - 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 new_message1b = new_message1.encode_to_vec(); + let old_message1b = old_message1.encode_to_vec(); + let old_message2b = old_message2.encode_to_vec(); - 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.get_size()); - let mut writer = Writer::new(&mut old_message2b); - old_message2.write_message(&mut writer).unwrap(); - - let mut reader = BytesReader::from_bytes(&old_message1b[..]); - let new_message = - super::proto::Message::from_reader(&mut reader, &old_message1b[..]).unwrap(); + let new_message = super::proto::Message::decode(&old_message1b[..]).unwrap(); assert_eq!(new_message.topic, topic1.clone().into_string()); - let mut reader = BytesReader::from_bytes(&old_message2b[..]); - let new_message = - super::proto::Message::from_reader(&mut reader, &old_message2b[..]).unwrap(); + let new_message = super::proto::Message::decode(&old_message2b[..]).unwrap(); assert_eq!(new_message.topic, topic2.into_string()); - let mut reader = BytesReader::from_bytes(&new_message1b[..]); - let old_message = - compat::pb::Message::from_reader(&mut reader, &new_message1b[..]).unwrap(); + let old_message = compat_pb::Message::decode(&new_message1b[..]).unwrap(); assert_eq!(old_message.topic_ids, vec![topic1.into_string()]); } } diff --git a/protocols/gossipsub/src/topic.rs b/protocols/gossipsub/src/topic.rs index adbdf58637f..e4102112205 100644 --- a/protocols/gossipsub/src/topic.rs +++ b/protocols/gossipsub/src/topic.rs @@ -21,7 +21,6 @@ use std::fmt; use base64::prelude::*; -use quick_protobuf::Writer; use sha2::{Digest, Sha256}; use crate::rpc_proto::proto; @@ -48,18 +47,14 @@ impl Hasher for Sha256Hash { /// Creates a [`TopicHash`] by SHA256 hashing the topic then base64 encoding the /// hash. fn hash(topic_string: String) -> TopicHash { - use quick_protobuf::MessageWrite; + use prost::Message; let topic_descriptor = proto::TopicDescriptor { name: Some(topic_string), auth: None, enc: None, }; - let mut bytes = Vec::with_capacity(topic_descriptor.get_size()); - let mut writer = Writer::new(&mut bytes); - topic_descriptor - .write_message(&mut writer) - .expect("Encoding to succeed"); + let bytes = topic_descriptor.encode_to_vec(); let hash = BASE64_STANDARD.encode(Sha256::digest(&bytes)); TopicHash { hash } } diff --git a/protocols/gossipsub/src/types.rs b/protocols/gossipsub/src/types.rs index 4c470f3e3e3..2bb05a7424d 100644 --- a/protocols/gossipsub/src/types.rs +++ b/protocols/gossipsub/src/types.rs @@ -28,7 +28,7 @@ use futures_timer::Delay; use hashlink::LinkedHashMap; use libp2p_identity::PeerId; use libp2p_swarm::ConnectionId; -use quick_protobuf::MessageWrite; +use prost::Message as _; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use web_time::Instant; @@ -186,7 +186,7 @@ impl RawMessage { signature: self.signature.clone(), key: self.key.clone(), }; - message.get_size() + message.encoded_len() } } @@ -385,7 +385,7 @@ pub enum RpcOut { impl RpcOut { /// Converts the GossipsubRPC into its protobuf format. // A convenience function to avoid explicitly specifying types. - pub fn into_protobuf(self) -> proto::RPC { + pub fn into_protobuf(self) -> proto::Rpc { self.into() } @@ -403,17 +403,17 @@ impl RpcOut { } } -impl From for proto::RPC { +impl From for proto::Rpc { /// Converts the RPC into protobuf format. fn from(rpc: RpcOut) -> Self { match rpc { - RpcOut::Publish { message, .. } => proto::RPC { + RpcOut::Publish { message, .. } => proto::Rpc { subscriptions: Vec::new(), publish: vec![message.into()], control: None, partial: None, }, - RpcOut::Forward { message, .. } => proto::RPC { + RpcOut::Forward { message, .. } => proto::Rpc { publish: vec![message.into()], subscriptions: Vec::new(), control: None, @@ -423,18 +423,18 @@ impl From for proto::RPC { topic, requests_partial, supports_partial, - } => proto::RPC { + } => proto::Rpc { publish: Vec::new(), subscriptions: vec![proto::SubOpts { subscribe: Some(true), topic_id: Some(topic.into_string()), - requestsPartial: Some(requests_partial), - supportsPartial: Some(supports_partial), + requests_partial: Some(requests_partial), + supports_partial: Some(supports_partial), }], control: None, partial: None, }, - RpcOut::SubscribeMany(topics) => proto::RPC { + RpcOut::SubscribeMany(topics) => proto::Rpc { publish: Vec::new(), subscriptions: topics .into_iter() @@ -442,21 +442,21 @@ impl From for proto::RPC { |(topic, requests_partial, supports_partial)| proto::SubOpts { subscribe: Some(true), topic_id: Some(topic.into_string()), - requestsPartial: Some(requests_partial), - supportsPartial: Some(supports_partial), + requests_partial: Some(requests_partial), + supports_partial: Some(supports_partial), }, ) .collect(), control: None, partial: None, }, - RpcOut::Unsubscribe(topic) => proto::RPC { + RpcOut::Unsubscribe(topic) => proto::Rpc { publish: Vec::new(), subscriptions: vec![proto::SubOpts { subscribe: Some(false), topic_id: Some(topic.into_string()), - requestsPartial: None, - supportsPartial: None, + requests_partial: None, + supports_partial: None, }], control: None, partial: None, @@ -464,7 +464,7 @@ impl From for proto::RPC { RpcOut::IHave(IHave { topic_hash, message_ids, - }) => proto::RPC { + }) => proto::Rpc { publish: Vec::new(), subscriptions: Vec::new(), control: Some(proto::ControlMessage { @@ -480,7 +480,7 @@ impl From for proto::RPC { }), partial: None, }, - RpcOut::IWant(IWant { message_ids }) => proto::RPC { + RpcOut::IWant(IWant { message_ids }) => proto::Rpc { publish: Vec::new(), subscriptions: Vec::new(), control: Some(proto::ControlMessage { @@ -495,7 +495,7 @@ impl From for proto::RPC { }), partial: None, }, - RpcOut::Graft(Graft { topic_hash }) => proto::RPC { + RpcOut::Graft(Graft { topic_hash }) => proto::Rpc { publish: Vec::new(), subscriptions: vec![], control: Some(proto::ControlMessage { @@ -515,7 +515,7 @@ impl From for proto::RPC { peers, backoff, }) => { - proto::RPC { + proto::Rpc { publish: Vec::new(), subscriptions: vec![], control: Some(proto::ControlMessage { @@ -540,7 +540,7 @@ impl From for proto::RPC { partial: None, } } - RpcOut::IDontWant(IDontWant { message_ids }) => proto::RPC { + RpcOut::IDontWant(IDontWant { message_ids }) => proto::Rpc { publish: Vec::new(), subscriptions: Vec::new(), control: Some(proto::ControlMessage { @@ -555,7 +555,7 @@ impl From for proto::RPC { }), partial: None, }, - RpcOut::Extensions(Extensions { partial_messages }) => proto::RPC { + RpcOut::Extensions(Extensions { partial_messages }) => proto::Rpc { publish: Vec::new(), subscriptions: Vec::new(), control: Some(proto::ControlMessage { @@ -564,13 +564,11 @@ impl From for proto::RPC { graft: vec![], prune: vec![], idontwant: vec![], - extensions: Some(proto::ControlExtensions { - partialMessages: partial_messages, - }), + extensions: Some(proto::ControlExtensions { partial_messages }), }), partial: None, }, - RpcOut::TestExtension => proto::RPC { + RpcOut::TestExtension => proto::Rpc { subscriptions: vec![], publish: vec![], control: None, @@ -582,15 +580,15 @@ impl From for proto::RPC { group_id, metadata, body, - }) => proto::RPC { + }) => proto::Rpc { subscriptions: vec![], publish: vec![], control: None, partial: Some(proto::PartialMessagesExtension { - topicID: Some(topic_hash.as_str().as_bytes().to_vec()), - groupID: Some(group_id), - partialMessage: body, - partsMetadata: metadata, + topic_id: Some(topic_hash.as_str().as_bytes().to_vec()), + group_id: Some(group_id), + partial_message: body, + parts_metadata: metadata, }), }, } diff --git a/protocols/identify/CHANGELOG.md b/protocols/identify/CHANGELOG.md index 5477beffd2e..69b7a7680ea 100644 --- a/protocols/identify/CHANGELOG.md +++ b/protocols/identify/CHANGELOG.md @@ -2,6 +2,8 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). ## 0.47.0 diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml index 94977d6e44c..4e9a3a25ada 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -18,8 +18,8 @@ futures-bounded = { workspace = true } libp2p-core = { workspace = true } libp2p-swarm = { workspace = true } libp2p-identity = { workspace = true } -quick-protobuf-codec = { workspace = true } -quick-protobuf = "0.8" +prost-codec = { workspace = true } +prost = { workspace = true } smallvec = "1.15.1" thiserror = { workspace = true } tracing = { workspace = true } diff --git a/protocols/identify/src/generated/mod.rs b/protocols/identify/src/generated/mod.rs index e52c5a80bc0..c271155936b 100644 --- a/protocols/identify/src/generated/mod.rs +++ b/protocols/identify/src/generated/mod.rs @@ -1,2 +1,2 @@ -// Automatically generated mod.rs +// Automatically generated by gen-proto. DO NOT EDIT. pub mod structs; diff --git a/protocols/identify/src/generated/structs.rs b/protocols/identify/src/generated/structs.rs index fcda2159a60..2705724f5f9 100644 --- a/protocols/identify/src/generated/structs.rs +++ b/protocols/identify/src/generated/structs.rs @@ -1,71 +1,38 @@ -// 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)] +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Identify { - pub protocolVersion: Option, - pub agentVersion: Option, - pub publicKey: Option>, - pub listenAddrs: Vec>, - pub observedAddr: Option>, - pub protocols: Vec, - pub signedPeerRecord: Option>, + /// protocolVersion determines compatibility between peers + /// + /// e.g. ipfs/1.0.0 + #[prost(string, optional, tag = "5")] + pub protocol_version: ::core::option::Option<::prost::alloc::string::String>, + /// agentVersion is like a UserAgent string in browsers, or client version in bittorrent + /// includes the client name and client. + /// + /// e.g. go-ipfs/0.1.0 + #[prost(string, optional, tag = "6")] + pub agent_version: ::core::option::Option<::prost::alloc::string::String>, + /// publicKey is this node's public key (which also gives its node.ID) + /// - may not need to be sent, as secure channel implies it has been sent. + /// - then again, if we change / disable secure channel, may still want it. + #[prost(bytes = "vec", optional, tag = "1")] + pub public_key: ::core::option::Option<::prost::alloc::vec::Vec>, + /// listenAddrs are the multiaddrs the sender node listens for open connections on + #[prost(bytes = "vec", repeated, tag = "2")] + pub listen_addrs: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + /// oservedAddr is the multiaddr of the remote endpoint that the sender node perceives + /// this is useful information to convey to the other side, as it helps the remote endpoint + /// determine whether its connection to the local peer goes through NAT. + #[prost(bytes = "vec", optional, tag = "4")] + pub observed_addr: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(string, repeated, tag = "3")] + pub protocols: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + /// signedPeerRecord contains a serialized SignedEnvelope containing a PeerRecord, + /// signed by the sending node. It contains the same addresses as the listenAddrs field, but + /// in a form that lets us share authenticated addrs with other peers. + /// see + /// and + /// for message definitions. + #[prost(bytes = "vec", optional, tag = "8")] + pub signed_peer_record: ::core::option::Option<::prost::alloc::vec::Vec>, } - -impl<'a> MessageRead<'a> for Identify { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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(66) => msg.signedPeerRecord = Some(r.read_bytes(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::() - + self.observedAddr.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - + self.protocols.iter().map(|s| 1 + sizeof_len((s).len())).sum::() - + self.signedPeerRecord.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - } - - fn write_message(&self, w: &mut Writer) -> 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))?; } - if let Some(ref s) = self.signedPeerRecord { w.write_with_tag(66, |w| w.write_bytes(&**s))?; } - Ok(()) - } -} - diff --git a/protocols/identify/src/protocol.rs b/protocols/identify/src/protocol.rs index c8753d93abf..1dd41e6099d 100644 --- a/protocols/identify/src/protocol.rs +++ b/protocols/identify/src/protocol.rs @@ -104,13 +104,13 @@ where let pubkey_bytes = info.public_key.encode_protobuf(); let message = proto::Identify { - agentVersion: Some(info.agent_version.clone()), - protocolVersion: Some(info.protocol_version.clone()), - publicKey: Some(pubkey_bytes), - listenAddrs: listen_addrs, - observedAddr: Some(info.observed_addr.to_vec()), + agent_version: Some(info.agent_version.clone()), + protocol_version: Some(info.protocol_version.clone()), + public_key: Some(pubkey_bytes), + listen_addrs, + observed_addr: Some(info.observed_addr.to_vec()), protocols: info.protocols.iter().map(|p| p.to_string()).collect(), - signedPeerRecord: info + signed_peer_record: info .signed_peer_record .clone() .map(|r| r.into_protobuf_encoding()), @@ -118,7 +118,7 @@ where let mut framed_io = FramedWrite::new( io, - quick_protobuf_codec::Codec::::new(MAX_MESSAGE_SIZE_BYTES), + prost_codec::Codec::::new(MAX_MESSAGE_SIZE_BYTES), ); framed_io.send(message).await?; @@ -160,7 +160,7 @@ where let info = FramedRead::new( socket, - quick_protobuf_codec::Codec::::new(MAX_MESSAGE_SIZE_BYTES), + prost_codec::Codec::::new(MAX_MESSAGE_SIZE_BYTES), ) .next() .await @@ -220,7 +220,7 @@ impl TryFrom for Info { fn try_from(msg: proto::Identify) -> Result { let identify_public_key = { - match parse_public_key(msg.publicKey) { + match parse_public_key(msg.public_key) { Some(key) => key, // This will always produce a DecodingError if the public key is missing. None => PublicKey::try_decode_protobuf(Default::default())?, @@ -231,7 +231,7 @@ impl TryFrom for Info { // When signedPeerRecord is invalid or signed by others, ignore the signedPeerRecord(set to // `None`). let (listen_addrs, signed_envelope) = msg - .signedPeerRecord + .signed_peer_record .and_then(|b| { let envelope = SignedEnvelope::from_protobuf_encoding(b.as_ref()).ok()?; let peer_record = PeerRecord::from_signed_envelope(envelope).ok()?; @@ -240,15 +240,15 @@ impl TryFrom for Info { Some(peer_record.into_signed_envelope()), )) }) - .unwrap_or_else(|| (parse_listen_addrs(msg.listenAddrs), None)); + .unwrap_or_else(|| (parse_listen_addrs(msg.listen_addrs), None)); let info = Info { public_key: identify_public_key, - protocol_version: msg.protocolVersion.unwrap_or_default(), - agent_version: msg.agentVersion.unwrap_or_default(), + protocol_version: msg.protocol_version.unwrap_or_default(), + agent_version: msg.agent_version.unwrap_or_default(), listen_addrs, protocols: parse_protocols(msg.protocols), - observed_addr: parse_observed_addr(msg.observedAddr).unwrap_or(Multiaddr::empty()), + observed_addr: parse_observed_addr(msg.observed_addr).unwrap_or(Multiaddr::empty()), signed_peer_record: signed_envelope, }; @@ -261,12 +261,12 @@ impl TryFrom for PushInfo { fn try_from(msg: proto::Identify) -> Result { let info = PushInfo { - public_key: parse_public_key(msg.publicKey), - protocol_version: msg.protocolVersion, - agent_version: msg.agentVersion, - listen_addrs: parse_listen_addrs(msg.listenAddrs), + public_key: parse_public_key(msg.public_key), + protocol_version: msg.protocol_version, + agent_version: msg.agent_version, + listen_addrs: parse_listen_addrs(msg.listen_addrs), protocols: parse_protocols(msg.protocols), - observed_addr: parse_observed_addr(msg.observedAddr), + observed_addr: parse_observed_addr(msg.observed_addr), }; Ok(info) @@ -276,7 +276,7 @@ impl TryFrom for PushInfo { #[derive(Debug, Error)] pub enum UpgradeError { #[error(transparent)] - Codec(#[from] quick_protobuf_codec::Error), + Codec(#[from] prost_codec::Error), #[error("I/O interaction failed")] Io(#[from] io::Error), #[error("Stream closed")] @@ -293,7 +293,7 @@ mod tests { use libp2p_core::PeerRecord; use libp2p_identity as identity; - use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer}; + use prost::Message; use super::*; @@ -309,17 +309,17 @@ mod tests { }; let payload = proto::Identify { - agentVersion: None, - listenAddrs: vec![valid_multiaddr_bytes, invalid_multiaddr], - observedAddr: None, - protocolVersion: None, + agent_version: None, + listen_addrs: vec![valid_multiaddr_bytes, invalid_multiaddr], + observed_addr: None, + protocol_version: None, protocols: vec![], - publicKey: Some( + public_key: Some( identity::Keypair::generate_ed25519() .public() .encode_protobuf(), ), - signedPeerRecord: None, + signed_peer_record: None, }; let info = PushInfo::try_from(payload).expect("not to fail"); @@ -362,10 +362,7 @@ mod tests { 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x2f, 0x70, 0x62, ]; - let mut buf = [0u8; 375]; - let mut message = - proto::Identify::from_reader(&mut BytesReader::from_bytes(&go_protobuf), &go_protobuf) - .expect("read to succeed"); + let mut message = proto::Identify::decode(&go_protobuf[..]).expect("decode to succeed"); // The actual bytes they put in is "github.com/libp2p/go-libp2p/p2p/protocol/identify/pb". // Starting with Z4 means it is zig-zag-encoded 4-byte varint of string, appended by @@ -373,17 +370,18 @@ mod tests { assert_eq!( String::from_utf8( message - .signedPeerRecord + .signed_peer_record .clone() .expect("field to be present") ) .expect("parse to succeed"), "Z4github.com/libp2p/go-libp2p/p2p/protocol/identify/pb".to_string() ); - message - .write_message(&mut Writer::new(&mut buf[..])) - .expect("same length after roundtrip"); - assert_eq!(go_protobuf, buf); + // Note: prost does not preserve unknown fields, so re-encoding may produce + // different bytes than the original. Verify encode/decode roundtrip instead. + let buf = message.encode_to_vec(); + let roundtripped = proto::Identify::decode(&buf[..]).expect("roundtrip decode to succeed"); + assert_eq!(message, roundtripped); let identity = identity::Keypair::generate_ed25519(); let record = PeerRecord::new( @@ -392,14 +390,10 @@ mod tests { ) .expect("infallible siging using ed25519"); message - .signedPeerRecord + .signed_peer_record .replace(record.into_signed_envelope().into_protobuf_encoding()); - let mut buf = Vec::new(); - message - .write_message(&mut Writer::new(&mut buf)) - .expect("write to succeed"); - let parsed_message = proto::Identify::from_reader(&mut BytesReader::from_bytes(&buf), &buf) - .expect("read to succeed"); + let buf = message.encode_to_vec(); + let parsed_message = proto::Identify::decode(&buf[..]).expect("decode to succeed"); assert_eq!(message, parsed_message) } } diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 38ef8e8a89d..544a6652626 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -2,6 +2,8 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). - Remove no longer constructed GetRecordError::QuorumFailed. See [PR 6106](https://github.com/libp2p/rust-libp2p/pull/6106) diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index a5eb4ac2f1a..6dd537a21bf 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -19,8 +19,8 @@ futures = { workspace = true } libp2p-core = { workspace = true } libp2p-swarm = { workspace = true } futures-bounded = { workspace = true } -quick-protobuf = "0.8" -quick-protobuf-codec = { workspace = true } +prost = { workspace = true } +prost-codec = { workspace = true } libp2p-identity = { workspace = true, features = ["rand"] } rand = "0.8" sha2 = "0.10.8" diff --git a/protocols/kad/src/generated/dht.pb.rs b/protocols/kad/src/generated/dht.pb.rs new file mode 100644 index 00000000000..615456d3b27 --- /dev/null +++ b/protocols/kad/src/generated/dht.pb.rs @@ -0,0 +1,161 @@ +// This file is @generated by prost-build. +/// Record represents a dht record that contains a value +/// for a key value pair +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct Record { + /// The key that references this record + #[prost(bytes = "vec", tag = "1")] + pub key: ::prost::alloc::vec::Vec, + /// The actual value this record is storing + #[prost(bytes = "vec", tag = "2")] + pub value: ::prost::alloc::vec::Vec, + /// Time the record was received, set by receiver + #[prost(string, tag = "5")] + pub time_received: ::prost::alloc::string::String, + /// The original publisher of the record. + /// Currently specific to rust-libp2p. + #[prost(bytes = "vec", tag = "666")] + pub publisher: ::prost::alloc::vec::Vec, + /// The remaining TTL of the record, in seconds. + /// Currently specific to rust-libp2p. + #[prost(uint32, tag = "777")] + pub ttl: u32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Message { + /// defines what type of message it is. + #[prost(enumeration = "message::MessageType", tag = "1")] + pub r#type: i32, + /// defines what coral cluster level this query/response belongs to. + /// in case we want to implement coral's cluster rings in the future. + /// + /// NOT USED + #[prost(int32, tag = "10")] + pub cluster_level_raw: i32, + /// Used to specify the key associated with this message. + /// PUT_VALUE, GET_VALUE, ADD_PROVIDER, GET_PROVIDERS + #[prost(bytes = "vec", tag = "2")] + pub key: ::prost::alloc::vec::Vec, + /// Used to return a value + /// PUT_VALUE, GET_VALUE + #[prost(message, optional, tag = "3")] + pub record: ::core::option::Option, + /// Used to return peers closer to a key in a query + /// GET_VALUE, GET_PROVIDERS, FIND_NODE + #[prost(message, repeated, tag = "8")] + pub closer_peers: ::prost::alloc::vec::Vec, + /// Used to return Providers + /// GET_VALUE, ADD_PROVIDER, GET_PROVIDERS + #[prost(message, repeated, tag = "9")] + pub provider_peers: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `Message`. +pub mod message { + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct Peer { + /// ID of a given peer. + #[prost(bytes = "vec", tag = "1")] + pub id: ::prost::alloc::vec::Vec, + /// multiaddrs for a given peer + #[prost(bytes = "vec", repeated, tag = "2")] + pub addrs: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + /// used to signal the sender's connection capabilities to the peer + #[prost(enumeration = "ConnectionType", tag = "3")] + pub connection: i32, + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum MessageType { + PutValue = 0, + GetValue = 1, + AddProvider = 2, + GetProviders = 3, + FindNode = 4, + Ping = 5, + } + impl MessageType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::PutValue => "PUT_VALUE", + Self::GetValue => "GET_VALUE", + Self::AddProvider => "ADD_PROVIDER", + Self::GetProviders => "GET_PROVIDERS", + Self::FindNode => "FIND_NODE", + Self::Ping => "PING", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "PUT_VALUE" => Some(Self::PutValue), + "GET_VALUE" => Some(Self::GetValue), + "ADD_PROVIDER" => Some(Self::AddProvider), + "GET_PROVIDERS" => Some(Self::GetProviders), + "FIND_NODE" => Some(Self::FindNode), + "PING" => Some(Self::Ping), + _ => None, + } + } + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum ConnectionType { + /// sender does not have a connection to peer, and no extra information (default) + NotConnected = 0, + /// sender has a live connection to peer + Connected = 1, + /// sender recently connected to peer + CanConnect = 2, + /// sender recently tried to connect to peer repeatedly but failed to connect + /// ("try" here is loose, but this should signal "made strong effort, failed") + CannotConnect = 3, + } + impl ConnectionType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::NotConnected => "NOT_CONNECTED", + Self::Connected => "CONNECTED", + Self::CanConnect => "CAN_CONNECT", + Self::CannotConnect => "CANNOT_CONNECT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "NOT_CONNECTED" => Some(Self::NotConnected), + "CONNECTED" => Some(Self::Connected), + "CAN_CONNECT" => Some(Self::CanConnect), + "CANNOT_CONNECT" => Some(Self::CannotConnect), + _ => None, + } + } + } +} diff --git a/protocols/kad/src/generated/dht/mod.rs b/protocols/kad/src/generated/dht/mod.rs deleted file mode 100644 index aec6164c7ef..00000000000 --- a/protocols/kad/src/generated/dht/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Automatically generated mod.rs -pub mod pb; diff --git a/protocols/kad/src/generated/dht/pb.rs b/protocols/kad/src/generated/dht/pb.rs deleted file mode 100644 index 56b819b1a9c..00000000000 --- a/protocols/kad/src/generated/dht/pb.rs +++ /dev/null @@ -1,243 +0,0 @@ -// 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, - pub value: Vec, - pub timeReceived: String, - pub publisher: Vec, - pub ttl: u32, -} - -impl<'a> MessageRead<'a> for Record { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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(&self, w: &mut Writer) -> 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, - pub record: Option, - pub closerPeers: Vec, - pub providerPeers: Vec, -} - -impl<'a> MessageRead<'a> for Message { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::(bytes)?), - Ok(66) => msg.closerPeers.push(r.read_message::(bytes)?), - Ok(74) => msg.providerPeers.push(r.read_message::(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::() - + self.providerPeers.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::() - } - - fn write_message(&self, w: &mut Writer) -> 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, - pub addrs: Vec>, - pub connection: dht::pb::mod_Message::ConnectionType, -} - -impl<'a> MessageRead<'a> for Peer { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::() - + if self.connection == dht::pb::mod_Message::ConnectionType::NOT_CONNECTED { 0 } else { 1 + sizeof_varint(*(&self.connection) as u64) } - } - - fn write_message(&self, w: &mut Writer) -> 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 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 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(), - } - } -} - -} - diff --git a/protocols/kad/src/generated/mod.rs b/protocols/kad/src/generated/mod.rs index 6ffc566d1a0..846b9d0d361 100644 --- a/protocols/kad/src/generated/mod.rs +++ b/protocols/kad/src/generated/mod.rs @@ -1,2 +1,3 @@ -// Automatically generated mod.rs -pub mod dht; +// Automatically generated by gen-proto. DO NOT EDIT. +#[path = "dht.pb.rs"] +pub mod dht_pb; diff --git a/protocols/kad/src/lib.rs b/protocols/kad/src/lib.rs index e3009940bd1..9c7f6b07ff1 100644 --- a/protocols/kad/src/lib.rs +++ b/protocols/kad/src/lib.rs @@ -48,9 +48,9 @@ mod record; mod proto { #![allow(unreachable_pub)] include!("generated/mod.rs"); - pub use self::dht::pb::{ + pub use self::dht_pb::{ Message, Record, - mod_Message::{ConnectionType, MessageType, Peer}, + message::{ConnectionType, MessageType, Peer}, }; } diff --git a/protocols/kad/src/protocol.rs b/protocols/kad/src/protocol.rs index 0ee798718f1..94b0937d8be 100644 --- a/protocols/kad/src/protocol.rs +++ b/protocols/kad/src/protocol.rs @@ -68,10 +68,10 @@ impl From for ConnectionType { fn from(raw: proto::ConnectionType) -> ConnectionType { use proto::ConnectionType::*; match raw { - NOT_CONNECTED => ConnectionType::NotConnected, - CONNECTED => ConnectionType::Connected, - CAN_CONNECT => ConnectionType::CanConnect, - CANNOT_CONNECT => ConnectionType::CannotConnect, + NotConnected => ConnectionType::NotConnected, + Connected => ConnectionType::Connected, + CanConnect => ConnectionType::CanConnect, + CannotConnect => ConnectionType::CannotConnect, } } } @@ -80,10 +80,10 @@ impl From for proto::ConnectionType { fn from(val: ConnectionType) -> Self { use proto::ConnectionType::*; match val { - ConnectionType::NotConnected => NOT_CONNECTED, - ConnectionType::Connected => CONNECTED, - ConnectionType::CanConnect => CAN_CONNECT, - ConnectionType::CannotConnect => CANNOT_CONNECT, + ConnectionType::NotConnected => NotConnected, + ConnectionType::Connected => Connected, + ConnectionType::CanConnect => CanConnect, + ConnectionType::CannotConnect => CannotConnect, } } } @@ -122,7 +122,9 @@ impl TryFrom for KadPeer { Ok(KadPeer { node_id, multiaddrs: addrs, - connection_ty: peer.connection.into(), + connection_ty: proto::ConnectionType::try_from(peer.connection) + .unwrap_or(proto::ConnectionType::NotConnected) + .into(), }) } } @@ -132,7 +134,7 @@ impl From for proto::Peer { proto::Peer { id: peer.node_id.to_bytes(), addrs: peer.multiaddrs.into_iter().map(|a| a.to_vec()).collect(), - connection: peer.connection_ty.into(), + connection: proto::ConnectionType::from(peer.connection_ty) as i32, } } } @@ -193,13 +195,13 @@ impl UpgradeInfo for ProtocolConfig { /// Codec for Kademlia inbound and outbound message framing. pub struct Codec { - codec: quick_protobuf_codec::Codec, + codec: prost_codec::Codec, __phantom: PhantomData<(A, B)>, } impl Codec { fn new(max_packet_size: usize) -> Self { Codec { - codec: quick_protobuf_codec::Codec::new(max_packet_size), + codec: prost_codec::Codec::new(max_packet_size), __phantom: PhantomData, } } @@ -361,36 +363,36 @@ impl TryFrom for KadResponseMsg { fn req_msg_to_proto(kad_msg: KadRequestMsg) -> proto::Message { match kad_msg { KadRequestMsg::Ping => proto::Message { - type_pb: proto::MessageType::PING, + r#type: proto::MessageType::Ping as i32, ..proto::Message::default() }, KadRequestMsg::FindNode { key } => proto::Message { - type_pb: proto::MessageType::FIND_NODE, + r#type: proto::MessageType::FindNode as i32, key, - clusterLevelRaw: 10, + cluster_level_raw: 10, ..proto::Message::default() }, KadRequestMsg::GetProviders { key } => proto::Message { - type_pb: proto::MessageType::GET_PROVIDERS, + r#type: proto::MessageType::GetProviders as i32, key: key.to_vec(), - clusterLevelRaw: 10, + cluster_level_raw: 10, ..proto::Message::default() }, KadRequestMsg::AddProvider { key, provider } => proto::Message { - type_pb: proto::MessageType::ADD_PROVIDER, - clusterLevelRaw: 10, + r#type: proto::MessageType::AddProvider as i32, + cluster_level_raw: 10, key: key.to_vec(), - providerPeers: vec![provider.into()], + provider_peers: vec![provider.into()], ..proto::Message::default() }, KadRequestMsg::GetValue { key } => proto::Message { - type_pb: proto::MessageType::GET_VALUE, - clusterLevelRaw: 10, + r#type: proto::MessageType::GetValue as i32, + cluster_level_raw: 10, key: key.to_vec(), ..proto::Message::default() }, KadRequestMsg::PutValue { record } => proto::Message { - type_pb: proto::MessageType::PUT_VALUE, + r#type: proto::MessageType::PutValue as i32, key: record.key.to_vec(), record: Some(record_to_proto(record)), ..proto::Message::default() @@ -402,37 +404,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 { - type_pb: proto::MessageType::PING, + r#type: proto::MessageType::Ping as i32, ..proto::Message::default() }, KadResponseMsg::FindNode { closer_peers } => proto::Message { - type_pb: proto::MessageType::FIND_NODE, - clusterLevelRaw: 9, - closerPeers: closer_peers.into_iter().map(KadPeer::into).collect(), + r#type: proto::MessageType::FindNode as i32, + cluster_level_raw: 9, + closer_peers: closer_peers.into_iter().map(KadPeer::into).collect(), ..proto::Message::default() }, KadResponseMsg::GetProviders { closer_peers, provider_peers, } => proto::Message { - 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(), + r#type: proto::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(), ..proto::Message::default() }, KadResponseMsg::GetValue { record, closer_peers, } => proto::Message { - type_pb: proto::MessageType::GET_VALUE, - clusterLevelRaw: 9, - closerPeers: closer_peers.into_iter().map(KadPeer::into).collect(), + r#type: proto::MessageType::GetValue as i32, + cluster_level_raw: 9, + closer_peers: closer_peers.into_iter().map(KadPeer::into).collect(), record: record.map(record_to_proto), ..proto::Message::default() }, KadResponseMsg::PutValue { key, value } => proto::Message { - type_pb: proto::MessageType::PUT_VALUE, + r#type: proto::MessageType::PutValue as i32, key: key.to_vec(), record: Some(proto::Record { key: key.to_vec(), @@ -448,25 +450,28 @@ 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 { - match message.type_pb { - proto::MessageType::PING => Ok(KadRequestMsg::Ping), - proto::MessageType::PUT_VALUE => { + let msg_type = proto::MessageType::try_from(message.r#type) + .map_err(|_| invalid_data(format!("unknown message type: {}", message.r#type)))?; + + match msg_type { + proto::MessageType::Ping => Ok(KadRequestMsg::Ping), + proto::MessageType::PutValue => { let record = record_from_proto(message.record.unwrap_or_default())?; Ok(KadRequestMsg::PutValue { record }) } - proto::MessageType::GET_VALUE => Ok(KadRequestMsg::GetValue { + proto::MessageType::GetValue => Ok(KadRequestMsg::GetValue { key: record::Key::from(message.key), }), - proto::MessageType::FIND_NODE => Ok(KadRequestMsg::FindNode { key: message.key }), - proto::MessageType::GET_PROVIDERS => Ok(KadRequestMsg::GetProviders { + proto::MessageType::FindNode => Ok(KadRequestMsg::FindNode { key: message.key }), + proto::MessageType::GetProviders => Ok(KadRequestMsg::GetProviders { key: record::Key::from(message.key), }), - proto::MessageType::ADD_PROVIDER => { + proto::MessageType::AddProvider => { // 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 - .providerPeers + .provider_peers .into_iter() .find_map(|peer| KadPeer::try_from(peer).ok()); @@ -484,9 +489,12 @@ fn proto_to_req_msg(message: proto::Message) -> Result /// /// Fails if the protobuf message is not a valid and supported Kademlia response message. fn proto_to_resp_msg(message: proto::Message) -> Result { - match message.type_pb { - proto::MessageType::PING => Ok(KadResponseMsg::Pong), - proto::MessageType::GET_VALUE => { + let msg_type = proto::MessageType::try_from(message.r#type) + .map_err(|_| invalid_data(format!("unknown message type: {}", message.r#type)))?; + + match msg_type { + proto::MessageType::Ping => Ok(KadResponseMsg::Pong), + proto::MessageType::GetValue => { let record = if let Some(r) = message.record { Some(record_from_proto(r)?) } else { @@ -494,7 +502,7 @@ fn proto_to_resp_msg(message: proto::Message) -> Result Result { + proto::MessageType::FindNode => { let closer_peers = message - .closerPeers + .closer_peers .into_iter() .filter_map(|peer| KadPeer::try_from(peer).ok()) .collect(); @@ -515,15 +523,15 @@ fn proto_to_resp_msg(message: proto::Message) -> Result { + proto::MessageType::GetProviders => { let closer_peers = message - .closerPeers + .closer_peers .into_iter() .filter_map(|peer| KadPeer::try_from(peer).ok()) .collect(); let provider_peers = message - .providerPeers + .provider_peers .into_iter() .filter_map(|peer| KadPeer::try_from(peer).ok()) .collect(); @@ -534,7 +542,7 @@ fn proto_to_resp_msg(message: proto::Message) -> Result { + proto::MessageType::PutValue => { let key = record::Key::from(message.key); let rec = message .record @@ -546,7 +554,7 @@ fn proto_to_resp_msg(message: proto::Message) -> Result { + proto::MessageType::AddProvider => { Err(invalid_data("received an unexpected AddProvider message")) } } @@ -594,7 +602,7 @@ fn record_to_proto(record: Record) -> proto::Record { } }) .unwrap_or(0), - timeReceived: String::new(), + time_received: String::new(), } } @@ -618,7 +626,7 @@ mod tests { let payload = proto::Peer { id: peer_id.to_bytes(), addrs: vec![multiaddr.to_vec()], - connection: proto::ConnectionType::CAN_CONNECT, + connection: proto::ConnectionType::CanConnect as i32, }; let peer = KadPeer::try_from(payload).unwrap(); @@ -652,7 +660,7 @@ mod tests { multiaddr_with_incorrect_peer_id.to_vec(), invalid_multiaddr, ], - connection: proto::ConnectionType::CAN_CONNECT, + connection: proto::ConnectionType::CanConnect as i32, }; let peer = KadPeer::try_from(payload).unwrap(); diff --git a/protocols/relay/CHANGELOG.md b/protocols/relay/CHANGELOG.md index 2b792309416..328b2b171a9 100644 --- a/protocols/relay/CHANGELOG.md +++ b/protocols/relay/CHANGELOG.md @@ -2,6 +2,8 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). - Automatically configure HOP protocol advertisement based on external addresses, with the ability to override this functionality using `Behaviour::set_status` to explicitly set `Status::{Enable,Disable}` to enable or disable protocol advertisement. diff --git a/protocols/relay/Cargo.toml b/protocols/relay/Cargo.toml index bba481db11f..62fc740e93e 100644 --- a/protocols/relay/Cargo.toml +++ b/protocols/relay/Cargo.toml @@ -21,8 +21,8 @@ web-time = { workspace = true } libp2p-core = { workspace = true } libp2p-swarm = { workspace = true } libp2p-identity = { workspace = true } -quick-protobuf = "0.8" -quick-protobuf-codec = { workspace = true } +prost = { workspace = true } +prost-codec = { workspace = true } rand = "0.8.4" static_assertions = "1" thiserror = { workspace = true } diff --git a/protocols/relay/src/behaviour.rs b/protocols/relay/src/behaviour.rs index e4b101f1179..dc129dcaa1a 100644 --- a/protocols/relay/src/behaviour.rs +++ b/protocols/relay/src/behaviour.rs @@ -586,7 +586,7 @@ impl NetworkBehaviour for Behaviour { peer_id: event_source, event: Either::Left(handler::In::DenyReservationReq { inbound_reservation_req, - status: proto::Status::RESOURCE_LIMIT_EXCEEDED, + status: proto::Status::ResourceLimitExceeded, }), } } else { @@ -708,7 +708,7 @@ impl NetworkBehaviour for Behaviour { event: Either::Left(handler::In::DenyCircuitReq { circuit_id: None, inbound_circuit_req, - status: proto::Status::RESOURCE_LIMIT_EXCEEDED, + status: proto::Status::ResourceLimitExceeded, }), } } else if let Some((dst_conn, status)) = self @@ -745,7 +745,7 @@ impl NetworkBehaviour for Behaviour { event: Either::Left(handler::In::DenyCircuitReq { circuit_id: None, inbound_circuit_req, - status: proto::Status::NO_RESERVATION, + status: proto::Status::NoReservation, }), } }; @@ -995,14 +995,14 @@ pub enum StatusCode { impl From for StatusCode { fn from(other: proto::Status) -> Self { match other { - proto::Status::OK => Self::OK, - proto::Status::RESERVATION_REFUSED => Self::ReservationRefused, - proto::Status::RESOURCE_LIMIT_EXCEEDED => Self::ResourceLimitExceeded, - proto::Status::PERMISSION_DENIED => Self::PermissionDenied, - proto::Status::CONNECTION_FAILED => Self::ConnectionFailed, - proto::Status::NO_RESERVATION => Self::NoReservation, - proto::Status::MALFORMED_MESSAGE => Self::MalformedMessage, - proto::Status::UNEXPECTED_MESSAGE => Self::UnexpectedMessage, + proto::Status::Ok => Self::OK, + proto::Status::ReservationRefused => Self::ReservationRefused, + proto::Status::ResourceLimitExceeded => Self::ResourceLimitExceeded, + proto::Status::PermissionDenied => Self::PermissionDenied, + proto::Status::ConnectionFailed => Self::ConnectionFailed, + proto::Status::NoReservation => Self::NoReservation, + proto::Status::MalformedMessage => Self::MalformedMessage, + proto::Status::UnexpectedMessage => Self::UnexpectedMessage, } } } diff --git a/protocols/relay/src/behaviour/handler.rs b/protocols/relay/src/behaviour/handler.rs index 8b509fbb7f1..a91a4625bfc 100644 --- a/protocols/relay/src/behaviour/handler.rs +++ b/protocols/relay/src/behaviour/handler.rs @@ -492,7 +492,7 @@ impl Handler { src_peer_id: stop_command.src_peer_id, src_connection_id: stop_command.src_connection_id, inbound_circuit_req: stop_command.inbound_circuit_req, - status: proto::Status::CONNECTION_FAILED, + status: proto::Status::ConnectionFailed, error, }, )); @@ -742,7 +742,7 @@ impl ConnectionHandler for Handler { src_peer_id: connect.src_peer_id, src_connection_id: connect.src_connection_id, inbound_circuit_req: connect.inbound_circuit_req, - status: proto::Status::CONNECTION_FAILED, // Best fit? + status: proto::Status::ConnectionFailed, // Best fit? error: outbound_stop::Error::Io(io::ErrorKind::TimedOut.into()), }, )); diff --git a/protocols/relay/src/generated/message_v2.pb.rs b/protocols/relay/src/generated/message_v2.pb.rs new file mode 100644 index 00000000000..464c0fe4ec4 --- /dev/null +++ b/protocols/relay/src/generated/message_v2.pb.rs @@ -0,0 +1,178 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct HopMessage { + #[prost(enumeration = "hop_message::Type", required, tag = "1")] + pub r#type: i32, + #[prost(message, optional, tag = "2")] + pub peer: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub reservation: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub limit: ::core::option::Option, + #[prost(enumeration = "Status", optional, tag = "5")] + pub status: ::core::option::Option, +} +/// Nested message and enum types in `HopMessage`. +pub mod hop_message { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Type { + Reserve = 0, + Connect = 1, + Status = 2, + } + impl Type { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Reserve => "RESERVE", + Self::Connect => "CONNECT", + Self::Status => "STATUS", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "RESERVE" => Some(Self::Reserve), + "CONNECT" => Some(Self::Connect), + "STATUS" => Some(Self::Status), + _ => None, + } + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct StopMessage { + #[prost(enumeration = "stop_message::Type", required, tag = "1")] + pub r#type: i32, + #[prost(message, optional, tag = "2")] + pub peer: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub limit: ::core::option::Option, + #[prost(enumeration = "Status", optional, tag = "4")] + pub status: ::core::option::Option, +} +/// Nested message and enum types in `StopMessage`. +pub mod stop_message { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Type { + Connect = 0, + Status = 1, + } + impl Type { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Connect => "CONNECT", + Self::Status => "STATUS", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "CONNECT" => Some(Self::Connect), + "STATUS" => Some(Self::Status), + _ => None, + } + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct Peer { + #[prost(bytes = "vec", required, tag = "1")] + pub id: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", repeated, tag = "2")] + pub addrs: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct Reservation { + /// Unix expiration time (UTC) + #[prost(uint64, required, tag = "1")] + pub expire: u64, + /// relay addrs for reserving peer + #[prost(bytes = "vec", repeated, tag = "2")] + pub addrs: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + /// reservation voucher + #[prost(bytes = "vec", optional, tag = "3")] + pub voucher: ::core::option::Option<::prost::alloc::vec::Vec>, +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct Limit { + /// seconds + #[prost(uint32, optional, tag = "1")] + pub duration: ::core::option::Option, + /// bytes + #[prost(uint64, optional, tag = "2")] + pub data: ::core::option::Option, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum Status { + Ok = 100, + ReservationRefused = 200, + ResourceLimitExceeded = 201, + PermissionDenied = 202, + ConnectionFailed = 203, + NoReservation = 204, + MalformedMessage = 400, + UnexpectedMessage = 401, +} +impl Status { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Ok => "OK", + Self::ReservationRefused => "RESERVATION_REFUSED", + Self::ResourceLimitExceeded => "RESOURCE_LIMIT_EXCEEDED", + Self::PermissionDenied => "PERMISSION_DENIED", + Self::ConnectionFailed => "CONNECTION_FAILED", + Self::NoReservation => "NO_RESERVATION", + Self::MalformedMessage => "MALFORMED_MESSAGE", + Self::UnexpectedMessage => "UNEXPECTED_MESSAGE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "OK" => Some(Self::Ok), + "RESERVATION_REFUSED" => Some(Self::ReservationRefused), + "RESOURCE_LIMIT_EXCEEDED" => Some(Self::ResourceLimitExceeded), + "PERMISSION_DENIED" => Some(Self::PermissionDenied), + "CONNECTION_FAILED" => Some(Self::ConnectionFailed), + "NO_RESERVATION" => Some(Self::NoReservation), + "MALFORMED_MESSAGE" => Some(Self::MalformedMessage), + "UNEXPECTED_MESSAGE" => Some(Self::UnexpectedMessage), + _ => None, + } + } +} diff --git a/protocols/relay/src/generated/message_v2/mod.rs b/protocols/relay/src/generated/message_v2/mod.rs deleted file mode 100644 index aec6164c7ef..00000000000 --- a/protocols/relay/src/generated/message_v2/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Automatically generated mod.rs -pub mod pb; diff --git a/protocols/relay/src/generated/message_v2/pb.rs b/protocols/relay/src/generated/message_v2/pb.rs deleted file mode 100644 index 2344f26b541..00000000000 --- a/protocols/relay/src/generated/message_v2/pb.rs +++ /dev/null @@ -1,346 +0,0 @@ -// 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 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, - pub reservation: Option, - pub limit: Option, - pub status: Option, -} - -impl<'a> MessageRead<'a> for HopMessage { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::(bytes)?), - Ok(26) => msg.reservation = Some(r.read_message::(bytes)?), - Ok(34) => msg.limit = Some(r.read_message::(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(&self, w: &mut Writer) -> 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 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, - pub limit: Option, - pub status: Option, -} - -impl<'a> MessageRead<'a> for StopMessage { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::(bytes)?), - Ok(26) => msg.limit = Some(r.read_message::(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(&self, w: &mut Writer) -> 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 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, - pub addrs: Vec>, -} - -impl<'a> MessageRead<'a> for Peer { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::() - } - - fn write_message(&self, w: &mut Writer) -> 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>, - pub voucher: Option>, -} - -impl<'a> MessageRead<'a> for Reservation { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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::() - + self.voucher.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - } - - fn write_message(&self, w: &mut Writer) -> 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, - pub data: Option, -} - -impl<'a> MessageRead<'a> for Limit { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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(&self, w: &mut Writer) -> 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(()) - } -} - diff --git a/protocols/relay/src/generated/mod.rs b/protocols/relay/src/generated/mod.rs index 18bb20c7eb0..eba370fbab3 100644 --- a/protocols/relay/src/generated/mod.rs +++ b/protocols/relay/src/generated/mod.rs @@ -1,2 +1,3 @@ -// Automatically generated mod.rs -pub mod message_v2; +// Automatically generated by gen-proto. DO NOT EDIT. +#[path = "message_v2.pb.rs"] +pub mod message_v2_pb; diff --git a/protocols/relay/src/lib.rs b/protocols/relay/src/lib.rs index f53d80f4848..1c32cc8d8d0 100644 --- a/protocols/relay/src/lib.rs +++ b/protocols/relay/src/lib.rs @@ -32,10 +32,10 @@ mod protocol; mod proto { #![allow(unreachable_pub)] include!("generated/mod.rs"); - pub use self::message_v2::pb::mod_StopMessage::Type as StopMessageType; - pub(crate) use self::message_v2::pb::{ + pub use self::message_v2_pb::stop_message::Type as StopMessageType; + pub(crate) use self::message_v2_pb::{ HopMessage, Limit, Peer, Reservation, Status, StopMessage, - mod_HopMessage::Type as HopMessageType, + hop_message::Type as HopMessageType, }; } diff --git a/protocols/relay/src/priv_client/handler.rs b/protocols/relay/src/priv_client/handler.rs index 060e1e36820..5eb23c1bff2 100644 --- a/protocols/relay/src/priv_client/handler.rs +++ b/protocols/relay/src/priv_client/handler.rs @@ -166,7 +166,7 @@ impl Handler { if self .inflight_outbound_circuit_deny_requests - .try_push(circuit.deny(proto::Status::NO_RESERVATION)) + .try_push(circuit.deny(proto::Status::NoReservation)) .is_err() { tracing::warn!( diff --git a/protocols/relay/src/protocol/inbound_hop.rs b/protocols/relay/src/protocol/inbound_hop.rs index 01280d70897..0213ab689e3 100644 --- a/protocols/relay/src/protocol/inbound_hop.rs +++ b/protocols/relay/src/protocol/inbound_hop.rs @@ -30,12 +30,12 @@ use libp2p_swarm::Stream; use thiserror::Error; use web_time::SystemTime; -use crate::{proto, proto::message_v2::pb::mod_HopMessage::Type, protocol::MAX_MESSAGE_SIZE}; +use crate::{proto, proto::HopMessageType as Type, protocol::MAX_MESSAGE_SIZE}; #[derive(Debug, Error)] pub enum Error { #[error(transparent)] - Codec(#[from] quick_protobuf_codec::Error), + Codec(#[from] prost_codec::Error), #[error("Stream closed")] StreamClosed, #[error("Failed to parse peer id.")] @@ -44,10 +44,12 @@ pub enum Error { MissingPeer, #[error("Unexpected message type 'status'")] UnexpectedTypeStatus, + #[error("Unexpected message type '{0}'")] + UnexpectedType(String), } pub struct ReservationReq { - substream: Framed>, + substream: Framed>, reservation_duration: Duration, max_circuit_duration: Duration, max_circuit_bytes: u64, @@ -63,7 +65,7 @@ impl ReservationReq { } let msg = proto::HopMessage { - type_pb: proto::HopMessageType::STATUS, + r#type: proto::HopMessageType::Status as i32, peer: None, reservation: Some(proto::Reservation { addrs: addrs.into_iter().map(|a| a.to_vec()).collect(), @@ -82,7 +84,7 @@ impl ReservationReq { ), data: Some(self.max_circuit_bytes), }), - status: Some(proto::Status::OK), + status: Some(proto::Status::Ok as i32), }; self.send(msg).await @@ -90,11 +92,11 @@ impl ReservationReq { pub async fn deny(self, status: proto::Status) -> Result<(), Error> { let msg = proto::HopMessage { - type_pb: proto::HopMessageType::STATUS, + r#type: proto::HopMessageType::Status as i32, peer: None, reservation: None, limit: None, - status: Some(status), + status: Some(status as i32), }; self.send(msg).await @@ -111,7 +113,7 @@ impl ReservationReq { pub struct CircuitReq { dst: PeerId, - substream: Framed>, + substream: Framed>, max_circuit_duration: Duration, max_circuit_bytes: u64, } @@ -123,7 +125,7 @@ impl CircuitReq { pub async fn accept(mut self) -> Result<(Stream, Bytes), Error> { let msg = proto::HopMessage { - type_pb: proto::HopMessageType::STATUS, + r#type: proto::HopMessageType::Status as i32, peer: None, reservation: None, limit: Some(proto::Limit { @@ -135,7 +137,7 @@ impl CircuitReq { ), data: Some(self.max_circuit_bytes), }), - status: Some(proto::Status::OK), + status: Some(proto::Status::Ok as i32), }; self.send(msg).await?; @@ -156,17 +158,17 @@ impl CircuitReq { pub async fn deny(mut self, status: proto::Status) -> Result<(), Error> { let msg = proto::HopMessage { - type_pb: proto::HopMessageType::STATUS, + r#type: proto::HopMessageType::Status as i32, peer: None, reservation: None, limit: None, - status: Some(status), + status: Some(status as i32), }; self.send(msg).await?; self.substream.close().await.map_err(Into::into) } - async fn send(&mut self, msg: proto::HopMessage) -> Result<(), quick_protobuf_codec::Error> { + async fn send(&mut self, msg: proto::HopMessage) -> Result<(), prost_codec::Error> { self.substream.send(msg).await?; self.substream.flush().await?; @@ -180,7 +182,7 @@ pub(crate) async fn handle_inbound_request( max_circuit_duration: Duration, max_circuit_bytes: u64, ) -> Result, Error> { - let mut substream = Framed::new(io, quick_protobuf_codec::Codec::new(MAX_MESSAGE_SIZE)); + let mut substream = Framed::new(io, prost_codec::Codec::new(MAX_MESSAGE_SIZE)); let res = substream.next().await; @@ -189,21 +191,23 @@ pub(crate) async fn handle_inbound_request( } let proto::HopMessage { - type_pb, + r#type, peer, reservation: _, limit: _, status: _, } = res.unwrap().expect("should be ok"); - let req = match type_pb { - Type::RESERVE => Either::Left(ReservationReq { + let msg_type = Type::try_from(r#type).map_err(|_| Error::UnexpectedType(r#type.to_string()))?; + + let req = match msg_type { + Type::Reserve => Either::Left(ReservationReq { substream, reservation_duration, max_circuit_duration, max_circuit_bytes, }), - Type::CONNECT => { + Type::Connect => { let peer_id_res = match peer { Some(r) => PeerId::from_bytes(&r.id), None => return Err(Error::MissingPeer), @@ -218,7 +222,7 @@ pub(crate) async fn handle_inbound_request( max_circuit_bytes, }) } - Type::STATUS => return Err(Error::UnexpectedTypeStatus), + Type::Status => return Err(Error::UnexpectedTypeStatus), }; Ok(req) diff --git a/protocols/relay/src/protocol/inbound_stop.rs b/protocols/relay/src/protocol/inbound_stop.rs index 8994c2cff73..721bca4c572 100644 --- a/protocols/relay/src/protocol/inbound_stop.rs +++ b/protocols/relay/src/protocol/inbound_stop.rs @@ -33,10 +33,10 @@ use crate::{ }; pub(crate) async fn handle_open_circuit(io: Stream) -> Result { - let mut substream = Framed::new(io, quick_protobuf_codec::Codec::new(MAX_MESSAGE_SIZE)); + let mut substream = Framed::new(io, prost_codec::Codec::new(MAX_MESSAGE_SIZE)); let proto::StopMessage { - type_pb, + r#type, peer, limit, status: _, @@ -45,8 +45,11 @@ pub(crate) async fn handle_open_circuit(io: Stream) -> Result { .await .ok_or(Error::Io(io::ErrorKind::UnexpectedEof.into()))??; - match type_pb { - proto::StopMessageType::CONNECT => { + let msg_type = proto::StopMessageType::try_from(r#type) + .map_err(|_| ProtocolViolation::UnexpectedType(r#type.to_string()))?; + + match msg_type { + proto::StopMessageType::Connect => { let src_peer_id = PeerId::from_bytes(&peer.ok_or(ProtocolViolation::MissingPeer)?.id) .map_err(|_| ProtocolViolation::ParsePeerId)?; Ok(Circuit { @@ -55,7 +58,7 @@ pub(crate) async fn handle_open_circuit(io: Stream) -> Result { limit: limit.map(Into::into), }) } - proto::StopMessageType::STATUS => { + proto::StopMessageType::Status => { Err(Error::Protocol(ProtocolViolation::UnexpectedTypeStatus)) } } @@ -69,8 +72,8 @@ pub(crate) enum Error { Io(#[from] io::Error), } -impl From for Error { - fn from(error: quick_protobuf_codec::Error) -> Self { +impl From for Error { + fn from(error: prost_codec::Error) -> Self { Self::Protocol(ProtocolViolation::Codec(error)) } } @@ -78,17 +81,19 @@ impl From for Error { #[derive(Debug, Error)] pub(crate) enum ProtocolViolation { #[error(transparent)] - Codec(#[from] quick_protobuf_codec::Error), + Codec(#[from] prost_codec::Error), #[error("Failed to parse peer id.")] ParsePeerId, #[error("Expected 'peer' field to be set.")] MissingPeer, #[error("Unexpected message type 'status'")] UnexpectedTypeStatus, + #[error("Unexpected message type '{0}'")] + UnexpectedType(String), } pub(crate) struct Circuit { - substream: Framed>, + substream: Framed>, src_peer_id: PeerId, limit: Option, } @@ -104,10 +109,10 @@ impl Circuit { pub(crate) async fn accept(mut self) -> Result<(Stream, Bytes), Error> { let msg = proto::StopMessage { - type_pb: proto::StopMessageType::STATUS, + r#type: proto::StopMessageType::Status as i32, peer: None, limit: None, - status: Some(proto::Status::OK), + status: Some(proto::Status::Ok as i32), }; self.send(msg).await?; @@ -128,10 +133,10 @@ impl Circuit { pub(crate) async fn deny(mut self, status: proto::Status) -> Result<(), Error> { let msg = proto::StopMessage { - type_pb: proto::StopMessageType::STATUS, + r#type: proto::StopMessageType::Status as i32, peer: None, limit: None, - status: Some(status), + status: Some(status as i32), }; self.send(msg).await?; diff --git a/protocols/relay/src/protocol/outbound_hop.rs b/protocols/relay/src/protocol/outbound_hop.rs index 0b567ec7490..a2073cd740f 100644 --- a/protocols/relay/src/protocol/outbound_hop.rs +++ b/protocols/relay/src/protocol/outbound_hop.rs @@ -70,7 +70,7 @@ pub enum ReserveError { #[derive(Debug, Error)] pub enum ProtocolViolation { #[error(transparent)] - Codec(#[from] quick_protobuf_codec::Error), + Codec(#[from] prost_codec::Error), #[error("Expected 'status' field to be set.")] MissingStatusField, #[error("Expected 'reservation' field to be set.")] @@ -85,18 +85,27 @@ pub enum ProtocolViolation { UnexpectedTypeConnect, #[error("Unexpected message type 'reserve'")] UnexpectedTypeReserve, - #[error("Unexpected message status '{0:?}'")] - UnexpectedStatus(proto::Status), + #[error("Unexpected message type '{0}'")] + UnexpectedType(String), + #[error("Unexpected message status '{0}'")] + UnexpectedStatus(String), } -impl From for ConnectError { - fn from(e: quick_protobuf_codec::Error) -> Self { +fn format_proto_status(code: i32) -> String { + match proto::Status::try_from(code) { + Ok(status) => status.as_str_name().to_string(), + Err(_) => code.to_string(), + } +} + +impl From for ConnectError { + fn from(e: prost_codec::Error) -> Self { ConnectError::Protocol(ProtocolViolation::Codec(e)) } } -impl From for ReserveError { - fn from(e: quick_protobuf_codec::Error) -> Self { +impl From for ReserveError { + fn from(e: prost_codec::Error) -> Self { ReserveError::Protocol(ProtocolViolation::Codec(e)) } } @@ -115,20 +124,20 @@ pub(crate) struct Circuit { pub(crate) async fn make_reservation(stream: Stream) -> Result { let msg = proto::HopMessage { - type_pb: proto::HopMessageType::RESERVE, + r#type: proto::HopMessageType::Reserve as i32, peer: None, reservation: None, limit: None, status: None, }; - let mut substream = Framed::new(stream, quick_protobuf_codec::Codec::new(MAX_MESSAGE_SIZE)); + let mut substream = Framed::new(stream, prost_codec::Codec::new(MAX_MESSAGE_SIZE)); substream.send(msg).await?; substream.close().await?; let proto::HopMessage { - type_pb, + r#type, peer: _, reservation, limit, @@ -138,33 +147,37 @@ pub(crate) async fn make_reservation(stream: Stream) -> Result { + let msg_type = proto::HopMessageType::try_from(r#type) + .map_err(|_| ProtocolViolation::UnexpectedType(r#type.to_string()))?; + + match msg_type { + proto::HopMessageType::Connect => { return Err(ReserveError::Protocol( ProtocolViolation::UnexpectedTypeConnect, )); } - proto::HopMessageType::RESERVE => { + proto::HopMessageType::Reserve => { return Err(ReserveError::Protocol( ProtocolViolation::UnexpectedTypeReserve, )); } - proto::HopMessageType::STATUS => {} + proto::HopMessageType::Status => {} } let limit = limit.map(Into::into); - match status.ok_or(ProtocolViolation::MissingStatusField)? { - proto::Status::OK => {} - proto::Status::RESERVATION_REFUSED => { + let status_code = status.ok_or(ProtocolViolation::MissingStatusField)?; + match proto::Status::try_from(status_code) { + Ok(proto::Status::Ok) => {} + Ok(proto::Status::ReservationRefused) => { return Err(ReserveError::Refused); } - proto::Status::RESOURCE_LIMIT_EXCEEDED => { + Ok(proto::Status::ResourceLimitExceeded) => { return Err(ReserveError::ResourceLimitExceeded); } - s => { + _ => { return Err(ReserveError::Protocol(ProtocolViolation::UnexpectedStatus( - s, + format_proto_status(status_code), ))); } } @@ -214,7 +227,7 @@ pub(crate) async fn open_circuit( dst_peer_id: PeerId, ) -> Result { let msg = proto::HopMessage { - type_pb: proto::HopMessageType::CONNECT, + r#type: proto::HopMessageType::Connect as i32, peer: Some(proto::Peer { id: dst_peer_id.to_bytes(), addrs: vec![], @@ -224,12 +237,12 @@ pub(crate) async fn open_circuit( status: None, }; - let mut substream = Framed::new(protocol, quick_protobuf_codec::Codec::new(MAX_MESSAGE_SIZE)); + let mut substream = Framed::new(protocol, prost_codec::Codec::new(MAX_MESSAGE_SIZE)); substream.send(msg).await?; let proto::HopMessage { - type_pb, + r#type, peer: _, reservation: _, limit, @@ -239,39 +252,44 @@ pub(crate) async fn open_circuit( .await .ok_or(ConnectError::Io(io::ErrorKind::UnexpectedEof.into()))??; - match type_pb { - proto::HopMessageType::CONNECT => { + let msg_type = proto::HopMessageType::try_from(r#type) + .map_err(|_| ProtocolViolation::UnexpectedType(r#type.to_string()))?; + + match msg_type { + proto::HopMessageType::Connect => { return Err(ConnectError::Protocol( ProtocolViolation::UnexpectedTypeConnect, )); } - proto::HopMessageType::RESERVE => { + proto::HopMessageType::Reserve => { return Err(ConnectError::Protocol( ProtocolViolation::UnexpectedTypeReserve, )); } - proto::HopMessageType::STATUS => {} + proto::HopMessageType::Status => {} } match status { - Some(proto::Status::OK) => {} - Some(proto::Status::RESOURCE_LIMIT_EXCEEDED) => { - return Err(ConnectError::ResourceLimitExceeded); - } - Some(proto::Status::CONNECTION_FAILED) => { - return Err(ConnectError::ConnectionFailed); - } - Some(proto::Status::NO_RESERVATION) => { - return Err(ConnectError::NoReservation); - } - Some(proto::Status::PERMISSION_DENIED) => { - return Err(ConnectError::PermissionDenied); - } - Some(s) => { - return Err(ConnectError::Protocol(ProtocolViolation::UnexpectedStatus( - s, - ))); - } + Some(s) => match proto::Status::try_from(s) { + Ok(proto::Status::Ok) => {} + Ok(proto::Status::ResourceLimitExceeded) => { + return Err(ConnectError::ResourceLimitExceeded); + } + Ok(proto::Status::ConnectionFailed) => { + return Err(ConnectError::ConnectionFailed); + } + Ok(proto::Status::NoReservation) => { + return Err(ConnectError::NoReservation); + } + Ok(proto::Status::PermissionDenied) => { + return Err(ConnectError::PermissionDenied); + } + _ => { + return Err(ConnectError::Protocol(ProtocolViolation::UnexpectedStatus( + format_proto_status(s), + ))); + } + }, None => { return Err(ConnectError::Protocol( ProtocolViolation::MissingStatusField, diff --git a/protocols/relay/src/protocol/outbound_stop.rs b/protocols/relay/src/protocol/outbound_stop.rs index 0089d5bc384..d259a0ac69c 100644 --- a/protocols/relay/src/protocol/outbound_stop.rs +++ b/protocols/relay/src/protocol/outbound_stop.rs @@ -46,14 +46,14 @@ pub enum Error { impl Error { pub(crate) fn to_status(&self) -> proto::Status { match self { - Error::ResourceLimitExceeded => proto::Status::RESOURCE_LIMIT_EXCEEDED, - Error::PermissionDenied => proto::Status::PERMISSION_DENIED, - Error::Unsupported => proto::Status::CONNECTION_FAILED, - Error::Io(_) => proto::Status::CONNECTION_FAILED, + Error::ResourceLimitExceeded => proto::Status::ResourceLimitExceeded, + Error::PermissionDenied => proto::Status::PermissionDenied, + Error::Unsupported => proto::Status::ConnectionFailed, + Error::Io(_) => proto::Status::ConnectionFailed, Error::Protocol( ProtocolViolation::UnexpectedStatus(_) | ProtocolViolation::UnexpectedTypeConnect, - ) => proto::Status::UNEXPECTED_MESSAGE, - Error::Protocol(_) => proto::Status::MALFORMED_MESSAGE, + ) => proto::Status::UnexpectedMessage, + Error::Protocol(_) => proto::Status::MalformedMessage, } } } @@ -62,17 +62,19 @@ impl Error { #[derive(Debug, Error)] pub enum ProtocolViolation { #[error(transparent)] - Codec(#[from] quick_protobuf_codec::Error), + Codec(#[from] prost_codec::Error), #[error("Expected 'status' field to be set.")] MissingStatusField, #[error("Unexpected message type 'connect'")] UnexpectedTypeConnect, - #[error("Unexpected message status '{0:?}'")] - UnexpectedStatus(proto::Status), + #[error("Unexpected message type '{0}'")] + UnexpectedType(String), + #[error("Unexpected message status '{0}'")] + UnexpectedStatus(String), } -impl From for Error { - fn from(e: quick_protobuf_codec::Error) -> Self { +impl From for Error { + fn from(e: prost_codec::Error) -> Self { Error::Protocol(ProtocolViolation::Codec(e)) } } @@ -85,7 +87,7 @@ pub(crate) async fn connect( max_bytes: u64, ) -> Result { let msg = proto::StopMessage { - type_pb: proto::StopMessageType::CONNECT, + r#type: proto::StopMessageType::Connect as i32, peer: Some(proto::Peer { id: src_peer_id.to_bytes(), addrs: vec![], @@ -102,12 +104,12 @@ pub(crate) async fn connect( status: None, }; - let mut substream = Framed::new(io, quick_protobuf_codec::Codec::new(MAX_MESSAGE_SIZE)); + let mut substream = Framed::new(io, prost_codec::Codec::new(MAX_MESSAGE_SIZE)); substream.send(msg).await?; let proto::StopMessage { - type_pb, + r#type, peer: _, limit: _, status, @@ -116,18 +118,32 @@ pub(crate) async fn connect( .await .ok_or(Error::Io(io::ErrorKind::UnexpectedEof.into()))??; - match type_pb { - proto::StopMessageType::CONNECT => { + let msg_type = proto::StopMessageType::try_from(r#type) + .map_err(|_| Error::Protocol(ProtocolViolation::UnexpectedType(r#type.to_string())))?; + + match msg_type { + proto::StopMessageType::Connect => { return Err(Error::Protocol(ProtocolViolation::UnexpectedTypeConnect)); } - proto::StopMessageType::STATUS => {} + proto::StopMessageType::Status => {} } match status { - Some(proto::Status::OK) => {} - Some(proto::Status::RESOURCE_LIMIT_EXCEEDED) => return Err(Error::ResourceLimitExceeded), - Some(proto::Status::PERMISSION_DENIED) => return Err(Error::PermissionDenied), - Some(s) => return Err(Error::Protocol(ProtocolViolation::UnexpectedStatus(s))), + Some(s) => match proto::Status::try_from(s) { + Ok(proto::Status::Ok) => {} + Ok(proto::Status::ResourceLimitExceeded) => return Err(Error::ResourceLimitExceeded), + Ok(proto::Status::PermissionDenied) => return Err(Error::PermissionDenied), + Ok(other) => { + return Err(Error::Protocol(ProtocolViolation::UnexpectedStatus( + other.as_str_name().to_string(), + ))); + } + Err(_) => { + return Err(Error::Protocol(ProtocolViolation::UnexpectedStatus( + s.to_string(), + ))); + } + }, None => return Err(Error::Protocol(ProtocolViolation::MissingStatusField)), } diff --git a/protocols/rendezvous/CHANGELOG.md b/protocols/rendezvous/CHANGELOG.md index 9d026042151..f415fdf7d47 100644 --- a/protocols/rendezvous/CHANGELOG.md +++ b/protocols/rendezvous/CHANGELOG.md @@ -9,6 +9,9 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). + ## 0.17.1 - Add limits for the per-peer and total number of store registrations, and the stored client cookies. diff --git a/protocols/rendezvous/Cargo.toml b/protocols/rendezvous/Cargo.toml index 86952d8c303..01bd84aa7fb 100644 --- a/protocols/rendezvous/Cargo.toml +++ b/protocols/rendezvous/Cargo.toml @@ -21,8 +21,8 @@ libp2p-core = { workspace = true } libp2p-swarm = { workspace = true } libp2p-identity = { workspace = true } libp2p-request-response = { workspace = true } -quick-protobuf = "0.8" -quick-protobuf-codec = { workspace = true } +prost = { workspace = true } +prost-codec = { workspace = true } rand = "0.8" thiserror = { workspace = true } tracing = { workspace = true } diff --git a/protocols/rendezvous/src/codec.rs b/protocols/rendezvous/src/codec.rs index 264afa3a92e..ee1cee3902f 100644 --- a/protocols/rendezvous/src/codec.rs +++ b/protocols/rendezvous/src/codec.rs @@ -24,7 +24,7 @@ use asynchronous_codec::{BytesMut, Decoder, Encoder, FramedRead, FramedWrite}; use futures::{AsyncRead, AsyncWrite, SinkExt, StreamExt}; use libp2p_core::{PeerRecord, SignedEnvelope, peer_record, signed_envelope}; use libp2p_swarm::StreamProtocol; -use quick_protobuf_codec::Codec as ProtobufCodec; +use prost_codec::Codec as ProtobufCodec; use rand::RngCore; use crate::DEFAULT_TTL; @@ -305,7 +305,7 @@ impl libp2p_request_response::Codec for Codec { #[derive(Debug, thiserror::Error)] pub enum Error { #[error(transparent)] - Codec(#[from] quick_protobuf_codec::Error), + Codec(#[from] prost_codec::Error), #[error("Failed to read/write")] Io(#[from] std::io::Error), #[error("Failed to convert wire message to internal data model")] @@ -330,102 +330,104 @@ impl From for proto::Message { record, ttl, }) => proto::Message { - type_pb: Some(proto::MessageType::REGISTER), + r#type: Some(proto::MessageType::Register as i32), register: Some(proto::Register { ns: Some(namespace.into()), ttl, - signedPeerRecord: Some(record.into_signed_envelope().into_protobuf_encoding()), + signed_peer_record: Some( + record.into_signed_envelope().into_protobuf_encoding(), + ), }), - registerResponse: None, + register_response: None, unregister: None, discover: None, - discoverResponse: None, + discover_response: None, }, Message::RegisterResponse(Ok(ttl)) => proto::Message { - type_pb: Some(proto::MessageType::REGISTER_RESPONSE), - registerResponse: Some(proto::RegisterResponse { - status: Some(proto::ResponseStatus::OK), - statusText: None, + r#type: Some(proto::MessageType::RegisterResponse as i32), + register_response: Some(proto::RegisterResponse { + status: Some(proto::ResponseStatus::Ok as i32), + status_text: None, ttl: Some(ttl), }), register: None, discover: None, unregister: None, - discoverResponse: None, + discover_response: None, }, Message::RegisterResponse(Err(error)) => proto::Message { - type_pb: Some(proto::MessageType::REGISTER_RESPONSE), - registerResponse: Some(proto::RegisterResponse { - status: Some(proto::ResponseStatus::from(error)), - statusText: None, + r#type: Some(proto::MessageType::RegisterResponse as i32), + register_response: Some(proto::RegisterResponse { + status: Some(proto::ResponseStatus::from(error) as i32), + status_text: None, ttl: None, }), register: None, discover: None, unregister: None, - discoverResponse: None, + discover_response: None, }, Message::Unregister(namespace) => proto::Message { - type_pb: Some(proto::MessageType::UNREGISTER), + r#type: Some(proto::MessageType::Unregister as i32), unregister: Some(proto::Unregister { ns: Some(namespace.into()), id: None, }), register: None, - registerResponse: None, + register_response: None, discover: None, - discoverResponse: None, + discover_response: None, }, Message::Discover { namespace, cookie, limit, } => proto::Message { - type_pb: Some(proto::MessageType::DISCOVER), + r#type: Some(proto::MessageType::Discover as i32), discover: Some(proto::Discover { ns: namespace.map(|ns| ns.into()), cookie: cookie.map(|cookie| cookie.into_wire_encoding()), limit, }), register: None, - registerResponse: None, + register_response: None, unregister: None, - discoverResponse: None, + discover_response: None, }, Message::DiscoverResponse(Ok((registrations, cookie))) => proto::Message { - type_pb: Some(proto::MessageType::DISCOVER_RESPONSE), - discoverResponse: Some(proto::DiscoverResponse { + r#type: Some(proto::MessageType::DiscoverResponse as i32), + discover_response: Some(proto::DiscoverResponse { registrations: registrations .into_iter() .map(|reggo| proto::Register { ns: Some(reggo.namespace.into()), ttl: Some(reggo.ttl), - signedPeerRecord: Some( + signed_peer_record: Some( reggo.record.into_signed_envelope().into_protobuf_encoding(), ), }) .collect(), - status: Some(proto::ResponseStatus::OK), - statusText: None, + status: Some(proto::ResponseStatus::Ok as i32), + status_text: None, cookie: Some(cookie.into_wire_encoding()), }), register: None, discover: None, unregister: None, - registerResponse: None, + register_response: None, }, Message::DiscoverResponse(Err(error)) => proto::Message { - type_pb: Some(proto::MessageType::DISCOVER_RESPONSE), - discoverResponse: Some(proto::DiscoverResponse { + r#type: Some(proto::MessageType::DiscoverResponse as i32), + discover_response: Some(proto::DiscoverResponse { registrations: Vec::new(), - status: Some(proto::ResponseStatus::from(error)), - statusText: None, + status: Some(proto::ResponseStatus::from(error) as i32), + status_text: None, cookie: None, }), register: None, discover: None, unregister: None, - registerResponse: None, + register_response: None, }, } } @@ -435,111 +437,109 @@ impl TryFrom for Message { type Error = ConversionError; fn try_from(message: proto::Message) -> Result { - let message = match message { - proto::Message { - type_pb: Some(proto::MessageType::REGISTER), - register: - Some(proto::Register { - ns, - ttl, - signedPeerRecord: Some(signed_peer_record), - }), - .. - } => Message::Register(NewRegistration { - namespace: ns - .map(Namespace::new) - .transpose()? - .ok_or(ConversionError::MissingNamespace)?, - ttl, - record: PeerRecord::from_signed_envelope(SignedEnvelope::from_protobuf_encoding( - &signed_peer_record, - )?)?, - }), - proto::Message { - type_pb: Some(proto::MessageType::REGISTER_RESPONSE), - registerResponse: - Some(proto::RegisterResponse { - status: Some(proto::ResponseStatus::OK), - ttl, - .. - }), - .. - } => Message::RegisterResponse(Ok(ttl.ok_or(ConversionError::MissingTtl)?)), - proto::Message { - type_pb: Some(proto::MessageType::DISCOVER), - discover: Some(proto::Discover { ns, limit, cookie }), - .. - } => Message::Discover { - namespace: ns.map(Namespace::new).transpose()?, - cookie: cookie.map(Cookie::from_wire_encoding).transpose()?, - limit, - }, - proto::Message { - type_pb: Some(proto::MessageType::DISCOVER_RESPONSE), - discoverResponse: - Some(proto::DiscoverResponse { - registrations, - status: Some(proto::ResponseStatus::OK), - cookie: Some(cookie), - .. - }), - .. - } => { - let registrations = registrations - .into_iter() - .map(|reggo| { - Ok(Registration { - namespace: reggo - .ns - .map(Namespace::new) - .transpose()? - .ok_or(ConversionError::MissingNamespace)?, - record: PeerRecord::from_signed_envelope( - SignedEnvelope::from_protobuf_encoding( - ®go - .signedPeerRecord - .ok_or(ConversionError::MissingSignedPeerRecord)?, + let msg_type = message + .r#type + .and_then(|t| proto::MessageType::try_from(t).ok()) + .ok_or(ConversionError::InconsistentWireMessage)?; + + let result = match msg_type { + proto::MessageType::Register => { + let reg = message + .register + .ok_or(ConversionError::InconsistentWireMessage)?; + let signed_peer_record = reg + .signed_peer_record + .ok_or(ConversionError::InconsistentWireMessage)?; + Message::Register(NewRegistration { + namespace: reg + .ns + .map(Namespace::new) + .transpose()? + .ok_or(ConversionError::MissingNamespace)?, + ttl: reg.ttl, + record: PeerRecord::from_signed_envelope( + SignedEnvelope::from_protobuf_encoding(&signed_peer_record)?, + )?, + }) + } + proto::MessageType::RegisterResponse => { + let resp = message + .register_response + .ok_or(ConversionError::InconsistentWireMessage)?; + let status = resp + .status + .and_then(|s| proto::ResponseStatus::try_from(s).ok()) + .ok_or(ConversionError::BadStatusCode)?; + if status == proto::ResponseStatus::Ok { + Message::RegisterResponse(Ok(resp.ttl.ok_or(ConversionError::MissingTtl)?)) + } else { + Message::RegisterResponse(Err(status.try_into()?)) + } + } + proto::MessageType::Unregister => { + let unreg = message + .unregister + .ok_or(ConversionError::InconsistentWireMessage)?; + Message::Unregister( + unreg + .ns + .map(Namespace::new) + .transpose()? + .ok_or(ConversionError::MissingNamespace)?, + ) + } + proto::MessageType::Discover => { + let disc = message + .discover + .ok_or(ConversionError::InconsistentWireMessage)?; + Message::Discover { + namespace: disc.ns.map(Namespace::new).transpose()?, + cookie: disc.cookie.map(Cookie::from_wire_encoding).transpose()?, + limit: disc.limit, + } + } + proto::MessageType::DiscoverResponse => { + let resp = message + .discover_response + .ok_or(ConversionError::InconsistentWireMessage)?; + let status = resp + .status + .and_then(|s| proto::ResponseStatus::try_from(s).ok()) + .ok_or(ConversionError::BadStatusCode)?; + if status == proto::ResponseStatus::Ok { + let cookie = resp + .cookie + .ok_or(ConversionError::InconsistentWireMessage)?; + let registrations = resp + .registrations + .into_iter() + .map(|reggo| { + Ok(Registration { + namespace: reggo + .ns + .map(Namespace::new) + .transpose()? + .ok_or(ConversionError::MissingNamespace)?, + record: PeerRecord::from_signed_envelope( + SignedEnvelope::from_protobuf_encoding( + ®go + .signed_peer_record + .ok_or(ConversionError::MissingSignedPeerRecord)?, + )?, )?, - )?, - ttl: reggo.ttl.ok_or(ConversionError::MissingTtl)?, + ttl: reggo.ttl.ok_or(ConversionError::MissingTtl)?, + }) }) - }) - .collect::, ConversionError>>()?; - let cookie = Cookie::from_wire_encoding(cookie)?; - - Message::DiscoverResponse(Ok((registrations, cookie))) + .collect::, ConversionError>>()?; + let cookie = Cookie::from_wire_encoding(cookie)?; + Message::DiscoverResponse(Ok((registrations, cookie))) + } else { + Message::DiscoverResponse(Err(status.try_into()?)) + } } - proto::Message { - type_pb: Some(proto::MessageType::REGISTER_RESPONSE), - registerResponse: - Some(proto::RegisterResponse { - status: Some(response_status), - .. - }), - .. - } => Message::RegisterResponse(Err(response_status.try_into()?)), - proto::Message { - type_pb: Some(proto::MessageType::UNREGISTER), - unregister: Some(proto::Unregister { ns, .. }), - .. - } => Message::Unregister( - ns.map(Namespace::new) - .transpose()? - .ok_or(ConversionError::MissingNamespace)?, - ), - proto::Message { - type_pb: Some(proto::MessageType::DISCOVER_RESPONSE), - discoverResponse: - Some(proto::DiscoverResponse { - status: Some(response_status), - .. - }), - .. - } => Message::DiscoverResponse(Err(response_status.try_into()?)), - _ => return Err(ConversionError::InconsistentWireMessage), }; - Ok(message) + Ok(result) } } @@ -591,17 +591,15 @@ impl TryFrom for ErrorCode { type Error = UnmappableStatusCode; fn try_from(value: proto::ResponseStatus) -> Result { - use proto::ResponseStatus::*; - let code = match value { - OK => return Err(UnmappableStatusCode(value)), - E_INVALID_NAMESPACE => ErrorCode::InvalidNamespace, - E_INVALID_SIGNED_PEER_RECORD => ErrorCode::InvalidSignedPeerRecord, - E_INVALID_TTL => ErrorCode::InvalidTtl, - E_INVALID_COOKIE => ErrorCode::InvalidCookie, - E_NOT_AUTHORIZED => ErrorCode::NotAuthorized, - E_INTERNAL_ERROR => ErrorCode::InternalError, - E_UNAVAILABLE => ErrorCode::Unavailable, + proto::ResponseStatus::Ok => return Err(UnmappableStatusCode(value)), + proto::ResponseStatus::EInvalidNamespace => ErrorCode::InvalidNamespace, + proto::ResponseStatus::EInvalidSignedPeerRecord => ErrorCode::InvalidSignedPeerRecord, + proto::ResponseStatus::EInvalidTtl => ErrorCode::InvalidTtl, + proto::ResponseStatus::EInvalidCookie => ErrorCode::InvalidCookie, + proto::ResponseStatus::ENotAuthorized => ErrorCode::NotAuthorized, + proto::ResponseStatus::EInternalError => ErrorCode::InternalError, + proto::ResponseStatus::EUnavailable => ErrorCode::Unavailable, }; Ok(code) @@ -610,16 +608,14 @@ impl TryFrom for ErrorCode { impl From for proto::ResponseStatus { fn from(error_code: ErrorCode) -> Self { - use proto::ResponseStatus::*; - match error_code { - ErrorCode::InvalidNamespace => E_INVALID_NAMESPACE, - ErrorCode::InvalidSignedPeerRecord => E_INVALID_SIGNED_PEER_RECORD, - ErrorCode::InvalidTtl => E_INVALID_TTL, - ErrorCode::InvalidCookie => E_INVALID_COOKIE, - ErrorCode::NotAuthorized => E_NOT_AUTHORIZED, - ErrorCode::InternalError => E_INTERNAL_ERROR, - ErrorCode::Unavailable => E_UNAVAILABLE, + ErrorCode::InvalidNamespace => proto::ResponseStatus::EInvalidNamespace, + ErrorCode::InvalidSignedPeerRecord => proto::ResponseStatus::EInvalidSignedPeerRecord, + ErrorCode::InvalidTtl => proto::ResponseStatus::EInvalidTtl, + ErrorCode::InvalidCookie => proto::ResponseStatus::EInvalidCookie, + ErrorCode::NotAuthorized => proto::ResponseStatus::ENotAuthorized, + ErrorCode::InternalError => proto::ResponseStatus::EInternalError, + ErrorCode::Unavailable => proto::ResponseStatus::EUnavailable, } } } @@ -637,7 +633,7 @@ pub struct UnmappableStatusCode(proto::ResponseStatus); mod proto { #![allow(unreachable_pub)] include!("generated/mod.rs"); - pub(crate) use self::rendezvous::pb::{Message, mod_Message::*}; + pub(crate) use self::rendezvous_pb::{Message, message::*}; } #[cfg(test)] diff --git a/protocols/rendezvous/src/generated/mod.rs b/protocols/rendezvous/src/generated/mod.rs index 448a0207b2d..46bc2dacc7d 100644 --- a/protocols/rendezvous/src/generated/mod.rs +++ b/protocols/rendezvous/src/generated/mod.rs @@ -1,2 +1,3 @@ -// Automatically generated mod.rs -pub mod rendezvous; +// Automatically generated by gen-proto. DO NOT EDIT. +#[path = "rendezvous.pb.rs"] +pub mod rendezvous_pb; diff --git a/protocols/rendezvous/src/generated/rendezvous.pb.rs b/protocols/rendezvous/src/generated/rendezvous.pb.rs new file mode 100644 index 00000000000..2b39450edf3 --- /dev/null +++ b/protocols/rendezvous/src/generated/rendezvous.pb.rs @@ -0,0 +1,165 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Message { + #[prost(enumeration = "message::MessageType", optional, tag = "1")] + pub r#type: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub register: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub register_response: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub unregister: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub discover: ::core::option::Option, + #[prost(message, optional, tag = "6")] + pub discover_response: ::core::option::Option, +} +/// Nested message and enum types in `Message`. +pub mod message { + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct Register { + #[prost(string, optional, tag = "1")] + pub ns: ::core::option::Option<::prost::alloc::string::String>, + #[prost(bytes = "vec", optional, tag = "2")] + pub signed_peer_record: ::core::option::Option<::prost::alloc::vec::Vec>, + /// in seconds + #[prost(uint64, optional, tag = "3")] + pub ttl: ::core::option::Option, + } + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct RegisterResponse { + #[prost(enumeration = "ResponseStatus", optional, tag = "1")] + pub status: ::core::option::Option, + #[prost(string, optional, tag = "2")] + pub status_text: ::core::option::Option<::prost::alloc::string::String>, + /// in seconds + #[prost(uint64, optional, tag = "3")] + pub ttl: ::core::option::Option, + } + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct Unregister { + #[prost(string, optional, tag = "1")] + pub ns: ::core::option::Option<::prost::alloc::string::String>, + #[prost(bytes = "vec", optional, tag = "2")] + pub id: ::core::option::Option<::prost::alloc::vec::Vec>, + } + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] + pub struct Discover { + #[prost(string, optional, tag = "1")] + pub ns: ::core::option::Option<::prost::alloc::string::String>, + #[prost(uint64, optional, tag = "2")] + pub limit: ::core::option::Option, + #[prost(bytes = "vec", optional, tag = "3")] + pub cookie: ::core::option::Option<::prost::alloc::vec::Vec>, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct DiscoverResponse { + #[prost(message, repeated, tag = "1")] + pub registrations: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", optional, tag = "2")] + pub cookie: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(enumeration = "ResponseStatus", optional, tag = "3")] + pub status: ::core::option::Option, + #[prost(string, optional, tag = "4")] + pub status_text: ::core::option::Option<::prost::alloc::string::String>, + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum MessageType { + Register = 0, + RegisterResponse = 1, + Unregister = 2, + Discover = 3, + DiscoverResponse = 4, + } + impl MessageType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Register => "REGISTER", + Self::RegisterResponse => "REGISTER_RESPONSE", + Self::Unregister => "UNREGISTER", + Self::Discover => "DISCOVER", + Self::DiscoverResponse => "DISCOVER_RESPONSE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "REGISTER" => Some(Self::Register), + "REGISTER_RESPONSE" => Some(Self::RegisterResponse), + "UNREGISTER" => Some(Self::Unregister), + "DISCOVER" => Some(Self::Discover), + "DISCOVER_RESPONSE" => Some(Self::DiscoverResponse), + _ => None, + } + } + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum ResponseStatus { + Ok = 0, + EInvalidNamespace = 100, + EInvalidSignedPeerRecord = 101, + EInvalidTtl = 102, + EInvalidCookie = 103, + ENotAuthorized = 200, + EInternalError = 300, + EUnavailable = 400, + } + impl ResponseStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Ok => "OK", + Self::EInvalidNamespace => "E_INVALID_NAMESPACE", + Self::EInvalidSignedPeerRecord => "E_INVALID_SIGNED_PEER_RECORD", + Self::EInvalidTtl => "E_INVALID_TTL", + Self::EInvalidCookie => "E_INVALID_COOKIE", + Self::ENotAuthorized => "E_NOT_AUTHORIZED", + Self::EInternalError => "E_INTERNAL_ERROR", + Self::EUnavailable => "E_UNAVAILABLE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "OK" => Some(Self::Ok), + "E_INVALID_NAMESPACE" => Some(Self::EInvalidNamespace), + "E_INVALID_SIGNED_PEER_RECORD" => Some(Self::EInvalidSignedPeerRecord), + "E_INVALID_TTL" => Some(Self::EInvalidTtl), + "E_INVALID_COOKIE" => Some(Self::EInvalidCookie), + "E_NOT_AUTHORIZED" => Some(Self::ENotAuthorized), + "E_INTERNAL_ERROR" => Some(Self::EInternalError), + "E_UNAVAILABLE" => Some(Self::EUnavailable), + _ => None, + } + } + } +} diff --git a/protocols/rendezvous/src/generated/rendezvous/mod.rs b/protocols/rendezvous/src/generated/rendezvous/mod.rs deleted file mode 100644 index aec6164c7ef..00000000000 --- a/protocols/rendezvous/src/generated/rendezvous/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Automatically generated mod.rs -pub mod pb; diff --git a/protocols/rendezvous/src/generated/rendezvous/pb.rs b/protocols/rendezvous/src/generated/rendezvous/pb.rs deleted file mode 100644 index 2419ecf6a37..00000000000 --- a/protocols/rendezvous/src/generated/rendezvous/pb.rs +++ /dev/null @@ -1,364 +0,0 @@ -// 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 Message { - pub type_pb: Option, - pub register: Option, - pub registerResponse: Option, - pub unregister: Option, - pub discover: Option, - pub discoverResponse: Option, -} - -impl<'a> MessageRead<'a> for Message { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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.register = Some(r.read_message::(bytes)?), - Ok(26) => msg.registerResponse = Some(r.read_message::(bytes)?), - Ok(34) => msg.unregister = Some(r.read_message::(bytes)?), - Ok(42) => msg.discover = Some(r.read_message::(bytes)?), - Ok(50) => msg.discoverResponse = Some(r.read_message::(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.register.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size())) - + self.registerResponse.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size())) - + self.unregister.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size())) - + self.discover.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size())) - + self.discoverResponse.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size())) - } - - fn write_message(&self, w: &mut Writer) -> 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.register { w.write_with_tag(18, |w| w.write_message(s))?; } - if let Some(ref s) = self.registerResponse { w.write_with_tag(26, |w| w.write_message(s))?; } - if let Some(ref s) = self.unregister { w.write_with_tag(34, |w| w.write_message(s))?; } - if let Some(ref s) = self.discover { w.write_with_tag(42, |w| w.write_message(s))?; } - if let Some(ref s) = self.discoverResponse { w.write_with_tag(50, |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 Register { - pub ns: Option, - pub signedPeerRecord: Option>, - pub ttl: Option, -} - -impl<'a> MessageRead<'a> for Register { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.ns = Some(r.read_string(bytes)?.to_owned()), - Ok(18) => msg.signedPeerRecord = Some(r.read_bytes(bytes)?.to_owned()), - Ok(24) => msg.ttl = Some(r.read_uint64(bytes)?), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for Register { - fn get_size(&self) -> usize { - 0 - + self.ns.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - + self.signedPeerRecord.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - + self.ttl.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64)) - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if let Some(ref s) = self.ns { w.write_with_tag(10, |w| w.write_string(&**s))?; } - if let Some(ref s) = self.signedPeerRecord { w.write_with_tag(18, |w| w.write_bytes(&**s))?; } - if let Some(ref s) = self.ttl { 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 RegisterResponse { - pub status: Option, - pub statusText: Option, - pub ttl: Option, -} - -impl<'a> MessageRead<'a> for RegisterResponse { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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(24) => msg.ttl = Some(r.read_uint64(bytes)?), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for RegisterResponse { - 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.ttl.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64)) - } - - fn write_message(&self, w: &mut Writer) -> 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.ttl { 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 Unregister { - pub ns: Option, - pub id: Option>, -} - -impl<'a> MessageRead<'a> for Unregister { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.ns = Some(r.read_string(bytes)?.to_owned()), - Ok(18) => msg.id = Some(r.read_bytes(bytes)?.to_owned()), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for Unregister { - fn get_size(&self) -> usize { - 0 - + self.ns.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - + self.id.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if let Some(ref s) = self.ns { w.write_with_tag(10, |w| w.write_string(&**s))?; } - if let Some(ref s) = self.id { 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 Discover { - pub ns: Option, - pub limit: Option, - pub cookie: Option>, -} - -impl<'a> MessageRead<'a> for Discover { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.ns = Some(r.read_string(bytes)?.to_owned()), - Ok(16) => msg.limit = Some(r.read_uint64(bytes)?), - Ok(26) => msg.cookie = Some(r.read_bytes(bytes)?.to_owned()), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for Discover { - fn get_size(&self) -> usize { - 0 - + self.ns.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - + self.limit.as_ref().map_or(0, |m| 1 + sizeof_varint(*(m) as u64)) - + self.cookie.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if let Some(ref s) = self.ns { w.write_with_tag(10, |w| w.write_string(&**s))?; } - if let Some(ref s) = self.limit { w.write_with_tag(16, |w| w.write_uint64(*s))?; } - if let Some(ref s) = self.cookie { 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 DiscoverResponse { - pub registrations: Vec, - pub cookie: Option>, - pub status: Option, - pub statusText: Option, -} - -impl<'a> MessageRead<'a> for DiscoverResponse { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.registrations.push(r.read_message::(bytes)?), - Ok(18) => msg.cookie = Some(r.read_bytes(bytes)?.to_owned()), - Ok(24) => msg.status = Some(r.read_enum(bytes)?), - Ok(34) => msg.statusText = Some(r.read_string(bytes)?.to_owned()), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for DiscoverResponse { - fn get_size(&self) -> usize { - 0 - + self.registrations.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::() - + self.cookie.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - + 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())) - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - for s in &self.registrations { w.write_with_tag(10, |w| w.write_message(s))?; } - if let Some(ref s) = self.cookie { w.write_with_tag(18, |w| w.write_bytes(&**s))?; } - if let Some(ref s) = self.status { w.write_with_tag(24, |w| w.write_enum(*s as i32))?; } - if let Some(ref s) = self.statusText { w.write_with_tag(34, |w| w.write_string(&**s))?; } - Ok(()) - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum MessageType { - REGISTER = 0, - REGISTER_RESPONSE = 1, - UNREGISTER = 2, - DISCOVER = 3, - DISCOVER_RESPONSE = 4, -} - -impl Default for MessageType { - fn default() -> Self { - MessageType::REGISTER - } -} - -impl From for MessageType { - fn from(i: i32) -> Self { - match i { - 0 => MessageType::REGISTER, - 1 => MessageType::REGISTER_RESPONSE, - 2 => MessageType::UNREGISTER, - 3 => MessageType::DISCOVER, - 4 => MessageType::DISCOVER_RESPONSE, - _ => Self::default(), - } - } -} - -impl<'a> From<&'a str> for MessageType { - fn from(s: &'a str) -> Self { - match s { - "REGISTER" => MessageType::REGISTER, - "REGISTER_RESPONSE" => MessageType::REGISTER_RESPONSE, - "UNREGISTER" => MessageType::UNREGISTER, - "DISCOVER" => MessageType::DISCOVER, - "DISCOVER_RESPONSE" => MessageType::DISCOVER_RESPONSE, - _ => Self::default(), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum ResponseStatus { - OK = 0, - E_INVALID_NAMESPACE = 100, - E_INVALID_SIGNED_PEER_RECORD = 101, - E_INVALID_TTL = 102, - E_INVALID_COOKIE = 103, - E_NOT_AUTHORIZED = 200, - E_INTERNAL_ERROR = 300, - E_UNAVAILABLE = 400, -} - -impl Default for ResponseStatus { - fn default() -> Self { - ResponseStatus::OK - } -} - -impl From for ResponseStatus { - fn from(i: i32) -> Self { - match i { - 0 => ResponseStatus::OK, - 100 => ResponseStatus::E_INVALID_NAMESPACE, - 101 => ResponseStatus::E_INVALID_SIGNED_PEER_RECORD, - 102 => ResponseStatus::E_INVALID_TTL, - 103 => ResponseStatus::E_INVALID_COOKIE, - 200 => ResponseStatus::E_NOT_AUTHORIZED, - 300 => ResponseStatus::E_INTERNAL_ERROR, - 400 => ResponseStatus::E_UNAVAILABLE, - _ => Self::default(), - } - } -} - -impl<'a> From<&'a str> for ResponseStatus { - fn from(s: &'a str) -> Self { - match s { - "OK" => ResponseStatus::OK, - "E_INVALID_NAMESPACE" => ResponseStatus::E_INVALID_NAMESPACE, - "E_INVALID_SIGNED_PEER_RECORD" => ResponseStatus::E_INVALID_SIGNED_PEER_RECORD, - "E_INVALID_TTL" => ResponseStatus::E_INVALID_TTL, - "E_INVALID_COOKIE" => ResponseStatus::E_INVALID_COOKIE, - "E_NOT_AUTHORIZED" => ResponseStatus::E_NOT_AUTHORIZED, - "E_INTERNAL_ERROR" => ResponseStatus::E_INTERNAL_ERROR, - "E_UNAVAILABLE" => ResponseStatus::E_UNAVAILABLE, - _ => Self::default(), - } - } -} - -} - diff --git a/transports/noise/CHANGELOG.md b/transports/noise/CHANGELOG.md index 6eec7062312..ba50fa8f494 100644 --- a/transports/noise/CHANGELOG.md +++ b/transports/noise/CHANGELOG.md @@ -2,6 +2,8 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). ## 0.46.1 - Remove `once_cell` dependency. diff --git a/transports/noise/Cargo.toml b/transports/noise/Cargo.toml index dca4818f8db..5c68a98ef82 100644 --- a/transports/noise/Cargo.toml +++ b/transports/noise/Cargo.toml @@ -16,7 +16,7 @@ libp2p-core = { workspace = true } libp2p-identity = { workspace = true, features = ["ed25519"] } multiaddr = { workspace = true } multihash = { workspace = true } -quick-protobuf = "0.8" +prost = { workspace = true } rand = "0.8.3" static_assertions = "1" thiserror = { workspace = true } diff --git a/transports/noise/src/generated/mod.rs b/transports/noise/src/generated/mod.rs index c2153dd9066..afa5b24c3d0 100644 --- a/transports/noise/src/generated/mod.rs +++ b/transports/noise/src/generated/mod.rs @@ -1,2 +1,3 @@ -// Automatically generated mod.rs -pub mod payload; +// Automatically generated by gen-proto. DO NOT EDIT. +#[path = "payload.proto.rs"] +pub mod payload_proto; diff --git a/transports/noise/src/generated/payload.proto.rs b/transports/noise/src/generated/payload.proto.rs new file mode 100644 index 00000000000..0eb4da139c6 --- /dev/null +++ b/transports/noise/src/generated/payload.proto.rs @@ -0,0 +1,17 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct NoiseExtensions { + #[prost(bytes = "vec", repeated, tag = "1")] + pub webtransport_certhashes: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + #[prost(string, repeated, tag = "2")] + pub stream_muxers: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct NoiseHandshakePayload { + #[prost(bytes = "vec", tag = "1")] + pub identity_key: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "2")] + pub identity_sig: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "4")] + pub extensions: ::core::option::Option, +} diff --git a/transports/noise/src/generated/payload/mod.rs b/transports/noise/src/generated/payload/mod.rs deleted file mode 100644 index 5e3889634fb..00000000000 --- a/transports/noise/src/generated/payload/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Automatically generated mod.rs -pub mod proto; diff --git a/transports/noise/src/generated/payload/proto.rs b/transports/noise/src/generated/payload/proto.rs deleted file mode 100644 index 98808ed466a..00000000000 --- a/transports/noise/src/generated/payload/proto.rs +++ /dev/null @@ -1,91 +0,0 @@ -// Automatically generated rust module for 'payload.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 NoiseExtensions { - pub webtransport_certhashes: Vec>, - pub stream_muxers: Vec, -} - -impl<'a> MessageRead<'a> for NoiseExtensions { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.webtransport_certhashes.push(r.read_bytes(bytes)?.to_owned()), - Ok(18) => msg.stream_muxers.push(r.read_string(bytes)?.to_owned()), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for NoiseExtensions { - fn get_size(&self) -> usize { - 0 - + self.webtransport_certhashes.iter().map(|s| 1 + sizeof_len((s).len())).sum::() - + self.stream_muxers.iter().map(|s| 1 + sizeof_len((s).len())).sum::() - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - for s in &self.webtransport_certhashes { w.write_with_tag(10, |w| w.write_bytes(&**s))?; } - for s in &self.stream_muxers { 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 NoiseHandshakePayload { - pub identity_key: Vec, - pub identity_sig: Vec, - pub extensions: Option, -} - -impl<'a> MessageRead<'a> for NoiseHandshakePayload { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - let mut msg = Self::default(); - while !r.is_eof() { - match r.next_tag(bytes) { - Ok(10) => msg.identity_key = r.read_bytes(bytes)?.to_owned(), - Ok(18) => msg.identity_sig = r.read_bytes(bytes)?.to_owned(), - Ok(34) => msg.extensions = Some(r.read_message::(bytes)?), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for NoiseHandshakePayload { - fn get_size(&self) -> usize { - 0 - + if self.identity_key.is_empty() { 0 } else { 1 + sizeof_len((&self.identity_key).len()) } - + if self.identity_sig.is_empty() { 0 } else { 1 + sizeof_len((&self.identity_sig).len()) } - + self.extensions.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size())) - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if !self.identity_key.is_empty() { w.write_with_tag(10, |w| w.write_bytes(&**&self.identity_key))?; } - if !self.identity_sig.is_empty() { w.write_with_tag(18, |w| w.write_bytes(&**&self.identity_sig))?; } - if let Some(ref s) = self.extensions { w.write_with_tag(34, |w| w.write_message(s))?; } - Ok(()) - } -} - diff --git a/transports/noise/src/io/framed.rs b/transports/noise/src/io/framed.rs index b6fcb4a819a..87a4473ff6d 100644 --- a/transports/noise/src/io/framed.rs +++ b/transports/noise/src/io/framed.rs @@ -27,7 +27,7 @@ use std::{io, mem::size_of}; use asynchronous_codec::{Decoder, Encoder}; use bytes::{Buf, Bytes, BytesMut}; -use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer}; +use prost::Message; use super::handshake::proto; use crate::{Error, protocol::PublicKey}; @@ -47,9 +47,8 @@ static_assertions::const_assert! { pub(crate) struct Codec { session: S, - // We reuse write and encryption buffers across multiple messages to avoid reallocations. + // We reuse the encryption buffer across multiple messages to avoid reallocations. // We cannot reuse read and decryption buffers because we cannot return borrowed data. - write_buffer: BytesMut, encrypt_buffer: BytesMut, } @@ -57,7 +56,6 @@ impl Codec { pub(crate) fn new(session: S) -> Self { Codec { session, - write_buffer: BytesMut::default(), encrypt_buffer: BytesMut::default(), } } @@ -103,19 +101,11 @@ impl Encoder for Codec { type Item<'a> = &'a proto::NoiseHandshakePayload; fn encode(&mut self, item: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> { - let item_size = item.get_size(); + let encoded = item.encode_to_vec(); - self.write_buffer.resize(item_size, 0); - let mut writer = Writer::new(&mut self.write_buffer[..item_size]); - item.write_message(&mut writer) - .expect("Protobuf encoding to succeed"); - - encrypt( - &self.write_buffer[..item_size], - dst, - &mut self.encrypt_buffer, - |item, buffer| self.session.write_message(item, buffer), - )?; + encrypt(&encoded, dst, &mut self.encrypt_buffer, |item, buffer| { + self.session.write_message(item, buffer) + })?; Ok(()) } @@ -133,14 +123,12 @@ impl Decoder for Codec { return Ok(None); }; - let mut reader = BytesReader::from_bytes(&cleartext[..]); - let pb = - proto::NoiseHandshakePayload::from_reader(&mut reader, &cleartext).map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidData, - "Failed decoding handshake payload", - ) - })?; + let pb = proto::NoiseHandshakePayload::decode(&cleartext[..]).map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidData, + "Failed decoding handshake payload", + ) + })?; Ok(Some(pb)) } diff --git a/transports/noise/src/io/handshake.rs b/transports/noise/src/io/handshake.rs index 73d7ea5578e..b3b9cf7d6a9 100644 --- a/transports/noise/src/io/handshake.rs +++ b/transports/noise/src/io/handshake.rs @@ -23,7 +23,7 @@ pub(super) mod proto { #![allow(unreachable_pub)] include!("../generated/mod.rs"); - pub use self::payload::proto::{NoiseExtensions, NoiseHandshakePayload}; + pub use self::payload_proto::{NoiseExtensions, NoiseHandshakePayload}; } use std::{collections::HashSet, io, mem}; @@ -32,7 +32,7 @@ use asynchronous_codec::Framed; use futures::prelude::*; use libp2p_identity as identity; use multihash::Multihash; -use quick_protobuf::MessageWrite; +use prost::Message; use super::framed::Codec; use crate::{ @@ -205,7 +205,7 @@ where T: AsyncRead + Unpin, { let payload = recv(state).await?; - if payload.get_size() != 0 { + if payload.encoded_len() != 0 { return Err(io::Error::new(io::ErrorKind::InvalidData, "Expected empty payload.").into()); } diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 06c00baf297..fc41ab26066 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -253,7 +253,7 @@ pub enum Error { #[derive(Debug, thiserror::Error)] #[error(transparent)] -pub struct DecodeError(quick_protobuf::Error); +pub struct DecodeError(prost::DecodeError); fn certhashes_to_string(certhashes: &HashSet>) -> String { let mut s = String::new(); diff --git a/transports/plaintext/CHANGELOG.md b/transports/plaintext/CHANGELOG.md index 6297ec7583b..15487b73386 100644 --- a/transports/plaintext/CHANGELOG.md +++ b/transports/plaintext/CHANGELOG.md @@ -2,6 +2,8 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). ## 0.43.0 diff --git a/transports/plaintext/Cargo.toml b/transports/plaintext/Cargo.toml index 8d1c35bd996..333bdf1fe7c 100644 --- a/transports/plaintext/Cargo.toml +++ b/transports/plaintext/Cargo.toml @@ -16,9 +16,9 @@ bytes = "1" futures = { workspace = true } libp2p-core = { workspace = true } libp2p-identity = { workspace = true } -quick-protobuf = "0.8" +prost = { workspace = true } tracing = { workspace = true } -quick-protobuf-codec = { workspace = true } +prost-codec = { workspace = true } [dev-dependencies] libp2p-identity = { workspace = true, features = ["ed25519", "rand"] } diff --git a/transports/plaintext/src/error.rs b/transports/plaintext/src/error.rs index 2d352562528..b96928d7eb6 100644 --- a/transports/plaintext/src/error.rs +++ b/transports/plaintext/src/error.rs @@ -39,7 +39,7 @@ pub enum Error { } #[derive(Debug)] -pub struct DecodeError(pub(crate) quick_protobuf_codec::Error); +pub struct DecodeError(pub(crate) prost_codec::Error); impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/transports/plaintext/src/generated/mod.rs b/transports/plaintext/src/generated/mod.rs index e52c5a80bc0..c271155936b 100644 --- a/transports/plaintext/src/generated/mod.rs +++ b/transports/plaintext/src/generated/mod.rs @@ -1,2 +1,2 @@ -// Automatically generated mod.rs +// Automatically generated by gen-proto. DO NOT EDIT. pub mod structs; diff --git a/transports/plaintext/src/generated/structs.rs b/transports/plaintext/src/generated/structs.rs index aa4d94f35dd..cf6e6657ed2 100644 --- a/transports/plaintext/src/generated/structs.rs +++ b/transports/plaintext/src/generated/structs.rs @@ -1,51 +1,8 @@ -// 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)] +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Exchange { - pub id: Option>, - pub pubkey: Option>, + #[prost(bytes = "vec", optional, tag = "1")] + pub id: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", optional, tag = "2")] + pub pubkey: ::core::option::Option<::prost::alloc::vec::Vec>, } - -impl<'a> MessageRead<'a> for Exchange { - fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result { - 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.pubkey = Some(r.read_bytes(bytes)?.to_owned()), - Ok(t) => { r.read_unknown(bytes, t)?; } - Err(e) => return Err(e), - } - } - Ok(msg) - } -} - -impl MessageWrite for Exchange { - fn get_size(&self) -> usize { - 0 - + self.id.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - + self.pubkey.as_ref().map_or(0, |m| 1 + sizeof_len((m).len())) - } - - fn write_message(&self, w: &mut Writer) -> Result<()> { - if let Some(ref s) = self.id { w.write_with_tag(10, |w| w.write_bytes(&**s))?; } - if let Some(ref s) = self.pubkey { w.write_with_tag(18, |w| w.write_bytes(&**s))?; } - Ok(()) - } -} - diff --git a/transports/plaintext/src/handshake.rs b/transports/plaintext/src/handshake.rs index 5876e10811d..e18bb082802 100644 --- a/transports/plaintext/src/handshake.rs +++ b/transports/plaintext/src/handshake.rs @@ -36,7 +36,7 @@ where S: AsyncRead + AsyncWrite + Send + Unpin, { // The handshake messages all start with a variable-length integer indicating the size. - let mut framed_socket = Framed::new(socket, quick_protobuf_codec::Codec::::new(100)); + let mut framed_socket = Framed::new(socket, prost_codec::Codec::::new(100)); tracing::trace!("sending exchange to remote"); framed_socket diff --git a/transports/webrtc/CHANGELOG.md b/transports/webrtc/CHANGELOG.md index 7d0268e4b7c..962080216e6 100644 --- a/transports/webrtc/CHANGELOG.md +++ b/transports/webrtc/CHANGELOG.md @@ -2,6 +2,8 @@ - Raise MSRV to 1.88.0. See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273). +- Revert migration from `prost` to `quick-protobuf`; this reintroduces the `protoc` build-time dependency (revert of [PR 3312]). + See [PR 6363](https://github.com/libp2p/rust-libp2p/pull/6363). - reduce allocations by replacing `get_or_insert` with `get_or_insert_with` See [PR 6136](https://github.com/libp2p/rust-libp2p/pull/6136)