reth-primitives: Allow feature gating zstd for non default feature set (#7296)

This commit is contained in:
Nikolai Golub
2024-03-25 21:12:01 +01:00
committed by GitHub
parent d2fb8f245a
commit d611f11a07
4 changed files with 182 additions and 21 deletions

View File

@ -49,7 +49,7 @@ serde_json.workspace = true
sha2 = { version = "0.10.7", optional = true }
tempfile = { workspace = true, optional = true }
thiserror.workspace = true
zstd = { version = "0.12", features = ["experimental"] }
zstd = { version = "0.12", features = ["experimental"], optional = true }
roaring = "0.10.2"
cfg-if = "1.0.0"
@ -90,7 +90,7 @@ pprof = { workspace = true, features = ["flamegraph", "frame-pointer", "criterio
secp256k1.workspace = true
[features]
default = ["c-kzg"]
default = ["c-kzg", "zstd-codec"]
asm-keccak = ["alloy-primitives/asm-keccak"]
arbitrary = [
"revm-primitives/arbitrary",
@ -102,8 +102,12 @@ arbitrary = [
"dep:arbitrary",
"dep:proptest",
"dep:proptest-derive",
"zstd-codec"
]
c-kzg = ["dep:c-kzg", "revm/c-kzg", "revm-primitives/c-kzg", "dep:sha2", "dep:tempfile"]
zstd-codec = [
"dep:zstd"
]
clap = ["dep:clap"]
optimism = [
"reth-codecs/optimism",

View File

@ -21,6 +21,7 @@ mod account;
pub mod basefee;
mod block;
mod chain;
#[cfg(feature = "zstd-codec")]
mod compression;
pub mod constants;
pub mod eip4844;
@ -58,6 +59,7 @@ pub use chain::{
ChainSpecBuilder, DisplayHardforks, ForkBaseFeeParams, ForkCondition, ForkTimestamps,
NamedChain, DEV, GOERLI, HOLESKY, MAINNET, SEPOLIA,
};
#[cfg(feature = "zstd-codec")]
pub use compression::*;
pub use constants::{
DEV_GENESIS_HASH, EMPTY_OMMER_ROOT_HASH, GOERLI_GENESIS_HASH, HOLESKY_GENESIS_HASH,

View File

@ -1,19 +1,21 @@
use crate::{
compression::{RECEIPT_COMPRESSOR, RECEIPT_DECOMPRESSOR},
logs_bloom, Bloom, Bytes, Log, PruneSegmentError, TxType, B256,
};
#[cfg(feature = "zstd-codec")]
use crate::compression::{RECEIPT_COMPRESSOR, RECEIPT_DECOMPRESSOR};
use crate::{logs_bloom, Bloom, Bytes, Log, PruneSegmentError, TxType, B256};
use alloy_rlp::{length_of_length, Decodable, Encodable};
use bytes::{Buf, BufMut};
#[cfg(any(test, feature = "arbitrary"))]
use proptest::strategy::Strategy;
use reth_codecs::{add_arbitrary_tests, main_codec, Compact, CompactZstd};
#[cfg(feature = "zstd-codec")]
use reth_codecs::CompactZstd;
use reth_codecs::{add_arbitrary_tests, main_codec, Compact};
use std::{
cmp::Ordering,
ops::{Deref, DerefMut},
};
/// Receipt containing result of transaction execution.
#[main_codec(no_arbitrary, zstd)]
#[cfg_attr(feature = "zstd-codec", main_codec(no_arbitrary, zstd))]
#[cfg_attr(not(feature = "zstd-codec"), main_codec(no_arbitrary))]
#[add_arbitrary_tests]
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct Receipt {

View File

@ -1,7 +1,7 @@
use crate::{
compression::{TRANSACTION_COMPRESSOR, TRANSACTION_DECOMPRESSOR},
keccak256, Address, BlockHashOrNumber, Bytes, TxHash, B256, U256,
};
#[cfg(any(feature = "arbitrary", feature = "zstd-codec"))]
use crate::compression::{TRANSACTION_COMPRESSOR, TRANSACTION_DECOMPRESSOR};
use crate::{keccak256, Address, BlockHashOrNumber, Bytes, TxHash, B256, U256};
use alloy_rlp::{
Decodable, Encodable, Error as RlpError, Header, EMPTY_LIST_CODE, EMPTY_STRING_CODE,
};
@ -52,6 +52,7 @@ mod variant;
#[cfg(feature = "optimism")]
mod optimism;
#[cfg(feature = "optimism")]
pub use optimism::TxDeposit;
#[cfg(feature = "optimism")]
@ -884,6 +885,7 @@ impl TransactionSignedNoHash {
}
}
#[cfg(feature = "zstd-codec")]
impl Compact for TransactionSignedNoHash {
fn to_compact<B>(self, buf: &mut B) -> usize
where
@ -946,6 +948,64 @@ impl Compact for TransactionSignedNoHash {
}
}
#[cfg(not(feature = "zstd-codec"))]
impl Compact for TransactionSignedNoHash {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
to_compact_ztd_unaware(self, buf)
}
fn from_compact(mut 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<B>(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;
if zstd_bit != 0 {
panic!(
"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<TransactionSignedNoHash> for TransactionSigned {
fn from(tx: TransactionSignedNoHash) -> Self {
tx.with_hash()
@ -1405,7 +1465,7 @@ impl Decodable for TransactionSigned {
/// header if the first byte is less than `0xf7`.
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
if buf.is_empty() {
return Err(RlpError::InputTooShort)
return Err(RlpError::InputTooShort);
}
// decode header
@ -1602,17 +1662,18 @@ mod tests {
use crate::{
hex, sign_message,
transaction::{
signature::Signature, TransactionKind, TxEip1559, TxLegacy,
MIN_LENGTH_EIP1559_TX_ENCODED, MIN_LENGTH_EIP2930_TX_ENCODED,
MIN_LENGTH_EIP4844_TX_ENCODED, MIN_LENGTH_LEGACY_TX_ENCODED,
PARALLEL_SENDER_RECOVERY_THRESHOLD,
from_compact_zstd_unaware, signature::Signature, to_compact_ztd_unaware,
TransactionKind, TxEip1559, TxLegacy, MIN_LENGTH_EIP1559_TX_ENCODED,
MIN_LENGTH_EIP2930_TX_ENCODED, MIN_LENGTH_EIP4844_TX_ENCODED,
MIN_LENGTH_LEGACY_TX_ENCODED, PARALLEL_SENDER_RECOVERY_THRESHOLD,
},
Address, Bytes, Transaction, TransactionSigned, TransactionSignedEcRecovered, TxEip2930,
TxEip4844, B256, U256,
Address, Bytes, Transaction, TransactionSigned, TransactionSignedEcRecovered,
TransactionSignedNoHash, TxEip2930, TxEip4844, B256, U256,
};
use alloy_primitives::{address, b256, bytes};
use alloy_rlp::{Decodable, Encodable, Error as RlpError};
use bytes::BytesMut;
use reth_codecs::Compact;
use secp256k1::{KeyPair, Secp256k1};
use std::str::FromStr;
@ -1684,7 +1745,7 @@ mod tests {
b256!("0152d8e24762ff22b1cfd9f8c0683786a7ca63ba49973818b3d1e9512cd2cec4"),
b256!("013b98c6c83e066d5b14af2b85199e3d4fc7d1e778dd53130d180f5077e2d1c7"),
b256!("01148b495d6e859114e670ca54fb6e2657f0cbae5b08063605093a4b3dc9f8f1"),
b256!("011ac212f13c5dff2b2c6b600a79635103d6f580a4221079951181b25c7e6549")
b256!("011ac212f13c5dff2b2c6b600a79635103d6f580a4221079951181b25c7e6549"),
])
);
}
@ -1837,7 +1898,7 @@ mod tests {
let hash: B256 =
hex!("559fb34c4a7f115db26cbf8505389475caaab3df45f5c7a0faa4abfa3835306c").into();
let signer: Address = hex!("641c5d790f862a58ec7abcfd644c0442e9c201b3").into();
let raw =hex!("f88b8212b085028fa6ae00830f424094aad593da0c8116ef7d2d594dd6a63241bccfc26c80a48318b64b000000000000000000000000641c5d790f862a58ec7abcfd644c0442e9c201b32aa0a6ef9e170bca5ffb7ac05433b13b7043de667fbb0b4a5e45d3b54fb2d6efcc63a0037ec2c05c3d60c5f5f78244ce0a3859e3a18a36c61efb061b383507d3ce19d2");
let raw = hex!("f88b8212b085028fa6ae00830f424094aad593da0c8116ef7d2d594dd6a63241bccfc26c80a48318b64b000000000000000000000000641c5d790f862a58ec7abcfd644c0442e9c201b32aa0a6ef9e170bca5ffb7ac05433b13b7043de667fbb0b4a5e45d3b54fb2d6efcc63a0037ec2c05c3d60c5f5f78244ce0a3859e3a18a36c61efb061b383507d3ce19d2");
let mut pointer = raw.as_ref();
let tx = TransactionSigned::decode(&mut pointer).unwrap();
@ -2036,4 +2097,96 @@ mod tests {
TransactionSigned::decode(&mut &encoded[..]).unwrap();
}
#[test]
fn transaction_signed_no_hash_zstd_codec() {
// will use same signature everywhere.
// We don't need signature to match tx, just decoded to the same signature
let signature = Signature {
odd_y_parity: false,
r: U256::from_str("0xeb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae")
.unwrap(),
s: U256::from_str("0x3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18")
.unwrap(),
};
let inputs: Vec<Vec<u8>> = vec![
vec![],
vec![0],
vec![255],
vec![1u8; 31],
vec![255u8; 31],
vec![1u8; 32],
vec![255u8; 32],
vec![1u8; 64],
vec![255u8; 64],
];
for input in inputs {
let transaction = Transaction::Legacy(TxLegacy {
chain_id: Some(4u64),
nonce: 2,
gas_price: 1000000000,
gas_limit: 100000,
to: TransactionKind::Call(
Address::from_str("d3e8763675e4c425df46cc3b5c0f6cbdac396046").unwrap(),
),
value: U256::from(1000000000000000u64),
input: Bytes::from(input),
});
let tx_signed_no_hash = TransactionSignedNoHash { signature, transaction };
test_transaction_signed_to_from_compact(tx_signed_no_hash);
}
}
fn test_transaction_signed_to_from_compact(tx_signed_no_hash: TransactionSignedNoHash) {
// zstd aware `to_compact`
let mut buff: Vec<u8> = Vec::new();
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<u8> = 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<u8> = 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: TransactionKind::Call(
Address::from_str("d3e8763675e4c425df46cc3b5c0f6cbdac396046").unwrap(),
),
value: U256::from(1000000000000000u64),
input: Bytes::from(vec![3u8; 64]),
});
let tx_signed_no_hash = TransactionSignedNoHash { signature, transaction };
let mut buff: Vec<u8> = Vec::new();
let written_bytes = tx_signed_no_hash.to_compact(&mut buff);
from_compact_zstd_unaware(&buff, written_bytes);
}
}