diff --git a/crates/e2e-test-utils/src/testsuite/actions.rs b/crates/e2e-test-utils/src/testsuite/actions.rs index a1fd24a584..98e11aafeb 100644 --- a/crates/e2e-test-utils/src/testsuite/actions.rs +++ b/crates/e2e-test-utils/src/testsuite/actions.rs @@ -20,7 +20,10 @@ use tracing::debug; /// Actions execute operations and potentially make assertions in a single step. /// The action name indicates what it does (e.g., `AssertMineBlock` would both /// mine a block and assert it worked). -pub trait Action: Send + 'static { +pub trait Action: Send + 'static +where + I: EngineTypes, +{ /// Executes the action fn execute<'a>(&'a mut self, env: &'a mut Environment) -> BoxFuture<'a, Result<()>>; } @@ -29,7 +32,10 @@ pub trait Action: Send + 'static { #[expect(missing_debug_implementations)] pub struct ActionBox(Box>); -impl ActionBox { +impl ActionBox +where + I: EngineTypes + 'static, +{ /// Constructor for [`ActionBox`]. pub fn new>(action: A) -> Self { Self(Box::new(action)) @@ -47,6 +53,7 @@ impl ActionBox { /// This allows using closures directly as actions with `.with_action(async move |env| {...})`. impl Action for F where + I: EngineTypes, F: FnMut(&Environment) -> Fut + Send + 'static, Fut: Future> + Send + 'static, { @@ -227,7 +234,8 @@ pub struct GeneratePayloadAttributes {} impl Action for GeneratePayloadAttributes where - Engine: EngineTypes, + Engine: EngineTypes + PayloadTypes, + Engine::PayloadAttributes: From, { fn execute<'a>(&'a mut self, env: &'a mut Environment) -> BoxFuture<'a, Result<()>> { Box::pin(async move { @@ -237,7 +245,7 @@ where .ok_or_else(|| eyre::eyre!("No latest block information available"))?; let block_number = latest_block.number; let timestamp = env.latest_header_time + env.block_timestamp_increment; - let payload_attributes = alloy_rpc_types_engine::PayloadAttributes { + let payload_attributes = PayloadAttributes { timestamp, prev_randao: B256::random(), suggested_fee_recipient: alloy_primitives::Address::random(), @@ -257,9 +265,8 @@ pub struct GenerateNextPayload {} impl Action for GenerateNextPayload where - Engine: EngineTypes + PayloadTypes, - reth_node_ethereum::engine::EthPayloadAttributes: - From<::ExecutionPayloadEnvelopeV3>, + Engine: EngineTypes + PayloadTypes, + Engine::PayloadAttributes: From + Clone, { fn execute<'a>(&'a mut self, env: &'a mut Environment) -> BoxFuture<'a, Result<()>> { Box::pin(async move { @@ -277,7 +284,7 @@ where finalized_block_hash: parent_hash, }; - let payload_attributes: PayloadAttributes = env + let payload_attributes = env .payload_attributes .get(&latest_block.number) .cloned() @@ -286,7 +293,7 @@ where let fcu_result = EngineApiClient::::fork_choice_updated_v3( &env.node_clients[0].engine.http_client(), fork_choice_state, - Some(payload_attributes.clone()), + Some(payload_attributes.clone().into()), ) .await?; @@ -301,12 +308,14 @@ where sleep(Duration::from_secs(1)).await; - let built_payload: PayloadAttributes = EngineApiClient::::get_payload_v3( + let _built_payload_envelope = EngineApiClient::::get_payload_v3( &env.node_clients[0].engine.http_client(), payload_id, ) - .await? - .into(); + .await?; + + // Store the payload attributes that were used to generate this payload + let built_payload = payload_attributes.clone(); env.payload_id_history.insert(latest_block.number + 1, payload_id); env.latest_payload_built = Some(built_payload); @@ -321,9 +330,8 @@ pub struct BroadcastLatestForkchoice {} impl Action for BroadcastLatestForkchoice where - Engine: EngineTypes + PayloadTypes, - reth_node_ethereum::engine::EthPayloadAttributes: - From<::ExecutionPayloadEnvelopeV3>, + Engine: EngineTypes + PayloadTypes, + Engine::PayloadAttributes: From + Clone, { fn execute<'a>(&'a mut self, env: &'a mut Environment) -> BoxFuture<'a, Result<()>> { Box::pin(async move { @@ -355,7 +363,7 @@ where match EngineApiClient::::fork_choice_updated_v3( &client.engine.http_client(), fork_choice_state, - payload.clone(), + payload.clone().map(|p| p.into()), ) .await { @@ -386,9 +394,8 @@ pub struct CheckPayloadAccepted {} impl Action for CheckPayloadAccepted where - Engine: EngineTypes - + PayloadTypes, - ExecutionPayloadEnvelopeV3: From<::ExecutionPayloadEnvelopeV3>, + Engine: EngineTypes, + Engine::ExecutionPayloadEnvelopeV3: Into, { fn execute<'a>(&'a mut self, env: &'a mut Environment) -> BoxFuture<'a, Result<()>> { Box::pin(async move { @@ -428,7 +435,7 @@ where ) .await?; - let execution_payload_envelope: ExecutionPayloadEnvelopeV3 = built_payload; + let execution_payload_envelope: ExecutionPayloadEnvelopeV3 = built_payload.into(); let new_payload_block_hash = execution_payload_envelope .execution_payload .payload_inner @@ -511,7 +518,8 @@ impl Default for ProduceBlocks { impl Action for ProduceBlocks where - Engine: EngineTypes, + Engine: EngineTypes + PayloadTypes, + Engine::PayloadAttributes: From + Clone, { fn execute<'a>(&'a mut self, env: &'a mut Environment) -> BoxFuture<'a, Result<()>> { Box::pin(async move { @@ -519,6 +527,9 @@ where let mut sequence = Sequence::new(vec![ Box::new(PickNextBlockProducer::default()), Box::new(GeneratePayloadAttributes::default()), + Box::new(GenerateNextPayload::default()), + Box::new(BroadcastNextNewPayload::default()), + Box::new(BroadcastLatestForkchoice::default()), ]); for _ in 0..self.num_blocks { sequence.execute(env).await?; @@ -542,7 +553,10 @@ impl Sequence { } } -impl Action for Sequence { +impl Action for Sequence +where + I: EngineTypes + Sync + Send + 'static, +{ fn execute<'a>(&'a mut self, env: &'a mut Environment) -> BoxFuture<'a, Result<()>> { Box::pin(async move { // Execute each action in sequence @@ -561,9 +575,8 @@ pub struct BroadcastNextNewPayload {} impl Action for BroadcastNextNewPayload where - Engine: EngineTypes + PayloadTypes, - reth_node_ethereum::engine::EthPayloadAttributes: - From<::ExecutionPayloadEnvelopeV3>, + Engine: EngineTypes + PayloadTypes, + Engine::PayloadAttributes: From + Clone, { fn execute<'a>(&'a mut self, env: &'a mut Environment) -> BoxFuture<'a, Result<()>> { Box::pin(async move { diff --git a/crates/e2e-test-utils/src/testsuite/mod.rs b/crates/e2e-test-utils/src/testsuite/mod.rs index 0cea19f28a..6729bf609c 100644 --- a/crates/e2e-test-utils/src/testsuite/mod.rs +++ b/crates/e2e-test-utils/src/testsuite/mod.rs @@ -8,7 +8,7 @@ use alloy_primitives::B256; use eyre::Result; use jsonrpsee::http_client::HttpClient; use reth_engine_local::LocalPayloadAttributesBuilder; -use reth_node_api::{NodeTypes, PayloadTypes}; +use reth_node_api::{EngineTypes, NodeTypes, PayloadTypes}; use reth_payload_builder::PayloadId; use std::{collections::HashMap, marker::PhantomData}; pub mod actions; @@ -46,7 +46,10 @@ pub struct LatestBlockInfo { } /// Represents a test environment. #[derive(Debug)] -pub struct Environment { +pub struct Environment +where + I: EngineTypes, +{ /// Combined clients with both RPC and Engine API endpoints pub node_clients: Vec, /// Tracks instance generic. @@ -77,7 +80,10 @@ pub struct Environment { pub slots_to_finalized: u64, } -impl Default for Environment { +impl Default for Environment +where + I: EngineTypes, +{ fn default() -> Self { Self { node_clients: vec![], @@ -100,17 +106,31 @@ impl Default for Environment { /// Builder for creating test scenarios #[expect(missing_debug_implementations)] -#[derive(Default)] -pub struct TestBuilder { +pub struct TestBuilder +where + I: EngineTypes, +{ setup: Option>, actions: Vec>, env: Environment, } -impl TestBuilder { +impl Default for TestBuilder +where + I: EngineTypes, +{ + fn default() -> Self { + Self { setup: None, actions: Vec::new(), env: Default::default() } + } +} + +impl TestBuilder +where + I: EngineTypes + 'static, +{ /// Create a new test builder pub fn new() -> Self { - Self { setup: None, actions: Vec::new(), env: Default::default() } + Self::default() } /// Set the test setup diff --git a/crates/e2e-test-utils/src/testsuite/setup.rs b/crates/e2e-test-utils/src/testsuite/setup.rs index f6450bd93d..85827cc699 100644 --- a/crates/e2e-test-utils/src/testsuite/setup.rs +++ b/crates/e2e-test-utils/src/testsuite/setup.rs @@ -9,7 +9,7 @@ use eyre::{eyre, Result}; use reth_chainspec::ChainSpec; use reth_engine_local::LocalPayloadAttributesBuilder; use reth_ethereum_primitives::Block; -use reth_node_api::{NodeTypes, PayloadTypes}; +use reth_node_api::{EngineTypes, NodeTypes, PayloadTypes}; use reth_node_core::primitives::RecoveredBlock; use reth_payload_builder::EthPayloadBuilderAttributes; use reth_rpc_api::clients::EthApiClient; @@ -66,7 +66,10 @@ impl Drop for Setup { } } -impl Setup { +impl Setup +where + I: EngineTypes, +{ /// Create a new setup with default values pub fn new() -> Self { Self::default()