diff --git a/Cargo.lock b/Cargo.lock index 9567d373e..d69ad6688 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3620,9 +3620,12 @@ dependencies = [ name = "reth-codecs" version = "0.1.0" dependencies = [ + "arbitrary", "bytes", "codecs-derive", "modular-bitfield", + "proptest", + "proptest-derive", "revm-interpreter", "serde", "test-fuzz", @@ -3668,6 +3671,8 @@ dependencies = [ "page_size", "parity-scale-codec", "postcard", + "proptest", + "proptest-derive", "rand 0.8.5", "reth-codecs", "reth-db", @@ -3992,6 +3997,7 @@ dependencies = [ "parity-scale-codec", "plain_hasher", "proptest", + "proptest-derive", "rand 0.8.5", "reth-codecs", "reth-rlp", diff --git a/crates/cli/utils/src/lib.rs b/crates/cli/utils/src/lib.rs index b2361cbab..fb8b7bd8e 100644 --- a/crates/cli/utils/src/lib.rs +++ b/crates/cli/utils/src/lib.rs @@ -145,7 +145,7 @@ mod tests { fn parse_socket_addresses() { for value in ["localhost:9000", ":9000", "9000", "localhost"] { let socket_addr = parse_socket_address(value) - .expect(&format!("could not parse socket address: {}", value)); + .unwrap_or_else(|_| panic!("could not parse socket address: {value}")); assert!(socket_addr.ip().is_loopback()); assert_eq!(socket_addr.port(), 9000); diff --git a/crates/executor/src/executor.rs b/crates/executor/src/executor.rs index 8833b32d6..e8afa1aac 100644 --- a/crates/executor/src/executor.rs +++ b/crates/executor/src/executor.rs @@ -365,7 +365,7 @@ pub fn execute( .map(|l| Log { address: H160(l.address.0), topics: l.topics.into_iter().map(|h| H256(h.0)).collect(), - data: l.data, + data: l.data.into(), }) .collect(); diff --git a/crates/executor/src/revm_wrap.rs b/crates/executor/src/revm_wrap.rs index a35e92048..06722aef9 100644 --- a/crates/executor/src/revm_wrap.rs +++ b/crates/executor/src/revm_wrap.rs @@ -184,7 +184,7 @@ pub fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSignedEcRecovere pub fn is_log_equal(revm_log: &revm::Log, reth_log: &reth_primitives::Log) -> bool { revm_log.topics.len() == reth_log.topics.len() && revm_log.address.0 == reth_log.address.0 && - revm_log.data == reth_log.data && + revm_log.data == reth_log.data.0 && !revm_log .topics .iter() diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 3eb1bf7e4..0be69c853 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -58,19 +58,21 @@ triehash = "0.8" plain_hasher = "0.2" hash-db = "0.15" -# optional +# arbitrary utils arbitrary = { version = "1.1.7", features = ["derive"], optional = true } proptest = { version = "1.0", optional = true } +proptest-derive = { version = "0.3", optional = true } [dev-dependencies] -arbitrary = { version = "1.1.7", features = ["derive"] } serde_json = "1.0" hex-literal = "0.3" test-fuzz = "3.0.4" rand = "0.8" revm-interpreter = { git = "https://github.com/bluealloy/revm", rev = "a05fb262d87c78ee52d400e6c0f4708d4c527f32", features = ["serde", "arbitrary"] } -proptest = { version = "1.0" } +arbitrary = { version = "1.1.7", features = ["derive"] } +proptest = { version = "1.0" } +proptest-derive = "0.3" # necessary so we don't hit a "undeclared 'std'": # https://github.com/paradigmxyz/reth/pull/177#discussion_r1021172198 @@ -78,4 +80,4 @@ secp256k1 = "0.24.2" [features] default = [] -arbitrary = ["dep:arbitrary", "dep:proptest", "revm-interpreter/arbitrary"] \ No newline at end of file +arbitrary = ["revm-interpreter/arbitrary", "dep:arbitrary", "dep:proptest", "dep:proptest-derive"] diff --git a/crates/primitives/src/bloom.rs b/crates/primitives/src/bloom.rs index 07c2b7402..f6a16c393 100644 --- a/crates/primitives/src/bloom.rs +++ b/crates/primitives/src/bloom.rs @@ -7,7 +7,7 @@ use impl_serde::impl_fixed_hash_serde; use reth_codecs::{impl_hash_compact, Compact}; use reth_rlp::{RlpDecodableWrapper, RlpEncodableWrapper}; -#[cfg(test)] +#[cfg(any(test, feature = "arbitrary"))] use proptest::{ arbitrary::{any_with, Arbitrary as PropTestArbitrary, ParamsFor}, strategy::{BoxedStrategy, Strategy}, @@ -29,7 +29,7 @@ construct_fixed_hash! { impl_hash_compact!(Bloom); impl_fixed_hash_serde!(Bloom, BLOOM_BYTE_LENGTH); -#[cfg(test)] +#[cfg(any(test, feature = "arbitrary"))] impl PropTestArbitrary for Bloom { type Parameters = ParamsFor; type Strategy = BoxedStrategy; diff --git a/crates/primitives/src/log.rs b/crates/primitives/src/log.rs index 5f94d85ad..5ff087fd5 100644 --- a/crates/primitives/src/log.rs +++ b/crates/primitives/src/log.rs @@ -1,4 +1,4 @@ -use crate::{Address, H256}; +use crate::{Address, Bytes, H256}; use reth_codecs::{main_codec, Compact}; use reth_rlp::{RlpDecodable, RlpEncodable}; @@ -11,5 +11,5 @@ pub struct Log { /// Topics of the log. The number of logs depend on what `LOG` opcode is used. pub topics: Vec, /// Arbitrary length data. - pub data: bytes::Bytes, + pub data: Bytes, } diff --git a/crates/primitives/src/proofs.rs b/crates/primitives/src/proofs.rs index 53fdc04bb..e83994724 100644 --- a/crates/primitives/src/proofs.rs +++ b/crates/primitives/src/proofs.rs @@ -74,7 +74,6 @@ mod tests { proofs::{calculate_receipt_root, calculate_transaction_root}, Block, Bloom, Log, Receipt, TxType, H160, H256, }; - use bytes::Bytes; use reth_rlp::Decodable; #[test] @@ -89,7 +88,7 @@ mod tests { #[test] fn check_receipt_root() { - let logs = vec![Log { address: H160::zero(), topics: vec![], data: Bytes::default() }]; + let logs = vec![Log { address: H160::zero(), topics: vec![], data: Default::default() }]; let bloom = Bloom(hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001")); let receipt = Receipt { tx_type: TxType::EIP2930, diff --git a/crates/primitives/src/receipt.rs b/crates/primitives/src/receipt.rs index a103ede18..1e9fa1727 100644 --- a/crates/primitives/src/receipt.rs +++ b/crates/primitives/src/receipt.rs @@ -186,7 +186,7 @@ mod tests { ) .unwrap(), ], - data: Bytes::from_str("0100ff").unwrap().0, + data: Bytes::from_str("0100ff").unwrap().0.into(), }], success: false, }; @@ -220,7 +220,7 @@ mod tests { ) .unwrap(), ], - data: Bytes::from_str("0100ff").unwrap().0, + data: Bytes::from_str("0100ff").unwrap().0.into(), }], success: false, }; diff --git a/crates/primitives/src/transaction/tx_type.rs b/crates/primitives/src/transaction/tx_type.rs index 1e17405b5..b2dd851eb 100644 --- a/crates/primitives/src/transaction/tx_type.rs +++ b/crates/primitives/src/transaction/tx_type.rs @@ -1,7 +1,8 @@ -use reth_codecs::Compact; +use reth_codecs::{derive_compact_arbitrary, Compact}; use serde::{Deserialize, Serialize}; /// Transaction Type +#[derive_compact_arbitrary] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)] pub enum TxType { /// Legacy transaction pre EIP-2929 diff --git a/crates/storage/codecs/Cargo.toml b/crates/storage/codecs/Cargo.toml index 37cc7897e..78f43eb19 100644 --- a/crates/storage/codecs/Cargo.toml +++ b/crates/storage/codecs/Cargo.toml @@ -18,7 +18,16 @@ bytes = "1.2.1" codecs-derive = { version = "0.1.0", path = "./derive", default-features = false } revm-interpreter = { git = "https://github.com/bluealloy/revm", rev = "a05fb262d87c78ee52d400e6c0f4708d4c527f32", features = ["serde"] } +# arbitrary utils +arbitrary = { version = "1.1.7", features = ["derive"], optional = true } +proptest = { version = "1.0", optional = true } +proptest-derive = { version = "0.3", optional = true } + [dev-dependencies] serde = "1.0" modular-bitfield = "0.11.2" -test-fuzz = "3.0.4" \ No newline at end of file +test-fuzz = "3.0.4" + +arbitrary = { version = "1.1.7", features = ["derive"] } +proptest = { version = "1.0" } +proptest-derive = "0.3" diff --git a/crates/storage/codecs/derive/src/lib.rs b/crates/storage/codecs/derive/src/lib.rs index 3a5412544..fa2b60a63 100644 --- a/crates/storage/codecs/derive/src/lib.rs +++ b/crates/storage/codecs/derive/src/lib.rs @@ -1,5 +1,5 @@ use proc_macro::{self, TokenStream}; -use quote::quote; +use quote::{format_ident, quote}; use syn::{parse_macro_input, DeriveInput}; mod compact; @@ -73,9 +73,53 @@ pub fn use_postcard(_args: TokenStream, input: TokenStream) -> TokenStream { pub fn use_compact(_args: TokenStream, input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); + derive_compact_arbitrary( + _args, + quote! { + #[derive(Compact, serde::Serialize, serde::Deserialize)] + #ast + } + .into(), + ) +} + +#[proc_macro_attribute] +pub fn derive_compact_arbitrary(_args: TokenStream, input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + + // Avoid duplicate names + let prop_import = format_ident!("{}PropTestArbitratry", ast.ident); + let arb_import = format_ident!("{}Arbitratry", ast.ident); + let mod_tests = format_ident!("{}Tests", ast.ident); + let type_ident = ast.ident.clone(); + quote! { - #[derive(Compact, serde::Serialize, serde::Deserialize)] + #[cfg(any(test, feature = "arbitrary"))] + use proptest_derive::Arbitrary as #prop_import; + + #[cfg(any(test, feature = "arbitrary"))] + use arbitrary::Arbitrary as #arb_import; + + #[cfg_attr(any(test, feature = "arbitrary"), derive(#prop_import, #arb_import))] #ast + + #[allow(non_snake_case)] + #[cfg(test)] + mod #mod_tests { + use super::Compact; + + #[test] + fn proptest() { + proptest::proptest!(|(field: super::#type_ident)| { + let mut buf = vec![]; + + let len = field.clone().to_compact(&mut buf); + let (decoded, _) = super::#type_ident::from_compact(&buf, len); + + assert!(field == decoded); + }); + } + } } .into() } diff --git a/crates/storage/db/Cargo.toml b/crates/storage/db/Cargo.toml index 766f0ca94..4200f7ee2 100644 --- a/crates/storage/db/Cargo.toml +++ b/crates/storage/db/Cargo.toml @@ -22,7 +22,6 @@ parity-scale-codec = { version = "3.2.1", features = ["bytes"] } futures = "0.3.25" tokio-stream = "0.1.11" rand = "0.8.5" -arbitrary = { version = "1.1.7", features = ["derive"], optional = true } secp256k1 = { version = "0.24.2", default-features = false, features = ["alloc", "recovery", "rand"], optional = true } modular-bitfield = "0.11.2" @@ -32,6 +31,11 @@ page_size = "0.4.2" thiserror = "1.0.37" tempfile = { version = "3.3.0", optional = true } +# arbitrary utils +arbitrary = { version = "1.1.7", features = ["derive"], optional = true } +proptest = { version = "1.0", optional = true } +proptest-derive = { version = "0.3", optional = true } + [dev-dependencies] tempfile = "3.3.0" test-fuzz = "3.0.4" @@ -39,7 +43,6 @@ test-fuzz = "3.0.4" criterion = "0.4.0" iai = "0.1.1" tokio = { version = "1.21.2", features = ["full"] } -arbitrary = { version = "1.1.7", features = ["derive"]} reth-db = { path = ".", features = ["test-utils","bench"]} # needed for test-fuzz to work properly, see https://github.com/paradigmxyz/reth/pull/177#discussion_r1021172198 @@ -48,6 +51,11 @@ secp256k1 = "0.24.2" reth-interfaces = { path = "../../interfaces", features=["bench"] } async-trait = "0.1.58" +arbitrary = { version = "1.1.7", features = ["derive"] } +proptest = { version = "1.0" } +proptest-derive = "0.3" + + [features] default = ["mdbx"] test-utils = ["tempfile"]