Skip to content

Commit

Permalink
reth-primitives: Allow feature gating zstd for non default feature …
Browse files Browse the repository at this point in the history
  • Loading branch information
citizen-stig authored Mar 25, 2024
1 parent d2fb8f2 commit d611f11
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 21 deletions.
8 changes: 6 additions & 2 deletions crates/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 8 additions & 6 deletions crates/primitives/src/receipt.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
179 changes: 166 additions & 13 deletions crates/primitives/src/transaction/mod.rs
Original file line number Diff line number Diff line change
@@ -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,
};
Expand Down Expand Up @@ -52,6 +52,7 @@ mod variant;

#[cfg(feature = "optimism")]
mod optimism;

#[cfg(feature = "optimism")]
pub use optimism::TxDeposit;
#[cfg(feature = "optimism")]
Expand Down Expand Up @@ -884,6 +885,7 @@ impl TransactionSignedNoHash {
}
}

#[cfg(feature = "zstd-codec")]
impl Compact for TransactionSignedNoHash {
fn to_compact<B>(self, buf: &mut B) -> usize
where
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -1684,7 +1745,7 @@ mod tests {
b256!("0152d8e24762ff22b1cfd9f8c0683786a7ca63ba49973818b3d1e9512cd2cec4"),
b256!("013b98c6c83e066d5b14af2b85199e3d4fc7d1e778dd53130d180f5077e2d1c7"),
b256!("01148b495d6e859114e670ca54fb6e2657f0cbae5b08063605093a4b3dc9f8f1"),
b256!("011ac212f13c5dff2b2c6b600a79635103d6f580a4221079951181b25c7e6549")
b256!("011ac212f13c5dff2b2c6b600a79635103d6f580a4221079951181b25c7e6549"),
])
);
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}
}

0 comments on commit d611f11

Please sign in to comment.