diff --git a/Cargo.lock b/Cargo.lock index ab66b3b56..9fa1553c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5780,6 +5780,16 @@ dependencies = [ "unarray", ] +[[package]] +name = "proptest-arbitrary-interop" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1981e49bd2432249da8b0e11e5557099a8e74690d6b94e721f7dc0bb7f3555f" +dependencies = [ + "arbitrary", + "proptest", +] + [[package]] name = "proptest-derive" version = "0.4.0" @@ -6182,6 +6192,7 @@ dependencies = [ "ahash", "alloy-rlp", "aquamarine", + "arbitrary", "assert_matches", "backon", "boyer-moore-magiclen", @@ -6199,6 +6210,7 @@ dependencies = [ "libc", "metrics-process", "proptest", + "proptest-arbitrary-interop", "rand 0.8.5", "ratatui", "rayon", @@ -6492,6 +6504,7 @@ dependencies = [ "bytes", "modular-bitfield", "proptest", + "proptest-arbitrary-interop", "proptest-derive", "reth-codecs-derive", "serde", @@ -6621,6 +6634,7 @@ dependencies = [ "paste", "pprof", "proptest", + "proptest-arbitrary-interop", "proptest-derive", "rand 0.8.5", "reth-codecs", @@ -6866,6 +6880,7 @@ dependencies = [ "futures", "pin-project", "proptest", + "proptest-arbitrary-interop", "proptest-derive", "rand 0.8.5", "reth-chainspec", @@ -6900,6 +6915,7 @@ dependencies = [ "bytes", "derive_more", "proptest", + "proptest-arbitrary-interop", "proptest-derive", "rand 0.8.5", "reth-chainspec", @@ -7688,6 +7704,7 @@ dependencies = [ "once_cell", "pprof", "proptest", + "proptest-arbitrary-interop", "proptest-derive", "rand 0.8.5", "rayon", @@ -7726,6 +7743,7 @@ dependencies = [ "derive_more", "modular-bitfield", "proptest", + "proptest-arbitrary-interop", "proptest-derive", "rand 0.8.5", "reth-codecs", @@ -7818,6 +7836,7 @@ dependencies = [ "derive_more", "modular-bitfield", "proptest", + "proptest-arbitrary-interop", "proptest-derive", "reth-codecs", "serde", @@ -8153,6 +8172,7 @@ dependencies = [ "bytes", "modular-bitfield", "proptest", + "proptest-arbitrary-interop", "proptest-derive", "rand 0.8.5", "reth-codecs", @@ -8285,6 +8305,7 @@ dependencies = [ "paste", "pprof", "proptest", + "proptest-arbitrary-interop", "rand 0.8.5", "reth-chainspec", "reth-eth-wire-types", @@ -8319,6 +8340,7 @@ dependencies = [ "metrics", "once_cell", "proptest", + "proptest-arbitrary-interop", "rayon", "reth-chainspec", "reth-db", @@ -8358,6 +8380,7 @@ dependencies = [ "nybbles", "plain_hasher", "proptest", + "proptest-arbitrary-interop", "proptest-derive", "reth-codecs", "reth-primitives-traits", @@ -8378,6 +8401,7 @@ dependencies = [ "itertools 0.13.0", "metrics", "proptest", + "proptest-arbitrary-interop", "rand 0.8.5", "rayon", "reth-db", diff --git a/Cargo.toml b/Cargo.toml index db4613a04..069452a7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -468,6 +468,7 @@ jsonrpsee-http-client = "0.23" http = "1.0" http-body = "1.0" jsonwebtoken = "9" +proptest-arbitrary-interop = "0.1.0" # crypto secp256k1 = { version = "0.29", default-features = false, features = [ diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index 882c1afed..46636913f 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -86,6 +86,8 @@ metrics-process.workspace = true # test vectors generation proptest.workspace = true +arbitrary.workspace = true +proptest-arbitrary-interop.workspace = true rand.workspace = true # tui diff --git a/bin/reth/src/commands/test_vectors/tables.rs b/bin/reth/src/commands/test_vectors/tables.rs index 9442f52ae..d7138444f 100644 --- a/bin/reth/src/commands/test_vectors/tables.rs +++ b/bin/reth/src/commands/test_vectors/tables.rs @@ -1,15 +1,15 @@ -use std::collections::HashSet; - +use arbitrary::Arbitrary; use eyre::Result; use proptest::{ - arbitrary::Arbitrary, - prelude::{any_with, ProptestConfig}, + prelude::ProptestConfig, strategy::{Strategy, ValueTree}, test_runner::TestRunner, }; +use proptest_arbitrary_interop::arb; use reth_db::tables; use reth_db_api::table::{DupSort, Table, TableRow}; use reth_fs_util as fs; +use std::collections::HashSet; use tracing::error; const VECTORS_FOLDER: &str = "testdata/micro/db"; @@ -73,21 +73,14 @@ pub(crate) fn generate_vectors(mut tables: Vec) -> Result<()> { /// Generates test-vectors for normal tables. Keys are sorted and not repeated. fn generate_table_vector(runner: &mut TestRunner, per_table: usize) -> Result<()> where - T::Key: Arbitrary + serde::Serialize + Ord + std::hash::Hash, - T::Value: Arbitrary + serde::Serialize, T: Table, + T::Key: for<'a> Arbitrary<'a> + serde::Serialize + Ord + std::hash::Hash + Clone, + T::Value: for<'a> Arbitrary<'a> + serde::Serialize + Clone, { let mut rows = vec![]; let mut seen_keys = HashSet::new(); - let strategy = proptest::collection::vec( - any_with::>(( - ::Parameters::default(), - ::Parameters::default(), - )), - per_table - rows.len(), - ) - .no_shrink() - .boxed(); + let strategy = + proptest::collection::vec(arb::>(), per_table - rows.len()).no_shrink().boxed(); while rows.len() < per_table { // Generate all `per_table` rows: (Key, Value) @@ -111,23 +104,17 @@ where fn generate_dupsort_vector(runner: &mut TestRunner, per_table: usize) -> Result<()> where T: Table + DupSort, - T::Key: Arbitrary + serde::Serialize + Ord + std::hash::Hash, - T::Value: Arbitrary + serde::Serialize + Ord, + T::Key: for<'a> Arbitrary<'a> + serde::Serialize + Ord + std::hash::Hash + Clone, + T::Value: for<'a> Arbitrary<'a> + serde::Serialize + Ord + Clone, { let mut rows = vec![]; // We want to control our repeated keys let mut seen_keys = HashSet::new(); - let strat_values = proptest::collection::vec( - any_with::(::Parameters::default()), - 100..300, - ) - .no_shrink() - .boxed(); + let strat_values = proptest::collection::vec(arb::(), 100..300).no_shrink().boxed(); - let strat_keys = - any_with::(::Parameters::default()).no_shrink().boxed(); + let strat_keys = arb::().no_shrink().boxed(); while rows.len() < per_table { let key: T::Key = strat_keys.new_tree(runner).map_err(|e| eyre::eyre!("{e}"))?.current(); diff --git a/crates/net/eth-wire-types/Cargo.toml b/crates/net/eth-wire-types/Cargo.toml index d7766043e..f695e926b 100644 --- a/crates/net/eth-wire-types/Cargo.toml +++ b/crates/net/eth-wire-types/Cargo.toml @@ -27,7 +27,7 @@ serde = { workspace = true, optional = true } # arbitrary utils arbitrary = { workspace = true, features = ["derive"], optional = true } proptest = { workspace = true, optional = true } -proptest-derive = { workspace = true, optional = true } +proptest-arbitrary-interop = { workspace = true, optional = true } [dev-dependencies] reth-net-common.workspace = true @@ -40,6 +40,7 @@ rand.workspace = true arbitrary = { workspace = true, features = ["derive"] } proptest.workspace = true +proptest-arbitrary-interop.workspace = true proptest-derive.workspace = true async-stream.workspace = true @@ -49,7 +50,7 @@ arbitrary = [ "reth-primitives/arbitrary", "dep:arbitrary", "dep:proptest", - "dep:proptest-derive", + "dep:proptest-arbitrary-interop", ] serde = ["dep:serde"] diff --git a/crates/net/eth-wire-types/src/blocks.rs b/crates/net/eth-wire-types/src/blocks.rs index 97268ee64..c8668c251 100644 --- a/crates/net/eth-wire-types/src/blocks.rs +++ b/crates/net/eth-wire-types/src/blocks.rs @@ -3,13 +3,10 @@ use alloy_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper}; use reth_codecs_derive::{add_arbitrary_tests, derive_arbitrary}; +#[cfg(any(test, feature = "arbitrary"))] +use reth_primitives::generate_valid_header; use reth_primitives::{BlockBody, BlockHashOrNumber, Header, HeadersDirection, B256}; -#[cfg(any(test, feature = "arbitrary"))] -use proptest::{collection::vec, prelude::*}; -#[cfg(any(test, feature = "arbitrary"))] -use reth_primitives::{generate_valid_header, valid_header_strategy}; - #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -51,18 +48,6 @@ pub struct BlockHeaders( pub Vec
, ); -#[cfg(any(test, feature = "arbitrary"))] -impl proptest::arbitrary::Arbitrary for BlockHeaders { - type Parameters = (); - fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { - let headers_strategy = vec(valid_header_strategy(), 0..10); // Adjust the range as needed - - headers_strategy.prop_map(BlockHeaders).boxed() - } - - type Strategy = proptest::prelude::BoxedStrategy; -} - #[cfg(any(test, feature = "arbitrary"))] impl<'a> arbitrary::Arbitrary<'a> for BlockHeaders { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { @@ -111,12 +96,6 @@ impl From> for GetBlockBodies { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BlockBodies( /// The requested block bodies, each of which should correspond to a hash in the request. - #[cfg_attr( - any(test, feature = "arbitrary"), - proptest( - strategy = "proptest::collection::vec(proptest::arbitrary::any::(), 0..=20)" - ) - )] pub Vec, ); diff --git a/crates/net/eth-wire-types/src/broadcast.rs b/crates/net/eth-wire-types/src/broadcast.rs index e413ab9ee..1b5a3b411 100644 --- a/crates/net/eth-wire-types/src/broadcast.rs +++ b/crates/net/eth-wire-types/src/broadcast.rs @@ -19,6 +19,8 @@ use std::{ #[cfg(feature = "arbitrary")] use proptest::{collection::vec, prelude::*}; +#[cfg(feature = "arbitrary")] +use proptest_arbitrary_interop::arb; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -351,7 +353,7 @@ impl Arbitrary for NewPooledTransactionHashes68 { .prop_flat_map(|len| { // Use the generated length to create vectors of TxType, usize, and B256 let types_vec = - vec(any::().prop_map(|ty| ty as u8), len..=len); + vec(arb::().prop_map(|ty| ty as u8), len..=len); // Map the usize values to the range 0..131072(0x20000) let sizes_vec = vec(proptest::num::usize::ANY.prop_map(|x| x % 131072), len..=len); diff --git a/crates/net/eth-wire-types/src/receipts.rs b/crates/net/eth-wire-types/src/receipts.rs index 72424b0bd..4816f8554 100644 --- a/crates/net/eth-wire-types/src/receipts.rs +++ b/crates/net/eth-wire-types/src/receipts.rs @@ -23,12 +23,6 @@ pub struct GetReceipts( #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Receipts( /// Each receipt hash should correspond to a block hash in the request. - #[cfg_attr( - any(test, feature = "arbitrary"), - proptest( - strategy = "proptest::collection::vec(proptest::collection::vec(proptest::arbitrary::any::(), 0..=50), 0..=5)" - ) - )] pub Vec>, ); diff --git a/crates/net/eth-wire/Cargo.toml b/crates/net/eth-wire/Cargo.toml index 0add7b8a5..91bf9290f 100644 --- a/crates/net/eth-wire/Cargo.toml +++ b/crates/net/eth-wire/Cargo.toml @@ -39,8 +39,6 @@ snap = "1.0.5" # arbitrary utils arbitrary = { workspace = true, features = ["derive"], optional = true } -proptest = { workspace = true, optional = true } -proptest-derive = { workspace = true, optional = true } [dev-dependencies] reth-net-common.workspace = true @@ -58,6 +56,7 @@ secp256k1 = { workspace = true, features = [ arbitrary = { workspace = true, features = ["derive"] } proptest.workspace = true +proptest-arbitrary-interop.workspace = true proptest-derive.workspace = true async-stream.workspace = true @@ -66,8 +65,6 @@ default = ["serde"] arbitrary = [ "reth-primitives/arbitrary", "dep:arbitrary", - "dep:proptest", - "dep:proptest-derive", ] optimism = ["reth-primitives/optimism"] serde = ["dep:serde"] diff --git a/crates/net/eth-wire/src/capability.rs b/crates/net/eth-wire/src/capability.rs index 2bf096287..776cc375f 100644 --- a/crates/net/eth-wire/src/capability.rs +++ b/crates/net/eth-wire/src/capability.rs @@ -129,22 +129,6 @@ impl<'a> arbitrary::Arbitrary<'a> for Capability { } } -#[cfg(any(test, feature = "arbitrary"))] -impl proptest::arbitrary::Arbitrary for Capability { - type Parameters = proptest::arbitrary::ParamsFor; - fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { - use proptest::strategy::Strategy; - proptest::arbitrary::any_with::(args) // TODO: what possible values? - .prop_flat_map(move |name| { - proptest::arbitrary::any_with::(()) // TODO: What's the max? - .prop_map(move |version| Self::new(name.clone(), version)) - }) - .boxed() - } - - type Strategy = proptest::strategy::BoxedStrategy; -} - /// Represents all capabilities of a node. #[derive(Debug, Clone, Eq, PartialEq)] pub struct Capabilities { diff --git a/crates/primitives-traits/Cargo.toml b/crates/primitives-traits/Cargo.toml index 050f84c03..638cdccc6 100644 --- a/crates/primitives-traits/Cargo.toml +++ b/crates/primitives-traits/Cargo.toml @@ -19,7 +19,7 @@ alloy-eips.workspace = true alloy-genesis.workspace = true alloy-primitives.workspace = true alloy-rlp.workspace = true -alloy-rpc-types-eth = { workspace = true, optional = true } +alloy-rpc-types-eth = { workspace = true, optional = true } derive_more.workspace = true revm-primitives = { workspace = true, features = ["serde"] } @@ -37,11 +37,12 @@ serde.workspace = true # arbitrary utils arbitrary = { workspace = true, features = ["derive"], optional = true } proptest = { workspace = true, optional = true } -proptest-derive = { workspace = true, optional = true } +proptest-arbitrary-interop = { workspace = true, optional = true } [dev-dependencies] arbitrary = { workspace = true, features = ["derive"] } proptest.workspace = true +proptest-arbitrary-interop.workspace = true proptest-derive.workspace = true test-fuzz.workspace = true rand.workspace = true @@ -55,6 +56,6 @@ arbitrary = [ "alloy-consensus/arbitrary", "dep:arbitrary", "dep:proptest", - "dep:proptest-derive" + "dep:proptest-arbitrary-interop", ] -alloy-compat = ["alloy-rpc-types-eth"] \ No newline at end of file +alloy-compat = ["alloy-rpc-types-eth"] diff --git a/crates/primitives-traits/src/header/mod.rs b/crates/primitives-traits/src/header/mod.rs index cb85a3363..e817965a6 100644 --- a/crates/primitives-traits/src/header/mod.rs +++ b/crates/primitives-traits/src/header/mod.rs @@ -16,11 +16,12 @@ use alloy_primitives::{keccak256, Address, BlockNumber, Bloom, Bytes, B256, B64, use alloy_rlp::{length_of_length, Decodable, Encodable}; use bytes::BufMut; use core::mem; -use reth_codecs::{main_codec, Compact}; +use reth_codecs::{add_arbitrary_tests, main_codec, Compact}; use revm_primitives::{calc_blob_gasprice, calc_excess_blob_gas}; /// Block header -#[main_codec] +#[main_codec(no_arbitrary)] +#[add_arbitrary_tests(rlp, 25)] #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Header { /// The Keccak 256-bit hash of the parent @@ -487,3 +488,42 @@ impl Decodable for Header { Ok(this) } } + +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for Header { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + // Generate an arbitrary header, passing it to the generate_valid_header function to make + // sure it is valid _with respect to hardforks only_. + let base = Self { + parent_hash: u.arbitrary()?, + ommers_hash: u.arbitrary()?, + beneficiary: u.arbitrary()?, + state_root: u.arbitrary()?, + transactions_root: u.arbitrary()?, + receipts_root: u.arbitrary()?, + logs_bloom: u.arbitrary()?, + difficulty: u.arbitrary()?, + number: u.arbitrary()?, + gas_limit: u.arbitrary()?, + gas_used: u.arbitrary()?, + timestamp: u.arbitrary()?, + extra_data: u.arbitrary()?, + mix_hash: u.arbitrary()?, + nonce: u.arbitrary()?, + base_fee_per_gas: u.arbitrary()?, + blob_gas_used: u.arbitrary()?, + excess_blob_gas: u.arbitrary()?, + parent_beacon_block_root: u.arbitrary()?, + requests_root: u.arbitrary()?, + withdrawals_root: u.arbitrary()?, + }; + + Ok(test_utils::generate_valid_header( + base, + u.arbitrary()?, + u.arbitrary()?, + u.arbitrary()?, + u.arbitrary()?, + )) + } +} diff --git a/crates/primitives-traits/src/header/sealed.rs b/crates/primitives-traits/src/header/sealed.rs index 894bd28ae..355e4a9bc 100644 --- a/crates/primitives-traits/src/header/sealed.rs +++ b/crates/primitives-traits/src/header/sealed.rs @@ -7,8 +7,6 @@ use alloy_rlp::{Decodable, Encodable}; use bytes::BufMut; use core::mem; use derive_more::{AsRef, Deref}; -#[cfg(any(test, feature = "arbitrary"))] -use proptest::prelude::*; use reth_codecs::{add_arbitrary_tests, main_codec, Compact}; /// A [`Header`] that is sealed at a precalculated hash, use [`SealedHeader::unseal()`] if you want @@ -130,27 +128,9 @@ impl SealedHeader { } } -#[cfg(any(test, feature = "arbitrary"))] -impl proptest::arbitrary::Arbitrary for SealedHeader { - type Parameters = (); - fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { - // map valid header strategy by sealing - crate::test_utils::valid_header_strategy().prop_map(|header| header.seal_slow()).boxed() - } - type Strategy = proptest::strategy::BoxedStrategy; -} - #[cfg(any(test, feature = "arbitrary"))] impl<'a> arbitrary::Arbitrary<'a> for SealedHeader { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - let sealed_header = crate::test_utils::generate_valid_header( - u.arbitrary()?, - u.arbitrary()?, - u.arbitrary()?, - u.arbitrary()?, - u.arbitrary()?, - ) - .seal_slow(); - Ok(sealed_header) + Ok(Header::arbitrary(u)?.seal_slow()) } } diff --git a/crates/primitives-traits/src/header/test_utils.rs b/crates/primitives-traits/src/header/test_utils.rs index 07d00f03b..982b779d4 100644 --- a/crates/primitives-traits/src/header/test_utils.rs +++ b/crates/primitives-traits/src/header/test_utils.rs @@ -3,6 +3,7 @@ use crate::Header; use alloy_primitives::B256; use proptest::{arbitrary::any, prop_compose}; +use proptest_arbitrary_interop::arb; /// Generates a header which is valid __with respect to past and future forks__. This means, for /// example, that if the withdrawals root is present, the base fee per gas is also present. @@ -55,11 +56,11 @@ prop_compose! { /// /// See docs for [generate_valid_header] for more information. pub fn valid_header_strategy()( - header in any::
(), + header in arb::
(), eip_4844_active in any::(), blob_gas_used in any::(), excess_blob_gas in any::(), - parent_beacon_block_root in any::() + parent_beacon_block_root in arb::() ) -> Header { generate_valid_header(header, eip_4844_active, blob_gas_used, excess_blob_gas, parent_beacon_block_root) } diff --git a/crates/primitives-traits/src/log.rs b/crates/primitives-traits/src/log.rs index 823385978..aa6bc26a9 100644 --- a/crates/primitives-traits/src/log.rs +++ b/crates/primitives-traits/src/log.rs @@ -18,6 +18,7 @@ mod tests { use alloy_primitives::{Address, Bytes, Log as AlloyLog, B256}; use alloy_rlp::{RlpDecodable, RlpEncodable}; use proptest::proptest; + use proptest_arbitrary_interop::arb; use reth_codecs::{main_codec, Compact}; /// This type is kept for compatibility tests after the codec support was added to @@ -28,12 +29,6 @@ mod tests { /// Contract that emitted this log. address: Address, /// Topics of the log. The number of logs depend on what `LOG` opcode is used. - #[cfg_attr( - any(test, feature = "arbitrary"), - proptest( - strategy = "proptest::collection::vec(proptest::arbitrary::any::(), 0..=5)" - ) - )] topics: Vec, /// Arbitrary length data. data: Bytes, @@ -57,7 +52,7 @@ mod tests { proptest! { #[test] - fn test_roundtrip_conversion_between_log_and_alloy_log(log: Log) { + fn test_roundtrip_conversion_between_log_and_alloy_log(log in arb::()) { // Convert log to buffer and then create alloy_log from buffer and compare let mut compacted_log = Vec::::new(); let len = log.clone().to_compact(&mut compacted_log); diff --git a/crates/primitives-traits/src/withdrawal.rs b/crates/primitives-traits/src/withdrawal.rs index d9285f6bc..679c80cab 100644 --- a/crates/primitives-traits/src/withdrawal.rs +++ b/crates/primitives-traits/src/withdrawal.rs @@ -71,6 +71,7 @@ mod tests { use alloy_primitives::Address; use alloy_rlp::{RlpDecodable, RlpEncodable}; use proptest::proptest; + use proptest_arbitrary_interop::arb; /// This type is kept for compatibility tests after the codec support was added to alloy-eips /// Withdrawal type natively @@ -108,7 +109,7 @@ mod tests { proptest!( #[test] - fn test_roundtrip_withdrawal_compat(withdrawal: RethWithdrawal) { + fn test_roundtrip_withdrawal_compat(withdrawal in arb::()) { // Convert to buffer and then create alloy_access_list from buffer and // compare let mut compacted_reth_withdrawal = Vec::::new(); diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 29db6c993..1bd31171c 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -51,7 +51,7 @@ zstd = { version = "0.13", features = ["experimental"], optional = true } # arbitrary utils arbitrary = { workspace = true, features = ["derive"], optional = true } proptest = { workspace = true, optional = true } -proptest-derive = { workspace = true, optional = true } +# proptest-derive = { workspace = true, optional = true } [dev-dependencies] # eth @@ -64,6 +64,7 @@ alloy-eips = { workspace = true, features = ["arbitrary"] } assert_matches.workspace = true arbitrary = { workspace = true, features = ["derive"] } proptest.workspace = true +proptest-arbitrary-interop.workspace = true proptest-derive.workspace = true rand.workspace = true serde_json.workspace = true @@ -94,7 +95,6 @@ arbitrary = [ "alloy-eips/arbitrary", "dep:arbitrary", "dep:proptest", - "dep:proptest-derive", "zstd-codec", ] c-kzg = ["dep:c-kzg", "revm-primitives/c-kzg", "dep:tempfile", "alloy-eips/kzg"] diff --git a/crates/primitives/benches/validate_blob_tx.rs b/crates/primitives/benches/validate_blob_tx.rs index ec62353fb..40f8b9092 100644 --- a/crates/primitives/benches/validate_blob_tx.rs +++ b/crates/primitives/benches/validate_blob_tx.rs @@ -10,6 +10,7 @@ use proptest::{ strategy::ValueTree, test_runner::{RngAlgorithm, TestRng, TestRunner}, }; +use proptest_arbitrary_interop::arb; use reth_primitives::{ constants::eip4844::MAINNET_KZG_TRUSTED_SETUP, BlobTransactionSidecar, TxEip4844, }; @@ -42,13 +43,13 @@ fn validate_blob_tx( let mut runner = TestRunner::new_with_rng(config, rng); // generate tx and sidecar - let mut tx = any::().new_tree(&mut runner).unwrap().current(); + let mut tx = arb::().new_tree(&mut runner).unwrap().current(); let mut blob_sidecar = - any::().new_tree(&mut runner).unwrap().current(); + arb::().new_tree(&mut runner).unwrap().current(); while blob_sidecar.blobs.len() < num_blobs as usize { let blob_sidecar_ext = - any::().new_tree(&mut runner).unwrap().current(); + arb::().new_tree(&mut runner).unwrap().current(); // extend the sidecar with the new blobs blob_sidecar.blobs.extend(blob_sidecar_ext.blobs); diff --git a/crates/primitives/src/block.rs b/crates/primitives/src/block.rs index 4980ebe73..9b5e172e8 100644 --- a/crates/primitives/src/block.rs +++ b/crates/primitives/src/block.rs @@ -9,7 +9,7 @@ use alloy_rlp::{RlpDecodable, RlpEncodable}; use derive_more::{Deref, DerefMut}; #[cfg(any(test, feature = "arbitrary"))] use proptest::prelude::prop_compose; -use reth_codecs::derive_arbitrary; +use reth_codecs::{add_arbitrary_tests, derive_arbitrary}; #[cfg(any(test, feature = "arbitrary"))] pub use reth_primitives_traits::test_utils::{generate_valid_header, valid_header_strategy}; use reth_primitives_traits::Requests; @@ -31,38 +31,22 @@ prop_compose! { /// Ethereum full block. /// /// Withdrawals can be optionally included at the end of the RLP encoded message. -#[derive_arbitrary(rlp, 25)] +#[add_arbitrary_tests(rlp, 25)] #[derive( Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, Deref, RlpEncodable, RlpDecodable, )] #[rlp(trailing)] pub struct Block { /// Block header. - #[cfg_attr(any(test, feature = "arbitrary"), proptest(strategy = "valid_header_strategy()"))] #[deref] pub header: Header, /// Transactions in this block. - #[cfg_attr( - any(test, feature = "arbitrary"), - proptest( - strategy = "proptest::collection::vec(proptest::arbitrary::any::(), 0..=100)" - ) - )] pub body: Vec, /// Ommers/uncles header. - #[cfg_attr( - any(test, feature = "arbitrary"), - proptest(strategy = "proptest::collection::vec(valid_header_strategy(), 0..=2)") - )] pub ommers: Vec
, /// Block withdrawals. - #[cfg_attr( - any(test, feature = "arbitrary"), - proptest(strategy = "proptest::option::of(proptest::arbitrary::any::())") - )] pub withdrawals: Option, /// Block requests. - #[cfg_attr(any(test, feature = "arbitrary"), proptest(strategy = "empty_requests_strategy()"))] pub requests: Option, } @@ -187,6 +171,28 @@ impl Block { } } +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for Block { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + // first generate up to 100 txs + let transactions = (0..100) + .map(|_| TransactionSigned::arbitrary(u)) + .collect::>>()?; + + // then generate up to 2 ommers + let ommers = (0..2).map(|_| Header::arbitrary(u)).collect::>>()?; + + Ok(Self { + header: u.arbitrary()?, + body: transactions, + ommers, + // for now just generate empty requests, see HACK above + requests: u.arbitrary()?, + withdrawals: u.arbitrary()?, + }) + } +} + /// Sealed block with senders recovered from transactions. #[derive(Debug, Clone, PartialEq, Eq, Default, Deref, DerefMut)] pub struct BlockWithSenders { @@ -278,27 +284,12 @@ pub struct SealedBlock { #[deref_mut] pub header: SealedHeader, /// Transactions with signatures. - #[cfg_attr( - any(test, feature = "arbitrary"), - proptest( - strategy = "proptest::collection::vec(proptest::arbitrary::any::(), 0..=100)" - ) - )] pub body: Vec, /// Ommer/uncle headers - #[cfg_attr( - any(test, feature = "arbitrary"), - proptest(strategy = "proptest::collection::vec(valid_header_strategy(), 0..=2)") - )] pub ommers: Vec
, /// Block withdrawals. - #[cfg_attr( - any(test, feature = "arbitrary"), - proptest(strategy = "proptest::option::of(proptest::arbitrary::any::())") - )] pub withdrawals: Option, /// Block requests. - #[cfg_attr(any(test, feature = "arbitrary"), proptest(strategy = "empty_requests_strategy()"))] pub requests: Option, } @@ -548,30 +539,19 @@ impl SealedBlockWithSenders { /// A response to `GetBlockBodies`, containing bodies if any bodies were found. /// /// Withdrawals can be optionally included at the end of the RLP encoded message. -#[derive_arbitrary(rlp, 10)] +#[add_arbitrary_tests(rlp, 10)] #[derive( Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize, RlpEncodable, RlpDecodable, )] #[rlp(trailing)] pub struct BlockBody { /// Transactions in the block - #[cfg_attr( - any(test, feature = "arbitrary"), - proptest( - strategy = "proptest::collection::vec(proptest::arbitrary::any::(), 0..=100)" - ) - )] pub transactions: Vec, /// Uncle headers for the given block - #[cfg_attr( - any(test, feature = "arbitrary"), - proptest(strategy = "proptest::collection::vec(valid_header_strategy(), 0..=2)") - )] pub ommers: Vec
, /// Withdrawals in the block. pub withdrawals: Option, /// Requests in the block. - #[cfg_attr(any(test, feature = "arbitrary"), proptest(strategy = "empty_requests_strategy()"))] pub requests: Option, } @@ -634,6 +614,22 @@ impl From for BlockBody { } } +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for BlockBody { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + // first generate up to 100 txs + let transactions = (0..100) + .map(|_| TransactionSigned::arbitrary(u)) + .collect::>>()?; + + // then generate up to 2 ommers + let ommers = (0..2).map(|_| Header::arbitrary(u)).collect::>>()?; + + // for now just generate empty requests, see HACK above + Ok(Self { transactions, ommers, requests: None, withdrawals: u.arbitrary()? }) + } +} + #[cfg(test)] mod tests { use super::{BlockNumberOrTag::*, *}; diff --git a/crates/primitives/src/receipt.rs b/crates/primitives/src/receipt.rs index da84dda8b..1a9d917d6 100644 --- a/crates/primitives/src/receipt.rs +++ b/crates/primitives/src/receipt.rs @@ -6,8 +6,6 @@ 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(any(test, feature = "arbitrary"))] -use proptest::strategy::Strategy; #[cfg(feature = "zstd-codec")] use reth_codecs::CompactZstd; use reth_codecs::{add_arbitrary_tests, main_codec, Compact}; @@ -186,50 +184,6 @@ pub fn gas_spent_by_transactions>( .collect() } -#[cfg(any(test, feature = "arbitrary"))] -impl proptest::arbitrary::Arbitrary for Receipt { - type Parameters = (); - - fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { - use proptest::prelude::{any, prop_compose}; - - prop_compose! { - fn arbitrary_receipt()(tx_type in any::(), - success in any::(), - cumulative_gas_used in any::(), - logs in proptest::collection::vec(proptest::arbitrary::any::(), 0..=20), - _deposit_nonce in any::>(), - _deposit_receipt_version in any::>()) -> Receipt - { - // Only receipts for deposit transactions may contain a deposit nonce - #[cfg(feature = "optimism")] - let (deposit_nonce, deposit_receipt_version) = if tx_type == TxType::Deposit { - // The deposit receipt version is only present if the deposit nonce is present - let deposit_receipt_version = _deposit_nonce.and(_deposit_receipt_version); - (_deposit_nonce, deposit_receipt_version) - } else { - (None, None) - }; - - Receipt { tx_type, - success, - cumulative_gas_used, - logs, - // Only receipts for deposit transactions may contain a deposit nonce - #[cfg(feature = "optimism")] - deposit_nonce, - // Only receipts for deposit transactions may contain a deposit nonce - #[cfg(feature = "optimism")] - deposit_receipt_version - } - } - } - arbitrary_receipt().boxed() - } - - type Strategy = proptest::strategy::BoxedStrategy; -} - #[cfg(any(test, feature = "arbitrary"))] impl<'a> arbitrary::Arbitrary<'a> for Receipt { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { diff --git a/crates/primitives/src/transaction/access_list.rs b/crates/primitives/src/transaction/access_list.rs index acaf132c4..22e113fbd 100644 --- a/crates/primitives/src/transaction/access_list.rs +++ b/crates/primitives/src/transaction/access_list.rs @@ -10,6 +10,7 @@ mod tests { use crate::{Address, B256}; use alloy_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper}; use proptest::proptest; + use proptest_arbitrary_interop::arb; use reth_codecs::{main_codec, Compact}; /// This type is kept for compatibility tests after the codec support was added to alloy-eips @@ -18,12 +19,7 @@ mod tests { #[derive( Clone, Debug, PartialEq, Eq, Hash, Default, RlpDecodableWrapper, RlpEncodableWrapper, )] - struct RethAccessList( - #[proptest( - strategy = "proptest::collection::vec(proptest::arbitrary::any::(), 0..=20)" - )] - Vec, - ); + struct RethAccessList(Vec); impl PartialEq for RethAccessList { fn eq(&self, other: &AccessList) -> bool { @@ -41,9 +37,6 @@ mod tests { /// The storage keys to be loaded at the start of execution. /// /// Each key is a 32-byte value representing a specific storage slot. - #[proptest( - strategy = "proptest::collection::vec(proptest::arbitrary::any::(), 0..=20)" - )] storage_keys: Vec, } @@ -55,7 +48,7 @@ mod tests { proptest!( #[test] - fn test_roundtrip_accesslist_compat(access_list: RethAccessList) { + fn test_roundtrip_accesslist_compat(access_list in arb::()) { // Convert access_list to buffer and then create alloy_access_list from buffer and // compare let mut compacted_reth_access_list = Vec::::new(); diff --git a/crates/primitives/src/transaction/eip4844.rs b/crates/primitives/src/transaction/eip4844.rs index f4a2be8e2..f792d787a 100644 --- a/crates/primitives/src/transaction/eip4844.rs +++ b/crates/primitives/src/transaction/eip4844.rs @@ -148,20 +148,28 @@ impl TxEip4844 { /// - `max_fee_per_blob_gas` /// - `blob_versioned_hashes` pub fn decode_inner(buf: &mut &[u8]) -> alloy_rlp::Result { - Ok(Self { + let mut tx = Self { chain_id: Decodable::decode(buf)?, nonce: Decodable::decode(buf)?, max_priority_fee_per_gas: Decodable::decode(buf)?, max_fee_per_gas: Decodable::decode(buf)?, gas_limit: Decodable::decode(buf)?, - placeholder: Some(()), + placeholder: None, to: Decodable::decode(buf)?, value: Decodable::decode(buf)?, input: Decodable::decode(buf)?, access_list: Decodable::decode(buf)?, max_fee_per_blob_gas: Decodable::decode(buf)?, blob_versioned_hashes: Decodable::decode(buf)?, - }) + }; + + // HACK: our arbitrary implementation sets the placeholder this way for backwards + // compatibility, and should be removed once `placeholder` can be removed + if tx.to != Address::default() { + tx.placeholder = Some(()) + } + + Ok(tx) } /// Outputs the length of the transaction's fields, without a RLP header. diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 42e420a5e..7a6d2a85b 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -1463,40 +1463,6 @@ impl Decodable for TransactionSigned { } } -#[cfg(any(test, feature = "arbitrary"))] -impl proptest::arbitrary::Arbitrary for TransactionSigned { - type Parameters = (); - fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { - use proptest::prelude::{any, Strategy}; - - any::<(Transaction, Signature)>() - .prop_map(move |(mut transaction, sig)| { - if let Some(chain_id) = transaction.chain_id() { - // Otherwise we might overflow when calculating `v` on `recalculate_hash` - transaction.set_chain_id(chain_id % (u64::MAX / 2 - 36)); - } - - #[cfg(feature = "optimism")] - let sig = transaction - .is_deposit() - .then(Signature::optimism_deposit_tx_signature) - .unwrap_or(sig); - - if let Transaction::Eip4844(ref mut tx_eip_4844) = transaction { - tx_eip_4844.placeholder = - if tx_eip_4844.to != Address::default() { Some(()) } else { None }; - } - - let mut tx = Self { hash: Default::default(), signature: sig, transaction }; - tx.hash = tx.recalculate_hash(); - tx - }) - .boxed() - } - - type Strategy = proptest::strategy::BoxedStrategy; -} - #[cfg(any(test, feature = "arbitrary"))] impl<'a> arbitrary::Arbitrary<'a> for TransactionSigned { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { @@ -1506,6 +1472,11 @@ impl<'a> arbitrary::Arbitrary<'a> for TransactionSigned { transaction.set_chain_id(chain_id % (u64::MAX / 2 - 36)); } + if let Transaction::Eip4844(ref mut tx_eip_4844) = transaction { + tx_eip_4844.placeholder = + if tx_eip_4844.to != Address::default() { Some(()) } else { None }; + } + let signature = Signature::arbitrary(u)?; #[cfg(feature = "optimism")] @@ -1654,6 +1625,7 @@ mod tests { }; use alloy_primitives::{address, b256, bytes}; use alloy_rlp::{Decodable, Encodable, Error as RlpError}; + use proptest_arbitrary_interop::arb; use reth_codecs::Compact; use secp256k1::{Keypair, Secp256k1}; use std::str::FromStr; @@ -1929,7 +1901,7 @@ mod tests { #![proptest_config(proptest::prelude::ProptestConfig::with_cases(1))] #[test] - fn test_parallel_recovery_order(txes in proptest::collection::vec(proptest::prelude::any::(), *PARALLEL_SENDER_RECOVERY_THRESHOLD * 5)) { + fn test_parallel_recovery_order(txes in proptest::collection::vec(arb::(), *PARALLEL_SENDER_RECOVERY_THRESHOLD * 5)) { let mut rng =rand::thread_rng(); let secp = Secp256k1::new(); let txes: Vec = txes.into_iter().map(|mut tx| { diff --git a/crates/primitives/src/transaction/pooled.rs b/crates/primitives/src/transaction/pooled.rs index 2ca58b179..a72d22d9f 100644 --- a/crates/primitives/src/transaction/pooled.rs +++ b/crates/primitives/src/transaction/pooled.rs @@ -615,33 +615,6 @@ impl<'a> arbitrary::Arbitrary<'a> for PooledTransactionsElement { } } -#[cfg(any(test, feature = "arbitrary"))] -impl proptest::arbitrary::Arbitrary for PooledTransactionsElement { - type Parameters = (); - fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { - use proptest::prelude::{any, Strategy}; - - any::<(TransactionSigned, crate::BlobTransactionSidecar)>() - .prop_map(move |(transaction, sidecar)| { - match Self::try_from(transaction) { - Ok(Self::BlobTransaction(mut tx)) => { - tx.sidecar = sidecar; - Self::BlobTransaction(tx) - } - Ok(tx) => tx, - Err(_) => Self::Eip1559 { - transaction: Default::default(), - signature: Default::default(), - hash: Default::default(), - }, // Gen an Eip1559 as arbitrary for testing purpose - } - }) - .boxed() - } - - type Strategy = proptest::strategy::BoxedStrategy; -} - /// A signed pooled transaction with recovered signer. #[derive(Debug, Clone, PartialEq, Eq, AsRef, Deref)] pub struct PooledTransactionsElementEcRecovered { diff --git a/crates/prune/types/Cargo.toml b/crates/prune/types/Cargo.toml index 3895ebcd0..4fd5b9336 100644 --- a/crates/prune/types/Cargo.toml +++ b/crates/prune/types/Cargo.toml @@ -26,6 +26,7 @@ arbitrary = { workspace = true, features = ["derive"] } assert_matches.workspace = true proptest.workspace = true proptest-derive.workspace = true +proptest-arbitrary-interop.workspace = true serde_json.workspace = true test-fuzz.workspace = true -toml.workspace = true \ No newline at end of file +toml.workspace = true diff --git a/crates/stages/types/Cargo.toml b/crates/stages/types/Cargo.toml index 973cd572c..76bb9f429 100644 --- a/crates/stages/types/Cargo.toml +++ b/crates/stages/types/Cargo.toml @@ -24,5 +24,6 @@ serde.workspace = true arbitrary = { workspace = true, features = ["derive"] } proptest.workspace = true proptest-derive.workspace = true +proptest-arbitrary-interop.workspace = true test-fuzz.workspace = true -rand.workspace = true \ No newline at end of file +rand.workspace = true diff --git a/crates/storage/codecs/Cargo.toml b/crates/storage/codecs/Cargo.toml index e370233d1..6864a5cf6 100644 --- a/crates/storage/codecs/Cargo.toml +++ b/crates/storage/codecs/Cargo.toml @@ -15,7 +15,7 @@ workspace = true reth-codecs-derive = { path = "./derive", default-features = false } # eth -alloy-consensus = { workspace = true, optional = true } +alloy-consensus = { workspace = true, optional = true, features = ["arbitrary"] } alloy-eips = { workspace = true, optional = true } alloy-genesis = { workspace = true, optional = true } alloy-primitives.workspace = true @@ -37,6 +37,7 @@ serde_json.workspace = true arbitrary = { workspace = true, features = ["derive"] } proptest.workspace = true proptest-derive.workspace = true +proptest-arbitrary-interop.workspace = true [features] default = ["std", "alloy"] diff --git a/crates/storage/codecs/derive/src/arbitrary.rs b/crates/storage/codecs/derive/src/arbitrary.rs index 32271c5f0..60bc9074a 100644 --- a/crates/storage/codecs/derive/src/arbitrary.rs +++ b/crates/storage/codecs/derive/src/arbitrary.rs @@ -87,12 +87,13 @@ pub fn maybe_generate_tests(args: TokenStream, ast: &DeriveInput) -> TokenStream #[cfg(test)] mod #mod_tests { #(#traits)* + use proptest_arbitrary_interop::arb; #[test] fn proptest() { let mut config = proptest::prelude::ProptestConfig::with_cases(#default_cases as u32); - proptest::proptest!(config, |(field: super::#type_ident)| { + proptest::proptest!(config, |(field in arb::())| { #(#roundtrips)* }); } diff --git a/crates/storage/codecs/derive/src/lib.rs b/crates/storage/codecs/derive/src/lib.rs index 7c668a6cb..e0022edc4 100644 --- a/crates/storage/codecs/derive/src/lib.rs +++ b/crates/storage/codecs/derive/src/lib.rs @@ -69,7 +69,7 @@ pub fn main_codec(args: TokenStream, input: TokenStream) -> TokenStream { derive_arbitrary(TokenStream::from_iter(args), compact) } -/// Adds `Arbitrary` and `proptest::Arbitrary` imports into scope and derives the struct/enum. +/// Adds `Arbitrary` imports into scope and derives the struct/enum. /// /// If `compact` or `rlp` is passed to `derive_arbitrary`, there will be proptest roundtrip tests /// generated. An integer value passed will limit the number of proptest cases generated (default: @@ -89,17 +89,13 @@ pub fn derive_arbitrary(args: TokenStream, input: TokenStream) -> TokenStream { let tests = arbitrary::maybe_generate_tests(args, &ast); // Avoid duplicate names - let prop_import = format_ident!("{}PropTestArbitrary", ast.ident); let arb_import = format_ident!("{}Arbitrary", ast.ident); quote! { - #[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))] + #[cfg_attr(any(test, feature = "arbitrary"), derive(#arb_import))] #ast #tests diff --git a/crates/storage/codecs/src/alloy/request.rs b/crates/storage/codecs/src/alloy/request.rs index c732e30b2..388f2a2b5 100644 --- a/crates/storage/codecs/src/alloy/request.rs +++ b/crates/storage/codecs/src/alloy/request.rs @@ -26,10 +26,11 @@ impl Compact for Request { mod tests { use super::*; use proptest::proptest; + use proptest_arbitrary_interop::arb; proptest! { #[test] - fn roundtrip(request: Request) { + fn roundtrip(request in arb::()) { let mut buf = Vec::::new(); request.to_compact(&mut buf); let (decoded, _) = Request::from_compact(&buf, buf.len()); diff --git a/crates/storage/db-api/Cargo.toml b/crates/storage/db-api/Cargo.toml index a3b33abfd..07d402d4a 100644 --- a/crates/storage/db-api/Cargo.toml +++ b/crates/storage/db-api/Cargo.toml @@ -36,7 +36,6 @@ bytes.workspace = true # arbitrary utils arbitrary = { workspace = true, features = ["derive"], optional = true } proptest = { workspace = true, optional = true } -proptest-derive = { workspace = true, optional = true } [dev-dependencies] # reth libs with arbitrary @@ -58,6 +57,7 @@ iai-callgrind.workspace = true arbitrary = { workspace = true, features = ["derive"] } proptest.workspace = true +proptest-arbitrary-interop.workspace = true proptest-derive.workspace = true paste.workspace = true @@ -70,6 +70,5 @@ arbitrary = [ "reth-primitives/arbitrary", "dep:arbitrary", "dep:proptest", - "dep:proptest-derive", ] optimism = [] diff --git a/crates/transaction-pool/Cargo.toml b/crates/transaction-pool/Cargo.toml index d66da4e19..f45e198cb 100644 --- a/crates/transaction-pool/Cargo.toml +++ b/crates/transaction-pool/Cargo.toml @@ -51,6 +51,7 @@ itertools.workspace = true rand = { workspace = true, optional = true } paste = { workspace = true, optional = true } proptest = { workspace = true, optional = true } +proptest-arbitrary-interop = { workspace = true, optional = true } [dev-dependencies] reth-primitives = { workspace = true, features = ["arbitrary"] } @@ -59,6 +60,7 @@ reth-tracing.workspace = true paste.workspace = true rand.workspace = true proptest.workspace = true +proptest-arbitrary-interop.workspace = true criterion.workspace = true pprof = { workspace = true, features = ["criterion", "flamegraph"] } assert_matches.workspace = true @@ -67,9 +69,9 @@ serde_json.workspace = true [features] default = ["serde"] -arbitrary = ["proptest", "reth-primitives/arbitrary"] serde = ["dep:serde"] test-utils = ["rand", "paste", "serde"] +arbitrary = ["proptest", "reth-primitives/arbitrary", "proptest-arbitrary-interop"] [[bench]] name = "truncate" diff --git a/crates/transaction-pool/src/test_utils/mock.rs b/crates/transaction-pool/src/test_utils/mock.rs index 9eb8d832e..72c7a4121 100644 --- a/crates/transaction-pool/src/test_utils/mock.rs +++ b/crates/transaction-pool/src/test_utils/mock.rs @@ -987,9 +987,10 @@ impl From for Transaction { impl proptest::arbitrary::Arbitrary for MockTransaction { type Parameters = (); fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { - use proptest::prelude::{any, Strategy}; + use proptest::prelude::Strategy; + use proptest_arbitrary_interop::arb; - any::<(Transaction, Address, B256)>() + arb::<(Transaction, Address, B256)>() .prop_map(|(tx, sender, tx_hash)| match &tx { Transaction::Legacy(TxLegacy { chain_id, diff --git a/crates/trie/common/Cargo.toml b/crates/trie/common/Cargo.toml index f9267c2b8..da5d5a828 100644 --- a/crates/trie/common/Cargo.toml +++ b/crates/trie/common/Cargo.toml @@ -32,13 +32,12 @@ nybbles = { workspace = true, features = ["serde", "rlp"] } hash-db = { version = "=0.15.2", optional = true } plain_hasher = { version = "0.2", optional = true } arbitrary = { workspace = true, features = ["derive"], optional = true } -proptest = { workspace = true, optional = true } -proptest-derive = { workspace = true, optional = true } [dev-dependencies] arbitrary = { workspace = true, features = ["derive"] } assert_matches.workspace = true proptest.workspace = true +proptest-arbitrary-interop.workspace = true proptest-derive.workspace = true serde_json.workspace = true test-fuzz.workspace = true @@ -51,6 +50,4 @@ test-utils = ["dep:plain_hasher", "dep:hash-db", "arbitrary"] arbitrary = [ "alloy-trie/arbitrary", "dep:arbitrary", - "dep:proptest", - "dep:proptest-derive", ] diff --git a/crates/trie/common/src/hash_builder/state.rs b/crates/trie/common/src/hash_builder/state.rs index c1fa9640f..c70d7817e 100644 --- a/crates/trie/common/src/hash_builder/state.rs +++ b/crates/trie/common/src/hash_builder/state.rs @@ -148,6 +148,7 @@ impl Compact for HashBuilderState { mod tests { use super::*; use proptest::prelude::*; + use proptest_arbitrary_interop::arb; #[test] fn hash_builder_state_regression() { @@ -161,7 +162,7 @@ mod tests { proptest! { #[test] - fn hash_builder_state_roundtrip(state: HashBuilderState) { + fn hash_builder_state_roundtrip(state in arb::()) { let mut buf = vec![]; let len = state.clone().to_compact(&mut buf); let (decoded, _) = HashBuilderState::from_compact(&buf, len); diff --git a/crates/trie/parallel/Cargo.toml b/crates/trie/parallel/Cargo.toml index 6a5509141..36b7cbdc4 100644 --- a/crates/trie/parallel/Cargo.toml +++ b/crates/trie/parallel/Cargo.toml @@ -54,6 +54,7 @@ tokio = { workspace = true, default-features = false, features = ["sync", "rt", rayon.workspace = true criterion = { workspace = true, features = ["async_tokio"] } proptest.workspace = true +proptest-arbitrary-interop.workspace = true [features] default = ["metrics", "async", "parallel"] diff --git a/crates/trie/parallel/benches/root.rs b/crates/trie/parallel/benches/root.rs index eba1cdd3d..d52702fbc 100644 --- a/crates/trie/parallel/benches/root.rs +++ b/crates/trie/parallel/benches/root.rs @@ -1,6 +1,7 @@ #![allow(missing_docs, unreachable_pub)] use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use proptest::{prelude::*, strategy::ValueTree, test_runner::TestRunner}; +use proptest_arbitrary_interop::arb; use rayon::ThreadPoolBuilder; use reth_primitives::{Account, B256, U256}; use reth_provider::{ @@ -82,7 +83,7 @@ fn generate_test_data(size: usize) -> (HashedPostState, HashedPostState) { let db_state = hash_map( any::(), ( - any::().prop_filter("non empty account", |a| !a.is_empty()), + arb::().prop_filter("non empty account", |a| !a.is_empty()), hash_map( any::(), any::().prop_filter("non zero value", |v| !v.is_zero()), diff --git a/crates/trie/trie/Cargo.toml b/crates/trie/trie/Cargo.toml index ea28d1329..04b03014e 100644 --- a/crates/trie/trie/Cargo.toml +++ b/crates/trie/trie/Cargo.toml @@ -57,6 +57,7 @@ triehash = "0.8" # misc proptest.workspace = true +proptest-arbitrary-interop.workspace = true tokio = { workspace = true, default-features = false, features = [ "sync", "rt", diff --git a/crates/trie/trie/benches/trie_root.rs b/crates/trie/trie/benches/trie_root.rs index 8a149404a..3f7efecc3 100644 --- a/crates/trie/trie/benches/trie_root.rs +++ b/crates/trie/trie/benches/trie_root.rs @@ -1,6 +1,7 @@ #![allow(missing_docs, unreachable_pub)] use criterion::{black_box, criterion_group, criterion_main, Criterion}; use proptest::{prelude::*, strategy::ValueTree, test_runner::TestRunner}; +use proptest_arbitrary_interop::arb; use reth_primitives::{ReceiptWithBloom, B256}; use reth_trie::triehash::KeccakHasher; @@ -26,7 +27,7 @@ pub fn trie_root_benchmark(c: &mut Criterion) { } fn generate_test_data(size: usize) -> Vec { - prop::collection::vec(any::(), size) + prop::collection::vec(arb::(), size) .new_tree(&mut TestRunner::new(ProptestConfig::default())) .unwrap() .current() diff --git a/crates/trie/trie/src/hashed_cursor/post_state.rs b/crates/trie/trie/src/hashed_cursor/post_state.rs index df04d332d..41b051b2a 100644 --- a/crates/trie/trie/src/hashed_cursor/post_state.rs +++ b/crates/trie/trie/src/hashed_cursor/post_state.rs @@ -374,6 +374,7 @@ mod tests { use super::*; use crate::{HashedPostState, HashedStorage}; use proptest::prelude::*; + use proptest_arbitrary_interop::arb; use reth_db::{tables, test_utils::create_test_rw_db}; use reth_db_api::{database::Database, transaction::DbTxMut}; use reth_primitives::StorageEntry; @@ -537,7 +538,7 @@ mod tests { #[test] fn fuzz_hashed_account_cursor() { - proptest!(ProptestConfig::with_cases(10), |(db_accounts: BTreeMap, post_state_accounts: BTreeMap>)| { + proptest!(ProptestConfig::with_cases(10), |(db_accounts in arb::>(), post_state_accounts in arb::>>())| { let db = create_test_rw_db(); db.update(|tx| { for (key, account) in &db_accounts { diff --git a/crates/trie/trie/src/trie.rs b/crates/trie/trie/src/trie.rs index 3fe97a6f7..25ae61658 100644 --- a/crates/trie/trie/src/trie.rs +++ b/crates/trie/trie/src/trie.rs @@ -551,6 +551,7 @@ mod tests { BranchNodeCompact, TrieMask, }; use proptest::{prelude::ProptestConfig, proptest}; + use proptest_arbitrary_interop::arb; use reth_db::{tables, test_utils::TempDatabase, DatabaseEnv}; use reth_db_api::{ cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO}, @@ -649,7 +650,7 @@ mod tests { #[test] fn arbitrary_storage_root() { - proptest!(ProptestConfig::with_cases(10), |(item: (Address, std::collections::BTreeMap))| { + proptest!(ProptestConfig::with_cases(10), |(item in arb::<(Address, std::collections::BTreeMap)>())| { let (address, storage) = item; let hashed_address = keccak256(address); @@ -759,7 +760,7 @@ mod tests { #[test] fn arbitrary_state_root() { proptest!( - ProptestConfig::with_cases(10), | (state: State) | { + ProptestConfig::with_cases(10), | (state in arb::()) | { test_state_root_with_state(state); } ); @@ -768,7 +769,7 @@ mod tests { #[test] fn arbitrary_state_root_with_progress() { proptest!( - ProptestConfig::with_cases(10), | (state: State) | { + ProptestConfig::with_cases(10), | (state in arb::()) | { let hashed_entries_total = state.len() + state.values().map(|(_, slots)| slots.len()).sum::();