From bc31f5da581793572d472db6eac7b917640e1005 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 16 Jul 2024 16:39:31 +0200 Subject: [PATCH] feat: feature gate reth-codec impl (#9492) --- crates/primitives/Cargo.toml | 9 +- crates/primitives/src/lib.rs | 6 +- crates/primitives/src/receipt.rs | 14 +- crates/primitives/src/transaction/eip1559.rs | 4 +- crates/primitives/src/transaction/eip2930.rs | 4 +- crates/primitives/src/transaction/eip4844.rs | 4 +- crates/primitives/src/transaction/legacy.rs | 2 +- crates/primitives/src/transaction/mod.rs | 123 ++---------------- crates/primitives/src/transaction/optimism.rs | 2 +- .../primitives/src/transaction/signature.rs | 9 +- crates/primitives/src/transaction/tx_type.rs | 15 ++- 11 files changed, 51 insertions(+), 141 deletions(-) diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 6804ac1e4d..53aaeffb81 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -14,12 +14,12 @@ workspace = true [dependencies] # reth reth-primitives-traits.workspace = true -reth-codecs.workspace = true reth-ethereum-forks.workspace = true reth-static-file-types.workspace = true reth-trie-common.workspace = true revm-primitives = { workspace = true, features = ["serde"] } reth-chainspec = { workspace = true, optional = true } +reth-codecs = { workspace = true, optional = true } # ethereum alloy-primitives = { workspace = true, features = ["rand", "rlp"] } @@ -58,6 +58,7 @@ proptest = { workspace = true, optional = true } reth-primitives-traits = { workspace = true, features = ["arbitrary"] } revm-primitives = { workspace = true, features = ["arbitrary"] } reth-chainspec.workspace = true +reth-codecs.workspace = true nybbles = { workspace = true, features = ["arbitrary"] } alloy-trie = { workspace = true, features = ["arbitrary"] } alloy-eips = { workspace = true, features = ["arbitrary"] } @@ -84,7 +85,8 @@ pprof = { workspace = true, features = [ secp256k1.workspace = true [features] -default = ["c-kzg", "zstd-codec", "alloy-compat", "std"] +default = ["c-kzg", "alloy-compat", "std", "reth-codec"] +reth-codec = ["dep:reth-codecs", "dep:zstd"] asm-keccak = ["alloy-primitives/asm-keccak"] arbitrary = [ "reth-primitives-traits/arbitrary", @@ -96,10 +98,9 @@ arbitrary = [ "alloy-eips/arbitrary", "dep:arbitrary", "dep:proptest", - "zstd-codec", + "reth-codec", ] c-kzg = ["dep:c-kzg", "revm-primitives/c-kzg", "dep:tempfile", "alloy-eips/kzg"] -zstd-codec = ["dep:zstd"] optimism = [ "reth-chainspec/optimism", "reth-ethereum-forks/optimism", diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index af78d86356..bde1a87001 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -7,6 +7,8 @@ //! - `alloy-compat`: Adds compatibility conversions for certain alloy types. //! - `arbitrary`: Adds `proptest` and `arbitrary` support for primitive types. //! - `test-utils`: Export utilities for testing +//! - `reth-codec`: Enables db codec support for reth types including zstd compression for certain +//! types. #![doc( html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", @@ -24,7 +26,7 @@ extern crate alloc; mod alloy_compat; pub mod basefee; mod block; -#[cfg(feature = "zstd-codec")] +#[cfg(feature = "reth-codec")] mod compression; pub mod constants; pub mod eip4844; @@ -40,7 +42,7 @@ pub use block::{ Block, BlockBody, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag, BlockWithSenders, ForkBlock, RpcBlockHash, SealedBlock, SealedBlockWithSenders, }; -#[cfg(feature = "zstd-codec")] +#[cfg(feature = "reth-codec")] pub use compression::*; pub use constants::{ DEV_GENESIS_HASH, EMPTY_OMMER_ROOT_HASH, HOLESKY_GENESIS_HASH, KECCAK_EMPTY, diff --git a/crates/primitives/src/receipt.rs b/crates/primitives/src/receipt.rs index 0c68967dc6..ab71b55b1d 100644 --- a/crates/primitives/src/receipt.rs +++ b/crates/primitives/src/receipt.rs @@ -1,4 +1,4 @@ -#[cfg(feature = "zstd-codec")] +#[cfg(feature = "reth-codec")] use crate::compression::{RECEIPT_COMPRESSOR, RECEIPT_DECOMPRESSOR}; use crate::{logs_bloom, Bloom, Bytes, TxType, B256}; use alloy_primitives::Log; @@ -6,18 +6,16 @@ use alloy_rlp::{length_of_length, Decodable, Encodable, RlpDecodable, RlpEncodab use bytes::{Buf, BufMut}; use core::{cmp::Ordering, ops::Deref}; use derive_more::{Deref, DerefMut, From, IntoIterator}; -#[cfg(feature = "zstd-codec")] -use reth_codecs::CompactZstd; -use reth_codecs::{add_arbitrary_tests, reth_codec, Compact}; +#[cfg(feature = "reth-codec")] +use reth_codecs::{Compact, CompactZstd}; use serde::{Deserialize, Serialize}; #[cfg(not(feature = "std"))] use alloc::{vec, vec::Vec}; /// Receipt containing result of transaction execution. -#[cfg_attr(feature = "zstd-codec", reth_codec(no_arbitrary, zstd))] -#[cfg_attr(not(feature = "zstd-codec"), reth_codec(no_arbitrary))] -#[add_arbitrary_tests] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::reth_codec(no_arbitrary, zstd))] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests)] #[derive(Clone, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)] #[rlp(trailing)] pub struct Receipt { @@ -142,7 +140,7 @@ impl From for ReceiptWithBloom { } /// [`Receipt`] with calculated bloom filter. -#[reth_codec] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::reth_codec)] #[derive(Clone, Debug, PartialEq, Eq, Default)] pub struct ReceiptWithBloom { /// Bloom filter build from logs. diff --git a/crates/primitives/src/transaction/eip1559.rs b/crates/primitives/src/transaction/eip1559.rs index af34a5f2d4..218d71d7d5 100644 --- a/crates/primitives/src/transaction/eip1559.rs +++ b/crates/primitives/src/transaction/eip1559.rs @@ -2,13 +2,13 @@ use super::access_list::AccessList; use crate::{keccak256, Bytes, ChainId, Signature, TxKind, TxType, B256, U256}; use alloy_rlp::{length_of_length, Decodable, Encodable, Header}; use core::mem; -use reth_codecs::{reth_codec, Compact}; +use reth_codecs::Compact; #[cfg(not(feature = "std"))] use alloc::vec::Vec; /// A transaction with a priority fee ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)). -#[reth_codec] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::reth_codec)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] pub struct TxEip1559 { /// Added as EIP-155: Simple replay attack protection diff --git a/crates/primitives/src/transaction/eip2930.rs b/crates/primitives/src/transaction/eip2930.rs index ce8b39462b..d745082557 100644 --- a/crates/primitives/src/transaction/eip2930.rs +++ b/crates/primitives/src/transaction/eip2930.rs @@ -2,13 +2,13 @@ use super::access_list::AccessList; use crate::{keccak256, Bytes, ChainId, Signature, TxKind, TxType, B256, U256}; use alloy_rlp::{length_of_length, Decodable, Encodable, Header}; use core::mem; -use reth_codecs::{reth_codec, Compact}; +use reth_codecs::Compact; #[cfg(not(feature = "std"))] use alloc::vec::Vec; /// Transaction with an [`AccessList`] ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930)). -#[reth_codec] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::reth_codec)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] pub struct TxEip2930 { /// Added as EIP-155: Simple replay attack protection diff --git a/crates/primitives/src/transaction/eip4844.rs b/crates/primitives/src/transaction/eip4844.rs index e7685be976..1c9bebd123 100644 --- a/crates/primitives/src/transaction/eip4844.rs +++ b/crates/primitives/src/transaction/eip4844.rs @@ -5,7 +5,7 @@ use crate::{ }; use alloy_rlp::{length_of_length, Decodable, Encodable, Header}; use core::mem; -use reth_codecs::{reth_codec, Compact, CompactPlaceholder}; +use reth_codecs::{Compact, CompactPlaceholder}; #[cfg(feature = "c-kzg")] use crate::kzg::KzgSettings; @@ -16,7 +16,7 @@ use alloc::vec::Vec; /// [EIP-4844 Blob Transaction](https://eips.ethereum.org/EIPS/eip-4844#blob-transaction) /// /// A transaction with blob hashes and max blob fee -#[reth_codec] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::reth_codec)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] pub struct TxEip4844 { /// Added as EIP-155: Simple replay attack protection diff --git a/crates/primitives/src/transaction/legacy.rs b/crates/primitives/src/transaction/legacy.rs index 8f2acd4da2..0751b0d3b8 100644 --- a/crates/primitives/src/transaction/legacy.rs +++ b/crates/primitives/src/transaction/legacy.rs @@ -7,7 +7,7 @@ use reth_codecs::{reth_codec, Compact}; use alloc::vec::Vec; /// Legacy transaction. -#[reth_codec] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codec)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] pub struct TxLegacy { /// Added as EIP-155: Simple replay attack protection diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 1749666b14..0f9f6a6a10 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -1,7 +1,5 @@ //! Transaction types. -#[cfg(any(feature = "arbitrary", feature = "zstd-codec"))] -use crate::compression::{TRANSACTION_COMPRESSOR, TRANSACTION_DECOMPRESSOR}; use crate::{ eip7702::SignedAuthorization, keccak256, Address, BlockHashOrNumber, Bytes, TxHash, TxKind, B256, U256, @@ -15,7 +13,6 @@ use core::mem; use derive_more::{AsRef, Deref}; use once_cell::sync::Lazy; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; -use reth_codecs::{add_arbitrary_tests, derive_arbitrary, Compact}; use serde::{Deserialize, Serialize}; pub use access_list::{AccessList, AccessListItem}; @@ -68,6 +65,9 @@ pub use optimism::TxDeposit; #[cfg(feature = "optimism")] pub use tx_type::DEPOSIT_TX_TYPE_ID; +#[cfg(test)] +use reth_codecs::Compact; + #[cfg(not(feature = "std"))] use alloc::vec::Vec; @@ -86,7 +86,7 @@ pub(crate) static PARALLEL_SENDER_RECOVERY_THRESHOLD: Lazy = /// A raw transaction. /// /// Transaction types were introduced in [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718). -#[derive_arbitrary(compact)] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::derive_arbitrary(compact))] #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Transaction { /// Legacy transaction (type `0x0`). @@ -679,7 +679,8 @@ impl From for Transaction { } } -impl Compact for Transaction { +#[cfg(any(test, feature = "reth-codec"))] +impl reth_codecs::Compact for Transaction { // Serializes the TxType to the buffer if necessary, returning 2 bits of the type as an // identifier instead of the length. fn to_compact(self, buf: &mut B) -> usize @@ -811,7 +812,7 @@ impl Encodable for Transaction { /// Signed transaction without its Hash. Used type for inserting into the DB. /// /// This can by converted to [`TransactionSigned`] by calling [`TransactionSignedNoHash::hash`]. -#[derive_arbitrary(compact)] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::derive_arbitrary(compact))] #[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref, Default, Serialize, Deserialize)] pub struct TransactionSignedNoHash { /// The transaction signature values @@ -909,8 +910,8 @@ impl TransactionSignedNoHash { } } -#[cfg(feature = "zstd-codec")] -impl Compact for TransactionSignedNoHash { +#[cfg(any(test, feature = "reth-codec"))] +impl reth_codecs::Compact for TransactionSignedNoHash { fn to_compact(self, buf: &mut B) -> usize where B: bytes::BufMut + AsMut<[u8]>, @@ -925,7 +926,7 @@ impl Compact for TransactionSignedNoHash { let zstd_bit = self.transaction.input().len() >= 32; let tx_bits = if zstd_bit { - TRANSACTION_COMPRESSOR.with(|compressor| { + crate::compression::TRANSACTION_COMPRESSOR.with(|compressor| { let mut compressor = compressor.borrow_mut(); let mut tmp = Vec::with_capacity(256); let tx_bits = self.transaction.to_compact(&mut tmp); @@ -953,7 +954,7 @@ impl Compact for TransactionSignedNoHash { let zstd_bit = bitflags >> 3; let (transaction, buf) = if zstd_bit != 0 { - TRANSACTION_DECOMPRESSOR.with(|decompressor| { + crate::compression::TRANSACTION_DECOMPRESSOR.with(|decompressor| { let mut decompressor = decompressor.borrow_mut(); // TODO: enforce that zstd is only present at a "top" level type @@ -973,63 +974,6 @@ impl Compact for TransactionSignedNoHash { } } -#[cfg(not(feature = "zstd-codec"))] -impl Compact for TransactionSignedNoHash { - fn to_compact(self, buf: &mut B) -> usize - where - B: bytes::BufMut + AsMut<[u8]>, - { - to_compact_ztd_unaware(self, buf) - } - - fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) { - from_compact_zstd_unaware(buf, _len) - } -} - -// Allowing dead code, as this function is extracted from behind feature, so it can be tested -#[allow(dead_code)] -fn to_compact_ztd_unaware(transaction: TransactionSignedNoHash, buf: &mut B) -> usize -where - B: bytes::BufMut + AsMut<[u8]>, -{ - let start = buf.as_mut().len(); - - // Placeholder for bitflags. - // The first byte uses 4 bits as flags: IsCompressed[1bit], TxType[2bits], Signature[1bit] - buf.put_u8(0); - - let sig_bit = transaction.signature.to_compact(buf) as u8; - let zstd_bit = false; - let tx_bits = transaction.transaction.to_compact(buf) as u8; - - // Replace bitflags with the actual values - buf.as_mut()[start] = sig_bit | (tx_bits << 1) | ((zstd_bit as u8) << 3); - - buf.as_mut().len() - start -} - -// Allowing dead code, as this function is extracted from behind feature, so it can be tested -#[allow(dead_code)] -fn from_compact_zstd_unaware(mut buf: &[u8], _len: usize) -> (TransactionSignedNoHash, &[u8]) { - // The first byte uses 4 bits as flags: IsCompressed[1], TxType[2], Signature[1] - let bitflags = buf.get_u8() as usize; - - let sig_bit = bitflags & 1; - let (signature, buf) = Signature::from_compact(buf, sig_bit); - - let zstd_bit = bitflags >> 3; - assert_eq!( - zstd_bit, 0, - "zstd-codec feature is not enabled, cannot decode `TransactionSignedNoHash` with zstd flag" - ); - - let transaction_type = bitflags >> 1; - let (transaction, buf) = Transaction::from_compact(buf, transaction_type); - - (TransactionSignedNoHash { signature, transaction }, buf) -} - impl From for TransactionSigned { fn from(tx: TransactionSignedNoHash) -> Self { tx.with_hash() @@ -1043,7 +987,7 @@ impl From for TransactionSignedNoHash { } /// Signed transaction. -#[add_arbitrary_tests(rlp)] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp))] #[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref, Default, Serialize, Deserialize)] pub struct TransactionSigned { /// Transaction hash @@ -1754,8 +1698,7 @@ mod tests { use crate::{ hex, sign_message, transaction::{ - from_compact_zstd_unaware, signature::Signature, to_compact_ztd_unaware, TxEip1559, - TxKind, TxLegacy, PARALLEL_SENDER_RECOVERY_THRESHOLD, + signature::Signature, TxEip1559, TxKind, TxLegacy, PARALLEL_SENDER_RECOVERY_THRESHOLD, }, Address, Bytes, Transaction, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, B256, U256, @@ -2145,46 +2088,6 @@ mod tests { let written_bytes = tx_signed_no_hash.clone().to_compact(&mut buff); let (decoded, _) = TransactionSignedNoHash::from_compact(&buff, written_bytes); assert_eq!(tx_signed_no_hash, decoded); - - // zstd unaware `to_compact`/`from_compact` - let mut buff: Vec = Vec::new(); - let written_bytes = to_compact_ztd_unaware(tx_signed_no_hash.clone(), &mut buff); - let (decoded_no_zstd, _something) = from_compact_zstd_unaware(&buff, written_bytes); - assert_eq!(tx_signed_no_hash, decoded_no_zstd); - - // zstd unaware `to_compact`, but decode with zstd awareness - let mut buff: Vec = Vec::new(); - let written_bytes = to_compact_ztd_unaware(tx_signed_no_hash.clone(), &mut buff); - let (decoded, _) = TransactionSignedNoHash::from_compact(&buff, written_bytes); - assert_eq!(tx_signed_no_hash, decoded); - } - - #[test] - #[should_panic( - expected = "zstd-codec feature is not enabled, cannot decode `TransactionSignedNoHash` with zstd flag" - )] - fn transaction_signed_zstd_encoded_no_zstd_decode() { - let signature = Signature { - odd_y_parity: false, - r: U256::from_str("0xeb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae") - .unwrap(), - s: U256::from_str("0x3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18") - .unwrap(), - }; - let transaction = Transaction::Legacy(TxLegacy { - chain_id: Some(4u64), - nonce: 2, - gas_price: 1000000000, - gas_limit: 100000, - to: Address::from_str("d3e8763675e4c425df46cc3b5c0f6cbdac396046").unwrap().into(), - value: U256::from(1000000000000000u64), - input: Bytes::from(vec![3u8; 64]), - }); - let tx_signed_no_hash = TransactionSignedNoHash { signature, transaction }; - - let mut buff: Vec = Vec::new(); - let written_bytes = tx_signed_no_hash.to_compact(&mut buff); - from_compact_zstd_unaware(&buff, written_bytes); } #[test] diff --git a/crates/primitives/src/transaction/optimism.rs b/crates/primitives/src/transaction/optimism.rs index fdb6f2a985..1d15532a24 100644 --- a/crates/primitives/src/transaction/optimism.rs +++ b/crates/primitives/src/transaction/optimism.rs @@ -7,7 +7,7 @@ use reth_codecs::{reth_codec, Compact}; use std::mem; /// Deposit transactions, also known as deposits are initiated on L1, and executed on L2. -#[reth_codec] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codec)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] pub struct TxDeposit { /// Hash that uniquely identifies the source of the deposit. diff --git a/crates/primitives/src/transaction/signature.rs b/crates/primitives/src/transaction/signature.rs index b74c41f55a..73b755a139 100644 --- a/crates/primitives/src/transaction/signature.rs +++ b/crates/primitives/src/transaction/signature.rs @@ -2,9 +2,11 @@ use crate::{transaction::util::secp256k1, Address, B256, U256}; use alloy_primitives::Bytes; use alloy_rlp::{Decodable, Encodable, Error as RlpError}; use bytes::Buf; -use reth_codecs::{derive_arbitrary, Compact}; use serde::{Deserialize, Serialize}; +#[cfg(test)] +use reth_codecs::Compact; + /// The order of the secp256k1 curve, divided by two. Signatures that should be checked according /// to EIP-2 should have an S value less than or equal to this. /// @@ -17,7 +19,7 @@ const SECP256K1N_HALF: U256 = U256::from_be_bytes([ /// r, s: Values corresponding to the signature of the /// transaction and used to determine the sender of /// the transaction; formally Tr and Ts. This is expanded in Appendix F of yellow paper. -#[derive_arbitrary(compact)] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::derive_arbitrary(compact))] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] pub struct Signature { /// The R field of the signature; the point on the curve. @@ -40,7 +42,8 @@ impl Signature { } } -impl Compact for Signature { +#[cfg(any(test, feature = "reth-codec"))] +impl reth_codecs::Compact for Signature { fn to_compact(self, buf: &mut B) -> usize where B: bytes::BufMut + AsMut<[u8]>, diff --git a/crates/primitives/src/transaction/tx_type.rs b/crates/primitives/src/transaction/tx_type.rs index 1f47f62b60..747537052a 100644 --- a/crates/primitives/src/transaction/tx_type.rs +++ b/crates/primitives/src/transaction/tx_type.rs @@ -1,9 +1,11 @@ use crate::{U64, U8}; use alloy_rlp::{Decodable, Encodable}; use bytes::Buf; -use reth_codecs::{derive_arbitrary, Compact}; use serde::{Deserialize, Serialize}; +#[cfg(test)] +use reth_codecs::Compact; + /// For backwards compatibility purposes only 2 bits of the type are encoded in the identifier /// parameter. In the case of a 3, the full transaction type is read from the buffer as a /// single byte. @@ -31,12 +33,12 @@ pub const DEPOSIT_TX_TYPE_ID: u8 = 126; /// Transaction Type /// -/// Currently being used as 2-bit type when encoding it to [`Compact`] on +/// Currently being used as 2-bit type when encoding it to `reth_codecs::Compact` on /// [`crate::TransactionSignedNoHash`]. Adding more transaction types will break the codec and /// database format. /// /// Other required changes when adding a new type can be seen on [PR#3953](https://github.com/paradigmxyz/reth/pull/3953/files). -#[derive_arbitrary(compact)] +#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::derive_arbitrary(compact))] #[derive( Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize, Hash, )] @@ -134,7 +136,8 @@ impl TryFrom for TxType { } } -impl Compact for TxType { +#[cfg(any(test, feature = "reth-codec"))] +impl reth_codecs::Compact for TxType { fn to_compact(self, buf: &mut B) -> usize where B: bytes::BufMut + AsMut<[u8]>, @@ -217,9 +220,9 @@ impl Decodable for TxType { #[cfg(test)] mod tests { - use rand::Rng; - use crate::hex; + use rand::Rng; + use reth_codecs::Compact; use super::*;