diff --git a/Cargo.lock b/Cargo.lock index a6503edb..4d1b150c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12855,6 +12855,7 @@ dependencies = [ "alloy-rpc-types-eth", "eyre", "getrandom 0.2.16", + "reth-e2e-test-utils", "reth-tracing", "scroll-alloy-network", "serde", diff --git a/tests/Cargo.toml b/tests/Cargo.toml index e6317524..af2102cd 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -20,3 +20,4 @@ tracing = { workspace = true } reth-tracing = { workspace = true } serde = { workspace = true } serde_json = "1.0" +reth-e2e-test-utils.workspace = true diff --git a/tests/l2geth-genesis-e2e.json b/tests/l2geth-genesis-e2e.json index fcf67d33..08dba5fc 100644 --- a/tests/l2geth-genesis-e2e.json +++ b/tests/l2geth-genesis-e2e.json @@ -110,6 +110,66 @@ "code": "0x", "nonce": "0x1", "storage": {} + }, + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x90F79bf6EB2c4f870365E785982E1f101E93b906": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x976EA74026E726554dB657fA54763abd0C3a0aa9": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xBcd4042DE499D14e55001CcbB24a551F3b954096": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x71bE63f3384f5fb98995898A86B02Fb2426c5788": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xFABB0ac9d68B0B445fB7357272Ff202C5651694a": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xcd3B766CCDd6AE721141F452C550Ca635964ce71": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x2546BcD3c84621e976D8185a91A922aE77ECEc30": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xbDA5747bFD65F08deb54cb465eB87D40e51B197E": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xdD2FD4581271e230360230F9337D5c0430Bf44C0": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199": { + "balance": "0xD3C21BCECCEDA1000000" } } } diff --git a/tests/l2reth-genesis-e2e.json b/tests/l2reth-genesis-e2e.json index 2d8e461e..4d774e79 100644 --- a/tests/l2reth-genesis-e2e.json +++ b/tests/l2reth-genesis-e2e.json @@ -103,6 +103,66 @@ "code": "0x", "nonce": "0x1", "storage": {} + }, + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x90F79bf6EB2c4f870365E785982E1f101E93b906": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x976EA74026E726554dB657fA54763abd0C3a0aa9": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xBcd4042DE499D14e55001CcbB24a551F3b954096": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x71bE63f3384f5fb98995898A86B02Fb2426c5788": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xFABB0ac9d68B0B445fB7357272Ff202C5651694a": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xcd3B766CCDd6AE721141F452C550Ca635964ce71": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x2546BcD3c84621e976D8185a91A922aE77ECEc30": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xbDA5747bFD65F08deb54cb465eB87D40e51B197E": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0xdD2FD4581271e230360230F9337D5c0430Bf44C0": { + "balance": "0xD3C21BCECCEDA1000000" + }, + "0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199": { + "balance": "0xD3C21BCECCEDA1000000" } } } diff --git a/tests/src/utils.rs b/tests/src/utils.rs index 06ae420a..b9c2fd68 100644 --- a/tests/src/utils.rs +++ b/tests/src/utils.rs @@ -1,6 +1,15 @@ +use alloy_primitives::{hex::ToHexExt, Bytes}; use alloy_rpc_types_eth::BlockNumberOrTag; -use eyre::Result; -use std::time::Duration; +use eyre::{Ok, Result}; +use reth_e2e_test_utils::{transaction::TransactionTestContext, wallet::Wallet}; +use std::{ + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + time::Duration, +}; +use tokio::{sync::Mutex, time::interval}; use crate::docker_compose::NamedProvider; @@ -214,3 +223,96 @@ pub async fn admin_remove_trusted_peer(provider: &NamedProvider, enode: &str) -> .await .map_err(|e| eyre::eyre!("Failed to remove trusted peer {}: {}", enode, e)) } + +pub fn create_wallet(chain_id: u64) -> Arc> { + Arc::new(Mutex::new(Wallet::default().with_chain_id(chain_id))) +} + +/// Generate a transfer transaction with the given wallet. +pub async fn generate_tx(wallet: Arc>) -> Bytes { + let mut wallet = wallet.lock().await; + let tx_fut = TransactionTestContext::transfer_tx_nonce_bytes( + wallet.chain_id, + wallet.inner.clone(), + wallet.inner_nonce, + ); + wallet.inner_nonce += 1; + tx_fut.await +} + +/// Send a raw transaction to multiple nodes, optionally waiting for confirmation. +pub async fn send_tx( + wallet: Arc>, + nodes: &[&NamedProvider], + wait_for_confirmation: bool, +) -> Result<()> { + let tx = generate_tx(wallet).await; + + tracing::debug!("Sending transaction: {:?}", tx); + let tx: Vec = tx.into(); + let mut pending_txs = Vec::new(); + + for node in nodes { + let builder = node.send_raw_transaction(&tx).await; + match builder { + std::result::Result::Ok(builder) => { + let pending_tx = builder.register().await?; + tracing::debug!( + "Sent transaction {:?} to node: {:?}", + pending_tx.tx_hash(), + node.name + ); + pending_txs.push(pending_tx); + } + Err(e) => { + if e.to_string().contains("already known") { + continue; + } + eyre::bail!("Failed to send transaction to node {}: {}", node.name, e); + } + }; + } + + if wait_for_confirmation { + for pending_tx in pending_txs { + let r = pending_tx.await?; + tracing::debug!("Transaction confirmed: {:?}", r.encode_hex()); + } + } + + Ok(()) +} + +/// Simple transaction sender that runs continuously until `stop` is set to true. +pub async fn run_continuous_tx_sender(stop: Arc, nodes: &[&NamedProvider]) -> u64 { + let mut interval = interval(Duration::from_millis(50)); + let mut tx_count = 0u64; + + let wallet = create_wallet(nodes[0].get_chain_id().await.expect("Failed to get chain id")); + + while !stop.load(Ordering::Relaxed) { + interval.tick().await; + + if let Err(e) = send_tx(wallet.clone(), nodes, false).await { + tracing::error!("Error sending transaction: {}", e); + } else { + tx_count += 1; + } + } + + tx_count +} + +pub async fn stop_continuous_tx_sender( + stop: Arc, + tx_sender: tokio::task::JoinHandle, +) -> Result<()> { + stop.store(true, Ordering::Relaxed); + let tx_count = tx_sender.await?; + tracing::info!( + "🔄 Stopped continuous transaction sender after sending {} transactions", + tx_count + ); + + Ok(()) +} diff --git a/tests/tests/heterogeneous_client_sync_and_sequencer_handoff.rs b/tests/tests/heterogeneous_client_sync_and_sequencer_handoff.rs index 167cf047..35bd07a3 100644 --- a/tests/tests/heterogeneous_client_sync_and_sequencer_handoff.rs +++ b/tests/tests/heterogeneous_client_sync_and_sequencer_handoff.rs @@ -1,4 +1,5 @@ use eyre::Result; +use std::sync::{atomic::AtomicBool, Arc}; use tests::*; /// Tests cross-client block propagation and synchronization between heterogeneous nodes. @@ -47,7 +48,8 @@ async fn docker_test_heterogeneous_client_sync_and_sequencer_handoff() -> Result reth_tracing::init_test_tracing(); tracing::info!("=== STARTING docker_test_heterogeneous_client_sync_and_sequencer_handoff ==="); - let env = DockerComposeEnv::new("multi-client-propagation").await?; + let env = DockerComposeEnv::new("docker_test_heterogeneous_client_sync_and_sequencer_handoff") + .await?; let rn_sequencer = env.get_rn_sequencer_provider().await?; let rn_follower = env.get_rn_follower_provider().await?; @@ -66,6 +68,18 @@ async fn docker_test_heterogeneous_client_sync_and_sequencer_handoff() -> Result // Enable block production on l2geth sequencer utils::miner_start(&l2geth_sequencer).await?; + // Start single continuous transaction sender for entire test + let stop = Arc::new(AtomicBool::new(false)); + let stop_clone = stop.clone(); + let rn_follower_clone = env.get_rn_follower_provider().await.unwrap(); + let l2geth_follower_clone = env.get_l2geth_follower_provider().await.unwrap(); + let tx_sender = tokio::spawn(async move { + utils::run_continuous_tx_sender(stop_clone, &[&rn_follower_clone, &l2geth_follower_clone]) + .await + }); + + tracing::info!("🔄 Started continuous transaction sender for entire test"); + // Wait for at least 10 blocks to be produced let target_block = 10; utils::wait_for_block(&[&l2geth_sequencer], target_block).await?; @@ -169,5 +183,7 @@ async fn docker_test_heterogeneous_client_sync_and_sequencer_handoff() -> Result utils::wait_for_block(&nodes, target_block).await?; assert_blocks_match(&nodes, target_block).await?; + utils::stop_continuous_tx_sender(stop, tx_sender).await?; + Ok(()) } diff --git a/tests/tests/migrate_sequencer.rs b/tests/tests/migrate_sequencer.rs index ae679d84..3b158342 100644 --- a/tests/tests/migrate_sequencer.rs +++ b/tests/tests/migrate_sequencer.rs @@ -1,4 +1,5 @@ use eyre::Result; +use std::sync::{atomic::AtomicBool, Arc}; use tests::*; #[tokio::test] @@ -28,6 +29,18 @@ async fn docker_test_migrate_sequencer() -> Result<()> { utils::admin_add_peer(&rn_follower, &env.rn_sequencer_enode()?).await?; utils::admin_add_peer(&rn_sequencer, &env.l2geth_sequencer_enode()?).await?; + // Start single continuous transaction sender for entire test + let stop = Arc::new(AtomicBool::new(false)); + let stop_clone = stop.clone(); + let rn_follower_clone = env.get_rn_follower_provider().await.unwrap(); + let l2geth_follower_clone = env.get_l2geth_follower_provider().await.unwrap(); + let tx_sender = tokio::spawn(async move { + utils::run_continuous_tx_sender(stop_clone, &[&rn_follower_clone, &l2geth_follower_clone]) + .await + }); + + tracing::info!("🔄 Started continuous transaction sender for entire test"); + // Enable block production on l2geth sequencer utils::miner_start(&l2geth_sequencer).await?; @@ -47,5 +60,7 @@ async fn docker_test_migrate_sequencer() -> Result<()> { utils::wait_for_block(&nodes, target_block).await?; utils::assert_blocks_match(&nodes, target_block).await?; + utils::stop_continuous_tx_sender(stop, tx_sender).await?; + Ok(()) }