From db82e0210e937d3aa0f0fed260357b04a7dbc5b0 Mon Sep 17 00:00:00 2001 From: Miguel Guarniz Date: Thu, 2 Mar 2023 05:45:07 -0500 Subject: [PATCH] feat: migrate to quick-protobuf Instead of relying on `protoc` and buildscripts, we generate the bindings using `pb-rs` and version them within our codebase. This makes for a better IDE integration, a faster build and an easier use of `rust-libp2p` because we don't force the `protoc` dependency onto them. Resolves #3024. Pull-Request: #3312. --- .github/workflows/ci.yml | 27 + Cargo.lock | 159 +---- Cargo.toml | 2 +- core/CHANGELOG.md | 2 + core/Cargo.toml | 5 +- core/build.rs | 31 - core/src/{ => generated}/envelope.proto | 0 core/src/generated/envelope_proto.rs | 59 ++ core/src/{ => generated}/keys.proto | 0 core/src/generated/keys_proto.rs | 125 ++++ core/src/generated/mod.rs | 4 + core/src/{ => generated}/peer_record.proto | 0 core/src/generated/peer_record_proto.rs | 93 +++ core/src/identity.rs | 119 ++-- core/src/identity/error.rs | 7 - core/src/lib.rs | 37 +- core/src/peer_record.rs | 40 +- core/src/signed_envelope.rs | 27 +- interop-tests/Dockerfile | 2 +- misc/prost-codec/CHANGELOG.md | 16 - misc/quick-protobuf-codec/CHANGELOG.md | 5 + .../Cargo.toml | 11 +- .../src/lib.rs | 29 +- protocols/autonat/CHANGELOG.md | 3 + protocols/autonat/Cargo.toml | 5 +- protocols/autonat/build.rs | 23 - protocols/autonat/src/generated/mod.rs | 2 + .../autonat/src/{ => generated}/structs.proto | 0 protocols/autonat/src/generated/structs.rs | 242 ++++++++ protocols/autonat/src/lib.rs | 6 +- protocols/autonat/src/protocol.rs | 146 ++--- protocols/dcutr/CHANGELOG.md | 3 + protocols/dcutr/Cargo.toml | 7 +- protocols/dcutr/build.rs | 23 - .../dcutr/src/generated/holepunch/mod.rs | 2 + protocols/dcutr/src/generated/holepunch/pb.rs | 88 +++ .../dcutr/src/{ => generated}/message.proto | 0 protocols/dcutr/src/generated/mod.rs | 2 + protocols/dcutr/src/lib.rs | 7 +- protocols/dcutr/src/protocol/inbound.rs | 39 +- protocols/dcutr/src/protocol/outbound.rs | 33 +- protocols/floodsub/CHANGELOG.md | 4 +- protocols/floodsub/Cargo.toml | 7 +- protocols/floodsub/build.rs | 23 - .../floodsub/src/generated/floodsub/mod.rs | 2 + .../floodsub/src/generated/floodsub/pb.rs | 137 +++++ protocols/floodsub/src/generated/mod.rs | 2 + .../floodsub/src/{ => generated}/rpc.proto | 0 protocols/floodsub/src/lib.rs | 6 +- protocols/floodsub/src/protocol.rs | 16 +- protocols/gossipsub/CHANGELOG.md | 3 + protocols/gossipsub/Cargo.toml | 7 +- protocols/gossipsub/build.rs | 23 - protocols/gossipsub/src/behaviour.rs | 68 +-- protocols/gossipsub/src/behaviour/tests.rs | 2 +- protocols/gossipsub/src/error_priv.rs | 4 +- .../src/{ => generated}/compat.proto | 0 .../gossipsub/src/generated/compat/mod.rs | 2 + .../gossipsub/src/generated/compat/pb.rs | 67 +++ .../gossipsub/src/generated/gossipsub/mod.rs | 2 + .../gossipsub/src/generated/gossipsub/pb.rs | 567 ++++++++++++++++++ protocols/gossipsub/src/generated/mod.rs | 3 + .../gossipsub/src/{ => generated}/rpc.proto | 0 protocols/gossipsub/src/handler.rs | 12 +- protocols/gossipsub/src/protocol.rs | 21 +- protocols/gossipsub/src/rpc_proto.rs | 46 +- protocols/gossipsub/src/topic.rs | 15 +- protocols/gossipsub/src/types.rs | 30 +- protocols/identify/CHANGELOG.md | 3 + protocols/identify/Cargo.toml | 7 +- protocols/identify/build.rs | 23 - protocols/identify/src/generated/mod.rs | 2 + .../src/{ => generated}/structs.proto | 0 protocols/identify/src/generated/structs.rs | 67 +++ protocols/identify/src/lib.rs | 6 +- protocols/identify/src/mod.rs | 2 + protocols/identify/src/protocol.rs | 46 +- protocols/identify/src/structs.rs | 67 +++ protocols/kad/CHANGELOG.md | 3 + protocols/kad/Cargo.toml | 5 +- protocols/kad/build.rs | 23 - protocols/kad/src/{ => generated}/dht.proto | 0 protocols/kad/src/generated/dht/mod.rs | 2 + protocols/kad/src/generated/dht/pb.rs | 243 ++++++++ protocols/kad/src/generated/mod.rs | 2 + protocols/kad/src/lib.rs | 9 +- protocols/kad/src/protocol.rs | 169 +++--- protocols/relay/CHANGELOG.md | 3 + protocols/relay/Cargo.toml | 7 +- protocols/relay/build.rs | 23 - protocols/relay/src/behaviour.rs | 8 +- protocols/relay/src/behaviour/handler.rs | 26 +- .../relay/src/{ => generated}/message.proto | 0 .../relay/src/generated/message_v2/mod.rs | 2 + .../relay/src/generated/message_v2/pb.rs | 346 +++++++++++ protocols/relay/src/generated/mod.rs | 2 + protocols/relay/src/lib.rs | 8 +- protocols/relay/src/priv_client/handler.rs | 4 +- protocols/relay/src/protocol.rs | 6 +- protocols/relay/src/protocol/inbound_hop.rs | 67 ++- protocols/relay/src/protocol/inbound_stop.rs | 45 +- protocols/relay/src/protocol/outbound_hop.rs | 68 ++- protocols/relay/src/protocol/outbound_stop.rs | 45 +- protocols/rendezvous/CHANGELOG.md | 4 + protocols/rendezvous/Cargo.toml | 7 +- protocols/rendezvous/build.rs | 3 - protocols/rendezvous/src/codec.rs | 228 ++++--- protocols/rendezvous/src/generated/mod.rs | 2 + .../src/generated/rendezvous/mod.rs | 2 + .../rendezvous/src/generated/rendezvous/pb.rs | 364 +++++++++++ .../rendezvous/src/{ => generated}/rpc.proto | 0 transports/noise/CHANGELOG.md | 3 + transports/noise/Cargo.toml | 5 +- transports/noise/build.rs | 23 - transports/noise/src/generated/mod.rs | 2 + .../{io/handshake => generated}/payload.proto | 0 transports/noise/src/generated/payload/mod.rs | 2 + .../noise/src/generated/payload/proto.rs | 55 ++ transports/noise/src/io/handshake.rs | 38 +- transports/noise/src/lib.rs | 23 +- transports/plaintext/CHANGELOG.md | 4 + transports/plaintext/Cargo.toml | 5 +- transports/plaintext/build.rs | 23 - transports/plaintext/src/error.rs | 6 +- transports/plaintext/src/generated/mod.rs | 2 + .../src/{ => generated}/structs.proto | 0 transports/plaintext/src/generated/structs.rs | 51 ++ transports/plaintext/src/handshake.rs | 14 +- transports/plaintext/src/lib.rs | 6 +- transports/webrtc/CHANGELOG.md | 4 + transports/webrtc/Cargo.toml | 7 +- transports/webrtc/build.rs | 23 - .../webrtc/src/{ => generated}/message.proto | 0 transports/webrtc/src/generated/mod.rs | 2 + transports/webrtc/src/generated/webrtc/mod.rs | 2 + transports/webrtc/src/generated/webrtc/pb.rs | 91 +++ transports/webrtc/src/lib.rs | 7 +- transports/webrtc/src/tokio/substream.rs | 35 +- .../src/tokio/substream/drop_listener.rs | 4 +- .../webrtc/src/tokio/substream/framed_dc.rs | 6 +- .../webrtc/src/tokio/substream/state.rs | 26 +- 141 files changed, 3652 insertions(+), 1266 deletions(-) delete mode 100644 core/build.rs rename core/src/{ => generated}/envelope.proto (100%) create mode 100644 core/src/generated/envelope_proto.rs rename core/src/{ => generated}/keys.proto (100%) create mode 100644 core/src/generated/keys_proto.rs create mode 100644 core/src/generated/mod.rs rename core/src/{ => generated}/peer_record.proto (100%) create mode 100644 core/src/generated/peer_record_proto.rs delete mode 100644 misc/prost-codec/CHANGELOG.md create mode 100644 misc/quick-protobuf-codec/CHANGELOG.md rename misc/{prost-codec => quick-protobuf-codec}/Cargo.toml (83%) rename misc/{prost-codec => quick-protobuf-codec}/src/lib.rs (67%) delete mode 100644 protocols/autonat/build.rs create mode 100644 protocols/autonat/src/generated/mod.rs rename protocols/autonat/src/{ => generated}/structs.proto (100%) create mode 100644 protocols/autonat/src/generated/structs.rs delete mode 100644 protocols/dcutr/build.rs create mode 100644 protocols/dcutr/src/generated/holepunch/mod.rs create mode 100644 protocols/dcutr/src/generated/holepunch/pb.rs rename protocols/dcutr/src/{ => generated}/message.proto (100%) create mode 100644 protocols/dcutr/src/generated/mod.rs delete mode 100644 protocols/floodsub/build.rs create mode 100644 protocols/floodsub/src/generated/floodsub/mod.rs create mode 100644 protocols/floodsub/src/generated/floodsub/pb.rs create mode 100644 protocols/floodsub/src/generated/mod.rs rename protocols/floodsub/src/{ => generated}/rpc.proto (100%) delete mode 100644 protocols/gossipsub/build.rs rename protocols/gossipsub/src/{ => generated}/compat.proto (100%) create mode 100644 protocols/gossipsub/src/generated/compat/mod.rs create mode 100644 protocols/gossipsub/src/generated/compat/pb.rs create mode 100644 protocols/gossipsub/src/generated/gossipsub/mod.rs create mode 100644 protocols/gossipsub/src/generated/gossipsub/pb.rs create mode 100644 protocols/gossipsub/src/generated/mod.rs rename protocols/gossipsub/src/{ => generated}/rpc.proto (100%) delete mode 100644 protocols/identify/build.rs create mode 100644 protocols/identify/src/generated/mod.rs rename protocols/identify/src/{ => generated}/structs.proto (100%) create mode 100644 protocols/identify/src/generated/structs.rs create mode 100644 protocols/identify/src/mod.rs create mode 100644 protocols/identify/src/structs.rs delete mode 100644 protocols/kad/build.rs rename protocols/kad/src/{ => generated}/dht.proto (100%) create mode 100644 protocols/kad/src/generated/dht/mod.rs create mode 100644 protocols/kad/src/generated/dht/pb.rs create mode 100644 protocols/kad/src/generated/mod.rs delete mode 100644 protocols/relay/build.rs rename protocols/relay/src/{ => generated}/message.proto (100%) create mode 100644 protocols/relay/src/generated/message_v2/mod.rs create mode 100644 protocols/relay/src/generated/message_v2/pb.rs create mode 100644 protocols/relay/src/generated/mod.rs delete mode 100644 protocols/rendezvous/build.rs create mode 100644 protocols/rendezvous/src/generated/mod.rs create mode 100644 protocols/rendezvous/src/generated/rendezvous/mod.rs create mode 100644 protocols/rendezvous/src/generated/rendezvous/pb.rs rename protocols/rendezvous/src/{ => generated}/rpc.proto (100%) delete mode 100644 transports/noise/build.rs create mode 100644 transports/noise/src/generated/mod.rs rename transports/noise/src/{io/handshake => generated}/payload.proto (100%) create mode 100644 transports/noise/src/generated/payload/mod.rs create mode 100644 transports/noise/src/generated/payload/proto.rs delete mode 100644 transports/plaintext/build.rs create mode 100644 transports/plaintext/src/generated/mod.rs rename transports/plaintext/src/{ => generated}/structs.proto (100%) create mode 100644 transports/plaintext/src/generated/structs.rs delete mode 100644 transports/webrtc/build.rs rename transports/webrtc/src/{ => generated}/message.proto (100%) create mode 100644 transports/webrtc/src/generated/mod.rs create mode 100644 transports/webrtc/src/generated/webrtc/mod.rs create mode 100644 transports/webrtc/src/generated/webrtc/pb.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c7a0cc28bf..b12914f9fa7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -293,3 +293,30 @@ jobs: echo "PR title is too long (greater than 72 characters)" exit 1 fi + + check-proto-files: + name: Check for changes in proto files + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 # v2.2.0 + + - run: cargo install --version 0.10.0 pb-rs --locked + + - name: Glob match + uses: tj-actions/glob@v16 + id: glob + with: + files: | + **/generated/*.proto + + - name: Generate proto files + run: pb-rs --dont_use_cow ${{ steps.glob.outputs.paths }} + + - name: Ensure generated files are unmodified # https://stackoverflow.com/a/5737794 + run: | + git_status=$(git status --porcelain) + + echo $git_status + test -z "$git_status" diff --git a/Cargo.lock b/Cargo.lock index 0e071f5e93f..8805be1d08b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1407,12 +1407,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flate2" version = "1.0.25" @@ -2177,8 +2171,7 @@ dependencies = [ "libp2p-tcp", "libp2p-yamux", "log", - "prost", - "prost-build", + "quick-protobuf", "rand 0.8.5", ] @@ -2208,8 +2201,7 @@ dependencies = [ "p256 0.12.0", "parking_lot 0.12.1", "pin-project", - "prost", - "prost-build", + "quick-protobuf", "quickcheck-ext", "rand 0.8.5", "ring", @@ -2248,9 +2240,8 @@ dependencies = [ "libp2p-tcp", "libp2p-yamux", "log", - "prost", - "prost-build", - "prost-codec", + "quick-protobuf", + "quick-protobuf-codec", "rand 0.8.5", "thiserror", "void", @@ -2296,9 +2287,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost", - "prost-build", - "prost-codec", + "quick-protobuf", + "quick-protobuf-codec", "rand 0.8.5", "smallvec", "thiserror", @@ -2327,9 +2317,8 @@ dependencies = [ "libp2p-yamux", "log", "prometheus-client", - "prost", - "prost-build", - "prost-codec", + "quick-protobuf", + "quick-protobuf-codec", "quickcheck-ext", "rand 0.8.5", "regex", @@ -2359,9 +2348,8 @@ dependencies = [ "libp2p-yamux", "log", "lru", - "prost", - "prost-build", - "prost-codec", + "quick-protobuf", + "quick-protobuf-codec", "smallvec", "thiserror", "void", @@ -2385,8 +2373,7 @@ dependencies = [ "libp2p-swarm", "libp2p-yamux", "log", - "prost", - "prost-build", + "quick-protobuf", "quickcheck-ext", "rand 0.8.5", "serde", @@ -2493,8 +2480,7 @@ dependencies = [ "libsodium-sys-stable", "log", "once_cell", - "prost", - "prost-build", + "quick-protobuf", "quickcheck-ext", "rand 0.8.5", "sha2 0.10.6", @@ -2536,8 +2522,7 @@ dependencies = [ "futures", "libp2p-core", "log", - "prost", - "prost-build", + "quick-protobuf", "quickcheck-ext", "rand 0.8.5", "unsigned-varint", @@ -2611,9 +2596,8 @@ dependencies = [ "libp2p-tcp", "libp2p-yamux", "log", - "prost", - "prost-build", - "prost-codec", + "quick-protobuf", + "quick-protobuf-codec", "quickcheck-ext", "rand 0.8.5", "static_assertions", @@ -2641,9 +2625,8 @@ dependencies = [ "libp2p-tcp", "libp2p-yamux", "log", - "prost", - "prost-build", - "prost-codec", + "quick-protobuf", + "quick-protobuf-codec", "rand 0.8.5", "thiserror", "tokio", @@ -2787,9 +2770,8 @@ dependencies = [ "libp2p-swarm", "log", "multihash", - "prost", - "prost-build", - "prost-codec", + "quick-protobuf", + "quick-protobuf-codec", "quickcheck", "rand 0.8.5", "rcgen 0.9.3", @@ -3103,12 +3085,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - [[package]] name = "multistream-select" version = "0.12.1" @@ -3441,16 +3417,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" -[[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" -dependencies = [ - "fixedbitset", - "indexmap", -] - [[package]] name = "pin-project" version = "1.0.12" @@ -3593,16 +3559,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "prettyplease" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" -dependencies = [ - "proc-macro2", - "syn", -] - [[package]] name = "primeorder" version = "0.12.1" @@ -3679,77 +3635,31 @@ dependencies = [ ] [[package]] -name = "prost" -version = "0.11.8" +name = "quick-error" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" -dependencies = [ - "bytes", - "prost-derive", -] +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] -name = "prost-build" -version = "0.11.8" +name = "quick-protobuf" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12" +checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" dependencies = [ - "bytes", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn", - "tempfile", - "which", + "byteorder", ] [[package]] -name = "prost-codec" -version = "0.3.0" +name = "quick-protobuf-codec" +version = "0.1.0" dependencies = [ "asynchronous-codec", "bytes", - "prost", - "prost-build", + "quick-protobuf", "thiserror", "unsigned-varint", ] -[[package]] -name = "prost-derive" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "prost-types" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88" -dependencies = [ - "prost", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quickcheck" version = "1.0.3" @@ -5374,17 +5284,6 @@ dependencies = [ "cc", ] -[[package]] -name = "which" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" -dependencies = [ - "either", - "libc", - "once_cell", -] - [[package]] name = "widestring" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index fa2a6d626ad..f95c4bf5f72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -146,7 +146,7 @@ members = [ "misc/multistream-select", "misc/rw-stream-sink", "misc/keygen", - "misc/prost-codec", + "misc/quick-protobuf-codec", "misc/quickcheck-ext", "muxers/mplex", "muxers/yamux", diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 94ef2873018..96363d327c3 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -2,7 +2,9 @@ - Move `ConnectionId` to `libp2p-swarm`. See [PR 3221]. - Move `PendingPoint` to `libp2p-swarm` and make it crate-private. See [PR 3221]. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 [PR 3221]: https://github.com/libp2p/rust-libp2p/pull/3221 # 0.38.0 diff --git a/core/Cargo.toml b/core/Cargo.toml index 0a3f75b2c77..b390f2489b4 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -27,7 +27,7 @@ multistream-select = { version = "0.12.1", path = "../misc/multistream-select" } p256 = { version = "0.12.0", default-features = false, features = ["ecdsa", "std"], optional = true } parking_lot = "0.12.0" pin-project = "1.0.0" -prost = "0.11" +quick-protobuf = "0.8" once_cell = "1.17.1" rand = "0.8" rw-stream-sink = { version = "0.3.0", path = "../misc/rw-stream-sink" } @@ -54,9 +54,6 @@ quickcheck = { package = "quickcheck-ext", path = "../misc/quickcheck-ext" } rmp-serde = "1.0" serde_json = "1.0" -[build-dependencies] -prost-build = "0.11" - [features] secp256k1 = [ "libsecp256k1" ] ecdsa = [ "p256" ] diff --git a/core/build.rs b/core/build.rs deleted file mode 100644 index f0c09f93abf..00000000000 --- a/core/build.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -fn main() { - prost_build::compile_protos( - &[ - "src/keys.proto", - "src/envelope.proto", - "src/peer_record.proto", - ], - &["src"], - ) - .unwrap(); -} diff --git a/core/src/envelope.proto b/core/src/generated/envelope.proto similarity index 100% rename from core/src/envelope.proto rename to core/src/generated/envelope.proto diff --git a/core/src/generated/envelope_proto.rs b/core/src/generated/envelope_proto.rs new file mode 100644 index 00000000000..268b6a334f3 --- /dev/null +++ b/core/src/generated/envelope_proto.rs @@ -0,0 +1,59 @@ +// Automatically generated rust module for 'envelope.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::*; + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct Envelope { + pub public_key: Option, + pub payload_type: Vec, + pub payload: Vec, + pub signature: 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 = Some(r.read_message::(bytes)?), + Ok(18) => msg.payload_type = r.read_bytes(bytes)?.to_owned(), + Ok(26) => msg.payload = r.read_bytes(bytes)?.to_owned(), + Ok(42) => msg.signature = r.read_bytes(bytes)?.to_owned(), + Ok(t) => { r.read_unknown(bytes, t)?; } + Err(e) => return Err(e), + } + } + Ok(msg) + } +} + +impl MessageWrite for Envelope { + fn get_size(&self) -> usize { + 0 + + self.public_key.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size())) + + if self.payload_type.is_empty() { 0 } else { 1 + sizeof_len((&self.payload_type).len()) } + + if self.payload.is_empty() { 0 } else { 1 + sizeof_len((&self.payload).len()) } + + if self.signature.is_empty() { 0 } else { 1 + sizeof_len((&self.signature).len()) } + } + + fn write_message(&self, w: &mut Writer) -> Result<()> { + if let Some(ref s) = self.public_key { w.write_with_tag(10, |w| w.write_message(s))?; } + if !self.payload_type.is_empty() { w.write_with_tag(18, |w| w.write_bytes(&**&self.payload_type))?; } + if !self.payload.is_empty() { w.write_with_tag(26, |w| w.write_bytes(&**&self.payload))?; } + if !self.signature.is_empty() { w.write_with_tag(42, |w| w.write_bytes(&**&self.signature))?; } + Ok(()) + } +} + diff --git a/core/src/keys.proto b/core/src/generated/keys.proto similarity index 100% rename from core/src/keys.proto rename to core/src/generated/keys.proto diff --git a/core/src/generated/keys_proto.rs b/core/src/generated/keys_proto.rs new file mode 100644 index 00000000000..ba15fed5004 --- /dev/null +++ b/core/src/generated/keys_proto.rs @@ -0,0 +1,125 @@ +// Automatically generated rust module for 'keys.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::*; + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum KeyType { + RSA = 0, + Ed25519 = 1, + Secp256k1 = 2, + ECDSA = 3, +} + +impl Default for KeyType { + fn default() -> Self { + KeyType::RSA + } +} + +impl From for KeyType { + fn from(i: i32) -> Self { + match i { + 0 => KeyType::RSA, + 1 => KeyType::Ed25519, + 2 => KeyType::Secp256k1, + 3 => KeyType::ECDSA, + _ => Self::default(), + } + } +} + +impl<'a> From<&'a str> for KeyType { + fn from(s: &'a str) -> Self { + match s { + "RSA" => KeyType::RSA, + "Ed25519" => KeyType::Ed25519, + "Secp256k1" => KeyType::Secp256k1, + "ECDSA" => KeyType::ECDSA, + _ => Self::default(), + } + } +} + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct PublicKey { + pub Type: keys_proto::KeyType, + pub Data: Vec, +} + +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)] +pub struct PrivateKey { + pub Type: keys_proto::KeyType, + pub Data: 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), + } + } + 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(()) + } +} + diff --git a/core/src/generated/mod.rs b/core/src/generated/mod.rs new file mode 100644 index 00000000000..964d125e02f --- /dev/null +++ b/core/src/generated/mod.rs @@ -0,0 +1,4 @@ +// Automatically generated mod.rs +pub mod envelope_proto; +pub mod keys_proto; +pub mod peer_record_proto; diff --git a/core/src/peer_record.proto b/core/src/generated/peer_record.proto similarity index 100% rename from core/src/peer_record.proto rename to core/src/generated/peer_record.proto diff --git a/core/src/generated/peer_record_proto.rs b/core/src/generated/peer_record_proto.rs new file mode 100644 index 00000000000..c771caacd2e --- /dev/null +++ b/core/src/generated/peer_record_proto.rs @@ -0,0 +1,93 @@ +// Automatically generated rust module for 'peer_record.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::*; + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct PeerRecord { + pub peer_id: Vec, + pub seq: u64, + pub addresses: 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) + } +} + +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/identity.rs b/core/src/identity.rs index e6e39e06ff1..5c290c11c5a 100644 --- a/core/src/identity.rs +++ b/core/src/identity.rs @@ -43,7 +43,8 @@ pub mod secp256k1; pub mod error; use self::error::*; -use crate::{keys_proto, PeerId}; +use crate::{proto, PeerId}; +use quick_protobuf::{BytesReader, Writer}; use std::convert::{TryFrom, TryInto}; /// Identity keypair of a node. @@ -147,12 +148,12 @@ impl Keypair { /// Encode a private key as protobuf structure. pub fn to_protobuf_encoding(&self) -> Result, DecodingError> { - use prost::Message; + use quick_protobuf::MessageWrite; let pk = match self { - Self::Ed25519(data) => keys_proto::PrivateKey { - r#type: keys_proto::KeyType::Ed25519.into(), - data: data.encode().into(), + Self::Ed25519(data) => proto::PrivateKey { + Type: proto::KeyType::Ed25519, + Data: data.encode().to_vec(), }, #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] Self::Rsa(_) => return Err(DecodingError::encoding_unsupported("RSA")), @@ -162,35 +163,38 @@ impl Keypair { Self::Ecdsa(_) => return Err(DecodingError::encoding_unsupported("ECDSA")), }; - Ok(pk.encode_to_vec()) + let mut buf = Vec::with_capacity(pk.get_size()); + let mut writer = Writer::new(&mut buf); + pk.write_message(&mut writer).expect("Encoding to succeed"); + + Ok(buf) } /// Decode a private key from a protobuf structure and parse it as a [`Keypair`]. pub fn from_protobuf_encoding(bytes: &[u8]) -> Result { - use prost::Message; + use quick_protobuf::MessageRead; - let mut private_key = keys_proto::PrivateKey::decode(bytes) + let mut reader = BytesReader::from_bytes(bytes); + let mut private_key = proto::PrivateKey::from_reader(&mut reader, bytes) .map_err(|e| DecodingError::bad_protobuf("private key bytes", e)) .map(zeroize::Zeroizing::new)?; - let key_type = keys_proto::KeyType::from_i32(private_key.r#type) - .ok_or_else(|| DecodingError::unknown_key_type(private_key.r#type))?; - - match key_type { - keys_proto::KeyType::Ed25519 => { - ed25519::Keypair::decode(&mut private_key.data).map(Keypair::Ed25519) + match private_key.Type { + proto::KeyType::Ed25519 => { + ed25519::Keypair::decode(&mut private_key.Data).map(Keypair::Ed25519) } - keys_proto::KeyType::Rsa => Err(DecodingError::decoding_unsupported("RSA")), - keys_proto::KeyType::Secp256k1 => Err(DecodingError::decoding_unsupported("secp256k1")), - keys_proto::KeyType::Ecdsa => Err(DecodingError::decoding_unsupported("ECDSA")), + proto::KeyType::RSA => Err(DecodingError::decoding_unsupported("RSA")), + proto::KeyType::Secp256k1 => Err(DecodingError::decoding_unsupported("secp256k1")), + proto::KeyType::ECDSA => Err(DecodingError::decoding_unsupported("ECDSA")), } } } -impl zeroize::Zeroize for keys_proto::PrivateKey { +impl zeroize::Zeroize for proto::PrivateKey { fn zeroize(&mut self) { - self.r#type.zeroize(); - self.data.zeroize(); + // KeyType cannot be zeroized. + self.Type = proto::KeyType::default(); + self.Data.zeroize(); } } @@ -232,23 +236,27 @@ impl PublicKey { /// Encode the public key into a protobuf structure for storage or /// exchange with other nodes. pub fn to_protobuf_encoding(&self) -> Vec { - use prost::Message; + use quick_protobuf::MessageWrite; - let public_key = keys_proto::PublicKey::from(self); + let public_key = proto::PublicKey::from(self); - let mut buf = Vec::with_capacity(public_key.encoded_len()); + let mut buf = Vec::with_capacity(public_key.get_size()); + let mut writer = Writer::new(&mut buf); public_key - .encode(&mut buf) - .expect("Vec provides capacity as needed"); + .write_message(&mut writer) + .expect("Encoding to succeed"); + buf } /// Decode a public key from a protobuf structure, e.g. read from storage /// or received from another node. pub fn from_protobuf_encoding(bytes: &[u8]) -> Result { - use prost::Message; + use quick_protobuf::MessageRead; - let pubkey = keys_proto::PublicKey::decode(bytes) + let mut reader = BytesReader::from_bytes(bytes); + + let pubkey = proto::PublicKey::from_reader(&mut reader, bytes) .map_err(|e| DecodingError::bad_protobuf("public key bytes", e))?; pubkey.try_into() @@ -260,67 +268,62 @@ impl PublicKey { } } -impl From<&PublicKey> for keys_proto::PublicKey { +impl From<&PublicKey> for proto::PublicKey { fn from(key: &PublicKey) -> Self { match key { - PublicKey::Ed25519(key) => keys_proto::PublicKey { - r#type: keys_proto::KeyType::Ed25519 as i32, - data: key.encode().to_vec(), + PublicKey::Ed25519(key) => proto::PublicKey { + Type: proto::KeyType::Ed25519, + Data: key.encode().to_vec(), }, #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - PublicKey::Rsa(key) => keys_proto::PublicKey { - r#type: keys_proto::KeyType::Rsa as i32, - data: key.encode_x509(), + PublicKey::Rsa(key) => proto::PublicKey { + Type: proto::KeyType::RSA, + Data: key.encode_x509(), }, #[cfg(feature = "secp256k1")] - PublicKey::Secp256k1(key) => keys_proto::PublicKey { - r#type: keys_proto::KeyType::Secp256k1 as i32, - data: key.encode().to_vec(), + PublicKey::Secp256k1(key) => proto::PublicKey { + Type: proto::KeyType::Secp256k1, + Data: key.encode().to_vec(), }, #[cfg(feature = "ecdsa")] - PublicKey::Ecdsa(key) => keys_proto::PublicKey { - r#type: keys_proto::KeyType::Ecdsa as i32, - data: key.encode_der(), + PublicKey::Ecdsa(key) => proto::PublicKey { + Type: proto::KeyType::ECDSA, + Data: key.encode_der(), }, } } } -impl TryFrom for PublicKey { +impl TryFrom for PublicKey { type Error = DecodingError; - fn try_from(pubkey: keys_proto::PublicKey) -> Result { - let key_type = keys_proto::KeyType::from_i32(pubkey.r#type) - .ok_or_else(|| DecodingError::unknown_key_type(pubkey.r#type))?; - - match key_type { - keys_proto::KeyType::Ed25519 => { - ed25519::PublicKey::decode(&pubkey.data).map(PublicKey::Ed25519) + fn try_from(pubkey: proto::PublicKey) -> Result { + match pubkey.Type { + proto::KeyType::Ed25519 => { + ed25519::PublicKey::decode(&pubkey.Data).map(PublicKey::Ed25519) } #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - keys_proto::KeyType::Rsa => { - rsa::PublicKey::decode_x509(&pubkey.data).map(PublicKey::Rsa) - } + proto::KeyType::RSA => rsa::PublicKey::decode_x509(&pubkey.Data).map(PublicKey::Rsa), #[cfg(any(not(feature = "rsa"), target_arch = "wasm32"))] - keys_proto::KeyType::Rsa => { + proto::KeyType::RSA => { log::debug!("support for RSA was disabled at compile-time"); Err(DecodingError::missing_feature("rsa")) } #[cfg(feature = "secp256k1")] - keys_proto::KeyType::Secp256k1 => { - secp256k1::PublicKey::decode(&pubkey.data).map(PublicKey::Secp256k1) + proto::KeyType::Secp256k1 => { + secp256k1::PublicKey::decode(&pubkey.Data).map(PublicKey::Secp256k1) } #[cfg(not(feature = "secp256k1"))] - keys_proto::KeyType::Secp256k1 => { + proto::KeyType::Secp256k1 => { log::debug!("support for secp256k1 was disabled at compile-time"); Err(DecodingError::missing_feature("secp256k1")) } #[cfg(feature = "ecdsa")] - keys_proto::KeyType::Ecdsa => { - ecdsa::PublicKey::decode_der(&pubkey.data).map(PublicKey::Ecdsa) + proto::KeyType::ECDSA => { + ecdsa::PublicKey::decode_der(&pubkey.Data).map(PublicKey::Ecdsa) } #[cfg(not(feature = "ecdsa"))] - keys_proto::KeyType::Ecdsa => { + proto::KeyType::ECDSA => { log::debug!("support for ECDSA was disabled at compile-time"); Err(DecodingError::missing_feature("ecdsa")) } diff --git a/core/src/identity/error.rs b/core/src/identity/error.rs index 522c21e4bf0..fb5d8eb2006 100644 --- a/core/src/identity/error.rs +++ b/core/src/identity/error.rs @@ -68,13 +68,6 @@ impl DecodingError { } } - pub(crate) fn unknown_key_type(key_type: i32) -> Self { - Self { - msg: format!("unknown key-type {key_type}"), - source: None, - } - } - pub(crate) fn decoding_unsupported(key_type: &'static str) -> Self { Self { msg: format!("decoding {key_type} key from Protobuf is unsupported"), diff --git a/core/src/lib.rs b/core/src/lib.rs index 2b20f5156e4..f3e00b1ff15 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -37,22 +37,18 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -#[allow(clippy::derive_partial_eq_without_eq)] -mod keys_proto { - include!(concat!(env!("OUT_DIR"), "/keys_proto.rs")); -} - -mod envelope_proto { - include!(concat!(env!("OUT_DIR"), "/envelope_proto.rs")); -} - -#[allow(clippy::derive_partial_eq_without_eq)] -mod peer_record_proto { - include!(concat!(env!("OUT_DIR"), "/peer_record_proto.rs")); +mod proto { + include!("generated/mod.rs"); + pub use self::{ + envelope_proto::*, keys_proto::*, peer_record_proto::mod_PeerRecord::*, + peer_record_proto::PeerRecord, + }; } /// Multi-address re-export. pub use multiaddr; +use std::fmt; +use std::fmt::Formatter; pub type Negotiated = multistream_select::Negotiated; mod peer_id; @@ -80,6 +76,17 @@ pub use translation::address_translation; pub use transport::Transport; pub use upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeError, UpgradeInfo}; -#[derive(thiserror::Error, Debug)] -#[error(transparent)] -pub struct DecodeError(prost::DecodeError); +#[derive(Debug, thiserror::Error)] +pub struct DecodeError(String); + +impl From for DecodeError { + fn from(e: quick_protobuf::Error) -> Self { + Self(e.to_string()) + } +} + +impl fmt::Display for DecodeError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/core/src/peer_record.rs b/core/src/peer_record.rs index 39cf985ee36..2a01a18fd42 100644 --- a/core/src/peer_record.rs +++ b/core/src/peer_record.rs @@ -1,8 +1,10 @@ use crate::identity::error::SigningError; use crate::identity::Keypair; +use crate::proto; use crate::signed_envelope::SignedEnvelope; -use crate::{peer_record_proto, signed_envelope, DecodeError, Multiaddr, PeerId}; +use crate::{signed_envelope, DecodeError, Multiaddr, PeerId}; use instant::SystemTime; +use quick_protobuf::{BytesReader, Writer}; use std::convert::TryInto; const PAYLOAD_TYPE: &str = "/libp2p/routing-state-record"; @@ -29,11 +31,13 @@ impl PeerRecord { /// /// If this function succeeds, the [`SignedEnvelope`] contained a peer record with a valid signature and can hence be considered authenticated. pub fn from_signed_envelope(envelope: SignedEnvelope) -> Result { - use prost::Message; + use quick_protobuf::MessageRead; let (payload, signing_key) = envelope.payload_and_signing_key(String::from(DOMAIN_SEP), PAYLOAD_TYPE.as_bytes())?; - let record = peer_record_proto::PeerRecord::decode(payload).map_err(DecodeError)?; + let mut reader = BytesReader::from_bytes(payload); + let record = + proto::PeerRecord::from_reader(&mut reader, payload).map_err(DecodeError::from)?; let peer_id = PeerId::from_bytes(&record.peer_id)?; @@ -45,7 +49,7 @@ impl PeerRecord { let addresses = record .addresses .into_iter() - .map(|a| a.multiaddr.try_into()) + .map(|a| a.multiaddr.to_vec().try_into()) .collect::, _>>()?; Ok(Self { @@ -60,7 +64,7 @@ impl PeerRecord { /// /// This is the same key that is used for authenticating every libp2p connection of your application, i.e. what you use when setting up your [`crate::transport::Transport`]. pub fn new(key: &Keypair, addresses: Vec) -> Result { - use prost::Message; + use quick_protobuf::MessageWrite; let seq = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) @@ -69,21 +73,23 @@ impl PeerRecord { let peer_id = key.public().to_peer_id(); let payload = { - let record = peer_record_proto::PeerRecord { + let record = proto::PeerRecord { peer_id: peer_id.to_bytes(), seq, addresses: addresses .iter() - .map(|m| peer_record_proto::peer_record::AddressInfo { + .map(|m| proto::AddressInfo { multiaddr: m.to_vec(), }) .collect(), }; - let mut buf = Vec::with_capacity(record.encoded_len()); + let mut buf = Vec::with_capacity(record.get_size()); + let mut writer = Writer::new(&mut buf); record - .encode(&mut buf) - .expect("Vec provides capacity as needed"); + .write_message(&mut writer) + .expect("Encoding to succeed"); + buf }; @@ -162,7 +168,7 @@ mod tests { #[test] fn mismatched_signature() { - use prost::Message; + use quick_protobuf::MessageWrite; let addr: Multiaddr = HOME.parse().unwrap(); @@ -171,18 +177,20 @@ mod tests { let identity_b = Keypair::generate_ed25519(); let payload = { - let record = peer_record_proto::PeerRecord { + let record = proto::PeerRecord { peer_id: identity_a.public().to_peer_id().to_bytes(), seq: 0, - addresses: vec![peer_record_proto::peer_record::AddressInfo { + addresses: vec![proto::AddressInfo { multiaddr: addr.to_vec(), }], }; - let mut buf = Vec::with_capacity(record.encoded_len()); + let mut buf = Vec::with_capacity(record.get_size()); + let mut writer = Writer::new(&mut buf); record - .encode(&mut buf) - .expect("Vec provides capacity as needed"); + .write_message(&mut writer) + .expect("Encoding to succeed"); + buf }; diff --git a/core/src/signed_envelope.rs b/core/src/signed_envelope.rs index d290354fa9c..12c1324efa9 100644 --- a/core/src/signed_envelope.rs +++ b/core/src/signed_envelope.rs @@ -1,6 +1,7 @@ use crate::identity::error::SigningError; use crate::identity::Keypair; -use crate::{identity, DecodeError, PublicKey}; +use crate::{identity, proto, DecodeError, PublicKey}; +use quick_protobuf::{BytesReader, Writer}; use std::convert::TryInto; use std::fmt; use unsigned_varint::encode::usize_buffer; @@ -73,37 +74,41 @@ impl SignedEnvelope { /// Encode this [`SignedEnvelope`] using the protobuf encoding specified in the RFC. pub fn into_protobuf_encoding(self) -> Vec { - use prost::Message; + use quick_protobuf::MessageWrite; - let envelope = crate::envelope_proto::Envelope { + let envelope = proto::Envelope { public_key: Some((&self.key).into()), payload_type: self.payload_type, payload: self.payload, signature: self.signature, }; - let mut buf = Vec::with_capacity(envelope.encoded_len()); + let mut buf = Vec::with_capacity(envelope.get_size()); + let mut writer = Writer::new(&mut buf); + envelope - .encode(&mut buf) - .expect("Vec provides capacity as needed"); + .write_message(&mut writer) + .expect("Encoding to succeed"); buf } /// Decode a [`SignedEnvelope`] using the protobuf encoding specified in the RFC. pub fn from_protobuf_encoding(bytes: &[u8]) -> Result { - use prost::Message; + use quick_protobuf::MessageRead; - let envelope = crate::envelope_proto::Envelope::decode(bytes).map_err(DecodeError)?; + let mut reader = BytesReader::from_bytes(bytes); + let envelope = + proto::Envelope::from_reader(&mut reader, bytes).map_err(DecodeError::from)?; Ok(Self { key: envelope .public_key .ok_or(DecodingError::MissingPublicKey)? .try_into()?, - payload_type: envelope.payload_type, - payload: envelope.payload, - signature: envelope.signature, + payload_type: envelope.payload_type.to_vec(), + payload: envelope.payload.to_vec(), + signature: envelope.signature.to_vec(), }) } } diff --git a/interop-tests/Dockerfile b/interop-tests/Dockerfile index b4bed894884..a9d1428c4b6 100644 --- a/interop-tests/Dockerfile +++ b/interop-tests/Dockerfile @@ -4,7 +4,7 @@ FROM rust:1.67.0 # Setup protoc. TODO this breaks reproducibility and uses an old version of protoc. # In the future protobuf generated files will be checked in, so we can remove this WORKDIR /protoc-setup -RUN apt-get update && apt-get install -y cmake protobuf-compiler +RUN apt-get update && apt-get install -y cmake # Run with access to the target cache to speed up builds WORKDIR /workspace diff --git a/misc/prost-codec/CHANGELOG.md b/misc/prost-codec/CHANGELOG.md deleted file mode 100644 index f21b9d5bc2f..00000000000 --- a/misc/prost-codec/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# 0.3.0 - -- Implement `From` trait for `std::io::Error`. See [PR 2622]. -- Don't leak `prost` dependency in `Error` type. See [PR 3058]. - -- Update `rust-version` to reflect the actual MSRV: 1.60.0. See [PR 3090]. - -[PR 2622]: https://github.com/libp2p/rust-libp2p/pull/2622/ -[PR 3058]: https://github.com/libp2p/rust-libp2p/pull/3058/ -[PR 3090]: https://github.com/libp2p/rust-libp2p/pull/3090 - -# 0.2.0 - -- Update to prost(-build) `v0.11`. See [PR 2788]. - -[PR 2788]: https://github.com/libp2p/rust-libp2p/pull/2788/ diff --git a/misc/quick-protobuf-codec/CHANGELOG.md b/misc/quick-protobuf-codec/CHANGELOG.md new file mode 100644 index 00000000000..03b075f332f --- /dev/null +++ b/misc/quick-protobuf-codec/CHANGELOG.md @@ -0,0 +1,5 @@ +# 0.1.0 [unreleased] + +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. + +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 diff --git a/misc/prost-codec/Cargo.toml b/misc/quick-protobuf-codec/Cargo.toml similarity index 83% rename from misc/prost-codec/Cargo.toml rename to misc/quick-protobuf-codec/Cargo.toml index c0446db8139..34eb7f43d3b 100644 --- a/misc/prost-codec/Cargo.toml +++ b/misc/quick-protobuf-codec/Cargo.toml @@ -1,9 +1,9 @@ [package] -name = "prost-codec" +name = "quick-protobuf-codec" edition = "2021" rust-version = "1.60.0" -description = "Asynchronous de-/encoding of Protobuf structs using asynchronous-codec, unsigned-varint and prost." -version = "0.3.0" +description = "Asynchronous de-/encoding of Protobuf structs using asynchronous-codec, unsigned-varint and quick-protobuf." +version = "0.1.0" authors = ["Max Inden "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" @@ -13,12 +13,9 @@ categories = ["asynchronous"] [dependencies] asynchronous-codec = { version = "0.6" } bytes = { version = "1" } -prost = "0.11" thiserror = "1.0" unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] } - -[dev-dependencies] -prost-build = "0.11" +quick-protobuf = "0.8" # Passing arguments to the docsrs builder in order to properly document cfg's. # More information: https://docs.rs/about/builds#cross-compiling diff --git a/misc/prost-codec/src/lib.rs b/misc/quick-protobuf-codec/src/lib.rs similarity index 67% rename from misc/prost-codec/src/lib.rs rename to misc/quick-protobuf-codec/src/lib.rs index dc5714d742f..54785fbe209 100644 --- a/misc/prost-codec/src/lib.rs +++ b/misc/quick-protobuf-codec/src/lib.rs @@ -1,15 +1,14 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] use asynchronous_codec::{Decoder, Encoder}; -use bytes::BytesMut; -use prost::Message; -use std::io::Cursor; +use bytes::{Bytes, BytesMut}; +use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer}; use std::marker::PhantomData; use unsigned_varint::codec::UviBytes; /// [`Codec`] implements [`Encoder`] and [`Decoder`], uses [`unsigned_varint`] -/// to prefix messages with their length and uses [`prost`] and a provided -/// `struct` implementing [`Message`] to do the encoding. +/// to prefix messages with their length and uses [`quick_protobuf`] and a provided +/// `struct` implementing [`MessageRead`] and [`MessageWrite`] to do the encoding. pub struct Codec { uvi: UviBytes, phantom: PhantomData<(In, Out)>, @@ -31,21 +30,25 @@ impl Codec { } } -impl Encoder for Codec { +impl Encoder for Codec { type Item = In; type Error = Error; fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> { - let mut encoded_msg = BytesMut::new(); - item.encode(&mut encoded_msg) - .expect("BytesMut to have sufficient capacity."); - self.uvi.encode(encoded_msg.freeze(), dst)?; + let mut encoded_msg = Vec::new(); + let mut writer = Writer::new(&mut encoded_msg); + item.write_message(&mut writer) + .expect("Encoding to succeed"); + self.uvi.encode(Bytes::from(encoded_msg), dst)?; Ok(()) } } -impl Decoder for Codec { +impl Decoder for Codec +where + Out: for<'a> MessageRead<'a>, +{ type Item = Out; type Error = Error; @@ -55,9 +58,9 @@ impl Decoder for Codec { Some(msg) => msg, }; - let message = Message::decode(Cursor::new(msg)) + let mut reader = BytesReader::from_bytes(&msg); + let message = Self::Item::from_reader(&mut reader, &msg) .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?; - Ok(Some(message)) } } diff --git a/protocols/autonat/CHANGELOG.md b/protocols/autonat/CHANGELOG.md index d37d10b092a..f90a7a69b32 100644 --- a/protocols/autonat/CHANGELOG.md +++ b/protocols/autonat/CHANGELOG.md @@ -8,6 +8,9 @@ - Update to `libp2p-swarm` `v0.42.0`. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. + +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 [PR 3153]: https://github.com/libp2p/rust-libp2p/pull/3153 # 0.9.1 diff --git a/protocols/autonat/Cargo.toml b/protocols/autonat/Cargo.toml index fbd713d9253..71a8cd89e73 100644 --- a/protocols/autonat/Cargo.toml +++ b/protocols/autonat/Cargo.toml @@ -10,9 +10,6 @@ repository = "https://github.com/libp2p/rust-libp2p" keywords = ["peer-to-peer", "libp2p", "networking"] categories = ["network-programming", "asynchronous"] -[build-dependencies] -prost-build = "0.11" - [dependencies] async-trait = "0.1" futures = "0.3" @@ -23,7 +20,7 @@ libp2p-swarm = { version = "0.42.0", path = "../../swarm" } libp2p-request-response = { version = "0.24.0", path = "../request-response" } log = "0.4" rand = "0.8" -prost = "0.11" +quick-protobuf = "0.8" [dev-dependencies] async-std = { version = "1.10", features = ["attributes"] } diff --git a/protocols/autonat/build.rs b/protocols/autonat/build.rs deleted file mode 100644 index d3714fdec14..00000000000 --- a/protocols/autonat/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2021 Protocol Labs. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -fn main() { - prost_build::compile_protos(&["src/structs.proto"], &["src"]).unwrap(); -} diff --git a/protocols/autonat/src/generated/mod.rs b/protocols/autonat/src/generated/mod.rs new file mode 100644 index 00000000000..e52c5a80bc0 --- /dev/null +++ b/protocols/autonat/src/generated/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod structs; diff --git a/protocols/autonat/src/structs.proto b/protocols/autonat/src/generated/structs.proto similarity index 100% rename from protocols/autonat/src/structs.proto rename to protocols/autonat/src/generated/structs.proto diff --git a/protocols/autonat/src/generated/structs.rs b/protocols/autonat/src/generated/structs.rs new file mode 100644 index 00000000000..3a6d416b2b1 --- /dev/null +++ b/protocols/autonat/src/generated/structs.rs @@ -0,0 +1,242 @@ +// Automatically generated rust module for 'structs.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::*; + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct Message { + pub type_pb: Option, + 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), + } + } + 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), + } + } + 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), + } + } + 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), + } + } + 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/lib.rs b/protocols/autonat/src/lib.rs index 07771fe0615..e0fc3e9bc81 100644 --- a/protocols/autonat/src/lib.rs +++ b/protocols/autonat/src/lib.rs @@ -34,7 +34,7 @@ pub use self::{ }; pub use libp2p_request_response::{InboundFailure, OutboundFailure}; -#[allow(clippy::derive_partial_eq_without_eq)] -mod structs_proto { - include!(concat!(env!("OUT_DIR"), "/structs.rs")); +mod proto { + include!("generated/mod.rs"); + pub use self::structs::{mod_Message::*, Message}; } diff --git a/protocols/autonat/src/protocol.rs b/protocols/autonat/src/protocol.rs index 9da7bb5a309..2bee14200d1 100644 --- a/protocols/autonat/src/protocol.rs +++ b/protocols/autonat/src/protocol.rs @@ -18,12 +18,12 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::structs_proto; +use crate::proto; use async_trait::async_trait; use futures::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; use libp2p_core::{upgrade, Multiaddr, PeerId}; use libp2p_request_response::{self as request_response, ProtocolName}; -use prost::Message; +use quick_protobuf::{BytesReader, Writer}; use std::{convert::TryFrom, io}; #[derive(Clone, Debug)] @@ -108,14 +108,17 @@ pub struct DialRequest { impl DialRequest { pub fn from_bytes(bytes: &[u8]) -> Result { - let msg = structs_proto::Message::decode(bytes) + use quick_protobuf::MessageRead; + + let mut reader = BytesReader::from_bytes(bytes); + let msg = proto::Message::from_reader(&mut reader, bytes) .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; - if msg.r#type != Some(structs_proto::message::MessageType::Dial as _) { + if msg.type_pb != Some(proto::MessageType::DIAL) { return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid type")); } - let (peer_id, addrs) = if let Some(structs_proto::message::Dial { + let (peer_id, addrs) = if let Some(proto::Dial { peer: - Some(structs_proto::message::PeerInfo { + Some(proto::PeerInfo { id: Some(peer_id), addrs, }), @@ -131,12 +134,13 @@ impl DialRequest { }; let peer_id = { - PeerId::try_from(peer_id) + PeerId::try_from(peer_id.to_vec()) .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid peer id"))? }; + let addrs = addrs .into_iter() - .filter_map(|a| match Multiaddr::try_from(a) { + .filter_map(|a| match Multiaddr::try_from(a.to_vec()) { Ok(a) => Some(a), Err(e) => { log::debug!("Unable to parse multiaddr: {e}"); @@ -151,6 +155,8 @@ impl DialRequest { } pub fn into_bytes(self) -> Vec { + use quick_protobuf::MessageWrite; + let peer_id = self.peer_id.to_bytes(); let addrs = self .addresses @@ -158,21 +164,21 @@ impl DialRequest { .map(|addr| addr.to_vec()) .collect(); - let msg = structs_proto::Message { - r#type: Some(structs_proto::message::MessageType::Dial as _), - dial: Some(structs_proto::message::Dial { - peer: Some(structs_proto::message::PeerInfo { - id: Some(peer_id), + let msg = proto::Message { + type_pb: Some(proto::MessageType::DIAL), + dial: Some(proto::Dial { + peer: Some(proto::PeerInfo { + id: Some(peer_id.to_vec()), addrs, }), }), - dial_response: None, + dialResponse: None, }; - let mut bytes = Vec::with_capacity(msg.encoded_len()); - msg.encode(&mut bytes) - .expect("Vec provides capacity as needed"); - bytes + let mut buf = Vec::with_capacity(msg.get_size()); + let mut writer = Writer::new(&mut buf); + msg.write_message(&mut writer).expect("Encoding to succeed"); + buf } } @@ -184,29 +190,27 @@ pub enum ResponseError { InternalError, } -impl From for i32 { +impl From for proto::ResponseStatus { fn from(t: ResponseError) -> Self { match t { - ResponseError::DialError => 100, - ResponseError::DialRefused => 101, - ResponseError::BadRequest => 200, - ResponseError::InternalError => 300, + ResponseError::DialError => proto::ResponseStatus::E_DIAL_ERROR, + ResponseError::DialRefused => proto::ResponseStatus::E_DIAL_REFUSED, + ResponseError::BadRequest => proto::ResponseStatus::E_BAD_REQUEST, + ResponseError::InternalError => proto::ResponseStatus::E_INTERNAL_ERROR, } } } -impl TryFrom for ResponseError { +impl TryFrom for ResponseError { type Error = io::Error; - fn try_from(value: structs_proto::message::ResponseStatus) -> Result { + fn try_from(value: proto::ResponseStatus) -> Result { match value { - structs_proto::message::ResponseStatus::EDialError => Ok(ResponseError::DialError), - structs_proto::message::ResponseStatus::EDialRefused => Ok(ResponseError::DialRefused), - structs_proto::message::ResponseStatus::EBadRequest => Ok(ResponseError::BadRequest), - structs_proto::message::ResponseStatus::EInternalError => { - Ok(ResponseError::InternalError) - } - structs_proto::message::ResponseStatus::Ok => { + proto::ResponseStatus::E_DIAL_ERROR => Ok(ResponseError::DialError), + proto::ResponseStatus::E_DIAL_REFUSED => Ok(ResponseError::DialRefused), + proto::ResponseStatus::E_BAD_REQUEST => Ok(ResponseError::BadRequest), + proto::ResponseStatus::E_INTERNAL_ERROR => Ok(ResponseError::InternalError), + proto::ResponseStatus::OK => { log::debug!("Received response with status code OK but expected error."); Err(io::Error::new( io::ErrorKind::InvalidData, @@ -225,38 +229,35 @@ pub struct DialResponse { impl DialResponse { pub fn from_bytes(bytes: &[u8]) -> Result { - let msg = structs_proto::Message::decode(bytes) + use quick_protobuf::MessageRead; + + let mut reader = BytesReader::from_bytes(bytes); + let msg = proto::Message::from_reader(&mut reader, bytes) .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; - if msg.r#type != Some(structs_proto::message::MessageType::DialResponse as _) { + if msg.type_pb != Some(proto::MessageType::DIAL_RESPONSE) { return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid type")); } - Ok(match msg.dial_response { - Some(structs_proto::message::DialResponse { - status: Some(status), - status_text, + Ok(match msg.dialResponse { + Some(proto::DialResponse { + status: Some(proto::ResponseStatus::OK), + statusText, addr: Some(addr), - }) if structs_proto::message::ResponseStatus::from_i32(status) - == Some(structs_proto::message::ResponseStatus::Ok) => - { - let addr = Multiaddr::try_from(addr) + }) => { + let addr = Multiaddr::try_from(addr.to_vec()) .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; Self { - status_text, + status_text: statusText, result: Ok(addr), } } - Some(structs_proto::message::DialResponse { + Some(proto::DialResponse { status: Some(status), - status_text, + statusText, addr: None, }) => Self { - status_text, - result: Err(ResponseError::try_from( - structs_proto::message::ResponseStatus::from_i32(status).ok_or_else(|| { - io::Error::new(io::ErrorKind::InvalidData, "invalid response status code") - })?, - )?), + status_text: statusText, + result: Err(ResponseError::try_from(status)?), }, _ => { log::debug!("Received malformed response message."); @@ -269,35 +270,38 @@ impl DialResponse { } pub fn into_bytes(self) -> Vec { + use quick_protobuf::MessageWrite; + let dial_response = match self.result { - Ok(addr) => structs_proto::message::DialResponse { - status: Some(0), - status_text: self.status_text, + Ok(addr) => proto::DialResponse { + status: Some(proto::ResponseStatus::OK), + statusText: self.status_text, addr: Some(addr.to_vec()), }, - Err(error) => structs_proto::message::DialResponse { + Err(error) => proto::DialResponse { status: Some(error.into()), - status_text: self.status_text, + statusText: self.status_text, addr: None, }, }; - let msg = structs_proto::Message { - r#type: Some(structs_proto::message::MessageType::DialResponse as _), + let msg = proto::Message { + type_pb: Some(proto::MessageType::DIAL_RESPONSE), dial: None, - dial_response: Some(dial_response), + dialResponse: Some(dial_response), }; - let mut bytes = Vec::with_capacity(msg.encoded_len()); - msg.encode(&mut bytes) - .expect("Vec provides capacity as needed"); - bytes + let mut buf = Vec::with_capacity(msg.get_size()); + let mut writer = Writer::new(&mut buf); + msg.write_message(&mut writer).expect("Encoding to succeed"); + buf } } #[cfg(test)] mod tests { use super::*; + use quick_protobuf::MessageWrite; #[test] fn test_request_encode_decode() { @@ -346,20 +350,20 @@ mod tests { a }; - let msg = structs_proto::Message { - r#type: Some(structs_proto::message::MessageType::Dial.into()), - dial: Some(structs_proto::message::Dial { - peer: Some(structs_proto::message::PeerInfo { + let msg = proto::Message { + type_pb: Some(proto::MessageType::DIAL), + dial: Some(proto::Dial { + peer: Some(proto::PeerInfo { id: Some(PeerId::random().to_bytes()), addrs: vec![valid_multiaddr_bytes, invalid_multiaddr], }), }), - dial_response: None, + dialResponse: None, }; - let mut bytes = Vec::with_capacity(msg.encoded_len()); - msg.encode(&mut bytes) - .expect("Vec provides capacity as needed"); + let mut bytes = Vec::with_capacity(msg.get_size()); + let mut writer = Writer::new(&mut bytes); + msg.write_message(&mut writer).expect("Encoding to succeed"); let request = DialRequest::from_bytes(&bytes).expect("not to fail"); diff --git a/protocols/dcutr/CHANGELOG.md b/protocols/dcutr/CHANGELOG.md index 79200cebd1a..4b171661ad6 100644 --- a/protocols/dcutr/CHANGELOG.md +++ b/protocols/dcutr/CHANGELOG.md @@ -11,10 +11,13 @@ - Rename types in public API to follow naming conventions defined in [issue 2217]. See [PR 3214]. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. + [PR 3213]: https://github.com/libp2p/rust-libp2p/pull/3213 [PR 3153]: https://github.com/libp2p/rust-libp2p/pull/3153 [issue 2217]: https://github.com/libp2p/rust-libp2p/issues/2217 [PR 3214]: https://github.com/libp2p/rust-libp2p/pull/3214 +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 # 0.8.1 diff --git a/protocols/dcutr/Cargo.toml b/protocols/dcutr/Cargo.toml index 71c75c4d15a..cea76076e0a 100644 --- a/protocols/dcutr/Cargo.toml +++ b/protocols/dcutr/Cargo.toml @@ -19,14 +19,11 @@ instant = "0.1.11" libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-swarm = { version = "0.42.0", path = "../../swarm" } log = "0.4" -prost-codec = { version = "0.3", path = "../../misc/prost-codec" } -prost = "0.11" +quick-protobuf = "0.8" +quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" } thiserror = "1.0" void = "1" -[build-dependencies] -prost-build = "0.11" - [dev-dependencies] clap = { version = "4.1.6", features = ["derive"] } env_logger = "0.10.0" diff --git a/protocols/dcutr/build.rs b/protocols/dcutr/build.rs deleted file mode 100644 index b159bb4c817..00000000000 --- a/protocols/dcutr/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2021 Protocol Labs. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -fn main() { - prost_build::compile_protos(&["src/message.proto"], &["src"]).unwrap(); -} diff --git a/protocols/dcutr/src/generated/holepunch/mod.rs b/protocols/dcutr/src/generated/holepunch/mod.rs new file mode 100644 index 00000000000..aec6164c7ef --- /dev/null +++ b/protocols/dcutr/src/generated/holepunch/mod.rs @@ -0,0 +1,2 @@ +// 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 new file mode 100644 index 00000000000..59f37040f14 --- /dev/null +++ b/protocols/dcutr/src/generated/holepunch/pb.rs @@ -0,0 +1,88 @@ +// Automatically generated rust module for 'message.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::super::*; + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct HolePunch { + pub type_pb: holepunch::pb::mod_HolePunch::Type, + pub ObsAddrs: Vec>, +} + +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/message.proto b/protocols/dcutr/src/generated/message.proto similarity index 100% rename from protocols/dcutr/src/message.proto rename to protocols/dcutr/src/generated/message.proto diff --git a/protocols/dcutr/src/generated/mod.rs b/protocols/dcutr/src/generated/mod.rs new file mode 100644 index 00000000000..89023be5535 --- /dev/null +++ b/protocols/dcutr/src/generated/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod holepunch; diff --git a/protocols/dcutr/src/lib.rs b/protocols/dcutr/src/lib.rs index d32ad011b5b..8d5db45000c 100644 --- a/protocols/dcutr/src/lib.rs +++ b/protocols/dcutr/src/lib.rs @@ -26,9 +26,10 @@ mod behaviour_impl; // TODO: Rename back `behaviour` once deprecation symbols are removed. mod handler; mod protocol; -#[allow(clippy::derive_partial_eq_without_eq)] -mod message_proto { - include!(concat!(env!("OUT_DIR"), "/holepunch.pb.rs")); + +mod proto { + include!("generated/mod.rs"); + pub use self::holepunch::pb::{mod_HolePunch::*, HolePunch}; } pub use behaviour_impl::Behaviour; diff --git a/protocols/dcutr/src/protocol/inbound.rs b/protocols/dcutr/src/protocol/inbound.rs index 05037da34dd..fde42c6c924 100644 --- a/protocols/dcutr/src/protocol/inbound.rs +++ b/protocols/dcutr/src/protocol/inbound.rs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::message_proto::{hole_punch, HolePunch}; +use crate::proto; use asynchronous_codec::Framed; use futures::{future::BoxFuture, prelude::*}; use libp2p_core::{multiaddr::Protocol, upgrade, Multiaddr}; @@ -46,19 +46,19 @@ impl upgrade::InboundUpgrade for Upgrade { fn upgrade_inbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future { let mut substream = Framed::new( substream, - prost_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES), + quick_protobuf_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES), ); async move { - let HolePunch { r#type, obs_addrs } = + let proto::HolePunch { type_pb, ObsAddrs } = substream.next().await.ok_or(UpgradeError::StreamClosed)??; - let obs_addrs = if obs_addrs.is_empty() { + let obs_addrs = if ObsAddrs.is_empty() { return Err(UpgradeError::NoAddresses); } else { - obs_addrs + ObsAddrs .into_iter() - .filter_map(|a| match Multiaddr::try_from(a) { + .filter_map(|a| match Multiaddr::try_from(a.to_vec()) { Ok(a) => Some(a), Err(e) => { log::debug!("Unable to parse multiaddr: {e}"); @@ -77,11 +77,9 @@ impl upgrade::InboundUpgrade for Upgrade { .collect::>() }; - let r#type = hole_punch::Type::from_i32(r#type).ok_or(UpgradeError::ParseTypeField)?; - - match r#type { - hole_punch::Type::Connect => {} - hole_punch::Type::Sync => return Err(UpgradeError::UnexpectedTypeSync), + match type_pb { + proto::Type::CONNECT => {} + proto::Type::SYNC => return Err(UpgradeError::UnexpectedTypeSync), } Ok(PendingConnect { @@ -94,7 +92,7 @@ impl upgrade::InboundUpgrade for Upgrade { } pub struct PendingConnect { - substream: Framed>, + substream: Framed>, remote_obs_addrs: Vec, } @@ -103,22 +101,21 @@ impl PendingConnect { mut self, local_obs_addrs: Vec, ) -> Result, UpgradeError> { - let msg = HolePunch { - r#type: hole_punch::Type::Connect.into(), - obs_addrs: local_obs_addrs.into_iter().map(|a| a.to_vec()).collect(), + let msg = proto::HolePunch { + type_pb: proto::Type::CONNECT, + ObsAddrs: local_obs_addrs.into_iter().map(|a| a.to_vec()).collect(), }; self.substream.send(msg).await?; - let HolePunch { r#type, .. } = self + let proto::HolePunch { type_pb, .. } = self .substream .next() .await .ok_or(UpgradeError::StreamClosed)??; - let r#type = hole_punch::Type::from_i32(r#type).ok_or(UpgradeError::ParseTypeField)?; - match r#type { - hole_punch::Type::Connect => return Err(UpgradeError::UnexpectedTypeConnect), - hole_punch::Type::Sync => {} + match type_pb { + proto::Type::CONNECT => return Err(UpgradeError::UnexpectedTypeConnect), + proto::Type::SYNC => {} } Ok(self.remote_obs_addrs) @@ -128,7 +125,7 @@ impl PendingConnect { #[derive(Debug, Error)] pub enum UpgradeError { #[error(transparent)] - Codec(#[from] prost_codec::Error), + Codec(#[from] quick_protobuf_codec::Error), #[error("Stream closed")] StreamClosed, #[error("Expected at least one address in reservation.")] diff --git a/protocols/dcutr/src/protocol/outbound.rs b/protocols/dcutr/src/protocol/outbound.rs index 20b3a781155..9bbb1eb89a8 100644 --- a/protocols/dcutr/src/protocol/outbound.rs +++ b/protocols/dcutr/src/protocol/outbound.rs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::message_proto::{hole_punch, HolePunch}; +use crate::proto; use asynchronous_codec::Framed; use futures::{future::BoxFuture, prelude::*}; use futures_timer::Delay; @@ -56,12 +56,12 @@ impl upgrade::OutboundUpgrade for Upgrade { fn upgrade_outbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future { let mut substream = Framed::new( substream, - prost_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES), + quick_protobuf_codec::Codec::new(super::MAX_MESSAGE_SIZE_BYTES), ); - let msg = HolePunch { - r#type: hole_punch::Type::Connect.into(), - obs_addrs: self.obs_addrs.into_iter().map(|a| a.to_vec()).collect(), + let msg = proto::HolePunch { + type_pb: proto::Type::CONNECT, + ObsAddrs: self.obs_addrs.into_iter().map(|a| a.to_vec()).collect(), }; async move { @@ -69,23 +69,22 @@ impl upgrade::OutboundUpgrade for Upgrade { let sent_time = Instant::now(); - let HolePunch { r#type, obs_addrs } = + let proto::HolePunch { type_pb, ObsAddrs } = substream.next().await.ok_or(UpgradeError::StreamClosed)??; let rtt = sent_time.elapsed(); - let r#type = hole_punch::Type::from_i32(r#type).ok_or(UpgradeError::ParseTypeField)?; - match r#type { - hole_punch::Type::Connect => {} - hole_punch::Type::Sync => return Err(UpgradeError::UnexpectedTypeSync), + match type_pb { + proto::Type::CONNECT => {} + proto::Type::SYNC => return Err(UpgradeError::UnexpectedTypeSync), } - let obs_addrs = if obs_addrs.is_empty() { + let obs_addrs = if ObsAddrs.is_empty() { return Err(UpgradeError::NoAddresses); } else { - obs_addrs + ObsAddrs .into_iter() - .filter_map(|a| match Multiaddr::try_from(a) { + .filter_map(|a| match Multiaddr::try_from(a.to_vec()) { Ok(a) => Some(a), Err(e) => { log::debug!("Unable to parse multiaddr: {e}"); @@ -104,9 +103,9 @@ impl upgrade::OutboundUpgrade for Upgrade { .collect::>() }; - let msg = HolePunch { - r#type: hole_punch::Type::Sync.into(), - obs_addrs: vec![], + let msg = proto::HolePunch { + type_pb: proto::Type::SYNC, + ObsAddrs: vec![], }; substream.send(msg).await?; @@ -126,7 +125,7 @@ pub struct Connect { #[derive(Debug, Error)] pub enum UpgradeError { #[error(transparent)] - Codec(#[from] prost_codec::Error), + Codec(#[from] quick_protobuf_codec::Error), #[error("Stream closed")] StreamClosed, #[error("Expected 'status' field to be set.")] diff --git a/protocols/floodsub/CHANGELOG.md b/protocols/floodsub/CHANGELOG.md index f78ba40a8d1..fc6c12ecf27 100644 --- a/protocols/floodsub/CHANGELOG.md +++ b/protocols/floodsub/CHANGELOG.md @@ -4,9 +4,9 @@ - Update to `libp2p-swarm` `v0.42.0`. -- Read and write protocols messages via `prost-codec`. See [PR 3224]. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. -[pr 3224]: https://github.com/libp2p/rust-libp2p/pull/3224 +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 # 0.41.0 diff --git a/protocols/floodsub/Cargo.toml b/protocols/floodsub/Cargo.toml index a9ee28e77b0..5b8686e5691 100644 --- a/protocols/floodsub/Cargo.toml +++ b/protocols/floodsub/Cargo.toml @@ -18,15 +18,12 @@ futures = "0.3.26" libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-swarm = { version = "0.42.0", path = "../../swarm" } log = "0.4" -prost = "0.11" -prost-codec = { version = "0.3", path = "../../misc/prost-codec" } +quick-protobuf = "0.8" +quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" } rand = "0.8" smallvec = "1.6.1" thiserror = "1.0.37" -[build-dependencies] -prost-build = "0.11" - # Passing arguments to the docsrs builder in order to properly document cfg's. # More information: https://docs.rs/about/builds#cross-compiling [package.metadata.docs.rs] diff --git a/protocols/floodsub/build.rs b/protocols/floodsub/build.rs deleted file mode 100644 index a3de99880dc..00000000000 --- a/protocols/floodsub/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -fn main() { - prost_build::compile_protos(&["src/rpc.proto"], &["src"]).unwrap(); -} diff --git a/protocols/floodsub/src/generated/floodsub/mod.rs b/protocols/floodsub/src/generated/floodsub/mod.rs new file mode 100644 index 00000000000..aec6164c7ef --- /dev/null +++ b/protocols/floodsub/src/generated/floodsub/mod.rs @@ -0,0 +1,2 @@ +// 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 new file mode 100644 index 00000000000..a11135ad053 --- /dev/null +++ b/protocols/floodsub/src/generated/floodsub/pb.rs @@ -0,0 +1,137 @@ +// Automatically generated rust module for 'rpc.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::super::*; + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct RPC { + pub subscriptions: Vec, + 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 new file mode 100644 index 00000000000..1cef0041eb6 --- /dev/null +++ b/protocols/floodsub/src/generated/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod floodsub; diff --git a/protocols/floodsub/src/rpc.proto b/protocols/floodsub/src/generated/rpc.proto similarity index 100% rename from protocols/floodsub/src/rpc.proto rename to protocols/floodsub/src/generated/rpc.proto diff --git a/protocols/floodsub/src/lib.rs b/protocols/floodsub/src/lib.rs index 7a37bfd9c21..c0d1327f2df 100644 --- a/protocols/floodsub/src/lib.rs +++ b/protocols/floodsub/src/lib.rs @@ -29,9 +29,9 @@ pub mod protocol; mod layer; mod topic; -#[allow(clippy::derive_partial_eq_without_eq)] -mod rpc_proto { - include!(concat!(env!("OUT_DIR"), "/floodsub.pb.rs")); +mod proto { + include!("generated/mod.rs"); + pub use self::floodsub::pb::{mod_RPC::SubOpts, Message, RPC}; } pub use self::layer::{Floodsub, FloodsubEvent}; diff --git a/protocols/floodsub/src/protocol.rs b/protocols/floodsub/src/protocol.rs index fe3f2859437..7a70806606d 100644 --- a/protocols/floodsub/src/protocol.rs +++ b/protocols/floodsub/src/protocol.rs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::rpc_proto; +use crate::proto; use crate::topic::Topic; use asynchronous_codec::Framed; use futures::{ @@ -65,7 +65,7 @@ where Box::pin(async move { let mut framed = Framed::new( socket, - prost_codec::Codec::::new(MAX_MESSAGE_LEN_BYTES), + quick_protobuf_codec::Codec::::new(MAX_MESSAGE_LEN_BYTES), ); let rpc = framed @@ -120,7 +120,7 @@ pub enum FloodsubError { #[derive(thiserror::Error, Debug)] #[error(transparent)] -pub struct CodecError(#[from] prost_codec::Error); +pub struct CodecError(#[from] quick_protobuf_codec::Error); /// An RPC received by the floodsub system. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -152,7 +152,7 @@ where Box::pin(async move { let mut framed = Framed::new( socket, - prost_codec::Codec::::new(MAX_MESSAGE_LEN_BYTES), + quick_protobuf_codec::Codec::::new(MAX_MESSAGE_LEN_BYTES), ); framed.send(self.into_rpc()).await?; framed.close().await?; @@ -163,12 +163,12 @@ where impl FloodsubRpc { /// Turns this `FloodsubRpc` into a message that can be sent to a substream. - fn into_rpc(self) -> rpc_proto::Rpc { - rpc_proto::Rpc { + fn into_rpc(self) -> proto::RPC { + proto::RPC { publish: self .messages .into_iter() - .map(|msg| rpc_proto::Message { + .map(|msg| proto::Message { from: Some(msg.source.to_bytes()), data: Some(msg.data), seqno: Some(msg.sequence_number), @@ -179,7 +179,7 @@ impl FloodsubRpc { subscriptions: self .subscriptions .into_iter() - .map(|topic| rpc_proto::rpc::SubOpts { + .map(|topic| proto::SubOpts { subscribe: Some(topic.action == FloodsubSubscriptionAction::Subscribe), topic_id: Some(topic.topic.into()), }) diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index 636575d6a51..ac8dd8cbf40 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -14,10 +14,13 @@ It is preferred to import the gossipsub protocol as a module (`use libp2p::gossipsub;`), and refer to its types via `gossipsub::`. For example: `gossipsub::Behaviour` or `gossipsub::RawMessage`. See [PR 3303]. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. + [PR 3207]: https://github.com/libp2p/rust-libp2p/pull/3207/ [PR 3303]: https://github.com/libp2p/rust-libp2p/pull/3303/ [PR 3381]: https://github.com/libp2p/rust-libp2p/pull/3381/ [discussion 2174]: https://github.com/libp2p/rust-libp2p/discussions/2174 +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 # 0.43.0 diff --git a/protocols/gossipsub/Cargo.toml b/protocols/gossipsub/Cargo.toml index 103142f8c25..b494548111f 100644 --- a/protocols/gossipsub/Cargo.toml +++ b/protocols/gossipsub/Cargo.toml @@ -24,8 +24,8 @@ log = "0.4.11" sha2 = "0.10.0" base64 = "0.21.0" smallvec = "1.6.1" -prost = "0.11" -prost-codec = { version = "0.3", path = "../../misc/prost-codec" } +quick-protobuf = "0.8" +quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" } hex_fmt = "0.3.0" regex = "1.5.5" serde = { version = "1", optional = true, features = ["derive"] } @@ -46,9 +46,6 @@ libp2p-swarm = { path = "../../swarm" } libp2p-yamux = { path = "../../muxers/yamux" } quickcheck = { package = "quickcheck-ext", path = "../../misc/quickcheck-ext" } -[build-dependencies] -prost-build = "0.11" - # Passing arguments to the docsrs builder in order to properly document cfg's. # More information: https://docs.rs/about/builds#cross-compiling [package.metadata.docs.rs] diff --git a/protocols/gossipsub/build.rs b/protocols/gossipsub/build.rs deleted file mode 100644 index a0c81052bdc..00000000000 --- a/protocols/gossipsub/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -fn main() { - prost_build::compile_protos(&["src/rpc.proto", "src/compat.proto"], &["src"]).unwrap(); -} diff --git a/protocols/gossipsub/src/behaviour.rs b/protocols/gossipsub/src/behaviour.rs index 8346e2317a0..9e778fd1b0f 100644 --- a/protocols/gossipsub/src/behaviour.rs +++ b/protocols/gossipsub/src/behaviour.rs @@ -32,7 +32,6 @@ use std::{ use futures::StreamExt; use log::{debug, error, trace, warn}; use prometheus_client::registry::Registry; -use prost::Message as _; use rand::{seq::SliceRandom, thread_rng}; use libp2p_core::{ @@ -64,8 +63,9 @@ use crate::types::{ Subscription, SubscriptionAction, }; use crate::types::{PeerConnections, PeerKind, Rpc}; -use crate::{rpc_proto, TopicScoreParams}; +use crate::{rpc_proto::proto, TopicScoreParams}; use crate::{PublishError, SubscriptionError, ValidationError}; +use quick_protobuf::{MessageWrite, Writer}; use std::{cmp::Ordering::Equal, fmt::Debug}; use wasm_timer::Interval; @@ -179,8 +179,8 @@ impl From for PublishConfig { let public_key = keypair.public(); let key_enc = public_key.to_protobuf_encoding(); let key = if key_enc.len() <= 42 { - // The public key can be inlined in [`rpc_proto::Message::from`], so we don't include it - // specifically in the [`rpc_proto::Message::key`] field. + // The public key can be inlined in [`rpc_proto::proto::::Message::from`], so we don't include it + // specifically in the [`rpc_proto::proto::Message::key`] field. None } else { // Include the protobuf encoding of the public key in the message. @@ -610,7 +610,7 @@ where .into_protobuf(); // check that the size doesn't exceed the max transmission size - if event.encoded_len() > self.config.max_transmit_size() { + if event.get_size() > self.config.max_transmit_size() { return Err(PublishError::MessageTooLarge); } @@ -721,7 +721,7 @@ where } // Send to peers we know are subscribed to the topic. - let msg_bytes = event.encoded_len(); + let msg_bytes = event.get_size(); for peer_id in recipient_peers.iter() { trace!("Sending message to peer: {:?}", peer_id); self.send_message(*peer_id, event.clone())?; @@ -1338,7 +1338,7 @@ where } .into_protobuf(); - let msg_bytes = message.encoded_len(); + let msg_bytes = message.get_size(); if self.send_message(*peer_id, message).is_err() { error!("Failed to send cached messages. Messages too large"); @@ -2733,7 +2733,7 @@ where } .into_protobuf(); - let msg_bytes = event.encoded_len(); + let msg_bytes = event.get_size(); for peer in recipient_peers.iter() { debug!("Sending message: {:?} to peer {:?}", msg_id, peer); self.send_message(*peer, event.clone())?; @@ -2764,7 +2764,7 @@ where let sequence_number: u64 = rand::random(); let signature = { - let message = rpc_proto::Message { + let message = proto::Message { from: Some(author.clone().to_bytes()), data: Some(data.clone()), seqno: Some(sequence_number.to_be_bytes().to_vec()), @@ -2773,10 +2773,12 @@ where key: None, }; - let mut buf = Vec::with_capacity(message.encoded_len()); + let mut buf = Vec::with_capacity(message.get_size()); + let mut writer = Writer::new(&mut buf); + message - .encode(&mut buf) - .expect("Buffer has sufficient capacity"); + .write_message(&mut writer) + .expect("Encoding to succeed"); // the signature is over the bytes "libp2p-pubsub:" let mut signature_bytes = SIGNING_PREFIX.to_vec(); @@ -2875,11 +2877,7 @@ where /// Send a [`Rpc`] message to a peer. This will wrap the message in an arc if it /// is not already an arc. - fn send_message( - &mut self, - peer_id: PeerId, - message: rpc_proto::Rpc, - ) -> Result<(), PublishError> { + fn send_message(&mut self, peer_id: PeerId, message: proto::RPC) -> Result<(), PublishError> { // If the message is oversized, try and fragment it. If it cannot be fragmented, log an // error and drop the message (all individual messages should be small enough to fit in the // max_transmit_size) @@ -2899,12 +2897,12 @@ where // If a message is too large to be sent as-is, this attempts to fragment it into smaller RPC // messages to be sent. - fn fragment_message(&self, rpc: rpc_proto::Rpc) -> Result, PublishError> { - if rpc.encoded_len() < self.config.max_transmit_size() { + fn fragment_message(&self, rpc: proto::RPC) -> Result, PublishError> { + if rpc.get_size() < self.config.max_transmit_size() { return Ok(vec![rpc]); } - let new_rpc = rpc_proto::Rpc { + let new_rpc = proto::RPC { subscriptions: Vec::new(), publish: Vec::new(), control: None, @@ -2920,7 +2918,7 @@ where // create a new RPC if the new object plus 5% of its size (for length prefix // buffers) exceeds the max transmit size. - if rpc_list[list_index].encoded_len() + (($object_size as f64) * 1.05) as usize + if rpc_list[list_index].get_size() + (($object_size as f64) * 1.05) as usize > self.config.max_transmit_size() && rpc_list[list_index] != new_rpc { @@ -2932,7 +2930,7 @@ where macro_rules! add_item { ($object: ident, $type: ident ) => { - let object_size = $object.encoded_len(); + let object_size = $object.get_size(); if object_size + 2 > self.config.max_transmit_size() { // This should not be possible. All received and published messages have already @@ -2960,12 +2958,12 @@ where // handle the control messages. If all are within the max_transmit_size, send them without // fragmenting, otherwise, fragment the control messages - let empty_control = rpc_proto::ControlMessage::default(); + let empty_control = proto::ControlMessage::default(); if let Some(control) = rpc.control.as_ref() { - if control.encoded_len() + 2 > self.config.max_transmit_size() { + if control.get_size() + 2 > self.config.max_transmit_size() { // fragment the RPC for ihave in &control.ihave { - let len = ihave.encoded_len(); + let len = ihave.get_size(); create_or_add_rpc!(len); rpc_list .last_mut() @@ -2976,7 +2974,7 @@ where .push(ihave.clone()); } for iwant in &control.iwant { - let len = iwant.encoded_len(); + let len = iwant.get_size(); create_or_add_rpc!(len); rpc_list .last_mut() @@ -2987,7 +2985,7 @@ where .push(iwant.clone()); } for graft in &control.graft { - let len = graft.encoded_len(); + let len = graft.get_size(); create_or_add_rpc!(len); rpc_list .last_mut() @@ -2998,7 +2996,7 @@ where .push(graft.clone()); } for prune in &control.prune { - let len = prune.encoded_len(); + let len = prune.get_size(); create_or_add_rpc!(len); rpc_list .last_mut() @@ -3009,7 +3007,7 @@ where .push(prune.clone()); } } else { - let len = control.encoded_len(); + let len = control.get_size(); create_or_add_rpc!(len); rpc_list.last_mut().expect("Always an element").control = Some(control.clone()); } @@ -3769,7 +3767,7 @@ mod local_test { // Messages over the limit should be split - while rpc_proto.encoded_len() < max_transmit_size { + while rpc_proto.get_size() < max_transmit_size { rpc.messages.push(test_message()); rpc_proto = rpc.clone().into_protobuf(); } @@ -3786,7 +3784,7 @@ mod local_test { // all fragmented messages should be under the limit for message in fragmented_messages { assert!( - message.encoded_len() < max_transmit_size, + message.get_size() < max_transmit_size, "all messages should be less than the transmission size" ); } @@ -3813,7 +3811,7 @@ mod local_test { .fragment_message(rpc_proto.clone()) .expect("Messages must be valid"); - if rpc_proto.encoded_len() < max_transmit_size { + if rpc_proto.get_size() < max_transmit_size { assert_eq!( fragmented_messages.len(), 1, @@ -3829,12 +3827,12 @@ mod local_test { // all fragmented messages should be under the limit for message in fragmented_messages { assert!( - message.encoded_len() < max_transmit_size, - "all messages should be less than the transmission size: list size {} max size{}", message.encoded_len(), max_transmit_size + message.get_size() < max_transmit_size, + "all messages should be less than the transmission size: list size {} max size{}", message.get_size(), max_transmit_size ); // ensure they can all be encoded - let mut buf = bytes::BytesMut::with_capacity(message.encoded_len()); + let mut buf = bytes::BytesMut::with_capacity(message.get_size()); codec.encode(message, &mut buf).unwrap() } } diff --git a/protocols/gossipsub/src/behaviour/tests.rs b/protocols/gossipsub/src/behaviour/tests.rs index d91bfdc8a28..6502c5986ec 100644 --- a/protocols/gossipsub/src/behaviour/tests.rs +++ b/protocols/gossipsub/src/behaviour/tests.rs @@ -284,7 +284,7 @@ where } // Converts a protobuf message into a gossipsub message for reading the Gossipsub event queue. -fn proto_to_message(rpc: &crate::rpc_proto::Rpc) -> Rpc { +fn proto_to_message(rpc: &proto::RPC) -> Rpc { // Store valid messages. let mut messages = Vec::with_capacity(rpc.publish.len()); let rpc = rpc.clone(); diff --git a/protocols/gossipsub/src/error_priv.rs b/protocols/gossipsub/src/error_priv.rs index fdd6dcbe55b..09bbfbb3543 100644 --- a/protocols/gossipsub/src/error_priv.rs +++ b/protocols/gossipsub/src/error_priv.rs @@ -100,7 +100,7 @@ pub enum HandlerError { #[error("Protocol negotiation failed.")] NegotiationProtocolError(ProtocolError), #[error("Failed to encode or decode")] - Codec(#[from] prost_codec::Error), + Codec(#[from] quick_protobuf_codec::Error), } #[derive(Debug, Clone, Copy)] @@ -136,7 +136,7 @@ impl std::error::Error for ValidationError {} impl From for HandlerError { fn from(error: std::io::Error) -> HandlerError { - HandlerError::Codec(prost_codec::Error::from(error)) + HandlerError::Codec(quick_protobuf_codec::Error::from(error)) } } diff --git a/protocols/gossipsub/src/compat.proto b/protocols/gossipsub/src/generated/compat.proto similarity index 100% rename from protocols/gossipsub/src/compat.proto rename to protocols/gossipsub/src/generated/compat.proto diff --git a/protocols/gossipsub/src/generated/compat/mod.rs b/protocols/gossipsub/src/generated/compat/mod.rs new file mode 100644 index 00000000000..aec6164c7ef --- /dev/null +++ b/protocols/gossipsub/src/generated/compat/mod.rs @@ -0,0 +1,2 @@ +// 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 new file mode 100644 index 00000000000..fd59c38e2b4 --- /dev/null +++ b/protocols/gossipsub/src/generated/compat/pb.rs @@ -0,0 +1,67 @@ +// Automatically generated rust module for 'compat.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::super::*; + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct Message { + pub from: Option>, + 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/mod.rs b/protocols/gossipsub/src/generated/gossipsub/mod.rs new file mode 100644 index 00000000000..aec6164c7ef --- /dev/null +++ b/protocols/gossipsub/src/generated/gossipsub/mod.rs @@ -0,0 +1,2 @@ +// 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 new file mode 100644 index 00000000000..9a074fd61fc --- /dev/null +++ b/protocols/gossipsub/src/generated/gossipsub/pb.rs @@ -0,0 +1,567 @@ +// Automatically generated rust module for 'rpc.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::super::*; + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct RPC { + pub subscriptions: Vec, + pub publish: Vec, + pub control: 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(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())) + } + + 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))?; } + 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: 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, +} + +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(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::() + } + + 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))?; } + 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 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(), + } + } +} + +} + +} + diff --git a/protocols/gossipsub/src/generated/mod.rs b/protocols/gossipsub/src/generated/mod.rs new file mode 100644 index 00000000000..7ac564f3c36 --- /dev/null +++ b/protocols/gossipsub/src/generated/mod.rs @@ -0,0 +1,3 @@ +// Automatically generated mod.rs +pub mod compat; +pub mod gossipsub; diff --git a/protocols/gossipsub/src/rpc.proto b/protocols/gossipsub/src/generated/rpc.proto similarity index 100% rename from protocols/gossipsub/src/rpc.proto rename to protocols/gossipsub/src/generated/rpc.proto diff --git a/protocols/gossipsub/src/handler.rs b/protocols/gossipsub/src/handler.rs index 0b8fcc72768..2c921286553 100644 --- a/protocols/gossipsub/src/handler.rs +++ b/protocols/gossipsub/src/handler.rs @@ -19,6 +19,7 @@ // DEALINGS IN THE SOFTWARE. use crate::protocol::{GossipsubCodec, ProtocolConfig}; +use crate::rpc_proto::proto; use crate::types::{PeerKind, RawMessage, Rpc}; use crate::{HandlerError, ValidationError}; use asynchronous_codec::Framed; @@ -67,7 +68,7 @@ pub enum HandlerEvent { #[derive(Debug)] pub enum HandlerIn { /// A gossipsub message to send. - Message(crate::rpc_proto::Rpc), + Message(proto::RPC), /// The peer has joined the mesh. JoinedMesh, /// The peer has left the mesh. @@ -93,7 +94,7 @@ pub struct Handler { inbound_substream: Option, /// Queue of values that we want to send to the remote. - send_queue: SmallVec<[crate::rpc_proto::Rpc; 16]>, + send_queue: SmallVec<[proto::RPC; 16]>, /// Flag indicating that an outbound substream is being established to prevent duplicate /// requests. @@ -149,10 +150,7 @@ enum OutboundSubstreamState { /// Waiting for the user to send a message. The idle state for an outbound substream. WaitingOutput(Framed), /// Waiting to send a message to the remote. - PendingSend( - Framed, - crate::rpc_proto::Rpc, - ), + PendingSend(Framed, proto::RPC), /// Waiting to flush the substream so that the data arrives to the remote. PendingFlush(Framed), /// The substream is being closed. Used by either substream. @@ -251,7 +249,7 @@ impl ConnectionHandler for Handler { type Error = HandlerError; type InboundOpenInfo = (); type InboundProtocol = ProtocolConfig; - type OutboundOpenInfo = crate::rpc_proto::Rpc; + type OutboundOpenInfo = proto::RPC; type OutboundProtocol = ProtocolConfig; fn listen_protocol(&self) -> SubstreamProtocol { diff --git a/protocols/gossipsub/src/protocol.rs b/protocols/gossipsub/src/protocol.rs index 9d9b460cee6..9fafbc04fa2 100644 --- a/protocols/gossipsub/src/protocol.rs +++ b/protocols/gossipsub/src/protocol.rs @@ -24,7 +24,7 @@ use crate::topic::TopicHash; use crate::types::{ ControlAction, MessageId, PeerInfo, PeerKind, RawMessage, Rpc, Subscription, SubscriptionAction, }; -use crate::{rpc_proto, Config}; +use crate::{rpc_proto::proto, Config}; use crate::{HandlerError, ValidationError}; use asynchronous_codec::{Decoder, Encoder, Framed}; use byteorder::{BigEndian, ByteOrder}; @@ -35,7 +35,7 @@ use libp2p_core::{ identity::PublicKey, InboundUpgrade, OutboundUpgrade, PeerId, ProtocolName, UpgradeInfo, }; use log::{debug, warn}; -use prost::Message as _; +use quick_protobuf::Writer; use std::pin::Pin; use unsigned_varint::codec; @@ -191,12 +191,12 @@ pub struct GossipsubCodec { /// Determines the level of validation performed on incoming messages. validation_mode: ValidationMode, /// The codec to handle common encoding/decoding of protobuf messages - codec: prost_codec::Codec, + codec: quick_protobuf_codec::Codec, } impl GossipsubCodec { pub fn new(length_codec: codec::UviBytes, validation_mode: ValidationMode) -> GossipsubCodec { - let codec = prost_codec::Codec::new(length_codec.max_len()); + let codec = quick_protobuf_codec::Codec::new(length_codec.max_len()); GossipsubCodec { validation_mode, codec, @@ -206,7 +206,9 @@ impl GossipsubCodec { /// Verifies a gossipsub message. This returns either a success or failure. All errors /// are logged, which prevents error handling in the codec and handler. We simply drop invalid /// messages and log warnings, rather than propagating errors through the codec. - fn verify_signature(message: &rpc_proto::Message) -> bool { + fn verify_signature(message: &proto::Message) -> bool { + use quick_protobuf::MessageWrite; + let from = match message.from.as_ref() { Some(v) => v, None => { @@ -258,10 +260,11 @@ impl GossipsubCodec { let mut message_sig = message.clone(); message_sig.signature = None; message_sig.key = None; - let mut buf = Vec::with_capacity(message_sig.encoded_len()); + let mut buf = Vec::with_capacity(message_sig.get_size()); + let mut writer = Writer::new(&mut buf); message_sig - .encode(&mut buf) - .expect("Buffer has sufficient capacity"); + .write_message(&mut writer) + .expect("Encoding to succeed"); let mut signature_bytes = SIGNING_PREFIX.to_vec(); signature_bytes.extend_from_slice(&buf); public_key.verify(&signature_bytes, signature) @@ -269,7 +272,7 @@ impl GossipsubCodec { } impl Encoder for GossipsubCodec { - type Item = rpc_proto::Rpc; + type Item = proto::RPC; type Error = HandlerError; fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), HandlerError> { diff --git a/protocols/gossipsub/src/rpc_proto.rs b/protocols/gossipsub/src/rpc_proto.rs index 7b952ef0926..5d198f2f575 100644 --- a/protocols/gossipsub/src/rpc_proto.rs +++ b/protocols/gossipsub/src/rpc_proto.rs @@ -17,27 +17,26 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -#![allow(clippy::derive_partial_eq_without_eq)] -include!(concat!(env!("OUT_DIR"), "/gossipsub.pb.rs")); +pub mod proto { + include!("generated/mod.rs"); + pub use self::gossipsub::pb::{mod_RPC::SubOpts, *}; +} #[cfg(test)] mod test { + use crate::rpc_proto::proto::compat; use crate::IdentTopic as Topic; use libp2p_core::PeerId; - use prost::Message; + use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer}; use rand::Rng; - mod compat_proto { - include!(concat!(env!("OUT_DIR"), "/compat.pb.rs")); - } - #[test] fn test_multi_topic_message_compatibility() { let topic1 = Topic::new("t1").hash(); let topic2 = Topic::new("t2").hash(); - let new_message1 = super::Message { + let new_message1 = super::proto::Message { from: Some(PeerId::random().to_bytes()), data: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), seqno: Some(rand::thread_rng().gen::<[u8; 8]>().to_vec()), @@ -45,7 +44,7 @@ mod test { signature: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), key: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), }; - let old_message1 = compat_proto::Message { + let old_message1 = compat::pb::Message { from: Some(PeerId::random().to_bytes()), data: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), seqno: Some(rand::thread_rng().gen::<[u8; 8]>().to_vec()), @@ -53,7 +52,7 @@ mod test { signature: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), key: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), }; - let old_message2 = compat_proto::Message { + let old_message2 = compat::pb::Message { from: Some(PeerId::random().to_bytes()), data: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), seqno: Some(rand::thread_rng().gen::<[u8; 8]>().to_vec()), @@ -62,22 +61,31 @@ mod test { key: Some(rand::thread_rng().gen::<[u8; 32]>().to_vec()), }; - let mut new_message1b = Vec::with_capacity(new_message1.encoded_len()); - new_message1.encode(&mut new_message1b).unwrap(); + let mut new_message1b = Vec::with_capacity(new_message1.get_size()); + let mut writer = Writer::new(&mut new_message1b); + new_message1.write_message(&mut writer).unwrap(); - let mut old_message1b = Vec::with_capacity(old_message1.encoded_len()); - old_message1.encode(&mut old_message1b).unwrap(); + let mut old_message1b = Vec::with_capacity(old_message1.get_size()); + let mut writer = Writer::new(&mut old_message1b); + old_message1.write_message(&mut writer).unwrap(); - let mut old_message2b = Vec::with_capacity(old_message2.encoded_len()); - old_message2.encode(&mut old_message2b).unwrap(); + let mut old_message2b = Vec::with_capacity(old_message2.get_size()); + let mut writer = Writer::new(&mut old_message2b); + old_message2.write_message(&mut writer).unwrap(); - let new_message = super::Message::decode(&old_message1b[..]).unwrap(); + let mut reader = BytesReader::from_bytes(&old_message1b[..]); + let new_message = + super::proto::Message::from_reader(&mut reader, &old_message1b[..]).unwrap(); assert_eq!(new_message.topic, topic1.clone().into_string()); - let new_message = super::Message::decode(&old_message2b[..]).unwrap(); + let mut reader = BytesReader::from_bytes(&old_message2b[..]); + let new_message = + super::proto::Message::from_reader(&mut reader, &old_message2b[..]).unwrap(); assert_eq!(new_message.topic, topic2.into_string()); - let old_message = compat_proto::Message::decode(&new_message1b[..]).unwrap(); + let mut reader = BytesReader::from_bytes(&new_message1b[..]); + let old_message = + compat::pb::Message::from_reader(&mut reader, &new_message1b[..]).unwrap(); assert_eq!(old_message.topic_ids, vec![topic1.into_string()]); } } diff --git a/protocols/gossipsub/src/topic.rs b/protocols/gossipsub/src/topic.rs index 18a498cce03..a73496b53f2 100644 --- a/protocols/gossipsub/src/topic.rs +++ b/protocols/gossipsub/src/topic.rs @@ -18,10 +18,10 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::rpc_proto; +use crate::rpc_proto::proto; use base64::prelude::*; use prometheus_client::encoding::EncodeLabelSet; -use prost::Message; +use quick_protobuf::Writer; use sha2::{Digest, Sha256}; use std::fmt; @@ -47,15 +47,18 @@ impl Hasher for Sha256Hash { /// Creates a [`TopicHash`] by SHA256 hashing the topic then base64 encoding the /// hash. fn hash(topic_string: String) -> TopicHash { - let topic_descripter = rpc_proto::TopicDescriptor { + use quick_protobuf::MessageWrite; + + let topic_descripter = proto::TopicDescriptor { name: Some(topic_string), auth: None, enc: None, }; - let mut bytes = Vec::with_capacity(topic_descripter.encoded_len()); + let mut bytes = Vec::with_capacity(topic_descripter.get_size()); + let mut writer = Writer::new(&mut bytes); topic_descripter - .encode(&mut bytes) - .expect("buffer is large enough"); + .write_message(&mut writer) + .expect("Encoding to succeed"); let hash = BASE64_STANDARD.encode(Sha256::digest(&bytes)); TopicHash { hash } } diff --git a/protocols/gossipsub/src/types.rs b/protocols/gossipsub/src/types.rs index 03e6fc05a1d..5a3f54752da 100644 --- a/protocols/gossipsub/src/types.rs +++ b/protocols/gossipsub/src/types.rs @@ -19,15 +19,15 @@ // DEALINGS IN THE SOFTWARE. //! A collection of types using the Gossipsub system. -use crate::rpc_proto; use crate::TopicHash; use libp2p_core::PeerId; use libp2p_swarm::ConnectionId; use prometheus_client::encoding::EncodeLabelValue; -use prost::Message as _; +use quick_protobuf::MessageWrite; use std::fmt; use std::fmt::Debug; +use crate::rpc_proto::proto; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -136,7 +136,7 @@ pub struct RawMessage { impl RawMessage { /// Calculates the encoded length of this message (used for calculating metrics). pub fn raw_protobuf_len(&self) -> usize { - let message = rpc_proto::Message { + let message = proto::Message { from: self.source.map(|m| m.to_bytes()), data: Some(self.data.clone()), seqno: self.sequence_number.map(|s| s.to_be_bytes().to_vec()), @@ -144,7 +144,7 @@ impl RawMessage { signature: self.signature.clone(), key: self.key.clone(), }; - message.encoded_len() + message.get_size() } } @@ -250,19 +250,19 @@ pub struct Rpc { impl Rpc { /// Converts the GossipsubRPC into its protobuf format. // A convenience function to avoid explicitly specifying types. - pub fn into_protobuf(self) -> rpc_proto::Rpc { + pub fn into_protobuf(self) -> proto::RPC { self.into() } } -impl From for rpc_proto::Rpc { +impl From for proto::RPC { /// Converts the RPC into protobuf format. fn from(rpc: Rpc) -> Self { // Messages let mut publish = Vec::new(); for message in rpc.messages.into_iter() { - let message = rpc_proto::Message { + let message = proto::Message { from: message.source.map(|m| m.to_bytes()), data: Some(message.data), seqno: message.sequence_number.map(|s| s.to_be_bytes().to_vec()), @@ -278,14 +278,14 @@ impl From for rpc_proto::Rpc { let subscriptions = rpc .subscriptions .into_iter() - .map(|sub| rpc_proto::rpc::SubOpts { + .map(|sub| proto::SubOpts { subscribe: Some(sub.action == SubscriptionAction::Subscribe), topic_id: Some(sub.topic_hash.into_string()), }) .collect::>(); // control messages - let mut control = rpc_proto::ControlMessage { + let mut control = proto::ControlMessage { ihave: Vec::new(), iwant: Vec::new(), graft: Vec::new(), @@ -301,20 +301,20 @@ impl From for rpc_proto::Rpc { topic_hash, message_ids, } => { - let rpc_ihave = rpc_proto::ControlIHave { + let rpc_ihave = proto::ControlIHave { topic_id: Some(topic_hash.into_string()), message_ids: message_ids.into_iter().map(|msg_id| msg_id.0).collect(), }; control.ihave.push(rpc_ihave); } ControlAction::IWant { message_ids } => { - let rpc_iwant = rpc_proto::ControlIWant { + let rpc_iwant = proto::ControlIWant { message_ids: message_ids.into_iter().map(|msg_id| msg_id.0).collect(), }; control.iwant.push(rpc_iwant); } ControlAction::Graft { topic_hash } => { - let rpc_graft = rpc_proto::ControlGraft { + let rpc_graft = proto::ControlGraft { topic_id: Some(topic_hash.into_string()), }; control.graft.push(rpc_graft); @@ -324,11 +324,11 @@ impl From for rpc_proto::Rpc { peers, backoff, } => { - let rpc_prune = rpc_proto::ControlPrune { + let rpc_prune = proto::ControlPrune { topic_id: Some(topic_hash.into_string()), peers: peers .into_iter() - .map(|info| rpc_proto::PeerInfo { + .map(|info| proto::PeerInfo { peer_id: info.peer_id.map(|id| id.to_bytes()), /// TODO, see https://github.com/libp2p/specs/pull/217 signed_peer_record: None, @@ -341,7 +341,7 @@ impl From for rpc_proto::Rpc { } } - rpc_proto::Rpc { + proto::RPC { subscriptions, publish, control: if empty_control_msg { diff --git a/protocols/identify/CHANGELOG.md b/protocols/identify/CHANGELOG.md index 268ea43d910..9411d0bb7fd 100644 --- a/protocols/identify/CHANGELOG.md +++ b/protocols/identify/CHANGELOG.md @@ -9,8 +9,11 @@ - Don't close the stream when reading the identify info in `protocol::recv`. See [PR 3344]. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. + [PR 3208]: https://github.com/libp2p/rust-libp2p/pull/3208 [PR 3344]: https://github.com/libp2p/rust-libp2p/pull/3344 +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 # 0.41.1 diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml index 9f9a5fa2fe0..35a783a4ea8 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -18,8 +18,8 @@ libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-swarm = { version = "0.42.0", path = "../../swarm" } log = "0.4.1" lru = "0.9.0" -prost-codec = { version = "0.3", path = "../../misc/prost-codec" } -prost = "0.11" +quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" } +quick-protobuf = "0.8" smallvec = "1.6.1" thiserror = "1.0" void = "1.0" @@ -34,9 +34,6 @@ libp2p-noise = { path = "../../transports/noise" } libp2p-swarm = { path = "../../swarm", features = ["async-std"] } libp2p-tcp = { path = "../../transports/tcp", features = ["async-io"] } -[build-dependencies] -prost-build = "0.11" - # Passing arguments to the docsrs builder in order to properly document cfg's. # More information: https://docs.rs/about/builds#cross-compiling [package.metadata.docs.rs] diff --git a/protocols/identify/build.rs b/protocols/identify/build.rs deleted file mode 100644 index 56c7b20121a..00000000000 --- a/protocols/identify/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -fn main() { - prost_build::compile_protos(&["src/structs.proto"], &["src"]).unwrap(); -} diff --git a/protocols/identify/src/generated/mod.rs b/protocols/identify/src/generated/mod.rs new file mode 100644 index 00000000000..e52c5a80bc0 --- /dev/null +++ b/protocols/identify/src/generated/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod structs; diff --git a/protocols/identify/src/structs.proto b/protocols/identify/src/generated/structs.proto similarity index 100% rename from protocols/identify/src/structs.proto rename to protocols/identify/src/generated/structs.proto diff --git a/protocols/identify/src/generated/structs.rs b/protocols/identify/src/generated/structs.rs new file mode 100644 index 00000000000..3be9b6f94ad --- /dev/null +++ b/protocols/identify/src/generated/structs.rs @@ -0,0 +1,67 @@ +// Automatically generated rust module for 'structs.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::*; + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct Identify { + pub protocolVersion: Option, + pub agentVersion: Option, + pub publicKey: Option>, + pub listenAddrs: Vec>, + pub observedAddr: Option>, + pub protocols: 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(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::() + } + + 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))?; } + Ok(()) + } +} + diff --git a/protocols/identify/src/lib.rs b/protocols/identify/src/lib.rs index 0155e1b64fe..7fb8df253ff 100644 --- a/protocols/identify/src/lib.rs +++ b/protocols/identify/src/lib.rs @@ -69,7 +69,7 @@ mod behaviour; mod handler; mod protocol; -#[allow(clippy::derive_partial_eq_without_eq)] -mod structs_proto { - include!(concat!(env!("OUT_DIR"), "/structs.rs")); +mod proto { + include!("generated/mod.rs"); + pub use self::structs::Identify; } diff --git a/protocols/identify/src/mod.rs b/protocols/identify/src/mod.rs new file mode 100644 index 00000000000..e52c5a80bc0 --- /dev/null +++ b/protocols/identify/src/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod structs; diff --git a/protocols/identify/src/protocol.rs b/protocols/identify/src/protocol.rs index 4da9cc0b977..e2271324e1b 100644 --- a/protocols/identify/src/protocol.rs +++ b/protocols/identify/src/protocol.rs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::structs_proto; +use crate::proto; use asynchronous_codec::{FramedRead, FramedWrite}; use futures::{future::BoxFuture, prelude::*}; use libp2p_core::{ @@ -169,18 +169,18 @@ where let pubkey_bytes = info.public_key.to_protobuf_encoding(); - let message = structs_proto::Identify { - agent_version: Some(info.agent_version), - protocol_version: Some(info.protocol_version), - public_key: Some(pubkey_bytes), - listen_addrs, - observed_addr: Some(info.observed_addr.to_vec()), + let message = proto::Identify { + agentVersion: Some(info.agent_version), + protocolVersion: Some(info.protocol_version), + publicKey: Some(pubkey_bytes), + listenAddrs: listen_addrs, + observedAddr: Some(info.observed_addr.to_vec()), protocols: info.protocols, }; let mut framed_io = FramedWrite::new( io, - prost_codec::Codec::::new(MAX_MESSAGE_SIZE_BYTES), + quick_protobuf_codec::Codec::::new(MAX_MESSAGE_SIZE_BYTES), ); framed_io.send(message).await?; @@ -200,7 +200,7 @@ where let info = FramedRead::new( socket, - prost_codec::Codec::::new(MAX_MESSAGE_SIZE_BYTES), + quick_protobuf_codec::Codec::::new(MAX_MESSAGE_SIZE_BYTES), ) .next() .await @@ -212,17 +212,17 @@ where Ok(info) } -impl TryFrom for Info { +impl TryFrom for Info { type Error = UpgradeError; - fn try_from(msg: structs_proto::Identify) -> Result { + fn try_from(msg: proto::Identify) -> Result { fn parse_multiaddr(bytes: Vec) -> Result { Multiaddr::try_from(bytes) } let listen_addrs = { let mut addrs = Vec::new(); - for addr in msg.listen_addrs.into_iter() { + for addr in msg.listenAddrs.into_iter() { match parse_multiaddr(addr) { Ok(a) => addrs.push(a), Err(e) => { @@ -233,9 +233,9 @@ impl TryFrom for Info { addrs }; - let public_key = PublicKey::from_protobuf_encoding(&msg.public_key.unwrap_or_default())?; + let public_key = PublicKey::from_protobuf_encoding(&msg.publicKey.unwrap_or_default())?; - let observed_addr = match parse_multiaddr(msg.observed_addr.unwrap_or_default()) { + let observed_addr = match parse_multiaddr(msg.observedAddr.unwrap_or_default()) { Ok(a) => a, Err(e) => { debug!("Unable to parse multiaddr: {e:?}"); @@ -244,8 +244,8 @@ impl TryFrom for Info { }; let info = Info { public_key, - protocol_version: msg.protocol_version.unwrap_or_default(), - agent_version: msg.agent_version.unwrap_or_default(), + protocol_version: msg.protocolVersion.unwrap_or_default(), + agent_version: msg.agentVersion.unwrap_or_default(), listen_addrs, protocols: msg.protocols, observed_addr, @@ -258,7 +258,7 @@ impl TryFrom for Info { #[derive(Debug, Error)] pub enum UpgradeError { #[error(transparent)] - Codec(#[from] prost_codec::Error), + Codec(#[from] quick_protobuf_codec::Error), #[error("I/O interaction failed")] Io(#[from] io::Error), #[error("Stream closed")] @@ -375,13 +375,13 @@ mod tests { a }; - let payload = structs_proto::Identify { - agent_version: None, - listen_addrs: vec![valid_multiaddr_bytes, invalid_multiaddr], - observed_addr: None, - protocol_version: None, + let payload = proto::Identify { + agentVersion: None, + listenAddrs: vec![valid_multiaddr_bytes, invalid_multiaddr], + observedAddr: None, + protocolVersion: None, protocols: vec![], - public_key: Some( + publicKey: Some( identity::Keypair::generate_ed25519() .public() .to_protobuf_encoding(), diff --git a/protocols/identify/src/structs.rs b/protocols/identify/src/structs.rs new file mode 100644 index 00000000000..3be9b6f94ad --- /dev/null +++ b/protocols/identify/src/structs.rs @@ -0,0 +1,67 @@ +// Automatically generated rust module for 'structs.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::*; + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct Identify { + pub protocolVersion: Option, + pub agentVersion: Option, + pub publicKey: Option>, + pub listenAddrs: Vec>, + pub observedAddr: Option>, + pub protocols: 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(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::() + } + + 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))?; } + Ok(()) + } +} + diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index f3f1a6364f6..6894af01fd6 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -10,8 +10,11 @@ - Bump MSRV to 1.65.0. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. + [PR 3239]: https://github.com/libp2p/rust-libp2p/pull/3239 [PR 3287]: https://github.com/libp2p/rust-libp2p/pull/3287 +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 # 0.42.1 diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index 26c19275014..45ea5c98d82 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3.26" log = "0.4" libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-swarm = { version = "0.42.0", path = "../../swarm" } -prost = "0.11" +quick-protobuf = "0.8" rand = "0.8" sha2 = "0.10.0" smallvec = "1.6.1" @@ -39,9 +39,6 @@ libp2p-noise = { path = "../../transports/noise" } libp2p-yamux = { path = "../../muxers/yamux" } quickcheck = { package = "quickcheck-ext", path = "../../misc/quickcheck-ext" } -[build-dependencies] -prost-build = "0.11" - [features] serde = ["dep:serde", "bytes/serde"] diff --git a/protocols/kad/build.rs b/protocols/kad/build.rs deleted file mode 100644 index f05e9e03190..00000000000 --- a/protocols/kad/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -fn main() { - prost_build::compile_protos(&["src/dht.proto"], &["src"]).unwrap(); -} diff --git a/protocols/kad/src/dht.proto b/protocols/kad/src/generated/dht.proto similarity index 100% rename from protocols/kad/src/dht.proto rename to protocols/kad/src/generated/dht.proto diff --git a/protocols/kad/src/generated/dht/mod.rs b/protocols/kad/src/generated/dht/mod.rs new file mode 100644 index 00000000000..aec6164c7ef --- /dev/null +++ b/protocols/kad/src/generated/dht/mod.rs @@ -0,0 +1,2 @@ +// 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 new file mode 100644 index 00000000000..56b819b1a9c --- /dev/null +++ b/protocols/kad/src/generated/dht/pb.rs @@ -0,0 +1,243 @@ +// Automatically generated rust module for 'dht.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::super::*; + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct Record { + pub key: Vec, + 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 new file mode 100644 index 00000000000..6ffc566d1a0 --- /dev/null +++ b/protocols/kad/src/generated/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod dht; diff --git a/protocols/kad/src/lib.rs b/protocols/kad/src/lib.rs index e712da0c7d3..3e9dcecc0e4 100644 --- a/protocols/kad/src/lib.rs +++ b/protocols/kad/src/lib.rs @@ -48,9 +48,12 @@ mod behaviour; mod jobs; mod query; -#[allow(clippy::derive_partial_eq_without_eq)] -mod dht_proto { - include!(concat!(env!("OUT_DIR"), "/dht.pb.rs")); +mod proto { + include!("generated/mod.rs"); + pub use self::dht::pb::{ + mod_Message::{ConnectionType, MessageType, Peer}, + Message, Record, + }; } pub use addresses::Addresses; diff --git a/protocols/kad/src/protocol.rs b/protocols/kad/src/protocol.rs index 3988d08f24d..47d7c33e496 100644 --- a/protocols/kad/src/protocol.rs +++ b/protocols/kad/src/protocol.rs @@ -26,7 +26,7 @@ //! to poll the underlying transport for incoming messages, and the `Sink` component //! is used to send messages to remote peers. -use crate::dht_proto as proto; +use crate::proto; use crate::record::{self, Record}; use asynchronous_codec::Framed; use bytes::BytesMut; @@ -35,7 +35,7 @@ use futures::prelude::*; use instant::Instant; use libp2p_core::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use libp2p_core::{Multiaddr, PeerId}; -use prost::Message; +use quick_protobuf::{BytesReader, Writer}; use std::{borrow::Cow, convert::TryFrom, time::Duration}; use std::{io, iter}; use unsigned_varint::codec; @@ -59,26 +59,26 @@ pub enum KadConnectionType { CannotConnect = 3, } -impl From for KadConnectionType { - fn from(raw: proto::message::ConnectionType) -> KadConnectionType { - use proto::message::ConnectionType::*; +impl From for KadConnectionType { + fn from(raw: proto::ConnectionType) -> KadConnectionType { + use proto::ConnectionType::*; match raw { - NotConnected => KadConnectionType::NotConnected, - Connected => KadConnectionType::Connected, - CanConnect => KadConnectionType::CanConnect, - CannotConnect => KadConnectionType::CannotConnect, + NOT_CONNECTED => KadConnectionType::NotConnected, + CONNECTED => KadConnectionType::Connected, + CAN_CONNECT => KadConnectionType::CanConnect, + CANNOT_CONNECT => KadConnectionType::CannotConnect, } } } -impl From for proto::message::ConnectionType { +impl From for proto::ConnectionType { fn from(val: KadConnectionType) -> Self { - use proto::message::ConnectionType::*; + use proto::ConnectionType::*; match val { - KadConnectionType::NotConnected => NotConnected, - KadConnectionType::Connected => Connected, - KadConnectionType::CanConnect => CanConnect, - KadConnectionType::CannotConnect => CannotConnect, + KadConnectionType::NotConnected => NOT_CONNECTED, + KadConnectionType::Connected => CONNECTED, + KadConnectionType::CanConnect => CAN_CONNECT, + KadConnectionType::CannotConnect => CANNOT_CONNECT, } } } @@ -95,10 +95,10 @@ pub struct KadPeer { } // Builds a `KadPeer` from a corresponding protobuf message. -impl TryFrom for KadPeer { +impl TryFrom for KadPeer { type Error = io::Error; - fn try_from(peer: proto::message::Peer) -> Result { + fn try_from(peer: proto::Peer) -> Result { // TODO: this is in fact a CID; not sure if this should be handled in `from_bytes` or // as a special case here let node_id = PeerId::from_bytes(&peer.id).map_err(|_| invalid_data("invalid peer id"))?; @@ -113,27 +113,20 @@ impl TryFrom for KadPeer { }; } - let connection_ty = proto::message::ConnectionType::from_i32(peer.connection) - .ok_or_else(|| invalid_data("unknown connection type"))? - .into(); - Ok(KadPeer { node_id, multiaddrs: addrs, - connection_ty, + connection_ty: peer.connection.into(), }) } } -impl From for proto::message::Peer { +impl From for proto::Peer { fn from(peer: KadPeer) -> Self { - proto::message::Peer { + proto::Peer { id: peer.node_id.to_bytes(), addrs: peer.multiaddrs.into_iter().map(|a| a.to_vec()).collect(), - connection: { - let ct: proto::message::ConnectionType = peer.connection_ty.into(); - ct as i32 - }, + connection: peer.connection_ty.into(), } } } @@ -195,6 +188,8 @@ where type Error = io::Error; fn upgrade_inbound(self, incoming: C, _: Self::Info) -> Self::Future { + use quick_protobuf::{MessageRead, MessageWrite}; + let mut codec = UviBytes::default(); codec.set_max_len(self.max_packet_size); @@ -203,14 +198,16 @@ where .err_into() .with::<_, _, fn(_) -> _, _>(|response| { let proto_struct = resp_msg_to_proto(response); - let mut buf = Vec::with_capacity(proto_struct.encoded_len()); + let mut buf = Vec::with_capacity(proto_struct.get_size()); + let mut writer = Writer::new(&mut buf); proto_struct - .encode(&mut buf) - .expect("Vec provides capacity as needed"); + .write_message(&mut writer) + .expect("Encoding to succeed"); future::ready(Ok(io::Cursor::new(buf))) }) .and_then::<_, fn(_) -> _>(|bytes| { - let request = match proto::Message::decode(bytes) { + let mut reader = BytesReader::from_bytes(&bytes); + let request = match proto::Message::from_reader(&mut reader, &bytes) { Ok(r) => r, Err(err) => return future::ready(Err(err.into())), }; @@ -229,6 +226,8 @@ where type Error = io::Error; fn upgrade_outbound(self, incoming: C, _: Self::Info) -> Self::Future { + use quick_protobuf::{MessageRead, MessageWrite}; + let mut codec = UviBytes::default(); codec.set_max_len(self.max_packet_size); @@ -237,14 +236,16 @@ where .err_into() .with::<_, _, fn(_) -> _, _>(|request| { let proto_struct = req_msg_to_proto(request); - let mut buf = Vec::with_capacity(proto_struct.encoded_len()); + let mut buf = Vec::with_capacity(proto_struct.get_size()); + let mut writer = Writer::new(&mut buf); proto_struct - .encode(&mut buf) - .expect("Vec provides capacity as needed"); + .write_message(&mut writer) + .expect("Encoding to succeed"); future::ready(Ok(io::Cursor::new(buf))) }) .and_then::<_, fn(_) -> _>(|bytes| { - let response = match proto::Message::decode(bytes) { + let mut reader = BytesReader::from_bytes(&bytes); + let response = match proto::Message::from_reader(&mut reader, &bytes) { Ok(r) => r, Err(err) => return future::ready(Err(err.into())), }; @@ -351,36 +352,36 @@ pub enum KadResponseMsg { fn req_msg_to_proto(kad_msg: KadRequestMsg) -> proto::Message { match kad_msg { KadRequestMsg::Ping => proto::Message { - r#type: proto::message::MessageType::Ping as i32, + type_pb: proto::MessageType::PING, ..proto::Message::default() }, KadRequestMsg::FindNode { key } => proto::Message { - r#type: proto::message::MessageType::FindNode as i32, + type_pb: proto::MessageType::FIND_NODE, key, - cluster_level_raw: 10, + clusterLevelRaw: 10, ..proto::Message::default() }, KadRequestMsg::GetProviders { key } => proto::Message { - r#type: proto::message::MessageType::GetProviders as i32, + type_pb: proto::MessageType::GET_PROVIDERS, key: key.to_vec(), - cluster_level_raw: 10, + clusterLevelRaw: 10, ..proto::Message::default() }, KadRequestMsg::AddProvider { key, provider } => proto::Message { - r#type: proto::message::MessageType::AddProvider as i32, - cluster_level_raw: 10, + type_pb: proto::MessageType::ADD_PROVIDER, + clusterLevelRaw: 10, key: key.to_vec(), - provider_peers: vec![provider.into()], + providerPeers: vec![provider.into()], ..proto::Message::default() }, KadRequestMsg::GetValue { key } => proto::Message { - r#type: proto::message::MessageType::GetValue as i32, - cluster_level_raw: 10, + type_pb: proto::MessageType::GET_VALUE, + clusterLevelRaw: 10, key: key.to_vec(), ..proto::Message::default() }, KadRequestMsg::PutValue { record } => proto::Message { - r#type: proto::message::MessageType::PutValue as i32, + type_pb: proto::MessageType::PUT_VALUE, key: record.key.to_vec(), record: Some(record_to_proto(record)), ..proto::Message::default() @@ -392,37 +393,37 @@ fn req_msg_to_proto(kad_msg: KadRequestMsg) -> proto::Message { fn resp_msg_to_proto(kad_msg: KadResponseMsg) -> proto::Message { match kad_msg { KadResponseMsg::Pong => proto::Message { - r#type: proto::message::MessageType::Ping as i32, + type_pb: proto::MessageType::PING, ..proto::Message::default() }, KadResponseMsg::FindNode { closer_peers } => proto::Message { - r#type: proto::message::MessageType::FindNode as i32, - cluster_level_raw: 9, - closer_peers: closer_peers.into_iter().map(KadPeer::into).collect(), + type_pb: proto::MessageType::FIND_NODE, + clusterLevelRaw: 9, + closerPeers: closer_peers.into_iter().map(KadPeer::into).collect(), ..proto::Message::default() }, KadResponseMsg::GetProviders { closer_peers, provider_peers, } => proto::Message { - r#type: proto::message::MessageType::GetProviders as i32, - cluster_level_raw: 9, - closer_peers: closer_peers.into_iter().map(KadPeer::into).collect(), - provider_peers: provider_peers.into_iter().map(KadPeer::into).collect(), + type_pb: proto::MessageType::GET_PROVIDERS, + clusterLevelRaw: 9, + closerPeers: closer_peers.into_iter().map(KadPeer::into).collect(), + providerPeers: provider_peers.into_iter().map(KadPeer::into).collect(), ..proto::Message::default() }, KadResponseMsg::GetValue { record, closer_peers, } => proto::Message { - r#type: proto::message::MessageType::GetValue as i32, - cluster_level_raw: 9, - closer_peers: closer_peers.into_iter().map(KadPeer::into).collect(), + type_pb: proto::MessageType::GET_VALUE, + clusterLevelRaw: 9, + closerPeers: closer_peers.into_iter().map(KadPeer::into).collect(), record: record.map(record_to_proto), ..proto::Message::default() }, KadResponseMsg::PutValue { key, value } => proto::Message { - r#type: proto::message::MessageType::PutValue as i32, + type_pb: proto::MessageType::PUT_VALUE, key: key.to_vec(), record: Some(proto::Record { key: key.to_vec(), @@ -438,28 +439,25 @@ fn resp_msg_to_proto(kad_msg: KadResponseMsg) -> proto::Message { /// /// Fails if the protobuf message is not a valid and supported Kademlia request message. fn proto_to_req_msg(message: proto::Message) -> Result { - let msg_type = proto::message::MessageType::from_i32(message.r#type) - .ok_or_else(|| invalid_data(format!("unknown message type: {}", message.r#type)))?; - - match msg_type { - proto::message::MessageType::Ping => Ok(KadRequestMsg::Ping), - proto::message::MessageType::PutValue => { + match message.type_pb { + proto::MessageType::PING => Ok(KadRequestMsg::Ping), + proto::MessageType::PUT_VALUE => { let record = record_from_proto(message.record.unwrap_or_default())?; Ok(KadRequestMsg::PutValue { record }) } - proto::message::MessageType::GetValue => Ok(KadRequestMsg::GetValue { + proto::MessageType::GET_VALUE => Ok(KadRequestMsg::GetValue { key: record::Key::from(message.key), }), - proto::message::MessageType::FindNode => Ok(KadRequestMsg::FindNode { key: message.key }), - proto::message::MessageType::GetProviders => Ok(KadRequestMsg::GetProviders { + proto::MessageType::FIND_NODE => Ok(KadRequestMsg::FindNode { key: message.key }), + proto::MessageType::GET_PROVIDERS => Ok(KadRequestMsg::GetProviders { key: record::Key::from(message.key), }), - proto::message::MessageType::AddProvider => { + proto::MessageType::ADD_PROVIDER => { // TODO: for now we don't parse the peer properly, so it is possible that we get // parsing errors for peers even when they are valid; we ignore these // errors for now, but ultimately we should just error altogether let provider = message - .provider_peers + .providerPeers .into_iter() .find_map(|peer| KadPeer::try_from(peer).ok()); @@ -477,12 +475,9 @@ fn proto_to_req_msg(message: proto::Message) -> Result /// /// Fails if the protobuf message is not a valid and supported Kademlia response message. fn proto_to_resp_msg(message: proto::Message) -> Result { - let msg_type = proto::message::MessageType::from_i32(message.r#type) - .ok_or_else(|| invalid_data(format!("unknown message type: {}", message.r#type)))?; - - match msg_type { - proto::message::MessageType::Ping => Ok(KadResponseMsg::Pong), - proto::message::MessageType::GetValue => { + match message.type_pb { + proto::MessageType::PING => Ok(KadResponseMsg::Pong), + proto::MessageType::GET_VALUE => { let record = if let Some(r) = message.record { Some(record_from_proto(r)?) } else { @@ -490,7 +485,7 @@ fn proto_to_resp_msg(message: proto::Message) -> Result Result { + proto::MessageType::FIND_NODE => { let closer_peers = message - .closer_peers + .closerPeers .into_iter() .filter_map(|peer| KadPeer::try_from(peer).ok()) .collect(); @@ -511,15 +506,15 @@ fn proto_to_resp_msg(message: proto::Message) -> Result { + proto::MessageType::GET_PROVIDERS => { let closer_peers = message - .closer_peers + .closerPeers .into_iter() .filter_map(|peer| KadPeer::try_from(peer).ok()) .collect(); let provider_peers = message - .provider_peers + .providerPeers .into_iter() .filter_map(|peer| KadPeer::try_from(peer).ok()) .collect(); @@ -530,7 +525,7 @@ fn proto_to_resp_msg(message: proto::Message) -> Result { + proto::MessageType::PUT_VALUE => { let key = record::Key::from(message.key); let rec = message .record @@ -542,7 +537,7 @@ fn proto_to_resp_msg(message: proto::Message) -> Result { + proto::MessageType::ADD_PROVIDER => { Err(invalid_data("received an unexpected AddProvider message")) } } @@ -590,7 +585,7 @@ fn record_to_proto(record: Record) -> proto::Record { } }) .unwrap_or(0), - time_received: String::new(), + timeReceived: String::new(), } } @@ -617,10 +612,10 @@ mod tests { a }; - let payload = proto::message::Peer { + let payload = proto::Peer { id: PeerId::random().to_bytes(), addrs: vec![valid_multiaddr_bytes, invalid_multiaddr], - connection: proto::message::ConnectionType::CanConnect.into(), + connection: proto::ConnectionType::CAN_CONNECT, }; let peer = KadPeer::try_from(payload).expect("not to fail"); diff --git a/protocols/relay/CHANGELOG.md b/protocols/relay/CHANGELOG.md index 7e0ccbcadbd..206d35e088f 100644 --- a/protocols/relay/CHANGELOG.md +++ b/protocols/relay/CHANGELOG.md @@ -11,8 +11,11 @@ - Update to `libp2p-swarm` `v0.42.0`. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. + [PR 3238]: https://github.com/libp2p/rust-libp2p/pull/3238 [discussion 2174]: https://github.com/libp2p/rust-libp2p/issues/2174 +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 # 0.14.0 diff --git a/protocols/relay/Cargo.toml b/protocols/relay/Cargo.toml index 9a8255f4ca0..31d413d79db 100644 --- a/protocols/relay/Cargo.toml +++ b/protocols/relay/Cargo.toml @@ -20,16 +20,13 @@ instant = "0.1.11" libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-swarm = { version = "0.42.0", path = "../../swarm" } log = "0.4" -prost-codec = { version = "0.3", path = "../../misc/prost-codec" } -prost = "0.11" +quick-protobuf = "0.8" +quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" } rand = "0.8.4" static_assertions = "1" thiserror = "1.0" void = "1" -[build-dependencies] -prost-build = "0.11" - [dev-dependencies] clap = { version = "4.1.6", features = ["derive"] } env_logger = "0.10.0" diff --git a/protocols/relay/build.rs b/protocols/relay/build.rs deleted file mode 100644 index 965fb241712..00000000000 --- a/protocols/relay/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -fn main() { - prost_build::compile_protos(&["src/message.proto"], &["src/"]).unwrap(); -} diff --git a/protocols/relay/src/behaviour.rs b/protocols/relay/src/behaviour.rs index 96c99697a7a..6a59cf3826c 100644 --- a/protocols/relay/src/behaviour.rs +++ b/protocols/relay/src/behaviour.rs @@ -24,8 +24,8 @@ mod handler; pub mod rate_limiter; use crate::behaviour::handler::Handler; -use crate::message_proto; use crate::multiaddr_ext::MultiaddrExt; +use crate::proto; use crate::protocol::{inbound_hop, outbound_stop}; use either::Either; use instant::Instant; @@ -381,7 +381,7 @@ impl NetworkBehaviour for Behaviour { peer_id: event_source, event: Either::Left(handler::In::DenyReservationReq { inbound_reservation_req, - status: message_proto::Status::ResourceLimitExceeded, + status: proto::Status::RESOURCE_LIMIT_EXCEEDED, }), } .into() @@ -496,7 +496,7 @@ impl NetworkBehaviour for Behaviour { event: Either::Left(handler::In::DenyCircuitReq { circuit_id: None, inbound_circuit_req, - status: message_proto::Status::ResourceLimitExceeded, + status: proto::Status::RESOURCE_LIMIT_EXCEEDED, }), } } else if let Some(dst_conn) = self @@ -532,7 +532,7 @@ impl NetworkBehaviour for Behaviour { event: Either::Left(handler::In::DenyCircuitReq { circuit_id: None, inbound_circuit_req, - status: message_proto::Status::NoReservation, + status: proto::Status::NO_RESERVATION, }), } }; diff --git a/protocols/relay/src/behaviour/handler.rs b/protocols/relay/src/behaviour/handler.rs index 4ed521d57c1..923d322fa2b 100644 --- a/protocols/relay/src/behaviour/handler.rs +++ b/protocols/relay/src/behaviour/handler.rs @@ -20,7 +20,7 @@ use crate::behaviour::CircuitId; use crate::copy_future::CopyFuture; -use crate::message_proto::Status; +use crate::proto; use crate::protocol::{inbound_hop, outbound_stop}; use bytes::Bytes; use either::Either; @@ -58,12 +58,12 @@ pub enum In { }, DenyReservationReq { inbound_reservation_req: inbound_hop::ReservationReq, - status: Status, + status: proto::Status, }, DenyCircuitReq { circuit_id: Option, inbound_circuit_req: inbound_hop::CircuitReq, - status: Status, + status: proto::Status, }, NegotiateOutboundConnect { circuit_id: CircuitId, @@ -208,7 +208,7 @@ pub enum Event { src_peer_id: PeerId, src_connection_id: ConnectionId, inbound_circuit_req: inbound_hop::CircuitReq, - status: Status, + status: proto::Status, error: ConnectionHandlerUpgrErr, }, /// An inbound circuit has closed. @@ -522,12 +522,14 @@ impl Handler { >, ) { let (non_fatal_error, status) = match error { - ConnectionHandlerUpgrErr::Timeout => { - (ConnectionHandlerUpgrErr::Timeout, Status::ConnectionFailed) - } - ConnectionHandlerUpgrErr::Timer => { - (ConnectionHandlerUpgrErr::Timer, Status::ConnectionFailed) - } + ConnectionHandlerUpgrErr::Timeout => ( + ConnectionHandlerUpgrErr::Timeout, + proto::Status::CONNECTION_FAILED, + ), + ConnectionHandlerUpgrErr::Timer => ( + ConnectionHandlerUpgrErr::Timer, + proto::Status::CONNECTION_FAILED, + ), ConnectionHandlerUpgrErr::Upgrade(upgrade::UpgradeError::Select( upgrade::NegotiationError::Failed, )) => { @@ -556,10 +558,10 @@ impl Handler { outbound_stop::UpgradeError::CircuitFailed(error) => { let status = match error { outbound_stop::CircuitFailedReason::ResourceLimitExceeded => { - Status::ResourceLimitExceeded + proto::Status::RESOURCE_LIMIT_EXCEEDED } outbound_stop::CircuitFailedReason::PermissionDenied => { - Status::PermissionDenied + proto::Status::PERMISSION_DENIED } }; ( diff --git a/protocols/relay/src/message.proto b/protocols/relay/src/generated/message.proto similarity index 100% rename from protocols/relay/src/message.proto rename to protocols/relay/src/generated/message.proto diff --git a/protocols/relay/src/generated/message_v2/mod.rs b/protocols/relay/src/generated/message_v2/mod.rs new file mode 100644 index 00000000000..aec6164c7ef --- /dev/null +++ b/protocols/relay/src/generated/message_v2/mod.rs @@ -0,0 +1,2 @@ +// 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 new file mode 100644 index 00000000000..2344f26b541 --- /dev/null +++ b/protocols/relay/src/generated/message_v2/pb.rs @@ -0,0 +1,346 @@ +// Automatically generated rust module for 'message.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::super::*; + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum Status { + OK = 100, + RESERVATION_REFUSED = 200, + RESOURCE_LIMIT_EXCEEDED = 201, + PERMISSION_DENIED = 202, + CONNECTION_FAILED = 203, + NO_RESERVATION = 204, + MALFORMED_MESSAGE = 400, + UNEXPECTED_MESSAGE = 401, +} + +impl Default for Status { + fn default() -> Self { + Status::OK + } +} + +impl From 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 new file mode 100644 index 00000000000..18bb20c7eb0 --- /dev/null +++ b/protocols/relay/src/generated/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod message_v2; diff --git a/protocols/relay/src/lib.rs b/protocols/relay/src/lib.rs index 87f3cee0e82..05b6292c9e2 100644 --- a/protocols/relay/src/lib.rs +++ b/protocols/relay/src/lib.rs @@ -30,9 +30,11 @@ mod priv_client; mod protocol; pub mod v2; -#[allow(clippy::derive_partial_eq_without_eq)] -mod message_proto { - include!(concat!(env!("OUT_DIR"), "/message_v2.pb.rs")); +mod proto { + include!("generated/mod.rs"); + pub use self::message_v2::pb::mod_HopMessage::Type as HopMessageType; + pub use self::message_v2::pb::mod_StopMessage::Type as StopMessageType; + pub use self::message_v2::pb::{HopMessage, Limit, Peer, Reservation, Status, StopMessage}; } pub use behaviour::{Behaviour, CircuitId, Config, Event}; diff --git a/protocols/relay/src/priv_client/handler.rs b/protocols/relay/src/priv_client/handler.rs index cae7db78322..69d89ee1389 100644 --- a/protocols/relay/src/priv_client/handler.rs +++ b/protocols/relay/src/priv_client/handler.rs @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::message_proto::Status; use crate::priv_client::transport; +use crate::proto; use crate::protocol::{self, inbound_stop, outbound_hop}; use either::Either; use futures::channel::{mpsc, oneshot}; @@ -218,7 +218,7 @@ impl Handler { .circuit_deny_futs .insert( src_peer_id, - inbound_circuit.deny(Status::NoReservation).boxed(), + inbound_circuit.deny(proto::Status::NO_RESERVATION).boxed(), ) .is_some() { diff --git a/protocols/relay/src/protocol.rs b/protocols/relay/src/protocol.rs index f688fe6ab67..4933eb6a523 100644 --- a/protocols/relay/src/protocol.rs +++ b/protocols/relay/src/protocol.rs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::message_proto; +use crate::proto; use std::time::Duration; pub mod inbound_hop; @@ -37,8 +37,8 @@ pub struct Limit { data_in_bytes: Option, } -impl From for Limit { - fn from(limit: message_proto::Limit) -> Self { +impl From for Limit { + fn from(limit: proto::Limit) -> Self { Limit { duration: limit.duration.map(|d| Duration::from_secs(d.into())), data_in_bytes: limit.data, diff --git a/protocols/relay/src/protocol/inbound_hop.rs b/protocols/relay/src/protocol/inbound_hop.rs index dec290e0e6c..283ceacc886 100644 --- a/protocols/relay/src/protocol/inbound_hop.rs +++ b/protocols/relay/src/protocol/inbound_hop.rs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::message_proto::{hop_message, HopMessage, Limit, Reservation, Status}; +use crate::proto; use crate::protocol::{HOP_PROTOCOL_NAME, MAX_MESSAGE_SIZE}; use asynchronous_codec::{Framed, FramedParts}; use bytes::Bytes; @@ -51,11 +51,14 @@ impl upgrade::InboundUpgrade for Upgrade { type Future = BoxFuture<'static, Result>; fn upgrade_inbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future { - let mut substream = Framed::new(substream, prost_codec::Codec::new(MAX_MESSAGE_SIZE)); + let mut substream = Framed::new( + substream, + quick_protobuf_codec::Codec::new(MAX_MESSAGE_SIZE), + ); async move { - let HopMessage { - r#type, + let proto::HopMessage { + type_pb, peer, reservation: _, limit: _, @@ -65,21 +68,19 @@ impl upgrade::InboundUpgrade for Upgrade { .await .ok_or(FatalUpgradeError::StreamClosed)??; - let r#type = - hop_message::Type::from_i32(r#type).ok_or(FatalUpgradeError::ParseTypeField)?; - let req = match r#type { - hop_message::Type::Reserve => Req::Reserve(ReservationReq { + let req = match type_pb { + proto::HopMessageType::RESERVE => Req::Reserve(ReservationReq { substream, reservation_duration: self.reservation_duration, max_circuit_duration: self.max_circuit_duration, max_circuit_bytes: self.max_circuit_bytes, }), - hop_message::Type::Connect => { + proto::HopMessageType::CONNECT => { let dst = PeerId::from_bytes(&peer.ok_or(FatalUpgradeError::MissingPeer)?.id) .map_err(|_| FatalUpgradeError::ParsePeerId)?; Req::Connect(CircuitReq { dst, substream }) } - hop_message::Type::Status => { + proto::HopMessageType::STATUS => { return Err(FatalUpgradeError::UnexpectedTypeStatus.into()) } }; @@ -96,8 +97,8 @@ pub enum UpgradeError { Fatal(#[from] FatalUpgradeError), } -impl From for UpgradeError { - fn from(error: prost_codec::Error) -> Self { +impl From for UpgradeError { + fn from(error: quick_protobuf_codec::Error) -> Self { Self::Fatal(error.into()) } } @@ -105,7 +106,7 @@ impl From for UpgradeError { #[derive(Debug, Error)] pub enum FatalUpgradeError { #[error(transparent)] - Codec(#[from] prost_codec::Error), + Codec(#[from] quick_protobuf_codec::Error), #[error("Stream closed")] StreamClosed, #[error("Failed to parse response type field.")] @@ -124,7 +125,7 @@ pub enum Req { } pub struct ReservationReq { - substream: Framed>, + substream: Framed>, reservation_duration: Duration, max_circuit_duration: Duration, max_circuit_bytes: u64, @@ -132,10 +133,10 @@ pub struct ReservationReq { impl ReservationReq { pub async fn accept(self, addrs: Vec) -> Result<(), UpgradeError> { - let msg = HopMessage { - r#type: hop_message::Type::Status.into(), + let msg = proto::HopMessage { + type_pb: proto::HopMessageType::STATUS, peer: None, - reservation: Some(Reservation { + reservation: Some(proto::Reservation { addrs: addrs.into_iter().map(|a| a.to_vec()).collect(), expire: (SystemTime::now() + self.reservation_duration) .duration_since(SystemTime::UNIX_EPOCH) @@ -143,7 +144,7 @@ impl ReservationReq { .as_secs(), voucher: None, }), - limit: Some(Limit { + limit: Some(proto::Limit { duration: Some( self.max_circuit_duration .as_secs() @@ -152,25 +153,25 @@ impl ReservationReq { ), data: Some(self.max_circuit_bytes), }), - status: Some(Status::Ok.into()), + status: Some(proto::Status::OK), }; self.send(msg).await } - pub async fn deny(self, status: Status) -> Result<(), UpgradeError> { - let msg = HopMessage { - r#type: hop_message::Type::Status.into(), + pub async fn deny(self, status: proto::Status) -> Result<(), UpgradeError> { + let msg = proto::HopMessage { + type_pb: proto::HopMessageType::STATUS, peer: None, reservation: None, limit: None, - status: Some(status.into()), + status: Some(status), }; self.send(msg).await } - async fn send(mut self, msg: HopMessage) -> Result<(), UpgradeError> { + async fn send(mut self, msg: proto::HopMessage) -> Result<(), UpgradeError> { self.substream.send(msg).await?; self.substream.flush().await?; self.substream.close().await?; @@ -181,7 +182,7 @@ impl ReservationReq { pub struct CircuitReq { dst: PeerId, - substream: Framed>, + substream: Framed>, } impl CircuitReq { @@ -190,12 +191,12 @@ impl CircuitReq { } pub async fn accept(mut self) -> Result<(NegotiatedSubstream, Bytes), UpgradeError> { - let msg = HopMessage { - r#type: hop_message::Type::Status.into(), + let msg = proto::HopMessage { + type_pb: proto::HopMessageType::STATUS, peer: None, reservation: None, limit: None, - status: Some(Status::Ok.into()), + status: Some(proto::Status::OK), }; self.send(msg).await?; @@ -214,19 +215,19 @@ impl CircuitReq { Ok((io, read_buffer.freeze())) } - pub async fn deny(mut self, status: Status) -> Result<(), UpgradeError> { - let msg = HopMessage { - r#type: hop_message::Type::Status.into(), + pub async fn deny(mut self, status: proto::Status) -> Result<(), UpgradeError> { + let msg = proto::HopMessage { + type_pb: proto::HopMessageType::STATUS, peer: None, reservation: None, limit: None, - status: Some(status.into()), + status: Some(status), }; self.send(msg).await?; self.substream.close().await.map_err(Into::into) } - async fn send(&mut self, msg: HopMessage) -> Result<(), prost_codec::Error> { + async fn send(&mut self, msg: proto::HopMessage) -> Result<(), quick_protobuf_codec::Error> { self.substream.send(msg).await?; self.substream.flush().await?; diff --git a/protocols/relay/src/protocol/inbound_stop.rs b/protocols/relay/src/protocol/inbound_stop.rs index d3cad292bd7..77152f0b237 100644 --- a/protocols/relay/src/protocol/inbound_stop.rs +++ b/protocols/relay/src/protocol/inbound_stop.rs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::message_proto::{stop_message, Status, StopMessage}; +use crate::proto; use crate::protocol::{self, MAX_MESSAGE_SIZE, STOP_PROTOCOL_NAME}; use asynchronous_codec::{Framed, FramedParts}; use bytes::Bytes; @@ -45,11 +45,14 @@ impl upgrade::InboundUpgrade for Upgrade { type Future = BoxFuture<'static, Result>; fn upgrade_inbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future { - let mut substream = Framed::new(substream, prost_codec::Codec::new(MAX_MESSAGE_SIZE)); + let mut substream = Framed::new( + substream, + quick_protobuf_codec::Codec::new(MAX_MESSAGE_SIZE), + ); async move { - let StopMessage { - r#type, + let proto::StopMessage { + type_pb, peer, limit, status: _, @@ -58,10 +61,8 @@ impl upgrade::InboundUpgrade for Upgrade { .await .ok_or(FatalUpgradeError::StreamClosed)??; - let r#type = - stop_message::Type::from_i32(r#type).ok_or(FatalUpgradeError::ParseTypeField)?; - match r#type { - stop_message::Type::Connect => { + match type_pb { + proto::StopMessageType::CONNECT => { let src_peer_id = PeerId::from_bytes(&peer.ok_or(FatalUpgradeError::MissingPeer)?.id) .map_err(|_| FatalUpgradeError::ParsePeerId)?; @@ -71,7 +72,9 @@ impl upgrade::InboundUpgrade for Upgrade { limit: limit.map(Into::into), }) } - stop_message::Type::Status => Err(FatalUpgradeError::UnexpectedTypeStatus.into()), + proto::StopMessageType::STATUS => { + Err(FatalUpgradeError::UnexpectedTypeStatus.into()) + } } } .boxed() @@ -84,8 +87,8 @@ pub enum UpgradeError { Fatal(#[from] FatalUpgradeError), } -impl From for UpgradeError { - fn from(error: prost_codec::Error) -> Self { +impl From for UpgradeError { + fn from(error: quick_protobuf_codec::Error) -> Self { Self::Fatal(error.into()) } } @@ -93,7 +96,7 @@ impl From for UpgradeError { #[derive(Debug, Error)] pub enum FatalUpgradeError { #[error(transparent)] - Codec(#[from] prost_codec::Error), + Codec(#[from] quick_protobuf_codec::Error), #[error("Stream closed")] StreamClosed, #[error("Failed to parse response type field.")] @@ -107,7 +110,7 @@ pub enum FatalUpgradeError { } pub struct Circuit { - substream: Framed>, + substream: Framed>, src_peer_id: PeerId, limit: Option, } @@ -122,11 +125,11 @@ impl Circuit { } pub async fn accept(mut self) -> Result<(NegotiatedSubstream, Bytes), UpgradeError> { - let msg = StopMessage { - r#type: stop_message::Type::Status.into(), + let msg = proto::StopMessage { + type_pb: proto::StopMessageType::STATUS, peer: None, limit: None, - status: Some(Status::Ok.into()), + status: Some(proto::Status::OK), }; self.send(msg).await?; @@ -145,18 +148,18 @@ impl Circuit { Ok((io, read_buffer.freeze())) } - pub async fn deny(mut self, status: Status) -> Result<(), UpgradeError> { - let msg = StopMessage { - r#type: stop_message::Type::Status.into(), + pub async fn deny(mut self, status: proto::Status) -> Result<(), UpgradeError> { + let msg = proto::StopMessage { + type_pb: proto::StopMessageType::STATUS, peer: None, limit: None, - status: Some(status.into()), + status: Some(status), }; self.send(msg).await.map_err(Into::into) } - async fn send(&mut self, msg: StopMessage) -> Result<(), prost_codec::Error> { + async fn send(&mut self, msg: proto::StopMessage) -> Result<(), quick_protobuf_codec::Error> { self.substream.send(msg).await?; self.substream.flush().await?; diff --git a/protocols/relay/src/protocol/outbound_hop.rs b/protocols/relay/src/protocol/outbound_hop.rs index c692c7a2596..e1ddda99738 100644 --- a/protocols/relay/src/protocol/outbound_hop.rs +++ b/protocols/relay/src/protocol/outbound_hop.rs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::message_proto::{hop_message, HopMessage, Peer, Status}; +use crate::proto; use crate::protocol::{Limit, HOP_PROTOCOL_NAME, MAX_MESSAGE_SIZE}; use asynchronous_codec::{Framed, FramedParts}; use bytes::Bytes; @@ -52,16 +52,16 @@ impl upgrade::OutboundUpgrade for Upgrade { fn upgrade_outbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future { let msg = match self { - Upgrade::Reserve => HopMessage { - r#type: hop_message::Type::Reserve.into(), + Upgrade::Reserve => proto::HopMessage { + type_pb: proto::HopMessageType::RESERVE, peer: None, reservation: None, limit: None, status: None, }, - Upgrade::Connect { dst_peer_id } => HopMessage { - r#type: hop_message::Type::Connect.into(), - peer: Some(Peer { + Upgrade::Connect { dst_peer_id } => proto::HopMessage { + type_pb: proto::HopMessageType::CONNECT, + peer: Some(proto::Peer { id: dst_peer_id.to_bytes(), addrs: vec![], }), @@ -71,12 +71,15 @@ impl upgrade::OutboundUpgrade for Upgrade { }, }; - let mut substream = Framed::new(substream, prost_codec::Codec::new(MAX_MESSAGE_SIZE)); + let mut substream = Framed::new( + substream, + quick_protobuf_codec::Codec::new(MAX_MESSAGE_SIZE), + ); async move { substream.send(msg).await?; - let HopMessage { - r#type, + let proto::HopMessage { + type_pb, peer: _, reservation, limit, @@ -86,31 +89,28 @@ impl upgrade::OutboundUpgrade for Upgrade { .await .ok_or(FatalUpgradeError::StreamClosed)??; - let r#type = - hop_message::Type::from_i32(r#type).ok_or(FatalUpgradeError::ParseTypeField)?; - match r#type { - hop_message::Type::Connect => { + match type_pb { + proto::HopMessageType::CONNECT => { return Err(FatalUpgradeError::UnexpectedTypeConnect.into()) } - hop_message::Type::Reserve => { + proto::HopMessageType::RESERVE => { return Err(FatalUpgradeError::UnexpectedTypeReserve.into()) } - hop_message::Type::Status => {} + proto::HopMessageType::STATUS => {} } - let status = Status::from_i32(status.ok_or(FatalUpgradeError::MissingStatusField)?) - .ok_or(FatalUpgradeError::ParseStatusField)?; - let limit = limit.map(Into::into); let output = match self { Upgrade::Reserve => { - match status { - Status::Ok => {} - Status::ReservationRefused => { + match status + .ok_or(UpgradeError::Fatal(FatalUpgradeError::MissingStatusField))? + { + proto::Status::OK => {} + proto::Status::RESERVATION_REFUSED => { return Err(ReservationFailedReason::Refused.into()) } - Status::ResourceLimitExceeded => { + proto::Status::RESOURCE_LIMIT_EXCEEDED => { return Err(ReservationFailedReason::ResourceLimitExceeded.into()) } s => return Err(FatalUpgradeError::UnexpectedStatus(s).into()), @@ -126,7 +126,7 @@ impl upgrade::OutboundUpgrade for Upgrade { let addrs = reservation .addrs .into_iter() - .map(TryFrom::try_from) + .map(|b| Multiaddr::try_from(b.to_vec())) .collect::, _>>() .map_err(|_| FatalUpgradeError::InvalidReservationAddrs)?; @@ -153,18 +153,20 @@ impl upgrade::OutboundUpgrade for Upgrade { } } Upgrade::Connect { .. } => { - match status { - Status::Ok => {} - Status::ResourceLimitExceeded => { + match status + .ok_or(UpgradeError::Fatal(FatalUpgradeError::MissingStatusField))? + { + proto::Status::OK => {} + proto::Status::RESOURCE_LIMIT_EXCEEDED => { return Err(CircuitFailedReason::ResourceLimitExceeded.into()) } - Status::ConnectionFailed => { + proto::Status::CONNECTION_FAILED => { return Err(CircuitFailedReason::ConnectionFailed.into()) } - Status::NoReservation => { + proto::Status::NO_RESERVATION => { return Err(CircuitFailedReason::NoReservation.into()) } - Status::PermissionDenied => { + proto::Status::PERMISSION_DENIED => { return Err(CircuitFailedReason::PermissionDenied.into()) } s => return Err(FatalUpgradeError::UnexpectedStatus(s).into()), @@ -205,8 +207,8 @@ pub enum UpgradeError { Fatal(#[from] FatalUpgradeError), } -impl From for UpgradeError { - fn from(error: prost_codec::Error) -> Self { +impl From for UpgradeError { + fn from(error: quick_protobuf_codec::Error) -> Self { Self::Fatal(error.into()) } } @@ -234,7 +236,7 @@ pub enum ReservationFailedReason { #[derive(Debug, Error)] pub enum FatalUpgradeError { #[error(transparent)] - Codec(#[from] prost_codec::Error), + Codec(#[from] quick_protobuf_codec::Error), #[error("Stream closed")] StreamClosed, #[error("Expected 'status' field to be set.")] @@ -256,7 +258,7 @@ pub enum FatalUpgradeError { #[error("Failed to parse response type field.")] ParseStatusField, #[error("Unexpected message status '{0:?}'")] - UnexpectedStatus(Status), + UnexpectedStatus(proto::Status), } pub enum Output { diff --git a/protocols/relay/src/protocol/outbound_stop.rs b/protocols/relay/src/protocol/outbound_stop.rs index 08056412d53..5302fed65a8 100644 --- a/protocols/relay/src/protocol/outbound_stop.rs +++ b/protocols/relay/src/protocol/outbound_stop.rs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::message_proto::{stop_message, Limit, Peer, Status, StopMessage}; +use crate::proto; use crate::protocol::{MAX_MESSAGE_SIZE, STOP_PROTOCOL_NAME}; use asynchronous_codec::{Framed, FramedParts}; use bytes::Bytes; @@ -51,13 +51,13 @@ impl upgrade::OutboundUpgrade for Upgrade { type Future = BoxFuture<'static, Result>; fn upgrade_outbound(self, substream: NegotiatedSubstream, _: Self::Info) -> Self::Future { - let msg = StopMessage { - r#type: stop_message::Type::Connect.into(), - peer: Some(Peer { + let msg = proto::StopMessage { + type_pb: proto::StopMessageType::CONNECT, + peer: Some(proto::Peer { id: self.relay_peer_id.to_bytes(), addrs: vec![], }), - limit: Some(Limit { + limit: Some(proto::Limit { duration: Some( self.max_circuit_duration .as_secs() @@ -69,12 +69,15 @@ impl upgrade::OutboundUpgrade for Upgrade { status: None, }; - let mut substream = Framed::new(substream, prost_codec::Codec::new(MAX_MESSAGE_SIZE)); + let mut substream = Framed::new( + substream, + quick_protobuf_codec::Codec::new(MAX_MESSAGE_SIZE), + ); async move { substream.send(msg).await?; - let StopMessage { - r#type, + let proto::StopMessage { + type_pb, peer: _, limit: _, status, @@ -83,23 +86,19 @@ impl upgrade::OutboundUpgrade for Upgrade { .await .ok_or(FatalUpgradeError::StreamClosed)??; - let r#type = - stop_message::Type::from_i32(r#type).ok_or(FatalUpgradeError::ParseTypeField)?; - match r#type { - stop_message::Type::Connect => { + match type_pb { + proto::StopMessageType::CONNECT => { return Err(FatalUpgradeError::UnexpectedTypeConnect.into()) } - stop_message::Type::Status => {} + proto::StopMessageType::STATUS => {} } - let status = Status::from_i32(status.ok_or(FatalUpgradeError::MissingStatusField)?) - .ok_or(FatalUpgradeError::ParseStatusField)?; - match status { - Status::Ok => {} - Status::ResourceLimitExceeded => { + match status.ok_or(UpgradeError::Fatal(FatalUpgradeError::MissingStatusField))? { + proto::Status::OK => {} + proto::Status::RESOURCE_LIMIT_EXCEEDED => { return Err(CircuitFailedReason::ResourceLimitExceeded.into()) } - Status::PermissionDenied => { + proto::Status::PERMISSION_DENIED => { return Err(CircuitFailedReason::PermissionDenied.into()) } s => return Err(FatalUpgradeError::UnexpectedStatus(s).into()), @@ -130,8 +129,8 @@ pub enum UpgradeError { Fatal(#[from] FatalUpgradeError), } -impl From for UpgradeError { - fn from(error: prost_codec::Error) -> Self { +impl From for UpgradeError { + fn from(error: quick_protobuf_codec::Error) -> Self { Self::Fatal(error.into()) } } @@ -147,7 +146,7 @@ pub enum CircuitFailedReason { #[derive(Debug, Error)] pub enum FatalUpgradeError { #[error(transparent)] - Codec(#[from] prost_codec::Error), + Codec(#[from] quick_protobuf_codec::Error), #[error("Stream closed")] StreamClosed, #[error("Expected 'status' field to be set.")] @@ -159,5 +158,5 @@ pub enum FatalUpgradeError { #[error("Failed to parse response type field.")] ParseStatusField, #[error("Unexpected message status '{0:?}'")] - UnexpectedStatus(Status), + UnexpectedStatus(proto::Status), } diff --git a/protocols/rendezvous/CHANGELOG.md b/protocols/rendezvous/CHANGELOG.md index ecfe8334fa0..212dcf954b2 100644 --- a/protocols/rendezvous/CHANGELOG.md +++ b/protocols/rendezvous/CHANGELOG.md @@ -4,6 +4,10 @@ - Update to `libp2p-swarm` `v0.42.0`. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. + +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 + # 0.11.0 - De- and encode protobuf messages using `prost-codec`. See [PR 3058]. diff --git a/protocols/rendezvous/Cargo.toml b/protocols/rendezvous/Cargo.toml index d8da3b29b99..1ff8bac95cd 100644 --- a/protocols/rendezvous/Cargo.toml +++ b/protocols/rendezvous/Cargo.toml @@ -19,8 +19,8 @@ instant = "0.1.11" libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-swarm = { version = "0.42.0", path = "../../swarm" } log = "0.4" -prost = "0.11" -prost-codec = { version = "0.3.0", path = "../../misc/prost-codec" } +quick-protobuf = "0.8" +quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" } rand = "0.8" thiserror = "1" void = "1" @@ -38,9 +38,6 @@ libp2p-tcp = { path = "../../transports/tcp", features = ["tokio"] } rand = "0.8" tokio = { version = "1.15", features = [ "rt-multi-thread", "time", "macros", "sync", "process", "fs", "net" ] } -[build-dependencies] -prost-build = "0.11" - # Passing arguments to the docsrs builder in order to properly document cfg's. # More information: https://docs.rs/about/builds#cross-compiling [package.metadata.docs.rs] diff --git a/protocols/rendezvous/build.rs b/protocols/rendezvous/build.rs deleted file mode 100644 index fa982fa3d90..00000000000 --- a/protocols/rendezvous/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - prost_build::compile_protos(&["src/rpc.proto"], &["src"]).unwrap(); -} diff --git a/protocols/rendezvous/src/codec.rs b/protocols/rendezvous/src/codec.rs index b14795417e0..39447a56bdb 100644 --- a/protocols/rendezvous/src/codec.rs +++ b/protocols/rendezvous/src/codec.rs @@ -200,13 +200,13 @@ pub enum ErrorCode { } pub struct RendezvousCodec { - inner: prost_codec::Codec, + inner: quick_protobuf_codec::Codec, } impl Default for RendezvousCodec { fn default() -> Self { Self { - inner: prost_codec::Codec::new(1024 * 1024), // 1MB + inner: quick_protobuf_codec::Codec::new(1024 * 1024), // 1MB } } } @@ -216,7 +216,7 @@ impl Encoder for RendezvousCodec { type Error = Error; fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> { - self.inner.encode(wire::Message::from(item), dst)?; + self.inner.encode(proto::Message::from(item), dst)?; Ok(()) } @@ -239,140 +239,134 @@ impl Decoder for RendezvousCodec { #[derive(Debug, thiserror::Error)] pub enum Error { #[error(transparent)] - Codec(#[from] prost_codec::Error), + Codec(#[from] quick_protobuf_codec::Error), #[error("Failed to read/write")] Io(#[from] std::io::Error), #[error("Failed to convert wire message to internal data model")] Conversion(#[from] ConversionError), } -impl From for wire::Message { +impl From for proto::Message { fn from(message: Message) -> Self { - use wire::message::*; - match message { Message::Register(NewRegistration { namespace, record, ttl, - }) => wire::Message { - r#type: Some(MessageType::Register.into()), - register: Some(Register { + }) => proto::Message { + type_pb: Some(proto::MessageType::REGISTER), + register: Some(proto::Register { ns: Some(namespace.into()), ttl, - signed_peer_record: Some( - record.into_signed_envelope().into_protobuf_encoding(), - ), + signedPeerRecord: Some(record.into_signed_envelope().into_protobuf_encoding()), }), - register_response: None, + registerResponse: None, unregister: None, discover: None, - discover_response: None, + discoverResponse: None, }, - Message::RegisterResponse(Ok(ttl)) => wire::Message { - r#type: Some(MessageType::RegisterResponse.into()), - register_response: Some(RegisterResponse { - status: Some(ResponseStatus::Ok.into()), - status_text: 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, ttl: Some(ttl), }), register: None, discover: None, unregister: None, - discover_response: None, + discoverResponse: None, }, - Message::RegisterResponse(Err(error)) => wire::Message { - r#type: Some(MessageType::RegisterResponse.into()), - register_response: Some(RegisterResponse { - status: Some(ResponseStatus::from(error).into()), - status_text: 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, ttl: None, }), register: None, discover: None, unregister: None, - discover_response: None, + discoverResponse: None, }, - Message::Unregister(namespace) => wire::Message { - r#type: Some(MessageType::Unregister.into()), - unregister: Some(Unregister { + Message::Unregister(namespace) => proto::Message { + type_pb: Some(proto::MessageType::UNREGISTER), + unregister: Some(proto::Unregister { ns: Some(namespace.into()), id: None, }), register: None, - register_response: None, + registerResponse: None, discover: None, - discover_response: None, + discoverResponse: None, }, Message::Discover { namespace, cookie, limit, - } => wire::Message { - r#type: Some(MessageType::Discover.into()), - discover: Some(Discover { + } => proto::Message { + type_pb: Some(proto::MessageType::DISCOVER), + discover: Some(proto::Discover { ns: namespace.map(|ns| ns.into()), cookie: cookie.map(|cookie| cookie.into_wire_encoding()), limit, }), register: None, - register_response: None, + registerResponse: None, unregister: None, - discover_response: None, + discoverResponse: None, }, - Message::DiscoverResponse(Ok((registrations, cookie))) => wire::Message { - r#type: Some(MessageType::DiscoverResponse.into()), - discover_response: Some(DiscoverResponse { + Message::DiscoverResponse(Ok((registrations, cookie))) => proto::Message { + type_pb: Some(proto::MessageType::DISCOVER_RESPONSE), + discoverResponse: Some(proto::DiscoverResponse { registrations: registrations .into_iter() - .map(|reggo| Register { + .map(|reggo| proto::Register { ns: Some(reggo.namespace.into()), ttl: Some(reggo.ttl), - signed_peer_record: Some( + signedPeerRecord: Some( reggo.record.into_signed_envelope().into_protobuf_encoding(), ), }) .collect(), - status: Some(ResponseStatus::Ok.into()), - status_text: None, + status: Some(proto::ResponseStatus::OK), + statusText: None, cookie: Some(cookie.into_wire_encoding()), }), register: None, discover: None, unregister: None, - register_response: None, + registerResponse: None, }, - Message::DiscoverResponse(Err(error)) => wire::Message { - r#type: Some(MessageType::DiscoverResponse.into()), - discover_response: Some(DiscoverResponse { + Message::DiscoverResponse(Err(error)) => proto::Message { + type_pb: Some(proto::MessageType::DISCOVER_RESPONSE), + discoverResponse: Some(proto::DiscoverResponse { registrations: Vec::new(), - status: Some(ResponseStatus::from(error).into()), - status_text: None, + status: Some(proto::ResponseStatus::from(error)), + statusText: None, cookie: None, }), register: None, discover: None, unregister: None, - register_response: None, + registerResponse: None, }, } } } -impl TryFrom for Message { +impl TryFrom for Message { type Error = ConversionError; - fn try_from(message: wire::Message) -> Result { - use wire::message::*; - + fn try_from(message: proto::Message) -> Result { let message = match message { - wire::Message { - r#type: Some(0), + proto::Message { + type_pb: Some(proto::MessageType::REGISTER), register: - Some(Register { + Some(proto::Register { ns, ttl, - signed_peer_record: Some(signed_peer_record), + signedPeerRecord: Some(signed_peer_record), }), .. } => Message::Register(NewRegistration { @@ -385,31 +379,31 @@ impl TryFrom for Message { &signed_peer_record, )?)?, }), - wire::Message { - r#type: Some(1), - register_response: - Some(RegisterResponse { - status: Some(0), + 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)?)), - wire::Message { - r#type: Some(3), - discover: Some(Discover { ns, limit, cookie }), + 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, }, - wire::Message { - r#type: Some(4), - discover_response: - Some(DiscoverResponse { + proto::Message { + type_pb: Some(proto::MessageType::DISCOVER_RESPONSE), + discoverResponse: + Some(proto::DiscoverResponse { registrations, - status: Some(0), + status: Some(proto::ResponseStatus::OK), cookie: Some(cookie), .. }), @@ -427,7 +421,7 @@ impl TryFrom for Message { record: PeerRecord::from_signed_envelope( SignedEnvelope::from_protobuf_encoding( ®go - .signed_peer_record + .signedPeerRecord .ok_or(ConversionError::MissingSignedPeerRecord)?, )?, )?, @@ -439,43 +433,33 @@ impl TryFrom for Message { Message::DiscoverResponse(Ok((registrations, cookie))) } - wire::Message { - r#type: Some(1), - register_response: - Some(RegisterResponse { - status: Some(error_code), + proto::Message { + type_pb: Some(proto::MessageType::REGISTER_RESPONSE), + registerResponse: + Some(proto::RegisterResponse { + status: Some(response_status), .. }), .. - } => { - let error_code = wire::message::ResponseStatus::from_i32(error_code) - .ok_or(ConversionError::BadStatusCode)? - .try_into()?; - Message::RegisterResponse(Err(error_code)) - } - wire::Message { - r#type: Some(2), - unregister: Some(Unregister { ns, .. }), + } => 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)?, ), - wire::Message { - r#type: Some(4), - discover_response: - Some(DiscoverResponse { - status: Some(error_code), + proto::Message { + type_pb: Some(proto::MessageType::DISCOVER_RESPONSE), + discoverResponse: + Some(proto::DiscoverResponse { + status: Some(response_status), .. }), .. - } => { - let error = wire::message::ResponseStatus::from_i32(error_code) - .ok_or(ConversionError::BadStatusCode)? - .try_into()?; - Message::DiscoverResponse(Err(error)) - } + } => Message::DiscoverResponse(Err(response_status.try_into()?)), _ => return Err(ConversionError::InconsistentWireMessage), }; @@ -527,39 +511,39 @@ impl ConversionError { } } -impl TryFrom for ErrorCode { +impl TryFrom for ErrorCode { type Error = UnmappableStatusCode; - fn try_from(value: wire::message::ResponseStatus) -> Result { - use wire::message::ResponseStatus::*; + fn try_from(value: proto::ResponseStatus) -> Result { + use proto::ResponseStatus::*; let code = match value { - Ok => return Err(UnmappableStatusCode(value)), - EInvalidNamespace => ErrorCode::InvalidNamespace, - EInvalidSignedPeerRecord => ErrorCode::InvalidSignedPeerRecord, - EInvalidTtl => ErrorCode::InvalidTtl, - EInvalidCookie => ErrorCode::InvalidCookie, - ENotAuthorized => ErrorCode::NotAuthorized, - EInternalError => ErrorCode::InternalError, - EUnavailable => ErrorCode::Unavailable, + 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, }; Result::Ok(code) } } -impl From for wire::message::ResponseStatus { +impl From for proto::ResponseStatus { fn from(error_code: ErrorCode) -> Self { - use wire::message::ResponseStatus::*; + use proto::ResponseStatus::*; match error_code { - ErrorCode::InvalidNamespace => EInvalidNamespace, - ErrorCode::InvalidSignedPeerRecord => EInvalidSignedPeerRecord, - ErrorCode::InvalidTtl => EInvalidTtl, - ErrorCode::InvalidCookie => EInvalidCookie, - ErrorCode::NotAuthorized => ENotAuthorized, - ErrorCode::InternalError => EInternalError, - ErrorCode::Unavailable => EUnavailable, + 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, } } } @@ -572,11 +556,11 @@ impl From for ConversionError { #[derive(Debug, thiserror::Error)] #[error("The response code ({0:?}) cannot be mapped to our ErrorCode enum")] -pub struct UnmappableStatusCode(wire::message::ResponseStatus); +pub struct UnmappableStatusCode(proto::ResponseStatus); -#[allow(clippy::derive_partial_eq_without_eq)] -mod wire { - include!(concat!(env!("OUT_DIR"), "/rendezvous.pb.rs")); +mod proto { + include!("generated/mod.rs"); + pub use self::rendezvous::pb::{mod_Message::*, Message}; } #[cfg(test)] diff --git a/protocols/rendezvous/src/generated/mod.rs b/protocols/rendezvous/src/generated/mod.rs new file mode 100644 index 00000000000..448a0207b2d --- /dev/null +++ b/protocols/rendezvous/src/generated/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod rendezvous; diff --git a/protocols/rendezvous/src/generated/rendezvous/mod.rs b/protocols/rendezvous/src/generated/rendezvous/mod.rs new file mode 100644 index 00000000000..aec6164c7ef --- /dev/null +++ b/protocols/rendezvous/src/generated/rendezvous/mod.rs @@ -0,0 +1,2 @@ +// 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 new file mode 100644 index 00000000000..2419ecf6a37 --- /dev/null +++ b/protocols/rendezvous/src/generated/rendezvous/pb.rs @@ -0,0 +1,364 @@ +// 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/protocols/rendezvous/src/rpc.proto b/protocols/rendezvous/src/generated/rpc.proto similarity index 100% rename from protocols/rendezvous/src/rpc.proto rename to protocols/rendezvous/src/generated/rpc.proto diff --git a/transports/noise/CHANGELOG.md b/transports/noise/CHANGELOG.md index 77730bd3437..8d1cff71107 100644 --- a/transports/noise/CHANGELOG.md +++ b/transports/noise/CHANGELOG.md @@ -6,8 +6,11 @@ - Deprecate `LegacyConfig` without replacement. See [PR 3265]. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. + [PR 3227]: https://github.com/libp2p/rust-libp2p/pull/3227 [PR 3265]: https://github.com/libp2p/rust-libp2p/pull/3265 +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 # 0.41.0 diff --git a/transports/noise/Cargo.toml b/transports/noise/Cargo.toml index 8666177861d..64514f6e54c 100644 --- a/transports/noise/Cargo.toml +++ b/transports/noise/Cargo.toml @@ -14,8 +14,8 @@ curve25519-dalek = "3.0.0" futures = "0.3.26" libp2p-core = { version = "0.39.0", path = "../../core" } log = "0.4" +quick-protobuf = "0.8" once_cell = "1.17.1" -prost = "0.11" rand = "0.8.3" sha2 = "0.10.0" static_assertions = "1" @@ -37,9 +37,6 @@ libp2p-tcp = { path = "../tcp", features = ["async-io"] } libsodium-sys-stable = { version = "1.19.22", features = ["fetch-latest"] } quickcheck = { package = "quickcheck-ext", path = "../../misc/quickcheck-ext" } -[build-dependencies] -prost-build = "0.11" - # Passing arguments to the docsrs builder in order to properly document cfg's. # More information: https://docs.rs/about/builds#cross-compiling [package.metadata.docs.rs] diff --git a/transports/noise/build.rs b/transports/noise/build.rs deleted file mode 100644 index c9cf60412cd..00000000000 --- a/transports/noise/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -fn main() { - prost_build::compile_protos(&["src/io/handshake/payload.proto"], &["src"]).unwrap(); -} diff --git a/transports/noise/src/generated/mod.rs b/transports/noise/src/generated/mod.rs new file mode 100644 index 00000000000..c2153dd9066 --- /dev/null +++ b/transports/noise/src/generated/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod payload; diff --git a/transports/noise/src/io/handshake/payload.proto b/transports/noise/src/generated/payload.proto similarity index 100% rename from transports/noise/src/io/handshake/payload.proto rename to transports/noise/src/generated/payload.proto diff --git a/transports/noise/src/generated/payload/mod.rs b/transports/noise/src/generated/payload/mod.rs new file mode 100644 index 00000000000..5e3889634fb --- /dev/null +++ b/transports/noise/src/generated/payload/mod.rs @@ -0,0 +1,2 @@ +// 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 new file mode 100644 index 00000000000..7b17a58ef37 --- /dev/null +++ b/transports/noise/src/generated/payload/proto.rs @@ -0,0 +1,55 @@ +// 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 NoiseHandshakePayload { + pub identity_key: Vec, + pub identity_sig: Vec, + pub data: Vec, +} + +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(26) => 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 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()) } + + if self.data.is_empty() { 0 } else { 1 + sizeof_len((&self.data).len()) } + } + + 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 !self.data.is_empty() { w.write_with_tag(26, |w| w.write_bytes(&**&self.data))?; } + Ok(()) + } +} + diff --git a/transports/noise/src/io/handshake.rs b/transports/noise/src/io/handshake.rs index cdcea04509a..1a6a8694ca2 100644 --- a/transports/noise/src/io/handshake.rs +++ b/transports/noise/src/io/handshake.rs @@ -20,9 +20,9 @@ //! Noise protocol handshake I/O. -#[allow(clippy::derive_partial_eq_without_eq)] -mod payload_proto { - include!(concat!(env!("OUT_DIR"), "/payload.proto.rs")); +mod proto { + include!("../generated/mod.rs"); + pub use self::payload::proto::NoiseHandshakePayload; } use crate::io::{framed::NoiseFramed, NoiseOutput}; @@ -33,7 +33,7 @@ use crate::NoiseError; use bytes::Bytes; use futures::prelude::*; use libp2p_core::identity; -use prost::Message; +use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer}; use std::io; /// The identity of the remote established during a handshake. @@ -178,7 +178,8 @@ where { let msg = recv(state).await?; - let mut pb_result = payload_proto::NoiseHandshakePayload::decode(&msg[..]); + let mut reader = BytesReader::from_bytes(&msg[..]); + let mut pb_result = proto::NoiseHandshakePayload::from_reader(&mut reader, &msg[..]); #[allow(deprecated)] if pb_result.is_err() && state.legacy.recv_legacy_handshake { @@ -200,7 +201,8 @@ where // frame length, because each length is encoded as a `u16`. if usize::from(u16::from_be_bytes(buf)) + 2 == msg.len() { log::debug!("Attempting fallback legacy protobuf decoding."); - payload_proto::NoiseHandshakePayload::decode(&msg[2..]) + let mut reader = BytesReader::from_bytes(&msg[2..]); + proto::NoiseHandshakePayload::from_reader(&mut reader, &msg[2..]) } else { Err(e) } @@ -233,7 +235,7 @@ pub async fn send_identity(state: &mut State) -> Result<(), NoiseError> where T: AsyncWrite + Unpin, { - let mut pb = payload_proto::NoiseHandshakePayload { + let mut pb = proto::NoiseHandshakePayload { identity_key: state.identity.public.to_protobuf_encoding(), ..Default::default() }; @@ -244,15 +246,15 @@ where #[allow(deprecated)] let mut msg = if state.legacy.send_legacy_handshake { - let mut msg = Vec::with_capacity(2 + pb.encoded_len()); - msg.extend_from_slice(&(pb.encoded_len() as u16).to_be_bytes()); + let mut msg = Vec::with_capacity(2 + pb.get_size()); + msg.extend_from_slice(&(pb.get_size() as u16).to_be_bytes()); msg } else { - Vec::with_capacity(pb.encoded_len()) + Vec::with_capacity(pb.get_size()) }; - pb.encode(&mut msg) - .expect("Vec provides capacity as needed"); + let mut writer = Writer::new(&mut msg); + pb.write_message(&mut writer).expect("Encoding to succeed"); state.io.send(&msg).await?; Ok(()) @@ -263,7 +265,7 @@ pub async fn send_signature_only(state: &mut State) -> Result<(), NoiseErr where T: AsyncWrite + Unpin, { - let mut pb = payload_proto::NoiseHandshakePayload::default(); + let mut pb = proto::NoiseHandshakePayload::default(); if let Some(ref sig) = state.identity.signature { pb.identity_sig = sig.clone() @@ -271,15 +273,15 @@ where #[allow(deprecated)] let mut msg = if state.legacy.send_legacy_handshake { - let mut msg = Vec::with_capacity(2 + pb.encoded_len()); - msg.extend_from_slice(&(pb.encoded_len() as u16).to_be_bytes()); + let mut msg = Vec::with_capacity(2 + pb.get_size()); + msg.extend_from_slice(&(pb.get_size() as u16).to_be_bytes()); msg } else { - Vec::with_capacity(pb.encoded_len()) + Vec::with_capacity(pb.get_size()) }; - pb.encode(&mut msg) - .expect("Vec provides capacity as needed"); + let mut writer = Writer::new(&mut msg); + pb.write_message(&mut writer).expect("Encoding to succeed"); state.io.send(&msg).await?; Ok(()) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 9e8a9ea21de..05a0d4d93a0 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -65,6 +65,8 @@ pub use protocol::x25519::X25519; pub use protocol::x25519_spec::X25519Spec; pub use protocol::{AuthenticKeypair, Keypair, KeypairIdentity, PublicKey, SecretKey}; pub use protocol::{Protocol, ProtocolParams, IK, IX, XX}; +use std::fmt; +use std::fmt::Formatter; use crate::handshake::State; use crate::io::handshake; @@ -284,12 +286,23 @@ pub enum NoiseError { } #[derive(Debug, thiserror::Error)] -#[error(transparent)] -pub struct DecodeError(prost::DecodeError); +pub struct DecodeError(String); -impl From for NoiseError { - fn from(e: prost::DecodeError) -> Self { - NoiseError::InvalidPayload(DecodeError(e)) +impl fmt::Display for DecodeError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for DecodeError { + fn from(e: quick_protobuf::Error) -> Self { + Self(e.to_string()) + } +} + +impl From for NoiseError { + fn from(e: quick_protobuf::Error) -> Self { + NoiseError::InvalidPayload(e.into()) } } diff --git a/transports/plaintext/CHANGELOG.md b/transports/plaintext/CHANGELOG.md index 3e34f3149cb..586d54690fd 100644 --- a/transports/plaintext/CHANGELOG.md +++ b/transports/plaintext/CHANGELOG.md @@ -2,6 +2,10 @@ - Update to `libp2p-core` `v0.39.0`. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. + +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 + # 0.38.0 - Add more specific error reporting and remove `prost::Error` from public API. See [PR 3058]. diff --git a/transports/plaintext/Cargo.toml b/transports/plaintext/Cargo.toml index 722bf1dae9f..05e8872de2f 100644 --- a/transports/plaintext/Cargo.toml +++ b/transports/plaintext/Cargo.toml @@ -16,7 +16,7 @@ bytes = "1" futures = "0.3.26" libp2p-core = { version = "0.39.0", path = "../../core" } log = "0.4.8" -prost = "0.11" +quick-protobuf = "0.8" unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] } void = "1.0.2" @@ -25,9 +25,6 @@ env_logger = "0.10.0" quickcheck = { package = "quickcheck-ext", path = "../../misc/quickcheck-ext" } rand = "0.8" -[build-dependencies] -prost-build = "0.11" - # Passing arguments to the docsrs builder in order to properly document cfg's. # More information: https://docs.rs/about/builds#cross-compiling [package.metadata.docs.rs] diff --git a/transports/plaintext/build.rs b/transports/plaintext/build.rs deleted file mode 100644 index 56c7b20121a..00000000000 --- a/transports/plaintext/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -fn main() { - prost_build::compile_protos(&["src/structs.proto"], &["src"]).unwrap(); -} diff --git a/transports/plaintext/src/error.rs b/transports/plaintext/src/error.rs index 3943bb068a0..133cca746af 100644 --- a/transports/plaintext/src/error.rs +++ b/transports/plaintext/src/error.rs @@ -41,7 +41,7 @@ pub enum PlainTextError { } #[derive(Debug)] -pub struct DecodeError(prost::DecodeError); +pub struct DecodeError(quick_protobuf::Error); impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -87,8 +87,8 @@ impl From for PlainTextError { } } -impl From for PlainTextError { - fn from(err: prost::DecodeError) -> PlainTextError { +impl From for PlainTextError { + fn from(err: quick_protobuf::Error) -> PlainTextError { PlainTextError::InvalidPayload(DecodeError(err)) } } diff --git a/transports/plaintext/src/generated/mod.rs b/transports/plaintext/src/generated/mod.rs new file mode 100644 index 00000000000..e52c5a80bc0 --- /dev/null +++ b/transports/plaintext/src/generated/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod structs; diff --git a/transports/plaintext/src/structs.proto b/transports/plaintext/src/generated/structs.proto similarity index 100% rename from transports/plaintext/src/structs.proto rename to transports/plaintext/src/generated/structs.proto diff --git a/transports/plaintext/src/generated/structs.rs b/transports/plaintext/src/generated/structs.rs new file mode 100644 index 00000000000..aa4d94f35dd --- /dev/null +++ b/transports/plaintext/src/generated/structs.rs @@ -0,0 +1,51 @@ +// Automatically generated rust module for 'structs.proto' file + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(unknown_lints)] +#![allow(clippy::all)] +#![cfg_attr(rustfmt, rustfmt_skip)] + + +use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result}; +use quick_protobuf::sizeofs::*; +use super::*; + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Debug, Default, PartialEq, Clone)] +pub struct Exchange { + pub id: Option>, + pub pubkey: Option>, +} + +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 0e17ac5bc46..8ce24f9df22 100644 --- a/transports/plaintext/src/handshake.rs +++ b/transports/plaintext/src/handshake.rs @@ -19,7 +19,7 @@ // DEALINGS IN THE SOFTWARE. use crate::error::PlainTextError; -use crate::structs_proto::Exchange; +use crate::proto::Exchange; use crate::PlainText2Config; use asynchronous_codec::{Framed, FramedParts}; @@ -27,7 +27,7 @@ use bytes::{Bytes, BytesMut}; use futures::prelude::*; use libp2p_core::{PeerId, PublicKey}; use log::{debug, trace}; -use prost::Message; +use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer}; use std::io::{Error as IoError, ErrorKind as IoErrorKind}; use unsigned_varint::codec::UviBytes; @@ -56,10 +56,11 @@ impl HandshakeContext { id: Some(config.local_public_key.to_peer_id().to_bytes()), pubkey: Some(config.local_public_key.to_protobuf_encoding()), }; - let mut buf = Vec::with_capacity(exchange.encoded_len()); + let mut buf = Vec::with_capacity(exchange.get_size()); + let mut writer = Writer::new(&mut buf); exchange - .encode(&mut buf) - .expect("Vec provides capacity as needed"); + .write_message(&mut writer) + .expect("Encoding to succeed"); Self { config, @@ -73,7 +74,8 @@ impl HandshakeContext { self, exchange_bytes: BytesMut, ) -> Result, PlainTextError> { - let prop = Exchange::decode(exchange_bytes)?; + let mut reader = BytesReader::from_bytes(&exchange_bytes); + let prop = Exchange::from_reader(&mut reader, &exchange_bytes)?; let public_key = PublicKey::from_protobuf_encoding(&prop.pubkey.unwrap_or_default())?; let peer_id = PeerId::from_bytes(&prop.id.unwrap_or_default())?; diff --git a/transports/plaintext/src/lib.rs b/transports/plaintext/src/lib.rs index 6a1d66c2af8..c4a6a2ed011 100644 --- a/transports/plaintext/src/lib.rs +++ b/transports/plaintext/src/lib.rs @@ -39,9 +39,9 @@ use void::Void; mod error; mod handshake; -#[allow(clippy::derive_partial_eq_without_eq)] -mod structs_proto { - include!(concat!(env!("OUT_DIR"), "/structs.rs")); +mod proto { + include!("generated/mod.rs"); + pub use self::structs::Exchange; } /// `PlainText1Config` is an insecure connection handshake for testing purposes only. diff --git a/transports/webrtc/CHANGELOG.md b/transports/webrtc/CHANGELOG.md index 34ee15d20b0..055b194c471 100644 --- a/transports/webrtc/CHANGELOG.md +++ b/transports/webrtc/CHANGELOG.md @@ -4,6 +4,10 @@ - Update to `libp2p-core` `v0.39.0`. +- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. + +[PR 3312]: https://github.com/libp2p/rust-libp2p/pull/3312 + # 0.4.0-alpha - Initial alpha release. \ No newline at end of file diff --git a/transports/webrtc/Cargo.toml b/transports/webrtc/Cargo.toml index 990d09101a7..762dc8bb359 100644 --- a/transports/webrtc/Cargo.toml +++ b/transports/webrtc/Cargo.toml @@ -22,8 +22,8 @@ libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-noise = { version = "0.42.0", path = "../../transports/noise" } log = "0.4" multihash = { version = "0.17.0", default-features = false, features = ["sha2"] } -prost = "0.11" -prost-codec = { version = "0.3.0", path = "../../misc/prost-codec" } +quick-protobuf = "0.8" +quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" } rand = "0.8" rcgen = "0.9.3" serde = { version = "1.0", features = ["derive"] } @@ -38,9 +38,6 @@ webrtc = { version = "0.6.0", optional = true } tokio = ["dep:tokio", "dep:tokio-util", "dep:webrtc", "if-watch/tokio"] pem = ["webrtc?/pem"] -[build-dependencies] -prost-build = "0.11" - [dev-dependencies] anyhow = "1.0" env_logger = "0.10" diff --git a/transports/webrtc/build.rs b/transports/webrtc/build.rs deleted file mode 100644 index 3f582337a68..00000000000 --- a/transports/webrtc/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2022 Protocol Labs. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -fn main() { - prost_build::compile_protos(&["src/message.proto"], &["src"]).unwrap(); -} diff --git a/transports/webrtc/src/message.proto b/transports/webrtc/src/generated/message.proto similarity index 100% rename from transports/webrtc/src/message.proto rename to transports/webrtc/src/generated/message.proto diff --git a/transports/webrtc/src/generated/mod.rs b/transports/webrtc/src/generated/mod.rs new file mode 100644 index 00000000000..5e9f6373b12 --- /dev/null +++ b/transports/webrtc/src/generated/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod webrtc; diff --git a/transports/webrtc/src/generated/webrtc/mod.rs b/transports/webrtc/src/generated/webrtc/mod.rs new file mode 100644 index 00000000000..aec6164c7ef --- /dev/null +++ b/transports/webrtc/src/generated/webrtc/mod.rs @@ -0,0 +1,2 @@ +// Automatically generated mod.rs +pub mod pb; diff --git a/transports/webrtc/src/generated/webrtc/pb.rs b/transports/webrtc/src/generated/webrtc/pb.rs new file mode 100644 index 00000000000..9e33e97188c --- /dev/null +++ b/transports/webrtc/src/generated/webrtc/pb.rs @@ -0,0 +1,91 @@ +// 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/transports/webrtc/src/lib.rs b/transports/webrtc/src/lib.rs index 3210ad38cac..95bd0ac6d7e 100644 --- a/transports/webrtc/src/lib.rs +++ b/transports/webrtc/src/lib.rs @@ -80,10 +80,9 @@ //! is to make the hash a part of the remote's multiaddr. On the server side, we turn //! certificate verification off. -mod message_proto { - #![allow(clippy::derive_partial_eq_without_eq)] - - include!(concat!(env!("OUT_DIR"), "/webrtc.pb.rs")); +mod proto { + include!("generated/mod.rs"); + pub use self::webrtc::pb::{mod_Message::Flag, Message}; } #[cfg(feature = "tokio")] diff --git a/transports/webrtc/src/tokio/substream.rs b/transports/webrtc/src/tokio/substream.rs index 8622719a37c..e3f9ef9e074 100644 --- a/transports/webrtc/src/tokio/substream.rs +++ b/transports/webrtc/src/tokio/substream.rs @@ -31,7 +31,7 @@ use std::{ task::{Context, Poll}, }; -use crate::message_proto::{message::Flag, Message}; +use crate::proto::{Flag, Message}; use crate::tokio::{ substream::drop_listener::GracefullyClosed, substream::framed_dc::FramedDc, @@ -94,7 +94,7 @@ impl Substream { ready!(self.io.poll_ready_unpin(cx))?; self.io.start_send_unpin(Message { - flag: Some(Flag::StopSending.into()), + flag: Some(Flag::STOP_SENDING), message: None, })?; self.state.close_read_message_sent(); @@ -150,7 +150,7 @@ impl AsyncRead for Substream { } } None => { - state.handle_inbound_flag(Flag::Fin, read_buffer); + state.handle_inbound_flag(Flag::FIN, read_buffer); return Poll::Ready(Ok(0)); } } @@ -212,7 +212,7 @@ impl AsyncWrite for Substream { ready!(self.io.poll_ready_unpin(cx))?; self.io.start_send_unpin(Message { - flag: Some(Flag::Fin.into()), + flag: Some(Flag::FIN), message: None, })?; self.state.close_write_message_sent(); @@ -238,22 +238,14 @@ impl AsyncWrite for Substream { } fn io_poll_next( - io: &mut Framed, prost_codec::Codec>, + io: &mut Framed, quick_protobuf_codec::Codec>, cx: &mut Context<'_>, ) -> Poll, Option>)>>> { match ready!(io.poll_next_unpin(cx)) .transpose() .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))? { - Some(Message { flag, message }) => { - let flag = flag - .map(|f| { - Flag::from_i32(f).ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "")) - }) - .transpose()?; - - Poll::Ready(Ok(Some((flag, message)))) - } + Some(Message { flag, message }) => Poll::Ready(Ok(Some((flag, message)))), None => Poll::Ready(Ok(None)), } } @@ -263,7 +255,7 @@ mod tests { use super::*; use asynchronous_codec::Encoder; use bytes::BytesMut; - use prost::Message; + use quick_protobuf::{MessageWrite, Writer}; use unsigned_varint::codec::UviBytes; #[test] @@ -271,20 +263,21 @@ mod tests { // Largest possible message. let message = [0; MAX_DATA_LEN]; - let protobuf = crate::message_proto::Message { - flag: Some(crate::message_proto::message::Flag::Fin.into()), + let protobuf = crate::proto::Message { + flag: Some(crate::proto::Flag::FIN), message: Some(message.to_vec()), }; - let mut encoded_msg = BytesMut::new(); + let mut encoded_msg = Vec::new(); + let mut writer = Writer::new(&mut encoded_msg); protobuf - .encode(&mut encoded_msg) - .expect("BytesMut to have sufficient capacity."); + .write_message(&mut writer) + .expect("Encoding to succeed"); assert_eq!(encoded_msg.len(), message.len() + PROTO_OVERHEAD); let mut uvi = UviBytes::default(); let mut dst = BytesMut::new(); - uvi.encode(encoded_msg.clone().freeze(), &mut dst).unwrap(); + uvi.encode(encoded_msg.as_slice(), &mut dst).unwrap(); // Ensure the varint prefixed and protobuf encoded largest message is no longer than the // maximum limit specified in the libp2p WebRTC specification. diff --git a/transports/webrtc/src/tokio/substream/drop_listener.rs b/transports/webrtc/src/tokio/substream/drop_listener.rs index 892d9c876a0..3e3dc18a1d6 100644 --- a/transports/webrtc/src/tokio/substream/drop_listener.rs +++ b/transports/webrtc/src/tokio/substream/drop_listener.rs @@ -27,7 +27,7 @@ use std::io; use std::pin::Pin; use std::task::{Context, Poll}; -use crate::message_proto::{message::Flag, Message}; +use crate::proto::{Flag, Message}; use crate::tokio::substream::framed_dc::FramedDc; #[must_use] @@ -100,7 +100,7 @@ impl Future for DropListener { State::SendingReset { mut stream } => match stream.poll_ready_unpin(cx)? { Poll::Ready(()) => { stream.start_send_unpin(Message { - flag: Some(Flag::Reset.into()), + flag: Some(Flag::RESET), message: None, })?; *state = State::Flushing { stream }; diff --git a/transports/webrtc/src/tokio/substream/framed_dc.rs b/transports/webrtc/src/tokio/substream/framed_dc.rs index 39bd117f1f1..1bf2b3cf769 100644 --- a/transports/webrtc/src/tokio/substream/framed_dc.rs +++ b/transports/webrtc/src/tokio/substream/framed_dc.rs @@ -26,9 +26,9 @@ use webrtc::data::data_channel::{DataChannel, PollDataChannel}; use std::sync::Arc; use super::{MAX_DATA_LEN, MAX_MSG_LEN, VARINT_LEN}; -use crate::message_proto::Message; +use crate::proto::Message; -pub type FramedDc = Framed, prost_codec::Codec>; +pub type FramedDc = Framed, quick_protobuf_codec::Codec>; pub fn new(data_channel: Arc) -> FramedDc { let mut inner = PollDataChannel::new(data_channel); @@ -36,7 +36,7 @@ pub fn new(data_channel: Arc) -> FramedDc { let mut framed = Framed::new( inner.compat(), - prost_codec::Codec::new(MAX_MSG_LEN - VARINT_LEN), + quick_protobuf_codec::Codec::new(MAX_MSG_LEN - VARINT_LEN), ); // If not set, `Framed` buffers up to 131kB of data before sending, which leads to "outbound // packet larger than maximum message size" error in webrtc-rs. diff --git a/transports/webrtc/src/tokio/substream/state.rs b/transports/webrtc/src/tokio/substream/state.rs index 6a5340fb1f1..a064c424ec3 100644 --- a/transports/webrtc/src/tokio/substream/state.rs +++ b/transports/webrtc/src/tokio/substream/state.rs @@ -22,7 +22,7 @@ use bytes::Bytes; use std::io; -use crate::message_proto::message::Flag; +use crate::proto::Flag; #[derive(Debug, Copy, Clone)] pub enum State { @@ -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::StopSending) => { + (Self::Open, Flag::STOP_SENDING) => { *self = Self::WriteClosed; } - (Self::ReadClosed, Flag::StopSending) => { + (Self::ReadClosed, Flag::STOP_SENDING) => { *self = Self::BothClosed { reset: false }; } - (_, Flag::Reset) => { + (_, Flag::RESET) => { buffer.clear(); *self = Self::BothClosed { reset: true }; } @@ -333,7 +333,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) @@ -355,7 +355,7 @@ mod tests { fn cannot_write_after_receiving_stop_sending() { let mut open = State::Open; - open.handle_inbound_flag(Flag::StopSending, &mut Bytes::default()); + open.handle_inbound_flag(Flag::STOP_SENDING, &mut Bytes::default()); let error = open.write_barrier().unwrap_err(); assert_eq!(error.kind(), ErrorKind::BrokenPipe) @@ -377,7 +377,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(); @@ -393,7 +393,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()) } @@ -402,8 +402,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::StopSending, &mut Bytes::default()); + open.handle_inbound_flag(Flag::FIN, &mut Bytes::default()); + open.handle_inbound_flag(Flag::STOP_SENDING, &mut Bytes::default()); let error1 = open.read_barrier().unwrap_err(); let error2 = open.write_barrier().unwrap_err(); @@ -503,7 +503,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()); }