From 3750edd905f90b3033bd225709b88f9fbd2b17bb Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Sat, 20 Apr 2024 13:58:03 +0100 Subject: [PATCH] chore(e2e): refactor e2e tests (#7773) --- .github/workflows/integration.yml | 2 +- Cargo.lock | 64 +++++++------ Cargo.toml | 3 +- .../Cargo.toml | 8 +- .../src/engine_api.rs | 43 +++++---- .../src/lib.rs | 3 + .../src/network.rs | 0 .../src/node.rs | 62 ++++++++---- .../src/payload.rs | 51 ++++------ crates/e2e-test-utils/src/traits.rs | 22 +++++ .../src/wallet.rs | 8 +- crates/node-ethereum/Cargo.toml | 9 +- .../tests}/assets/genesis.json | 0 .../it => node-ethereum/tests/e2e}/dev.rs | 0 .../it => node-ethereum/tests/e2e}/eth.rs | 17 ++-- .../it => node-ethereum/tests/e2e}/main.rs | 1 + .../it => node-ethereum/tests/e2e}/p2p.rs | 11 ++- crates/node-ethereum/tests/e2e/utils.rs | 15 +++ crates/optimism/node/Cargo.toml | 3 + .../optimism/node/tests/assets/genesis.json | 96 +++++++++++++++++++ crates/optimism/node/tests/e2e/main.rs | 7 ++ crates/optimism/node/tests/e2e/p2p.rs | 78 +++++++++++++++ crates/optimism/node/tests/e2e/utils.rs | 22 +++++ 23 files changed, 400 insertions(+), 125 deletions(-) rename crates/{node-e2e-tests => e2e-test-utils}/Cargo.toml (84%) rename crates/{node-e2e-tests => e2e-test-utils}/src/engine_api.rs (50%) rename crates/{node-e2e-tests => e2e-test-utils}/src/lib.rs (89%) rename crates/{node-e2e-tests => e2e-test-utils}/src/network.rs (100%) rename crates/{node-e2e-tests => e2e-test-utils}/src/node.rs (67%) rename crates/{node-e2e-tests => e2e-test-utils}/src/payload.rs (56%) create mode 100644 crates/e2e-test-utils/src/traits.rs rename crates/{node-e2e-tests => e2e-test-utils}/src/wallet.rs (88%) rename crates/{node-e2e-tests => node-ethereum/tests}/assets/genesis.json (100%) rename crates/{node-e2e-tests/tests/it => node-ethereum/tests/e2e}/dev.rs (100%) rename crates/{node-e2e-tests/tests/it => node-ethereum/tests/e2e}/eth.rs (89%) rename crates/{node-e2e-tests/tests/it => node-ethereum/tests/e2e}/main.rs (78%) rename crates/{node-e2e-tests/tests/it => node-ethereum/tests/e2e}/p2p.rs (88%) create mode 100644 crates/node-ethereum/tests/e2e/utils.rs create mode 100644 crates/optimism/node/tests/assets/genesis.json create mode 100644 crates/optimism/node/tests/e2e/main.rs create mode 100644 crates/optimism/node/tests/e2e/p2p.rs create mode 100644 crates/optimism/node/tests/e2e/utils.rs diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 7d01b0030c51..6f1e63a7ccf4 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -48,7 +48,7 @@ jobs: run: | cargo nextest run \ --locked --features "asm-keccak ${{ matrix.network }}" \ - --workspace --exclude examples --exclude ef-tests node-e2e-tests \ + --workspace --exclude examples --exclude ef-tests node-ethereum \ -E "kind(test)" sync: diff --git a/Cargo.lock b/Cargo.lock index 093aa53e10c3..90699db28083 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4882,33 +4882,6 @@ dependencies = [ "libc", ] -[[package]] -name = "node-e2e-tests" -version = "0.0.0" -dependencies = [ - "alloy-consensus", - "alloy-network", - "alloy-rpc-types", - "alloy-signer", - "alloy-signer-wallet", - "eyre", - "futures-util", - "jsonrpsee", - "rand 0.8.5", - "reth", - "reth-db", - "reth-node-core", - "reth-node-ethereum", - "reth-payload-builder", - "reth-primitives", - "reth-rpc", - "reth-tracing", - "secp256k1 0.27.0", - "serde_json", - "tokio", - "tokio-stream", -] - [[package]] name = "nom" version = "7.1.3" @@ -6446,6 +6419,33 @@ dependencies = [ "tracing", ] +[[package]] +name = "reth-e2e-test-utils" +version = "0.2.0-beta.5" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-rpc-types", + "alloy-signer", + "alloy-signer-wallet", + "eyre", + "futures-util", + "jsonrpsee", + "rand 0.8.5", + "reth", + "reth-db", + "reth-node-core", + "reth-node-ethereum", + "reth-payload-builder", + "reth-primitives", + "reth-rpc", + "reth-tracing", + "secp256k1 0.27.0", + "serde_json", + "tokio", + "tokio-stream", +] + [[package]] name = "reth-ecies" version = "0.2.0-beta.5" @@ -6962,8 +6962,11 @@ version = "0.2.0-beta.5" dependencies = [ "eyre", "futures", + "futures-util", + "reth", "reth-basic-payload-builder", "reth-db", + "reth-e2e-test-utils", "reth-ethereum-engine-primitives", "reth-ethereum-payload-builder", "reth-evm-ethereum", @@ -6971,10 +6974,14 @@ dependencies = [ "reth-network", "reth-node-api", "reth-node-builder", + "reth-node-core", "reth-payload-builder", + "reth-primitives", "reth-provider", "reth-tracing", "reth-transaction-pool", + "serde_json", + "tokio", ] [[package]] @@ -7011,8 +7018,10 @@ dependencies = [ "jsonrpsee", "parking_lot 0.12.1", "reqwest 0.11.27", + "reth", "reth-basic-payload-builder", "reth-db", + "reth-e2e-test-utils", "reth-evm", "reth-interfaces", "reth-network", @@ -7033,6 +7042,7 @@ dependencies = [ "serde", "serde_json", "thiserror", + "tokio", "tracing", ] diff --git a/Cargo.toml b/Cargo.toml index a7ca32ca09f2..96e4108293bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "crates/consensus/beacon-core/", "crates/consensus/common/", "crates/ethereum-forks/", + "crates/e2e-test-utils/", "crates/etl/", "crates/evm/", "crates/ethereum/evm", @@ -51,7 +52,6 @@ members = [ "crates/optimism/node/", "crates/node-core/", "crates/node/api/", - "crates/node-e2e-tests/", "crates/stages/", "crates/stages-api", "crates/static-file/", @@ -212,6 +212,7 @@ reth-db = { path = "crates/storage/db" } reth-discv4 = { path = "crates/net/discv4" } reth-discv5 = { path = "crates/net/discv5" } reth-dns-discovery = { path = "crates/net/dns" } +reth-e2e-test-utils = { path = "crates/e2e-test-utils" } reth-engine-primitives = { path = "crates/engine-primitives" } reth-ethereum-engine-primitives = { path = "crates/ethereum/engine-primitives" } reth-node-builder = { path = "crates/node-builder" } diff --git a/crates/node-e2e-tests/Cargo.toml b/crates/e2e-test-utils/Cargo.toml similarity index 84% rename from crates/node-e2e-tests/Cargo.toml rename to crates/e2e-test-utils/Cargo.toml index d3811f5f5cf1..f32ff029c2ed 100644 --- a/crates/node-e2e-tests/Cargo.toml +++ b/crates/e2e-test-utils/Cargo.toml @@ -1,9 +1,11 @@ [package] -name = "node-e2e-tests" -version = "0.0.0" -publish = false +name = "reth-e2e-test-utils" +version.workspace = true edition.workspace = true +rust-version.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [dependencies] diff --git a/crates/node-e2e-tests/src/engine_api.rs b/crates/e2e-test-utils/src/engine_api.rs similarity index 50% rename from crates/node-e2e-tests/src/engine_api.rs rename to crates/e2e-test-utils/src/engine_api.rs index 06c9afa311ca..ec8b058a3007 100644 --- a/crates/node-e2e-tests/src/engine_api.rs +++ b/crates/e2e-test-utils/src/engine_api.rs @@ -1,56 +1,57 @@ +use crate::traits::PayloadEnvelopeExt; use jsonrpsee::http_client::HttpClient; use reth::{ + api::{EngineTypes, PayloadBuilderAttributes}, providers::CanonStateNotificationStream, - rpc::{ - api::EngineApiClient, - types::engine::{ExecutionPayloadEnvelopeV3, ForkchoiceState}, - }, + rpc::{api::EngineApiClient, types::engine::ForkchoiceState}, }; -use reth_node_ethereum::EthEngineTypes; -use reth_payload_builder::{EthBuiltPayload, EthPayloadBuilderAttributes, PayloadId}; +use reth_payload_builder::PayloadId; use reth_primitives::B256; +use std::marker::PhantomData; /// Helper for engine api operations -pub struct EngineApiHelper { +pub struct EngineApiHelper { pub canonical_stream: CanonStateNotificationStream, pub engine_api_client: HttpClient, + pub _marker: PhantomData, } -impl EngineApiHelper { +impl EngineApiHelper { /// Retrieves a v3 payload from the engine api pub async fn get_payload_v3( &self, payload_id: PayloadId, - ) -> eyre::Result { - Ok(EngineApiClient::::get_payload_v3(&self.engine_api_client, payload_id) - .await?) + ) -> eyre::Result { + Ok(EngineApiClient::::get_payload_v3(&self.engine_api_client, payload_id).await?) } /// Submits a payload to the engine api pub async fn submit_payload( &self, - payload: EthBuiltPayload, - eth_attr: EthPayloadBuilderAttributes, - ) -> eyre::Result { + payload: E::BuiltPayload, + payload_builder_attributes: E::PayloadBuilderAttributes, + ) -> eyre::Result + where + E::ExecutionPayloadV3: From + PayloadEnvelopeExt, + { // setup payload for submission - let envelope_v3 = ExecutionPayloadEnvelopeV3::from(payload); - let payload_v3 = envelope_v3.execution_payload; + let envelope_v3: ::ExecutionPayloadV3 = payload.into(); // submit payload to engine api - let submission = EngineApiClient::::new_payload_v3( + let submission = EngineApiClient::::new_payload_v3( &self.engine_api_client, - payload_v3, + envelope_v3.execution_payload(), vec![], - eth_attr.parent_beacon_block_root.unwrap(), + payload_builder_attributes.parent_beacon_block_root().unwrap(), ) .await?; - assert!(submission.is_valid()); + assert!(submission.is_valid(), "{}", submission); Ok(submission.latest_valid_hash.unwrap()) } /// Sends forkchoice update to the engine api pub async fn update_forkchoice(&self, hash: B256) -> eyre::Result<()> { - EngineApiClient::::fork_choice_updated_v2( + EngineApiClient::::fork_choice_updated_v2( &self.engine_api_client, ForkchoiceState { head_block_hash: hash, diff --git a/crates/node-e2e-tests/src/lib.rs b/crates/e2e-test-utils/src/lib.rs similarity index 89% rename from crates/node-e2e-tests/src/lib.rs rename to crates/e2e-test-utils/src/lib.rs index 2799c4fe3fc7..016fb4d3e21b 100644 --- a/crates/node-e2e-tests/src/lib.rs +++ b/crates/e2e-test-utils/src/lib.rs @@ -12,3 +12,6 @@ mod network; /// Helper for engine api operations mod engine_api; + +/// Helper traits +mod traits; diff --git a/crates/node-e2e-tests/src/network.rs b/crates/e2e-test-utils/src/network.rs similarity index 100% rename from crates/node-e2e-tests/src/network.rs rename to crates/e2e-test-utils/src/network.rs diff --git a/crates/node-e2e-tests/src/node.rs b/crates/e2e-test-utils/src/node.rs similarity index 67% rename from crates/node-e2e-tests/src/node.rs rename to crates/e2e-test-utils/src/node.rs index f4e94b4ae47c..d88a428f05a1 100644 --- a/crates/node-e2e-tests/src/node.rs +++ b/crates/e2e-test-utils/src/node.rs @@ -1,8 +1,11 @@ -use crate::{engine_api::EngineApiHelper, network::NetworkHelper, payload::PayloadHelper}; +use crate::{ + engine_api::EngineApiHelper, network::NetworkHelper, payload::PayloadHelper, + traits::PayloadEnvelopeExt, +}; use alloy_rpc_types::BlockNumberOrTag; use eyre::Ok; use reth::{ - api::FullNodeComponents, + api::{BuiltPayload, EngineTypes, FullNodeComponents, PayloadBuilderAttributes}, builder::FullNode, providers::{BlockReaderIdExt, CanonStateSubscriptions}, rpc::{ @@ -10,28 +13,28 @@ use reth::{ types::engine::PayloadAttributes, }, }; - -use reth_node_ethereum::EthEngineTypes; use reth_payload_builder::EthPayloadBuilderAttributes; -use reth_primitives::{Address, Bytes, B256}; - -use std::time::{SystemTime, UNIX_EPOCH}; +use reth_primitives::{Address, BlockNumber, Bytes, B256}; +use std::{ + marker::PhantomData, + time::{SystemTime, UNIX_EPOCH}, +}; use tokio_stream::StreamExt; /// An helper struct to handle node actions pub struct NodeHelper where - Node: FullNodeComponents, + Node: FullNodeComponents, { pub inner: FullNode, payload: PayloadHelper, pub network: NetworkHelper, - pub engine_api: EngineApiHelper, + pub engine_api: EngineApiHelper, } impl NodeHelper where - Node: FullNodeComponents, + Node: FullNodeComponents, { /// Creates a new test node pub async fn new(node: FullNode) -> eyre::Result { @@ -44,17 +47,26 @@ where engine_api: EngineApiHelper { engine_api_client: node.auth_server_handle().http_client(), canonical_stream: node.provider.canonical_state_stream(), + _marker: PhantomData::, }, }) } /// Advances the node forward - pub async fn advance(&mut self, raw_tx: Bytes) -> eyre::Result<(B256, B256)> { + pub async fn advance( + &mut self, + raw_tx: Bytes, + attributes_generator: impl Fn(u64) -> ::PayloadBuilderAttributes, + ) -> eyre::Result<(B256, B256)> + where + ::ExecutionPayloadV3: + From<::BuiltPayload> + PayloadEnvelopeExt, + { // push tx into pool via RPC server let tx_hash = self.inject_tx(raw_tx).await?; // trigger new payload building draining the pool - let eth_attr = self.payload.new_payload().await.unwrap(); + let eth_attr = self.payload.new_payload(attributes_generator).await.unwrap(); // first event is the payload attributes self.payload.expect_attr_event(eth_attr.clone()).await?; @@ -69,13 +81,14 @@ where let payload = self.payload.expect_built_payload().await?; // submit payload via engine api + let block_number = payload.block().number; let block_hash = self.engine_api.submit_payload(payload, eth_attr.clone()).await?; // trigger forkchoice update via engine api to commit the block to the blockchain self.engine_api.update_forkchoice(block_hash).await?; // assert the block has been committed to the blockchain - self.assert_new_block(tx_hash, block_hash).await?; + self.assert_new_block(tx_hash, block_hash, block_number).await?; Ok((block_hash, tx_hash)) } @@ -91,6 +104,7 @@ where &mut self, tip_tx_hash: B256, block_hash: B256, + block_number: BlockNumber, ) -> eyre::Result<()> { // get head block from notifications stream and verify the tx has been pushed to the // pool is actually present in the canonical block @@ -98,14 +112,20 @@ where let tx = head.tip().transactions().next(); assert_eq!(tx.unwrap().hash().as_slice(), tip_tx_hash.as_slice()); - // wait for the block to commit - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - - // make sure the block hash we submitted via FCU engine api is the new latest block - // using an RPC call - let latest_block = - self.inner.provider.block_by_number_or_tag(BlockNumberOrTag::Latest)?.unwrap(); - assert_eq!(latest_block.hash_slow(), block_hash); + loop { + // wait for the block to commit + tokio::time::sleep(std::time::Duration::from_millis(20)).await; + if let Some(latest_block) = + self.inner.provider.block_by_number_or_tag(BlockNumberOrTag::Latest)? + { + if latest_block.number == block_number { + // make sure the block hash we submitted via FCU engine api is the new latest + // block using an RPC call + assert_eq!(latest_block.hash_slow(), block_hash); + break + } + } + } Ok(()) } } diff --git a/crates/node-e2e-tests/src/payload.rs b/crates/e2e-test-utils/src/payload.rs similarity index 56% rename from crates/node-e2e-tests/src/payload.rs rename to crates/e2e-test-utils/src/payload.rs index a23f7225f19f..37138cdd3ebf 100644 --- a/crates/node-e2e-tests/src/payload.rs +++ b/crates/e2e-test-utils/src/payload.rs @@ -1,34 +1,31 @@ -use std::time::{SystemTime, UNIX_EPOCH}; - use futures_util::StreamExt; -use reth::{ - api::{EngineTypes, PayloadBuilderAttributes}, - rpc::types::engine::PayloadAttributes, -}; -use reth_node_ethereum::EthEngineTypes; -use reth_payload_builder::{ - EthBuiltPayload, EthPayloadBuilderAttributes, Events, PayloadBuilderHandle, PayloadId, -}; -use reth_primitives::{Address, B256}; +use reth::api::{BuiltPayload, EngineTypes, PayloadBuilderAttributes}; +use reth_payload_builder::{Events, PayloadBuilderHandle, PayloadId}; use tokio_stream::wrappers::BroadcastStream; /// Helper for payload operations pub struct PayloadHelper { pub payload_event_stream: BroadcastStream>, payload_builder: PayloadBuilderHandle, + timestamp: u64, } -impl PayloadHelper { +impl PayloadHelper { /// Creates a new payload helper - pub async fn new(payload_builder: PayloadBuilderHandle) -> eyre::Result { + pub async fn new(payload_builder: PayloadBuilderHandle) -> eyre::Result { let payload_events = payload_builder.subscribe().await?; let payload_event_stream = payload_events.into_stream(); - Ok(Self { payload_event_stream, payload_builder }) + // Cancun timestamp + Ok(Self { payload_event_stream, payload_builder, timestamp: 1710338135 }) } /// Creates a new payload job from static attributes - pub async fn new_payload(&self) -> eyre::Result { - let attributes = eth_payload_attributes(); + pub async fn new_payload( + &mut self, + attributes_generator: impl Fn(u64) -> E::PayloadBuilderAttributes, + ) -> eyre::Result { + self.timestamp += 1; + let attributes: E::PayloadBuilderAttributes = attributes_generator(self.timestamp); self.payload_builder.new_payload(attributes.clone()).await.unwrap(); Ok(attributes) } @@ -36,11 +33,11 @@ impl PayloadHelper { /// Asserts that the next event is a payload attributes event pub async fn expect_attr_event( &mut self, - attrs: EthPayloadBuilderAttributes, + attrs: E::PayloadBuilderAttributes, ) -> eyre::Result<()> { let first_event = self.payload_event_stream.next().await.unwrap()?; if let reth::payload::Events::Attributes(attr) = first_event { - assert_eq!(attrs.timestamp, attr.timestamp()); + assert_eq!(attrs.timestamp(), attr.timestamp()); } else { panic!("Expect first event as payload attributes.") } @@ -52,7 +49,7 @@ impl PayloadHelper { loop { let payload = self.payload_builder.best_payload(payload_id).await.unwrap().unwrap(); if payload.block().body.is_empty() { - tokio::time::sleep(std::time::Duration::from_secs(1)).await; + tokio::time::sleep(std::time::Duration::from_millis(20)).await; continue; } break; @@ -60,7 +57,7 @@ impl PayloadHelper { } /// Expects the next event to be a built payload event or panics - pub async fn expect_built_payload(&mut self) -> eyre::Result { + pub async fn expect_built_payload(&mut self) -> eyre::Result { let second_event = self.payload_event_stream.next().await.unwrap()?; if let reth::payload::Events::BuiltPayload(payload) = second_event { Ok(payload) @@ -69,17 +66,3 @@ impl PayloadHelper { } } } - -/// Helper function to create a new eth payload attributes -fn eth_payload_attributes() -> EthPayloadBuilderAttributes { - let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); - - let attributes = PayloadAttributes { - timestamp, - prev_randao: B256::ZERO, - suggested_fee_recipient: Address::ZERO, - withdrawals: Some(vec![]), - parent_beacon_block_root: Some(B256::ZERO), - }; - EthPayloadBuilderAttributes::new(B256::ZERO, attributes) -} diff --git a/crates/e2e-test-utils/src/traits.rs b/crates/e2e-test-utils/src/traits.rs new file mode 100644 index 000000000000..2d8b4789da39 --- /dev/null +++ b/crates/e2e-test-utils/src/traits.rs @@ -0,0 +1,22 @@ +use reth::rpc::types::{ + engine::{ExecutionPayloadEnvelopeV3, OptimismExecutionPayloadEnvelopeV3}, + ExecutionPayloadV3, +}; + +/// The execution payload envelope type. +pub trait PayloadEnvelopeExt: Send + Sync + std::fmt::Debug { + /// Returns the execution payload V3 from the payload + fn execution_payload(&self) -> ExecutionPayloadV3; +} + +impl PayloadEnvelopeExt for OptimismExecutionPayloadEnvelopeV3 { + fn execution_payload(&self) -> ExecutionPayloadV3 { + self.execution_payload.clone() + } +} + +impl PayloadEnvelopeExt for ExecutionPayloadEnvelopeV3 { + fn execution_payload(&self) -> ExecutionPayloadV3 { + self.execution_payload.clone() + } +} diff --git a/crates/node-e2e-tests/src/wallet.rs b/crates/e2e-test-utils/src/wallet.rs similarity index 88% rename from crates/node-e2e-tests/src/wallet.rs rename to crates/e2e-test-utils/src/wallet.rs index 2351d0a0b1a2..0428c8675321 100644 --- a/crates/node-e2e-tests/src/wallet.rs +++ b/crates/e2e-test-utils/src/wallet.rs @@ -5,19 +5,20 @@ use reth_primitives::{Address, Bytes, U256}; /// One of the accounts of the genesis allocations. pub struct Wallet { inner: LocalWallet, + nonce: u64, } impl Wallet { /// Creates a new account from one of the secret/pubkeys of the genesis allocations (test.json) pub(crate) fn new(phrase: &str) -> Self { let inner = MnemonicBuilder::::default().phrase(phrase).build().unwrap(); - Self { inner } + Self { inner, nonce: 0 } } /// Creates a static transfer and signs it - pub async fn transfer_tx(&self) -> Bytes { + pub async fn transfer_tx(&mut self) -> Bytes { let tx = TransactionRequest { - nonce: Some(0), + nonce: Some(self.nonce), value: Some(U256::from(100)), to: Some(Address::random()), gas_price: Some(20e9 as u128), @@ -25,6 +26,7 @@ impl Wallet { chain_id: Some(1), ..Default::default() }; + self.nonce += 1; let signer = EthereumSigner::from(self.inner.clone()); tx.build(&signer).await.unwrap().encoded_2718().into() } diff --git a/crates/node-ethereum/Cargo.toml b/crates/node-ethereum/Cargo.toml index 4380e57377be..072f91b28fd6 100644 --- a/crates/node-ethereum/Cargo.toml +++ b/crates/node-ethereum/Cargo.toml @@ -27,8 +27,15 @@ reth-evm-ethereum.workspace = true eyre.workspace = true [dev-dependencies] +reth.workspace = true reth-db.workspace = true reth-exex.workspace = true reth-node-api.workspace = true - +reth-node-core.workspace = true +reth-primitives.workspace = true +reth-e2e-test-utils.workspace = true futures.workspace = true +tokio.workspace = true +futures-util.workspace = true +serde_json.workspace = true + diff --git a/crates/node-e2e-tests/assets/genesis.json b/crates/node-ethereum/tests/assets/genesis.json similarity index 100% rename from crates/node-e2e-tests/assets/genesis.json rename to crates/node-ethereum/tests/assets/genesis.json diff --git a/crates/node-e2e-tests/tests/it/dev.rs b/crates/node-ethereum/tests/e2e/dev.rs similarity index 100% rename from crates/node-e2e-tests/tests/it/dev.rs rename to crates/node-ethereum/tests/e2e/dev.rs diff --git a/crates/node-e2e-tests/tests/it/eth.rs b/crates/node-ethereum/tests/e2e/eth.rs similarity index 89% rename from crates/node-e2e-tests/tests/it/eth.rs rename to crates/node-ethereum/tests/e2e/eth.rs index a2c761221dfc..6f9eeb999108 100644 --- a/crates/node-e2e-tests/tests/it/eth.rs +++ b/crates/node-ethereum/tests/e2e/eth.rs @@ -1,9 +1,10 @@ -use node_e2e_tests::{node::NodeHelper, wallet::Wallet}; +use crate::utils::eth_payload_attributes; use reth::{ args::RpcServerArgs, builder::{NodeBuilder, NodeConfig, NodeHandle}, tasks::TaskManager, }; +use reth_e2e_test_utils::{node::NodeHelper, wallet::Wallet}; use reth_node_ethereum::EthereumNode; use reth_primitives::{ChainSpecBuilder, Genesis, MAINNET}; use std::sync::Arc; @@ -16,7 +17,7 @@ async fn can_run_eth_node() -> eyre::Result<()> { let exec = exec.executor(); // Chain spec with test allocs - let genesis: Genesis = serde_json::from_str(include_str!("../../assets/genesis.json")).unwrap(); + let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap(); let chain_spec = Arc::new( ChainSpecBuilder::default() .chain(MAINNET.chain) @@ -39,11 +40,11 @@ async fn can_run_eth_node() -> eyre::Result<()> { let mut node = NodeHelper::new(node).await?; // Configure wallet from test mnemonic and create dummy transfer tx - let wallet = Wallet::default(); + let mut wallet = Wallet::default(); let raw_tx = wallet.transfer_tx().await; // make the node advance - node.advance(raw_tx).await?; + node.advance(raw_tx, eth_payload_attributes).await?; Ok(()) } @@ -56,7 +57,7 @@ async fn can_run_eth_node_with_auth_engine_api_over_ipc() -> eyre::Result<()> { let exec = exec.executor(); // Chain spec with test allocs - let genesis: Genesis = serde_json::from_str(include_str!("../../assets/genesis.json")).unwrap(); + let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap(); let chain_spec = Arc::new( ChainSpecBuilder::default() .chain(MAINNET.chain) @@ -78,11 +79,11 @@ async fn can_run_eth_node_with_auth_engine_api_over_ipc() -> eyre::Result<()> { let mut node = NodeHelper::new(node).await?; // Configure wallet from test mnemonic and create dummy transfer tx - let wallet = Wallet::default(); + let mut wallet = Wallet::default(); let raw_tx = wallet.transfer_tx().await; // make the node advance - node.advance(raw_tx).await?; + node.advance(raw_tx, crate::utils::eth_payload_attributes).await?; Ok(()) } @@ -95,7 +96,7 @@ async fn test_failed_run_eth_node_with_no_auth_engine_api_over_ipc_opts() -> eyr let exec = exec.executor(); // Chain spec with test allocs - let genesis: Genesis = serde_json::from_str(include_str!("../../assets/genesis.json")).unwrap(); + let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap(); let chain_spec = Arc::new( ChainSpecBuilder::default() .chain(MAINNET.chain) diff --git a/crates/node-e2e-tests/tests/it/main.rs b/crates/node-ethereum/tests/e2e/main.rs similarity index 78% rename from crates/node-e2e-tests/tests/it/main.rs rename to crates/node-ethereum/tests/e2e/main.rs index ba13034645c2..6a8a01064966 100644 --- a/crates/node-e2e-tests/tests/it/main.rs +++ b/crates/node-ethereum/tests/e2e/main.rs @@ -1,5 +1,6 @@ mod dev; mod eth; mod p2p; +mod utils; fn main() {} diff --git a/crates/node-e2e-tests/tests/it/p2p.rs b/crates/node-ethereum/tests/e2e/p2p.rs similarity index 88% rename from crates/node-e2e-tests/tests/it/p2p.rs rename to crates/node-ethereum/tests/e2e/p2p.rs index d0a2716f5965..940096e189b8 100644 --- a/crates/node-e2e-tests/tests/it/p2p.rs +++ b/crates/node-ethereum/tests/e2e/p2p.rs @@ -1,11 +1,12 @@ use std::sync::Arc; -use node_e2e_tests::{node::NodeHelper, wallet::Wallet}; +use crate::utils::eth_payload_attributes; use reth::{ args::{DiscoveryArgs, NetworkArgs, RpcServerArgs}, builder::{NodeBuilder, NodeConfig, NodeHandle}, tasks::TaskManager, }; +use reth_e2e_test_utils::{node::NodeHelper, wallet::Wallet}; use reth_node_ethereum::EthereumNode; use reth_primitives::{ChainSpecBuilder, Genesis, MAINNET}; @@ -16,7 +17,7 @@ async fn can_sync() -> eyre::Result<()> { let tasks = TaskManager::current(); let exec = tasks.executor(); - let genesis: Genesis = serde_json::from_str(include_str!("../../assets/genesis.json")).unwrap(); + let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap(); let chain_spec = Arc::new( ChainSpecBuilder::default() .chain(MAINNET.chain) @@ -52,7 +53,7 @@ async fn can_sync() -> eyre::Result<()> { let mut second_node = NodeHelper::new(node).await?; - let wallet = Wallet::default(); + let mut wallet = Wallet::default(); let raw_tx = wallet.transfer_tx().await; // Make them peer @@ -64,13 +65,13 @@ async fn can_sync() -> eyre::Result<()> { second_node.network.expect_session().await; // Make the first node advance - let (block_hash, tx_hash) = first_node.advance(raw_tx.clone()).await?; + let (block_hash, tx_hash) = first_node.advance(raw_tx.clone(), eth_payload_attributes).await?; // only send forkchoice update to second node second_node.engine_api.update_forkchoice(block_hash).await?; // expect second node advanced via p2p gossip - second_node.assert_new_block(tx_hash, block_hash).await?; + second_node.assert_new_block(tx_hash, block_hash, 1).await?; Ok(()) } diff --git a/crates/node-ethereum/tests/e2e/utils.rs b/crates/node-ethereum/tests/e2e/utils.rs new file mode 100644 index 000000000000..52526c45f309 --- /dev/null +++ b/crates/node-ethereum/tests/e2e/utils.rs @@ -0,0 +1,15 @@ +use reth::rpc::types::engine::PayloadAttributes; +use reth_payload_builder::EthPayloadBuilderAttributes; +use reth_primitives::{Address, B256}; + +/// Helper function to create a new eth payload attributes +pub(crate) fn eth_payload_attributes(timestamp: u64) -> EthPayloadBuilderAttributes { + let attributes = PayloadAttributes { + timestamp, + prev_randao: B256::ZERO, + suggested_fee_recipient: Address::ZERO, + withdrawals: Some(vec![]), + parent_beacon_block_root: Some(B256::ZERO), + }; + EthPayloadBuilderAttributes::new(B256::ZERO, attributes) +} diff --git a/crates/optimism/node/Cargo.toml b/crates/optimism/node/Cargo.toml index c6d2ece405e2..afa23a6c64e2 100644 --- a/crates/optimism/node/Cargo.toml +++ b/crates/optimism/node/Cargo.toml @@ -52,8 +52,11 @@ thiserror.workspace = true jsonrpsee.workspace = true [dev-dependencies] +reth.workspace = true reth-db.workspace = true reth-revm = { workspace = true, features = ["test-utils"]} +reth-e2e-test-utils.workspace = true +tokio.workspace = true [features] optimism = [ diff --git a/crates/optimism/node/tests/assets/genesis.json b/crates/optimism/node/tests/assets/genesis.json new file mode 100644 index 000000000000..2bdfec4309f5 --- /dev/null +++ b/crates/optimism/node/tests/assets/genesis.json @@ -0,0 +1,96 @@ +{ + "config": { + "chainId": 1, + "homesteadBlock": 0, + "daoForkSupport": true, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "shanghaiTime": 0, + "cancunTime": 0, + "terminalTotalDifficulty": "0x0", + "terminalTotalDifficultyPassed": true + }, + "nonce": "0x0", + "timestamp": "0x0", + "extraData": "0x00", + "gasLimit": "0x1c9c380", + "difficulty": "0x0", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0x14dc79964da2c08b23698b3d3cc7ca32193d9955": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x15d34aaf54267db7d7c367839aaf71a00a2c6a65": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x1cbd3b2770909d4e10f157cabc84c7264073c9ec": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x2546bcd3c84621e976d8185a91a922ae77ecec30": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x70997970c51812dc3a010c7d01b50e0d17dc79c8": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x71be63f3384f5fb98995898a86b02fb2426c5788": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x8626f6940e2eb28930efb4cef49b2d1f2c9c1199": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x90f79bf6eb2c4f870365e785982e1f101e93b906": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x976ea74026e726554db657fa54763abd0c3a0aa9": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc": { + "balance": "0xd3c21bcecceda1000000" + }, + "0x9c41de96b2088cdc640c6182dfcf5491dc574a57": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xa0ee7a142d267c1f36714e4a8f75612f20a79720": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xbcd4042de499d14e55001ccbb24a551f3b954096": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xbda5747bfd65f08deb54cb465eb87d40e51b197e": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xcd3b766ccdd6ae721141f452c550ca635964ce71": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xdd2fd4581271e230360230f9337d5c0430bf44c0": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xdf3e18d64bc6a983f673ab319ccae4f1a57c7097": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": { + "balance": "0xd3c21bcecceda1000000" + }, + "0xfabb0ac9d68b0b445fb7357272ff202c5651694a": { + "balance": "0xd3c21bcecceda1000000" + } + }, + "number": "0x0" +} diff --git a/crates/optimism/node/tests/e2e/main.rs b/crates/optimism/node/tests/e2e/main.rs new file mode 100644 index 000000000000..221f8483dd7d --- /dev/null +++ b/crates/optimism/node/tests/e2e/main.rs @@ -0,0 +1,7 @@ +#[cfg(feature = "optimism")] +mod p2p; + +#[cfg(feature = "optimism")] +mod utils; + +fn main() {} diff --git a/crates/optimism/node/tests/e2e/p2p.rs b/crates/optimism/node/tests/e2e/p2p.rs new file mode 100644 index 000000000000..5bf36ace982a --- /dev/null +++ b/crates/optimism/node/tests/e2e/p2p.rs @@ -0,0 +1,78 @@ +use std::sync::Arc; + +use crate::utils::optimism_payload_attributes; +use reth::{ + args::{DiscoveryArgs, NetworkArgs, RpcServerArgs}, + builder::{NodeBuilder, NodeConfig, NodeHandle}, + tasks::TaskManager, +}; +use reth_e2e_test_utils::{node::NodeHelper, wallet::Wallet}; +use reth_node_optimism::node::OptimismNode; +use reth_primitives::{ChainSpecBuilder, Genesis, MAINNET}; + +#[tokio::test] +async fn can_sync() -> eyre::Result<()> { + reth_tracing::init_test_tracing(); + + let tasks = TaskManager::current(); + let exec = tasks.executor(); + + let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap(); + let chain_spec = Arc::new( + ChainSpecBuilder::default() + .chain(MAINNET.chain) + .genesis(genesis) + .cancun_activated() + .build(), + ); + + let network_config = NetworkArgs { + discovery: DiscoveryArgs { disable_discovery: true, ..DiscoveryArgs::default() }, + ..NetworkArgs::default() + }; + + let node_config = NodeConfig::test() + .with_chain(chain_spec) + .with_network(network_config) + .with_unused_ports() + .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); + + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config.clone()) + .testing_node(exec.clone()) + .node(OptimismNode::default()) + .launch() + .await?; + + let mut first_node = NodeHelper::new(node.clone()).await?; + + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) + .testing_node(exec) + .node(OptimismNode::default()) + .launch() + .await?; + + let mut second_node = NodeHelper::new(node).await?; + + let mut wallet = Wallet::default(); + let raw_tx = wallet.transfer_tx().await; + + // Make them peer + first_node.network.add_peer(second_node.network.record()).await; + second_node.network.add_peer(first_node.network.record()).await; + + // Make sure they establish a new session + first_node.network.expect_session().await; + second_node.network.expect_session().await; + + // Make the first node advance + let (block_hash, tx_hash) = + first_node.advance(raw_tx.clone(), optimism_payload_attributes).await?; + + // only send forkchoice update to second node + second_node.engine_api.update_forkchoice(block_hash).await?; + + // expect second node advanced via p2p gossip + second_node.assert_new_block(tx_hash, block_hash, 1).await?; + + Ok(()) +} diff --git a/crates/optimism/node/tests/e2e/utils.rs b/crates/optimism/node/tests/e2e/utils.rs new file mode 100644 index 000000000000..1f655502e67b --- /dev/null +++ b/crates/optimism/node/tests/e2e/utils.rs @@ -0,0 +1,22 @@ +use reth::rpc::types::engine::PayloadAttributes; +use reth_node_optimism::OptimismPayloadBuilderAttributes; +use reth_payload_builder::EthPayloadBuilderAttributes; +use reth_primitives::{Address, B256}; + +/// Helper function to create a new eth payload attributes +pub(crate) fn optimism_payload_attributes(timestamp: u64) -> OptimismPayloadBuilderAttributes { + let attributes = PayloadAttributes { + timestamp, + prev_randao: B256::ZERO, + suggested_fee_recipient: Address::ZERO, + withdrawals: Some(vec![]), + parent_beacon_block_root: Some(B256::ZERO), + }; + + OptimismPayloadBuilderAttributes { + payload_attributes: EthPayloadBuilderAttributes::new(B256::ZERO, attributes), + transactions: vec![], + no_tx_pool: false, + gas_limit: Some(30_000_000), + } +}