From 6c740ccf1a4d97080edd6845821a09c95af46f5a Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Tue, 20 Aug 2024 02:24:53 -0700 Subject: [PATCH] rm hardcoded mocked tx (#1332) * rm hardcoded mocked tx * fix tx signature * remove boiler * update test random_tx_signature * remove last boiler * fix comments * fix test --------- Co-authored-by: Gregory Edison --- Cargo.lock | 219 ++--------------- Cargo.toml | 4 +- .../database/types/transaction.rs | 229 +++++++----------- src/test_utils/katana/mod.rs | 14 +- src/test_utils/mongo/mod.rs | 108 ++------- tests/tests/debug_api.rs | 128 ++-------- tests/tests/eth_provider.rs | 22 +- tests/tests/txpool_api.rs | 2 +- 8 files changed, 183 insertions(+), 543 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5128f888..b780f732e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,23 +126,6 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" -[[package]] -name = "alloy" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ba1c79677c9ce51c8d45e20845b05e6fb070ea2c863fba03ad6af2c778474bd" -dependencies = [ - "alloy-consensus 0.1.4", - "alloy-core", - "alloy-eips 0.1.4", - "alloy-genesis 0.1.4", - "alloy-provider 0.1.4", - "alloy-rpc-client 0.1.4", - "alloy-rpc-types", - "alloy-serde 0.1.4", - "alloy-transport-http 0.1.4", -] - [[package]] name = "alloy-chains" version = "0.1.23" @@ -210,27 +193,15 @@ dependencies = [ "alloy-json-abi", "alloy-network 0.1.0", "alloy-primitives", - "alloy-provider 0.1.0", + "alloy-provider", "alloy-rpc-types-eth 0.1.0", "alloy-sol-types", - "alloy-transport 0.1.0", + "alloy-transport", "futures", "futures-util", "thiserror", ] -[[package]] -name = "alloy-core" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529fc6310dc1126c8de51c376cbc59c79c7f662bd742be7dc67055d5421a81b4" -dependencies = [ - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-primitives", - "alloy-sol-types", -] - [[package]] name = "alloy-dyn-abi" version = "0.7.7" @@ -343,19 +314,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "alloy-json-rpc" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d6f34930b7e3e2744bcc79056c217f00cb2abb33bc5d4ff88da7623c5bb078b" -dependencies = [ - "alloy-primitives", - "serde", - "serde_json", - "thiserror", - "tracing", -] - [[package]] name = "alloy-json-rpc" version = "0.2.1" @@ -388,26 +346,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "alloy-network" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f6895fc31b48fa12306ef9b4f78b7764f8bd6d7d91cdb0a40e233704a0f23f" -dependencies = [ - "alloy-consensus 0.1.4", - "alloy-eips 0.1.4", - "alloy-json-rpc 0.1.4", - "alloy-primitives", - "alloy-rpc-types-eth 0.1.4", - "alloy-serde 0.1.4", - "alloy-signer 0.1.4", - "alloy-sol-types", - "async-trait", - "auto_impl", - "futures-utils-wasm", - "thiserror", -] - [[package]] name = "alloy-network" version = "0.2.1" @@ -478,40 +416,10 @@ dependencies = [ "alloy-json-rpc 0.1.0", "alloy-network 0.1.0", "alloy-primitives", - "alloy-rpc-client 0.1.0", + "alloy-rpc-client", "alloy-rpc-types-eth 0.1.0", "alloy-rpc-types-trace 0.1.0", - "alloy-transport 0.1.0", - "async-stream", - "async-trait", - "auto_impl", - "dashmap", - "futures", - "futures-utils-wasm", - "lru", - "pin-project", - "serde", - "serde_json", - "tokio", - "tracing", -] - -[[package]] -name = "alloy-provider" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c538bfa893d07e27cb4f3c1ab5f451592b7c526d511d62b576a2ce59e146e4a" -dependencies = [ - "alloy-chains", - "alloy-consensus 0.1.4", - "alloy-eips 0.1.4", - "alloy-json-rpc 0.1.4", - "alloy-network 0.1.4", - "alloy-primitives", - "alloy-rpc-client 0.1.4", - "alloy-rpc-types-eth 0.1.4", - "alloy-transport 0.1.4", - "alloy-transport-http 0.1.4", + "alloy-transport", "async-stream", "async-trait", "auto_impl", @@ -520,12 +428,10 @@ dependencies = [ "futures-utils-wasm", "lru", "pin-project", - "reqwest 0.12.5", "serde", "serde_json", "tokio", "tracing", - "url", ] [[package]] @@ -556,37 +462,16 @@ version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-json-rpc 0.1.0", - "alloy-transport 0.1.0", - "alloy-transport-http 0.1.0", - "futures", - "pin-project", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tower", - "tracing", -] - -[[package]] -name = "alloy-rpc-client" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba31bae67773fd5a60020bea900231f8396202b7feca4d0c70c6b59308ab4a8" -dependencies = [ - "alloy-json-rpc 0.1.4", - "alloy-transport 0.1.4", - "alloy-transport-http 0.1.4", + "alloy-transport", + "alloy-transport-http", "futures", "pin-project", - "reqwest 0.12.5", "serde", "serde_json", "tokio", "tokio-stream", "tower", "tracing", - "url", ] [[package]] @@ -815,20 +700,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "alloy-signer" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b33753c09fa1ad85e5b092b8dc2372f1e337a42e84b9b4cff9fede75ba4adb32" -dependencies = [ - "alloy-primitives", - "async-trait", - "auto_impl", - "elliptic-curve 0.13.8", - "k256 0.13.3", - "thiserror", -] - [[package]] name = "alloy-signer" version = "0.2.1" @@ -945,46 +816,12 @@ dependencies = [ "url", ] -[[package]] -name = "alloy-transport" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b51a291f949f755e6165c3ed562883175c97423703703355f4faa4b7d0a57c" -dependencies = [ - "alloy-json-rpc 0.1.4", - "base64 0.22.1", - "futures-util", - "futures-utils-wasm", - "serde", - "serde_json", - "thiserror", - "tokio", - "tower", - "tracing", - "url", -] - [[package]] name = "alloy-transport-http" version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ - "alloy-transport 0.1.0", - "url", -] - -[[package]] -name = "alloy-transport-http" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d65871f9f1cafe1ed25cde2f1303be83e6473e995a2d56c275ae4fcce6119c" -dependencies = [ - "alloy-json-rpc 0.1.4", - "alloy-transport 0.1.4", - "reqwest 0.12.5", - "serde_json", - "tower", - "tracing", + "alloy-transport", "url", ] @@ -1628,7 +1465,7 @@ dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", - "itertools 0.12.1", + "itertools 0.11.0", "lazy_static", "lazycell", "proc-macro2", @@ -6596,22 +6433,6 @@ dependencies = [ "tokio-native-tls", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.4.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.6" @@ -7511,7 +7332,6 @@ dependencies = [ name = "kakarot-rpc" version = "0.6.20" dependencies = [ - "alloy", "alloy-contract", "alloy-dyn-abi", "alloy-json-abi", @@ -7558,6 +7378,7 @@ dependencies = [ "reth-rpc-eth-types", "reth-rpc-types", "reth-rpc-types-compat", + "reth-testing-utils", "revm-inspectors", "rstest 0.21.0", "serde", @@ -8931,7 +8752,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn 2.0.71", @@ -9843,7 +9664,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.71", @@ -10231,7 +10052,7 @@ dependencies = [ "http-body 0.4.6", "hyper 0.14.30", "hyper-rustls 0.24.2", - "hyper-tls 0.5.0", + "hyper-tls", "ipnet", "js-sys", "log", @@ -10281,13 +10102,11 @@ dependencies = [ "http-body-util", "hyper 1.4.1", "hyper-rustls 0.27.2", - "hyper-tls 0.6.0", "hyper-util", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -10301,7 +10120,6 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.1", "tokio", - "tokio-native-tls", "tokio-rustls 0.26.0", "tower-service", "url", @@ -11591,6 +11409,17 @@ dependencies = [ "tracing-futures", ] +[[package]] +name = "reth-testing-utils" +version = "1.0.1" +source = "git+https://github.com/paradigmxyz/reth.git?tag=v1.0.1#d599393771f9d7d137ea4abf271e1bd118184c73" +dependencies = [ + "alloy-genesis 0.1.4", + "rand 0.8.5", + "reth-primitives", + "secp256k1", +] + [[package]] name = "reth-tokio-util" version = "1.0.1" @@ -13026,7 +12855,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" dependencies = [ - "dirs 5.0.1", + "dirs 4.0.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4b2375e18..b65ffd4c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,6 +71,7 @@ reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth.git", tag = "v reth-revm = { git = "https://github.com/paradigmxyz/reth.git", tag = "v1.0.1", default-features = false } reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth.git", tag = "v1.0.1", default-features = false } reth-node-api = { git = "https://github.com/paradigmxyz/reth.git", tag = "v1.0.1", default-features = false } +reth-testing-utils = { git = "https://github.com/paradigmxyz/reth.git", tag = "v1.0.1", default-features = false, optional = true } revm-inspectors = "0.4" # Error @@ -120,7 +121,6 @@ http-body-util = { version = "0.1", default-features = false } pin-project-lite = { version = "0.2", default-features = false } # Testing crates -alloy = { version = "0.1.1", features = ["rpc-types"], optional = true } alloy-dyn-abi = { version = "0.7.6", default-features = false } alloy-json-abi = { version = "0.7.6", default-features = false, optional = true } alloy-primitives = { version = "0.7.2", default-features = false, optional = true } @@ -162,7 +162,7 @@ toml = { version = "0.8", default-features = false } [features] testing = [ - "alloy", + "reth-testing-utils", "alloy-json-abi", "alloy-primitives", "alloy-signer-local", diff --git a/src/providers/eth_provider/database/types/transaction.rs b/src/providers/eth_provider/database/types/transaction.rs index a1ed5d7b2..a9d494e7a 100644 --- a/src/providers/eth_provider/database/types/transaction.rs +++ b/src/providers/eth_provider/database/types/transaction.rs @@ -4,15 +4,10 @@ use serde::{Deserialize, Serialize}; use std::ops::Deref; #[cfg(any(test, feature = "arbitrary", feature = "testing"))] use { - crate::test_utils::mongo::{ - BLOCK_HASH, BLOCK_NUMBER, CHAIN_ID, EIP1599_TX_HASH, EIP2930_TX_HASH, LEGACY_TX_HASH, - RECOVERED_EIP1599_TX_ADDRESS, RECOVERED_EIP2930_TX_ADDRESS, RECOVERED_LEGACY_TX_ADDRESS, TEST_SIG_R, - TEST_SIG_S, TEST_SIG_V, - }, - alloy_signer::SignerSync, - alloy_signer_local::PrivateKeySigner, arbitrary::Arbitrary, - reth_primitives::{Address, TransactionSignedNoHash, TxType, U256}, + rand::Rng, + reth_primitives::U256, + reth_testing_utils::generators::{self}, }; /// A full transaction as stored in the database @@ -23,83 +18,6 @@ pub struct StoredTransaction { pub tx: Transaction, } -#[cfg(any(test, feature = "arbitrary", feature = "testing"))] -impl StoredTransaction { - pub fn mock_tx_with_type(tx_type: TxType) -> Self { - match tx_type { - TxType::Eip1559 => Self { - tx: reth_rpc_types::Transaction { - hash: *EIP1599_TX_HASH, - block_hash: Some(*BLOCK_HASH), - block_number: Some(BLOCK_NUMBER), - transaction_index: Some(0), - from: *RECOVERED_EIP1599_TX_ADDRESS, - to: Some(Address::ZERO), - gas_price: Some(10), - gas: 100, - max_fee_per_gas: Some(10), - max_priority_fee_per_gas: Some(1), - signature: Some(reth_rpc_types::Signature { - r: *TEST_SIG_R, - s: *TEST_SIG_S, - v: *TEST_SIG_V, - y_parity: Some(reth_rpc_types::Parity(true)), - }), - chain_id: Some(1), - access_list: Some(Default::default()), - transaction_type: Some(tx_type.into()), - ..Default::default() - }, - }, - TxType::Legacy => Self { - tx: reth_rpc_types::Transaction { - hash: *LEGACY_TX_HASH, - block_hash: Some(*BLOCK_HASH), - block_number: Some(BLOCK_NUMBER), - transaction_index: Some(0), - from: *RECOVERED_LEGACY_TX_ADDRESS, - to: Some(Address::ZERO), - gas_price: Some(10), - gas: 100, - signature: Some(reth_rpc_types::Signature { - r: *TEST_SIG_R, - s: *TEST_SIG_S, - v: CHAIN_ID.saturating_mul(U256::from(2)).saturating_add(U256::from(35)), - y_parity: Default::default(), - }), - chain_id: Some(1), - blob_versioned_hashes: Default::default(), - transaction_type: Some(tx_type.into()), - ..Default::default() - }, - }, - TxType::Eip2930 => Self { - tx: reth_rpc_types::Transaction { - hash: *EIP2930_TX_HASH, - block_hash: Some(*BLOCK_HASH), - block_number: Some(BLOCK_NUMBER), - transaction_index: Some(0), - from: *RECOVERED_EIP2930_TX_ADDRESS, - to: Some(Address::ZERO), - gas_price: Some(10), - gas: 100, - signature: Some(reth_rpc_types::Signature { - r: *TEST_SIG_R, - s: *TEST_SIG_S, - v: *TEST_SIG_V, - y_parity: Some(reth_rpc_types::Parity(true)), - }), - chain_id: Some(1), - access_list: Some(Default::default()), - transaction_type: Some(tx_type.into()), - ..Default::default() - }, - }, - TxType::Eip4844 => unimplemented!(), - } - } -} - impl From for Transaction { fn from(tx: StoredTransaction) -> Self { tx.tx @@ -129,67 +47,70 @@ impl Deref for StoredTransaction { #[cfg(any(test, feature = "arbitrary", feature = "testing"))] impl<'a> StoredTransaction { pub fn arbitrary_with_optional_fields(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - let mut primitive_transaction = reth_primitives::Transaction::arbitrary(u)?; - - // Ensure the transaction is not a blob transaction - while primitive_transaction.tx_type() == 3 { - primitive_transaction = reth_primitives::Transaction::arbitrary(u)?; - } - - // Force the chain ID to be set - let chain_id = u32::arbitrary(u)?.into(); - primitive_transaction.set_chain_id(chain_id); - - // Force nonce to be set - let nonce = u64::arbitrary(u)?; - primitive_transaction.set_nonce(nonce); - - // Compute the signing hash - let signing_hash = primitive_transaction.signature_hash(); - - // Sign the transaction with a local wallet - let signer = PrivateKeySigner::random(); - let signature = signer.sign_hash_sync(&signing_hash).map_err(|_| arbitrary::Error::IncorrectFormat)?; - - // Use TransactionSignedNoHash to compute the hash - let y_parity = signature.v().y_parity(); - let hash = TransactionSignedNoHash { - transaction: primitive_transaction.clone(), - signature: reth_primitives::Signature { r: signature.r(), s: signature.s(), odd_y_parity: y_parity }, - } - .hash(); - - // Convert the signature to the RPC format - let is_legacy = primitive_transaction.is_legacy(); - // See docs on `alloy::rpc::types::Signature` for `v` field. - let v: u64 = if is_legacy { 35 + 2 * chain_id + u64::from(y_parity) } else { u64::from(y_parity) }; - let signature = alloy::rpc::types::Signature { - r: signature.r(), - s: signature.s(), - v: U256::from(v), - y_parity: if is_legacy { None } else { Some(signature.v().y_parity().into()) }, + // Initialize a random number generator. + let mut rng = generators::rng(); + // Generate a random integer between 0 and 2 to decide which transaction type to create. + let random_choice = rng.gen_range(0..3); + + // Create a `primitive_tx` of a specific transaction type based on the random choice. + let primitive_tx = match random_choice { + 0 => reth_primitives::Transaction::Legacy(reth_primitives::transaction::TxLegacy { + chain_id: Some(u8::arbitrary(u)?.into()), + ..Arbitrary::arbitrary(u)? + }), + 1 => reth_primitives::Transaction::Eip2930(reth_primitives::TxEip2930::arbitrary(u)?), + _ => reth_primitives::Transaction::Eip1559(reth_primitives::TxEip1559::arbitrary(u)?), }; - let transaction = Transaction { - hash, - from: signer.address(), + // Sign the generated transaction with a randomly generated key pair. + let transaction_signed = generators::sign_tx_with_random_key_pair(&mut rng, primitive_tx); + + // Initialize a `Transaction` structure and populate it with the signed transaction's data. + let mut tx = Transaction { + hash: transaction_signed.hash, + from: transaction_signed.recover_signer().unwrap(), block_hash: Some(B256::arbitrary(u)?), block_number: Some(u64::arbitrary(u)?), transaction_index: Some(u64::arbitrary(u)?), - gas_price: Some(primitive_transaction.effective_gas_price(None)), - gas: u128::from(primitive_transaction.gas_limit()), - max_fee_per_gas: if is_legacy { None } else { Some(primitive_transaction.max_fee_per_gas()) }, - max_priority_fee_per_gas: primitive_transaction.max_priority_fee_per_gas(), - signature: Some(signature), - transaction_type: Some(primitive_transaction.tx_type() as u8), - chain_id: primitive_transaction.chain_id(), - nonce: primitive_transaction.nonce(), - other: Default::default(), - access_list: Some(reth_rpc_types::AccessList::arbitrary(u)?), + signature: Some(reth_rpc_types::Signature { + r: transaction_signed.signature.r, + s: transaction_signed.signature.s, + v: if transaction_signed.is_legacy() { + U256::from(transaction_signed.signature.v(transaction_signed.chain_id())) + } else { + U256::from(transaction_signed.signature.odd_y_parity) + }, + y_parity: Some(transaction_signed.signature.odd_y_parity.into()), + }), + nonce: transaction_signed.nonce(), + value: transaction_signed.value(), + input: transaction_signed.input().clone(), + chain_id: transaction_signed.chain_id(), + transaction_type: Some(transaction_signed.tx_type().into()), + to: transaction_signed.to(), + gas: transaction_signed.gas_limit().into(), ..Default::default() }; - Ok(Self { tx: transaction }) + // Populate the `tx` structure based on the specific type of transaction. + match transaction_signed.transaction { + reth_primitives::Transaction::Legacy(transaction) => { + tx.gas_price = Some(transaction.gas_price); + } + reth_primitives::Transaction::Eip2930(transaction) => { + tx.access_list = Some(transaction.access_list); + tx.gas_price = Some(transaction.gas_price); + } + reth_primitives::Transaction::Eip1559(transaction) => { + tx.max_fee_per_gas = Some(transaction.max_fee_per_gas); + tx.max_priority_fee_per_gas = Some(transaction.max_priority_fee_per_gas); + tx.access_list = Some(transaction.access_list); + } + reth_primitives::Transaction::Eip4844(_) => unreachable!("Non supported transaction type"), + }; + + // Return the constructed `StoredTransaction` instance. + Ok(Self { tx }) } } @@ -254,4 +175,36 @@ mod tests { let _ = StoredTransaction::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(); } + + #[test] + fn random_tx_signature() { + for _ in 0..10 { + let mut bytes = [0u8; 1024]; + rand::thread_rng().fill(bytes.as_mut_slice()); + + // Generate a random transaction + let transaction = + StoredTransaction::arbitrary_with_optional_fields(&mut arbitrary::Unstructured::new(&bytes)).unwrap(); + + // Extract the signature from the generated transaction. + let signature = transaction.signature.unwrap(); + + // Convert the transaction to primitive type. + let tx = transaction.clone().tx.try_into().unwrap(); + + // Reconstruct the signed transaction using the extracted `tx` and `signature`. + let transaction_signed = reth_primitives::TransactionSigned::from_transaction_and_signature( + tx, + reth_primitives::Signature { + r: signature.r, + s: signature.s, + odd_y_parity: signature.y_parity.unwrap_or(reth_rpc_types::Parity(false)).0, + }, + ); + + // Verify that the `from` address in the original transaction matches the recovered signer address + // from the reconstructed signed transaction. This confirms that the signature is valid. + assert_eq!(transaction.from, transaction_signed.recover_signer().unwrap()); + } + } } diff --git a/src/test_utils/katana/mod.rs b/src/test_utils/katana/mod.rs index e362d61b4..d5e0da477 100644 --- a/src/test_utils/katana/mod.rs +++ b/src/test_utils/katana/mod.rs @@ -35,7 +35,7 @@ use testcontainers::ContainerAsync; use { super::mongo::MongoFuzzer, dojo_test_utils::sequencer::SequencerConfig, - reth_primitives::{TxType, B256}, + reth_primitives::B256, reth_rpc_types::{Header, Transaction}, std::str::FromStr as _, }; @@ -121,18 +121,6 @@ impl<'a> Katana { mongo_fuzzer.add_random_transactions(10).expect("Failed to add documents in the database"); // Add a hardcoded block header range to the MongoDB database. mongo_fuzzer.add_hardcoded_block_header_range(0..4).expect("Failed to add block range in the database"); - // Add a hardcoded Eip1559 transaction to the MongoDB database. - mongo_fuzzer - .add_hardcoded_transaction(Some(TxType::Eip1559)) - .expect("Failed to add Eip1559 transaction in the database"); - // Add a hardcoded Eip2930 transaction to the MongoDB database. - mongo_fuzzer - .add_hardcoded_transaction(Some(TxType::Eip2930)) - .expect("Failed to add Eip2930 transaction in the database"); - // Add a hardcoded Legacy transaction to the MongoDB database. - mongo_fuzzer - .add_hardcoded_transaction(Some(TxType::Legacy)) - .expect("Failed to add Legacy transaction in the database"); // Add a hardcoded logs to the MongoDB database. mongo_fuzzer.add_random_logs(2).expect("Failed to logs in the database"); // Add a hardcoded header to the MongoDB database. diff --git a/src/test_utils/mongo/mod.rs b/src/test_utils/mongo/mod.rs index aa3cb90a4..e92b586ee 100644 --- a/src/test_utils/mongo/mod.rs +++ b/src/test_utils/mongo/mod.rs @@ -13,10 +13,10 @@ use mongodb::{ options::{DatabaseOptions, ReadConcern, UpdateModifications, UpdateOptions, WriteConcern}, Client, Collection, }; -use reth_primitives::{Address, TxType, B256, U256}; +use reth_primitives::{TxType, B256, U256}; use reth_rpc_types::Transaction; use serde::Serialize; -use std::{ops::Range, str::FromStr, sync::LazyLock}; +use std::{ops::Range, sync::LazyLock}; use strum::{EnumIter, IntoEnumIterator}; use testcontainers::{ core::{IntoContainerPort, WaitFor}, @@ -25,35 +25,7 @@ use testcontainers::{ }; pub static CHAIN_ID: LazyLock = LazyLock::new(|| U256::from(1)); -pub static BLOCK_HASH: LazyLock = LazyLock::new(|| B256::from(U256::from(0x1234))); -pub static EIP1599_TX_HASH: LazyLock = LazyLock::new(|| { - B256::from(U256::from_str("0xc92a4e464caa049999cb2073cc4d8586bebb42b518115f631710b2597155c962").unwrap()) -}); -pub static EIP2930_TX_HASH: LazyLock = LazyLock::new(|| { - B256::from(U256::from_str("0x972ba18c780c31bade31873d6f076a3be4e6d314776e2ad50a30eda861acab79").unwrap()) -}); -pub static LEGACY_TX_HASH: LazyLock = LazyLock::new(|| { - B256::from(U256::from_str("0x38c7e066854c56932100b896320a37adbab32713cca46d1e06307fe5d6062b7d").unwrap()) -}); -pub static TEST_SIG_R: LazyLock = - LazyLock::new(|| U256::from_str("0x1ae9d63d9152a0f628cc5c843c9d0edc6cb705b027d12d30b871365d7d9c8ed5").unwrap()); -pub static TEST_SIG_S: LazyLock = - LazyLock::new(|| U256::from_str("0x0d9fa834b490259ad6aa62a49d926053ca1b52acbb59a5e1cf8ecabd65304606").unwrap()); -pub static TEST_SIG_V: LazyLock = LazyLock::new(|| U256::from(1)); - -// Given constant r, s, v and transaction fields, we can derive the `Transaction.from` field "a posteriori" -// ⚠️ If the transaction fields change, the below addresses should be updated accordingly ⚠️ -// Recovered address from the above R, S, V, with EIP1559 transaction -pub static RECOVERED_EIP1599_TX_ADDRESS: LazyLock
= - LazyLock::new(|| Address::from_str("0x520666a744f86a09c2a794b8d56501c109afba2d").unwrap()); -// Recovered address from the above R, S, V, with EIP2930 transaction -pub static RECOVERED_EIP2930_TX_ADDRESS: LazyLock
= - LazyLock::new(|| Address::from_str("0x753925d9bbd7682e4b77f102c47d24ee0580aa8d").unwrap()); -// Recovered address from the above R, S, V, with Legacy transaction -pub static RECOVERED_LEGACY_TX_ADDRESS: LazyLock
= - LazyLock::new(|| Address::from_str("0x05ac0c7c5930a6f9003a709042dbb136e98220f2").unwrap()); - -pub const BLOCK_NUMBER: u64 = 0x1234; + pub const RANDOM_BYTES_SIZE: usize = 100_024; #[derive(Default, Debug)] @@ -155,29 +127,6 @@ impl MongoFuzzer { self.finalize().await } - /// Adds a transaction to the collection of transactions with custom values. - pub fn add_custom_transaction(&mut self, builder: TransactionBuilder) -> Result<(), Box> { - // Build a transaction using the provided builder and random byte size. - let transaction = builder.build(self.rnd_bytes_size)?; - - // Generate a receipt for the transaction. - let receipt = self.generate_transaction_receipt(&transaction.tx); - - // Convert the receipt into a vector of logs and append them to the existing logs collection. - self.logs.append(&mut Vec::from(receipt.clone())); - - // Generate a header for the transaction and add it to the headers collection. - self.headers.push(self.generate_transaction_header(&transaction.tx)); - - // Add the transaction to the transactions collection. - self.transactions.push(transaction); - - // Add the receipt to the receipts collection. - self.receipts.push(receipt); - - Ok(()) - } - /// Adds a hardcoded block header with a base fee to the collection of headers. pub fn add_hardcoded_block_header_with_base_fee( &mut self, @@ -209,11 +158,6 @@ impl MongoFuzzer { Ok(()) } - /// Adds a hardcoded transaction to the collection of transactions. - pub fn add_hardcoded_transaction(&mut self, tx_type: Option) -> Result<(), Box> { - self.add_custom_transaction(TransactionBuilder::default().with_tx_type(tx_type.unwrap_or_default())) - } - /// Adds random logs to the collection of logs. pub fn add_random_logs(&mut self, n_logs: usize) -> Result<(), Box> { for _ in 0..n_logs { @@ -246,7 +190,25 @@ impl MongoFuzzer { /// Adds random transactions to the collection of transactions. pub fn add_random_transactions(&mut self, n_transactions: usize) -> Result<(), Box> { for _ in 0..n_transactions { - self.add_custom_transaction(TransactionBuilder::default())?; + // Build a transaction using the random byte size. + let transaction = StoredTransaction::arbitrary_with_optional_fields(&mut arbitrary::Unstructured::new( + &(0..self.rnd_bytes_size).map(|_| rand::random::()).collect::>(), + ))?; + + // Generate a receipt for the transaction. + let receipt = self.generate_transaction_receipt(&transaction.tx); + + // Convert the receipt into a vector of logs and append them to the existing logs collection. + self.logs.append(&mut Vec::from(receipt.clone())); + + // Generate a header for the transaction and add it to the headers collection. + self.headers.push(self.generate_transaction_header(&transaction.tx)); + + // Add the transaction to the transactions collection. + self.transactions.push(transaction); + + // Add the receipt to the receipts collection. + self.receipts.push(receipt); } Ok(()) } @@ -357,32 +319,6 @@ impl MongoFuzzer { } } -/// Builder for constructing transactions with custom values. -#[derive(Default, Clone, Debug)] -pub struct TransactionBuilder { - /// The type of transaction to construct. - tx_type: Option, -} - -impl TransactionBuilder { - /// Specifies the type of transaction to build. - #[must_use] - pub const fn with_tx_type(mut self, tx_type: TxType) -> Self { - self.tx_type = Some(tx_type); - self - } - - /// Builds the transaction based on the specified values. - fn build(self, rnd_bytes_size: usize) -> Result> { - Ok(match self.tx_type { - Some(tx_type) => StoredTransaction::mock_tx_with_type(tx_type), - None => StoredTransaction::arbitrary_with_optional_fields(&mut arbitrary::Unstructured::new( - &(0..rnd_bytes_size).map(|_| rand::random::()).collect::>(), - ))?, - }) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/tests/tests/debug_api.rs b/tests/tests/debug_api.rs index 1ebe059b7..327e928e8 100644 --- a/tests/tests/debug_api.rs +++ b/tests/tests/debug_api.rs @@ -6,7 +6,6 @@ use kakarot_rpc::{ test_utils::{ fixtures::{katana, setup}, katana::Katana, - mongo::{BLOCK_HASH, BLOCK_NUMBER, EIP1599_TX_HASH, EIP2930_TX_HASH, LEGACY_TX_HASH}, rpc::{start_kakarot_rpc_server, RawRpcParamsBuilder}, }, }; @@ -24,16 +23,17 @@ async fn test_raw_transaction(#[future] katana: Katana, _setup: ()) { let (server_addr, server_handle) = start_kakarot_rpc_server(&katana).await.expect("Error setting up Kakarot RPC server"); + // First transaction of the database + let tx = katana.first_transaction().unwrap(); + // Associated block header + let header = katana.header_by_hash(tx.block_hash.unwrap()).unwrap(); + // EIP1559 let reqwest_client = reqwest::Client::new(); let res = reqwest_client .post(format!("http://localhost:{}", server_addr.port())) .header("Content-Type", "application/json") - .body( - RawRpcParamsBuilder::new("debug_getRawTransaction") - .add_param(format!("0x{:064x}", *EIP1599_TX_HASH)) - .build(), - ) + .body(RawRpcParamsBuilder::new("debug_getRawTransaction").add_param(format!("0x{:064x}", tx.hash)).build()) .send() .await .expect("Failed to call Debug RPC"); @@ -44,109 +44,19 @@ async fn test_raw_transaction(#[future] katana: Katana, _setup: ()) { // We can decode the RLP bytes to get the transaction and compare it with the original transaction let transaction = TransactionSigned::decode_enveloped(&mut rlp_bytes.unwrap().as_ref()).unwrap(); let signer = transaction.recover_signer().unwrap(); - let transaction = from_recovered_with_block_context( - TransactionSignedEcRecovered::from_signed_transaction(transaction, signer), - *BLOCK_HASH, - BLOCK_NUMBER, - None, - 0, - ); - let res = reqwest_client - .post(format!("http://localhost:{}", server_addr.port())) - .header("Content-Type", "application/json") - .body( - RawRpcParamsBuilder::new("eth_getTransactionByHash") - .add_param(format!("0x{:064x}", *EIP1599_TX_HASH)) - .build(), - ) - .send() - .await - .expect("Failed to call Debug RPC"); - let response = res.text().await.expect("Failed to get response body"); - let response: Value = serde_json::from_str(&response).expect("Failed to deserialize response body"); - let rpc_transaction: reth_rpc_types::Transaction = - serde_json::from_value(response["result"].clone()).expect("Failed to deserialize result"); - assert_eq!(transaction, rpc_transaction); - // EIP2930 - let reqwest_client = reqwest::Client::new(); - let res = reqwest_client - .post(format!("http://localhost:{}", server_addr.port())) - .header("Content-Type", "application/json") - .body( - RawRpcParamsBuilder::new("debug_getRawTransaction") - .add_param(format!("0x{:064x}", *EIP2930_TX_HASH)) - .build(), - ) - .send() - .await - .expect("Failed to call Debug RPC"); - let response = res.text().await.expect("Failed to get response body"); - let raw: Value = serde_json::from_str(&response).expect("Failed to deserialize response body"); - let rlp_bytes: Option = serde_json::from_value(raw["result"].clone()).expect("Failed to deserialize result"); - assert!(rlp_bytes.is_some()); - // We can decode the RLP bytes to get the transaction and compare it with the original transaction - let transaction = TransactionSigned::decode_enveloped(&mut rlp_bytes.unwrap().as_ref()).unwrap(); - let signer = transaction.recover_signer().unwrap(); - let transaction = from_recovered_with_block_context( + let mut transaction = from_recovered_with_block_context( TransactionSignedEcRecovered::from_signed_transaction(transaction, signer), - *BLOCK_HASH, - BLOCK_NUMBER, - None, - 0, + tx.block_hash.unwrap(), + tx.block_number.unwrap(), + header.base_fee_per_gas.map(|x| x.try_into().unwrap()), + tx.transaction_index.unwrap() as usize, ); - let res = reqwest_client - .post(format!("http://localhost:{}", server_addr.port())) - .header("Content-Type", "application/json") - .body( - RawRpcParamsBuilder::new("eth_getTransactionByHash") - .add_param(format!("0x{:064x}", *EIP2930_TX_HASH)) - .build(), - ) - .send() - .await - .expect("Failed to call Debug RPC"); - let response = res.text().await.expect("Failed to get response body"); - let response: Value = serde_json::from_str(&response).expect("Failed to deserialize response body"); - let rpc_transaction: reth_rpc_types::Transaction = - serde_json::from_value(response["result"].clone()).expect("Failed to deserialize result"); - assert_eq!(transaction, rpc_transaction); - // Legacy - let reqwest_client = reqwest::Client::new(); let res = reqwest_client .post(format!("http://localhost:{}", server_addr.port())) .header("Content-Type", "application/json") - .body( - RawRpcParamsBuilder::new("debug_getRawTransaction") - .add_param(format!("0x{:064x}", *LEGACY_TX_HASH)) - .build(), - ) - .send() - .await - .expect("Failed to call Debug RPC"); - let response = res.text().await.expect("Failed to get response body"); - let raw: Value = serde_json::from_str(&response).expect("Failed to deserialize response body"); - let rlp_bytes: Option = serde_json::from_value(raw["result"].clone()).expect("Failed to deserialize result"); - assert!(rlp_bytes.is_some()); - // We can decode the RLP bytes to get the transaction and compare it with the original transaction - let transaction = TransactionSigned::decode_enveloped(&mut rlp_bytes.unwrap().as_ref()).unwrap(); - let signer = transaction.recover_signer().unwrap(); - let transaction = from_recovered_with_block_context( - TransactionSignedEcRecovered::from_signed_transaction(transaction, signer), - *BLOCK_HASH, - BLOCK_NUMBER, - None, - 0, - ); - let res = reqwest_client - .post(format!("http://localhost:{}", server_addr.port())) - .header("Content-Type", "application/json") - .body( - RawRpcParamsBuilder::new("eth_getTransactionByHash") - .add_param(format!("0x{:064x}", *LEGACY_TX_HASH)) - .build(), - ) + .body(RawRpcParamsBuilder::new("eth_getTransactionByHash").add_param(format!("0x{:064x}", tx.hash)).build()) .send() .await .expect("Failed to call Debug RPC"); @@ -154,6 +64,20 @@ async fn test_raw_transaction(#[future] katana: Katana, _setup: ()) { let response: Value = serde_json::from_str(&response).expect("Failed to deserialize response body"); let rpc_transaction: reth_rpc_types::Transaction = serde_json::from_value(response["result"].clone()).expect("Failed to deserialize result"); + + // As per https://github.com/paradigmxyz/reth/blob/603e39ab74509e0863fc023461a4c760fb2126d1/crates/rpc/rpc-types-compat/src/transaction/signature.rs#L17 + if rpc_transaction.transaction_type.unwrap() == 0 { + transaction.signature = Some(reth_rpc_types::Signature { + y_parity: rpc_transaction.signature.unwrap().y_parity, + ..transaction.signature.unwrap() + }); + } + + // For EIP1559, `gas_price` is recomputed as per https://github.com/paradigmxyz/reth/blob/603e39ab74509e0863fc023461a4c760fb2126d1/crates/rpc/rpc-types-compat/src/transaction/mod.rs#L54 + if rpc_transaction.transaction_type.unwrap() == 2 { + transaction.gas_price = rpc_transaction.gas_price; + } + assert_eq!(transaction, rpc_transaction); drop(server_handle); diff --git a/tests/tests/eth_provider.rs b/tests/tests/eth_provider.rs index 884371ab2..5d9808487 100644 --- a/tests/tests/eth_provider.rs +++ b/tests/tests/eth_provider.rs @@ -13,7 +13,6 @@ use kakarot_rpc::{ evm_contract::{EvmContract, KakarotEvmContract}, fixtures::{contract_empty, counter, katana, plain_opcodes, setup}, katana::Katana, - mongo::{BLOCK_HASH, BLOCK_NUMBER}, tx_waiter::watch_tx, }, }; @@ -122,11 +121,15 @@ async fn test_block_transaction_count_by_hash(#[future] katana: Katana, _setup: // Given let eth_provider = katana.eth_provider(); + // Get the header of the first transaction + let first_tx = katana.first_transaction().unwrap(); + let header = katana.header_by_hash(first_tx.block_hash.unwrap()).unwrap(); + // When - let count = eth_provider.block_transaction_count_by_hash(*BLOCK_HASH).await.unwrap().unwrap(); + let count = eth_provider.block_transaction_count_by_hash(header.hash.unwrap()).await.unwrap().unwrap(); // Then - assert_eq!(count, U256::from(3)); + assert_eq!(count, U256::from(1)); // When let count = eth_provider @@ -146,12 +149,19 @@ async fn test_block_transaction_count_by_number(#[future] katana: Katana, _setup // Given: Ethereum provider instance let eth_provider = katana.eth_provider(); + // Get the header of the first transaction + let first_tx = katana.first_transaction().unwrap(); + let header = katana.header_by_hash(first_tx.block_hash.unwrap()).unwrap(); + // When: Retrieving transaction count for a specific block number - let count = - eth_provider.block_transaction_count_by_number(BlockNumberOrTag::Number(BLOCK_NUMBER)).await.unwrap().unwrap(); + let count = eth_provider + .block_transaction_count_by_number(BlockNumberOrTag::Number(header.number.unwrap())) + .await + .unwrap() + .unwrap(); // Then: Ensure the retrieved transaction count matches the expected value - assert_eq!(count, U256::from(3)); + assert_eq!(count, U256::from(1)); // When: Retrieving transaction count for the block of the most recent transaction let block_number = katana.most_recent_transaction().unwrap().block_number.unwrap(); diff --git a/tests/tests/txpool_api.rs b/tests/tests/txpool_api.rs index f417be376..72d673cf1 100644 --- a/tests/tests/txpool_api.rs +++ b/tests/tests/txpool_api.rs @@ -182,7 +182,7 @@ async fn test_txpool_inspect(#[future] katana: Katana, _setup: ()) { to: first_pending_tx.to, value: first_pending_tx.value, gas: first_pending_tx.gas, - gas_price: first_pending_tx.gas_price.unwrap() + gas_price: first_pending_tx.gas_price.unwrap_or_default(), } );