From 51dd7023f5a2b3316ab094c97784914f24740417 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 27 Oct 2023 09:25:04 +1100 Subject: [PATCH] chore: remove deprecated `libp2p-deflate` Related: #4522. Pull-Request: #4729. --- CHANGELOG.md | 1 - Cargo.lock | 34 ---- Cargo.toml | 2 - libp2p/CHANGELOG.md | 3 + libp2p/Cargo.toml | 3 - libp2p/src/lib.rs | 9 - transports/deflate/CHANGELOG.md | 115 ------------- transports/deflate/Cargo.toml | 33 ---- transports/deflate/src/lib.rs | 278 ------------------------------- transports/deflate/tests/test.rs | 82 --------- 10 files changed, 3 insertions(+), 557 deletions(-) delete mode 100644 transports/deflate/CHANGELOG.md delete mode 100644 transports/deflate/Cargo.toml delete mode 100644 transports/deflate/src/lib.rs delete mode 100644 transports/deflate/tests/test.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 77da18ba6f5..3c3466708c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,6 @@ ## Transport Protocols & Upgrades -- [`libp2p-deflate` CHANGELOG](transports/deflate/CHANGELOG.md) - [`libp2p-dns` CHANGELOG](transports/dns/CHANGELOG.md) - [`libp2p-noise` CHANGELOG](transports/noise/CHANGELOG.md) - [`libp2p-perf` CHANGELOG](transports/perf/CHANGELOG.md) diff --git a/Cargo.lock b/Cargo.lock index 647e20395bd..f2c3c20bec8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1001,15 +1001,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - [[package]] name = "criterion" version = "0.5.1" @@ -1527,16 +1518,6 @@ dependencies = [ "void", ] -[[package]] -name = "flate2" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" @@ -2379,7 +2360,6 @@ dependencies = [ "libp2p-connection-limits", "libp2p-core", "libp2p-dcutr", - "libp2p-deflate", "libp2p-dns", "libp2p-floodsub", "libp2p-gossipsub", @@ -2528,20 +2508,6 @@ dependencies = [ "void", ] -[[package]] -name = "libp2p-deflate" -version = "0.41.0" -dependencies = [ - "async-std", - "flate2", - "futures", - "futures_ringbuf", - "libp2p-core", - "libp2p-tcp", - "quickcheck-ext", - "rand 0.8.5", -] - [[package]] name = "libp2p-dns" version = "0.41.0" diff --git a/Cargo.toml b/Cargo.toml index b9fa927f354..2c823756bbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,6 @@ members = [ "swarm", "swarm-derive", "swarm-test", - "transports/deflate", "transports/dns", "transports/noise", "transports/plaintext", @@ -78,7 +77,6 @@ libp2p-autonat = { version = "0.12.0", path = "protocols/autonat" } libp2p-connection-limits = { version = "0.3.0", path = "misc/connection-limits" } libp2p-core = { version = "0.41.0", path = "core" } libp2p-dcutr = { version = "0.11.0", path = "protocols/dcutr" } -libp2p-deflate = { version = "0.41.0", path = "transports/deflate" } libp2p-dns = { version = "0.41.0", path = "transports/dns" } libp2p-floodsub = { version = "0.44.0", path = "protocols/floodsub" } libp2p-gossipsub = { version = "0.46.0", path = "protocols/gossipsub" } diff --git a/libp2p/CHANGELOG.md b/libp2p/CHANGELOG.md index 127138b8a2e..636d0622256 100644 --- a/libp2p/CHANGELOG.md +++ b/libp2p/CHANGELOG.md @@ -5,6 +5,9 @@ - Remove deprecated `libp2p-wasm-ext`. Users should use `libp2p-websocket-websys` instead. See [PR 4694](https://github.com/libp2p/rust-libp2p/pull/4694). +- Remove deprecated `libp2p-deflate`. + See [issue 4522](https://github.com/libp2p/rust-libp2p/issues/4522) for details. + See [PR 4729](https://github.com/libp2p/rust-libp2p/pull/4729). - Remove deprecated `development_transport`. Use `libp2p::SwarmBuilder` instead. See [PR 4732](https://github.com/libp2p/rust-libp2p/pull/4732). diff --git a/libp2p/Cargo.toml b/libp2p/Cargo.toml index 01c4fea81cc..8ea8ce19b26 100644 --- a/libp2p/Cargo.toml +++ b/libp2p/Cargo.toml @@ -16,7 +16,6 @@ full = [ "autonat", "cbor", "dcutr", - "deflate", "dns", "ecdsa", "ed25519", @@ -56,7 +55,6 @@ async-std = [ "libp2p-swarm/async-std", "libp2p-mdns?/async-io", "libp2p-tcp?/as autonat = ["dep:libp2p-autonat"] cbor = ["libp2p-request-response?/cbor"] dcutr = ["dep:libp2p-dcutr", "libp2p-metrics?/dcutr"] -deflate = ["dep:libp2p-deflate"] dns = ["dep:libp2p-dns"] ecdsa = ["libp2p-identity/ecdsa"] ed25519 = ["libp2p-identity/ed25519"] @@ -128,7 +126,6 @@ pin-project = "1.0.0" thiserror = "1.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -libp2p-deflate = { workspace = true, optional = true } libp2p-dns = { workspace = true, optional = true } libp2p-mdns = { workspace = true, optional = true } libp2p-memory-connection-limits = { workspace = true, optional = true } diff --git a/libp2p/src/lib.rs b/libp2p/src/lib.rs index 14b0dcc8670..58f911e9445 100644 --- a/libp2p/src/lib.rs +++ b/libp2p/src/lib.rs @@ -51,15 +51,6 @@ pub use libp2p_core as core; #[cfg(feature = "dcutr")] #[doc(inline)] pub use libp2p_dcutr as dcutr; - -#[cfg(feature = "deflate")] -#[cfg(not(target_arch = "wasm32"))] -#[deprecated( - note = "Will be removed in the next release, see https://github.com/libp2p/rust-libp2p/issues/4522 for details." -)] -pub mod deflate { - pub use libp2p_deflate::*; -} #[cfg(feature = "dns")] #[cfg_attr(docsrs, doc(cfg(feature = "dns")))] #[cfg(not(target_arch = "wasm32"))] diff --git a/transports/deflate/CHANGELOG.md b/transports/deflate/CHANGELOG.md deleted file mode 100644 index 2c5b9cd31e8..00000000000 --- a/transports/deflate/CHANGELOG.md +++ /dev/null @@ -1,115 +0,0 @@ -## 0.41.0 - unreleased - - -## 0.40.1 - -- Deprecate in preparation for removal from the workspace. - See [issue 4522](https://github.com/libp2p/rust-libp2p/issues/4522) for details. - See [PR 4540](https://github.com/libp2p/rust-libp2p/pull/4540). - -## 0.40.0 - -- Raise MSRV to 1.65. - See [PR 3715]. - -[PR 3715]: https://github.com/libp2p/rust-libp2p/pull/3715 - -## 0.39.0 - -- Update to `libp2p-core` `v0.39.0`. - -## 0.38.0 - -- Update to `libp2p-core` `v0.38.0`. - -- Update `rust-version` to reflect the actual MSRV: 1.60.0. See [PR 3090]. - -[PR 3090]: https://github.com/libp2p/rust-libp2p/pull/3090 - -## 0.37.0 - -- Update to `libp2p-core` `v0.37.0`. - -## 0.36.0 - -- Update to `libp2p-core` `v0.36.0`. - -## 0.35.0 - -- Update to `libp2p-core` `v0.35.0`. - -## 0.34.0 - -- Update to `libp2p-core` `v0.34.0`. - -## 0.33.0 - -- Update to `libp2p-core` `v0.33.0`. - -## 0.32.0 [2022-02-22] - -- Update to `libp2p-core` `v0.32.0`. - -## 0.31.0 [2022-01-27] - -- Update dependencies. - -- Migrate to Rust edition 2021 (see [PR 2339]). - -[PR 2339]: https://github.com/libp2p/rust-libp2p/pull/2339 - -## 0.30.0 [2021-11-01] - -- Make default features of `libp2p-core` optional. - [PR 2181](https://github.com/libp2p/rust-libp2p/pull/2181) - -- Update dependencies. - -## 0.29.0 [2021-07-12] - -- Update dependencies. - -## 0.28.0 [2021-03-17] - -- Update `libp2p-core`. - -## 0.27.1 [2021-01-27] - -- Ensure read buffers are initialised. - [PR 1933](https://github.com/libp2p/rust-libp2p/pull/1933). - -## 0.27.0 [2021-01-12] - -- Update dependencies. - -## 0.26.0 [2020-12-17] - -- Update `libp2p-core`. - -## 0.25.0 [2020-11-25] - -- Update `libp2p-core`. - -## 0.24.0 [2020-11-09] - -- Update dependencies. - -## 0.23.0 [2020-10-16] - -- Bump `libp2p-core` dependency. - -## 0.22.0 [2020-09-09] - -- Bump `libp2p-core` dependency. - -## 0.21.0 [2020-08-18] - -- Bump `libp2p-core` dependency. - -## 0.20.0 [2020-07-01] - -- Updated dependencies. - -## 0.19.2 [2020-06-22] - -- Updated dependencies. diff --git a/transports/deflate/Cargo.toml b/transports/deflate/Cargo.toml deleted file mode 100644 index 605b9b9e767..00000000000 --- a/transports/deflate/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "libp2p-deflate" -edition = "2021" -rust-version = { workspace = true } -description = "Deflate encryption protocol for libp2p" -version = "0.41.0" -authors = ["Parity Technologies "] -license = "MIT" -repository = "https://github.com/libp2p/rust-libp2p" -keywords = ["peer-to-peer", "libp2p", "networking"] -categories = ["network-programming", "asynchronous"] - -[dependencies] -futures = "0.3.28" -libp2p-core = { workspace = true } -flate2 = "1.0" - -[dev-dependencies] -async-std = "1.6.2" -libp2p-tcp = { workspace = true, features = ["async-io"] } -quickcheck = { workspace = true } -rand = "0.8" -futures_ringbuf = "0.4.0" - -# 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] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] -rustc-args = ["--cfg", "docsrs"] - -[lints] -workspace = true diff --git a/transports/deflate/src/lib.rs b/transports/deflate/src/lib.rs deleted file mode 100644 index 54367ff2bff..00000000000 --- a/transports/deflate/src/lib.rs +++ /dev/null @@ -1,278 +0,0 @@ -#![allow(deprecated)] -// Copyright 2019 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. -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] - -use futures::{prelude::*, ready}; -use libp2p_core::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}; -use std::{io, iter, pin::Pin, task::Context, task::Poll}; - -#[deprecated( - note = "Will be removed in the next release, see https://github.com/libp2p/rust-libp2p/issues/4522 for details." -)] -#[derive(Debug, Copy, Clone)] -pub struct DeflateConfig { - compression: flate2::Compression, -} - -impl Default for DeflateConfig { - fn default() -> Self { - DeflateConfig { - compression: flate2::Compression::fast(), - } - } -} - -impl UpgradeInfo for DeflateConfig { - type Info = &'static str; - type InfoIter = iter::Once; - - fn protocol_info(&self) -> Self::InfoIter { - iter::once("/deflate/1.0.0") - } -} - -impl InboundUpgrade for DeflateConfig -where - C: AsyncRead + AsyncWrite, -{ - type Output = DeflateOutput; - type Error = io::Error; - type Future = future::Ready>; - - fn upgrade_inbound(self, r: C, _: Self::Info) -> Self::Future { - future::ok(DeflateOutput::new(r, self.compression)) - } -} - -impl OutboundUpgrade for DeflateConfig -where - C: AsyncRead + AsyncWrite, -{ - type Output = DeflateOutput; - type Error = io::Error; - type Future = future::Ready>; - - fn upgrade_outbound(self, w: C, _: Self::Info) -> Self::Future { - future::ok(DeflateOutput::new(w, self.compression)) - } -} - -/// Decodes and encodes traffic using DEFLATE. -#[derive(Debug)] -pub struct DeflateOutput { - /// Inner stream where we read compressed data from and write compressed data to. - inner: S, - /// Internal object used to hold the state of the compression. - compress: flate2::Compress, - /// Internal object used to hold the state of the decompression. - decompress: flate2::Decompress, - /// Temporary buffer between `compress` and `inner`. Stores compressed bytes that need to be - /// sent out once `inner` is ready to accept more. - write_out: Vec, - /// Temporary buffer between `decompress` and `inner`. Stores compressed bytes that need to be - /// given to `decompress`. - read_interm: Vec, - /// When we read from `inner` and `Ok(0)` is returned, we set this to `true` so that we don't - /// read from it again. - inner_read_eof: bool, -} - -impl DeflateOutput { - fn new(inner: S, compression: flate2::Compression) -> Self { - DeflateOutput { - inner, - compress: flate2::Compress::new(compression, false), - decompress: flate2::Decompress::new(false), - write_out: Vec::with_capacity(256), - read_interm: Vec::with_capacity(256), - inner_read_eof: false, - } - } - - /// Tries to write the content of `self.write_out` to `self.inner`. - /// Returns `Ready(Ok(()))` if `self.write_out` is empty. - fn flush_write_out(&mut self, cx: &mut Context<'_>) -> Poll> - where - S: AsyncWrite + Unpin, - { - loop { - if self.write_out.is_empty() { - return Poll::Ready(Ok(())); - } - - match AsyncWrite::poll_write(Pin::new(&mut self.inner), cx, &self.write_out) { - Poll::Ready(Ok(0)) => return Poll::Ready(Err(io::ErrorKind::WriteZero.into())), - Poll::Ready(Ok(n)) => self.write_out = self.write_out.split_off(n), - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - Poll::Pending => return Poll::Pending, - }; - } - } -} - -impl AsyncRead for DeflateOutput -where - S: AsyncRead + Unpin, -{ - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - // We use a `this` variable because the compiler doesn't allow multiple mutable borrows - // across a `Deref`. - let this = &mut *self; - - loop { - // Read from `self.inner` into `self.read_interm` if necessary. - if this.read_interm.is_empty() && !this.inner_read_eof { - this.read_interm - .resize(this.read_interm.capacity() + 256, 0); - - match AsyncRead::poll_read(Pin::new(&mut this.inner), cx, &mut this.read_interm) { - Poll::Ready(Ok(0)) => { - this.inner_read_eof = true; - this.read_interm.clear(); - } - Poll::Ready(Ok(n)) => this.read_interm.truncate(n), - Poll::Ready(Err(err)) => { - this.read_interm.clear(); - return Poll::Ready(Err(err)); - } - Poll::Pending => { - this.read_interm.clear(); - return Poll::Pending; - } - } - } - debug_assert!(!this.read_interm.is_empty() || this.inner_read_eof); - - let before_out = this.decompress.total_out(); - let before_in = this.decompress.total_in(); - let ret = this.decompress.decompress( - &this.read_interm, - buf, - if this.inner_read_eof { - flate2::FlushDecompress::Finish - } else { - flate2::FlushDecompress::None - }, - )?; - - // Remove from `self.read_interm` the bytes consumed by the decompressor. - let consumed = (this.decompress.total_in() - before_in) as usize; - this.read_interm = this.read_interm.split_off(consumed); - - let read = (this.decompress.total_out() - before_out) as usize; - if read != 0 || ret == flate2::Status::StreamEnd { - return Poll::Ready(Ok(read)); - } - } - } -} - -impl AsyncWrite for DeflateOutput -where - S: AsyncWrite + Unpin, -{ - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - // We use a `this` variable because the compiler doesn't allow multiple mutable borrows - // across a `Deref`. - let this = &mut *self; - - // We don't want to accumulate too much data in `self.write_out`, so we only proceed if it - // is empty. - ready!(this.flush_write_out(cx))?; - - // We special-case this, otherwise an empty buffer would make the loop below infinite. - if buf.is_empty() { - return Poll::Ready(Ok(0)); - } - - // Unfortunately, the compressor might be in a "flushing mode", not accepting any input - // data. We don't want to return `Ok(0)` in that situation, as that would be wrong. - // Instead, we invoke the compressor in a loop until it accepts some of our data. - loop { - let before_in = this.compress.total_in(); - this.write_out.reserve(256); // compress_vec uses the Vec's capacity - let ret = this.compress.compress_vec( - buf, - &mut this.write_out, - flate2::FlushCompress::None, - )?; - let written = (this.compress.total_in() - before_in) as usize; - - if written != 0 || ret == flate2::Status::StreamEnd { - return Poll::Ready(Ok(written)); - } - } - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - // We use a `this` variable because the compiler doesn't allow multiple mutable borrows - // across a `Deref`. - let this = &mut *self; - - ready!(this.flush_write_out(cx))?; - this.compress - .compress_vec(&[], &mut this.write_out, flate2::FlushCompress::Sync)?; - - loop { - ready!(this.flush_write_out(cx))?; - - debug_assert!(this.write_out.is_empty()); - // We ask the compressor to flush everything into `self.write_out`. - this.write_out.reserve(256); // compress_vec uses the Vec's capacity - this.compress - .compress_vec(&[], &mut this.write_out, flate2::FlushCompress::None)?; - if this.write_out.is_empty() { - break; - } - } - - AsyncWrite::poll_flush(Pin::new(&mut this.inner), cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - // We use a `this` variable because the compiler doesn't allow multiple mutable borrows - // across a `Deref`. - let this = &mut *self; - - loop { - ready!(this.flush_write_out(cx))?; - - // We ask the compressor to flush everything into `self.write_out`. - debug_assert!(this.write_out.is_empty()); - this.write_out.reserve(256); // compress_vec uses the Vec's capacity - this.compress - .compress_vec(&[], &mut this.write_out, flate2::FlushCompress::Finish)?; - if this.write_out.is_empty() { - break; - } - } - - AsyncWrite::poll_close(Pin::new(&mut this.inner), cx) - } -} diff --git a/transports/deflate/tests/test.rs b/transports/deflate/tests/test.rs deleted file mode 100644 index 4224dcf435b..00000000000 --- a/transports/deflate/tests/test.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![allow(deprecated)] - -// Copyright 2019 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. - -use futures::prelude::*; -use libp2p_core::OutboundUpgrade; -use libp2p_deflate::DeflateConfig; -use quickcheck::{QuickCheck, TestResult}; -use rand::RngCore; - -#[test] -fn deflate() { - fn prop(message: Vec) -> TestResult { - if message.is_empty() { - return TestResult::discard(); - } - futures::executor::block_on(run(message)); - TestResult::passed() - } - QuickCheck::new().quickcheck(prop as fn(Vec) -> TestResult) -} - -#[test] -fn lot_of_data() { - let mut v = vec![0; 2 * 1024 * 1024]; - rand::thread_rng().fill_bytes(&mut v); - futures::executor::block_on(run(v)); -} - -async fn run(message1: Vec) { - let (server, client) = futures_ringbuf::Endpoint::pair(100, 100); - - let message2 = message1.clone(); - - let client_task = async move { - let mut client = DeflateConfig::default() - .upgrade_outbound(client, "") - .await - .unwrap(); - - let mut buf = vec![0; message2.len()]; - client.read_exact(&mut buf).await.expect("read_exact"); - assert_eq!(&buf[..], &message2[..]); - - client.write_all(&message2).await.expect("write_all"); - client.close().await.expect("close") - }; - - let server_task = async move { - let mut server = DeflateConfig::default() - .upgrade_outbound(server, "") - .await - .unwrap(); - - server.write_all(&message1).await.expect("write_all"); - server.close().await.expect("close"); - - let mut buf = Vec::new(); - server.read_to_end(&mut buf).await.expect("read_to_end"); - assert_eq!(&buf[..], &message1[..]); - }; - - futures::future::join(server_task, client_task).await; -}