Skip to content

Commit 4cc50f9

Browse files
authored
feat(e2e): add beacon consensus handle to NodeClient (#18632)
1 parent 064694b commit 4cc50f9

File tree

5 files changed

+70
-26
lines changed

5 files changed

+70
-26
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/e2e-test-utils/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ reth-tokio-util.workspace = true
3131
reth-stages-types.workspace = true
3232
reth-network-peers.workspace = true
3333
reth-engine-local.workspace = true
34+
reth-engine-primitives.workspace = true
3435
reth-tasks.workspace = true
3536
reth-node-ethereum.workspace = true
3637
reth-ethereum-primitives.workspace = true

crates/e2e-test-utils/src/node.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,4 +305,20 @@ where
305305
pub fn auth_server_handle(&self) -> AuthServerHandle {
306306
self.inner.auth_server_handle().clone()
307307
}
308+
309+
/// Creates a [`crate::testsuite::NodeClient`] from this test context.
310+
///
311+
/// This helper method extracts the necessary handles and creates a client
312+
/// that can interact with both the regular RPC and Engine API endpoints.
313+
/// It automatically includes the beacon engine handle for direct consensus engine interaction.
314+
pub fn to_node_client(&self) -> eyre::Result<crate::testsuite::NodeClient<Payload>> {
315+
let rpc = self
316+
.rpc_client()
317+
.ok_or_else(|| eyre::eyre!("Failed to create HTTP RPC client for node"))?;
318+
let auth = self.auth_server_handle();
319+
let url = self.rpc_url();
320+
let beacon_handle = self.inner.add_ons_handle.beacon_engine_handle.clone();
321+
322+
Ok(crate::testsuite::NodeClient::new_with_beacon_engine(rpc, auth, url, beacon_handle))
323+
}
308324
}

crates/e2e-test-utils/src/testsuite/mod.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,48 @@ pub mod setup;
1616
use crate::testsuite::setup::Setup;
1717
use alloy_provider::{Provider, ProviderBuilder};
1818
use alloy_rpc_types_engine::{ForkchoiceState, PayloadAttributes};
19+
use reth_engine_primitives::ConsensusEngineHandle;
1920
use reth_rpc_builder::auth::AuthServerHandle;
2021
use std::sync::Arc;
2122
use url::Url;
2223

2324
/// Client handles for both regular RPC and Engine API endpoints
2425
#[derive(Clone)]
25-
pub struct NodeClient {
26+
pub struct NodeClient<Payload>
27+
where
28+
Payload: PayloadTypes,
29+
{
2630
/// Regular JSON-RPC client
2731
pub rpc: HttpClient,
2832
/// Engine API client
2933
pub engine: AuthServerHandle,
34+
/// Beacon consensus engine handle for direct interaction with the consensus engine
35+
pub beacon_engine_handle: Option<ConsensusEngineHandle<Payload>>,
3036
/// Alloy provider for interacting with the node
3137
provider: Arc<dyn Provider + Send + Sync>,
3238
}
3339

34-
impl NodeClient {
40+
impl<Payload> NodeClient<Payload>
41+
where
42+
Payload: PayloadTypes,
43+
{
3544
/// Instantiates a new [`NodeClient`] with the given handles and RPC URL
3645
pub fn new(rpc: HttpClient, engine: AuthServerHandle, url: Url) -> Self {
3746
let provider =
3847
Arc::new(ProviderBuilder::new().connect_http(url)) as Arc<dyn Provider + Send + Sync>;
39-
Self { rpc, engine, provider }
48+
Self { rpc, engine, beacon_engine_handle: None, provider }
49+
}
50+
51+
/// Instantiates a new [`NodeClient`] with the given handles, RPC URL, and beacon engine handle
52+
pub fn new_with_beacon_engine(
53+
rpc: HttpClient,
54+
engine: AuthServerHandle,
55+
url: Url,
56+
beacon_engine_handle: ConsensusEngineHandle<Payload>,
57+
) -> Self {
58+
let provider =
59+
Arc::new(ProviderBuilder::new().connect_http(url)) as Arc<dyn Provider + Send + Sync>;
60+
Self { rpc, engine, beacon_engine_handle: Some(beacon_engine_handle), provider }
4061
}
4162

4263
/// Get a block by number using the alloy provider
@@ -56,11 +77,15 @@ impl NodeClient {
5677
}
5778
}
5879

59-
impl std::fmt::Debug for NodeClient {
80+
impl<Payload> std::fmt::Debug for NodeClient<Payload>
81+
where
82+
Payload: PayloadTypes,
83+
{
6084
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6185
f.debug_struct("NodeClient")
6286
.field("rpc", &self.rpc)
6387
.field("engine", &self.engine)
88+
.field("beacon_engine_handle", &self.beacon_engine_handle.is_some())
6489
.field("provider", &"<Provider>")
6590
.finish()
6691
}
@@ -152,7 +177,7 @@ where
152177
I: EngineTypes,
153178
{
154179
/// Combined clients with both RPC and Engine API endpoints
155-
pub node_clients: Vec<NodeClient>,
180+
pub node_clients: Vec<NodeClient<I>>,
156181
/// Per-node state tracking
157182
pub node_states: Vec<NodeState<I>>,
158183
/// Tracks instance generic.
@@ -323,7 +348,7 @@ where
323348
/// Run the test scenario
324349
pub async fn run<N>(mut self) -> Result<()>
325350
where
326-
N: NodeBuilderHelper,
351+
N: NodeBuilderHelper<Payload = I>,
327352
LocalPayloadAttributesBuilder<N::ChainSpec>: PayloadAttributesBuilder<
328353
<<N as NodeTypes>::Payload as PayloadTypes>::PayloadAttributes,
329354
>,

crates/e2e-test-utils/src/testsuite/setup.rs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ where
142142
rlp_path: &Path,
143143
) -> Result<()>
144144
where
145-
N: NodeBuilderHelper,
145+
N: NodeBuilderHelper<Payload = I>,
146146
LocalPayloadAttributesBuilder<N::ChainSpec>: PayloadAttributesBuilder<
147147
<<N as NodeTypes>::Payload as PayloadTypes>::PayloadAttributes,
148148
>,
@@ -158,7 +158,7 @@ where
158158
rlp_path: &Path,
159159
) -> Result<()>
160160
where
161-
N: NodeBuilderHelper,
161+
N: NodeBuilderHelper<Payload = I>,
162162
LocalPayloadAttributesBuilder<N::ChainSpec>: PayloadAttributesBuilder<
163163
<<N as NodeTypes>::Payload as PayloadTypes>::PayloadAttributes,
164164
>,
@@ -175,6 +175,7 @@ where
175175
.ok_or_else(|| eyre!("Failed to create HTTP RPC client for node"))?;
176176
let auth = node.auth_server_handle();
177177
let url = node.rpc_url();
178+
// TODO: Pass beacon_engine_handle once import system supports generic types
178179
node_clients.push(crate::testsuite::NodeClient::new(rpc, auth, url));
179180
}
180181

@@ -189,7 +190,7 @@ where
189190
/// Apply the setup to the environment
190191
pub async fn apply<N>(&mut self, env: &mut Environment<I>) -> Result<()>
191192
where
192-
N: NodeBuilderHelper,
193+
N: NodeBuilderHelper<Payload = I>,
193194
LocalPayloadAttributesBuilder<N::ChainSpec>: PayloadAttributesBuilder<
194195
<<N as NodeTypes>::Payload as PayloadTypes>::PayloadAttributes,
195196
>,
@@ -201,7 +202,7 @@ where
201202
/// Apply the setup to the environment
202203
async fn apply_<N>(&mut self, env: &mut Environment<I>) -> Result<()>
203204
where
204-
N: NodeBuilderHelper,
205+
N: NodeBuilderHelper<Payload = I>,
205206
LocalPayloadAttributesBuilder<N::ChainSpec>: PayloadAttributesBuilder<
206207
<<N as NodeTypes>::Payload as PayloadTypes>::PayloadAttributes,
207208
>,
@@ -236,13 +237,7 @@ where
236237
Ok((nodes, executor, _wallet)) => {
237238
// create HTTP clients for each node's RPC and Engine API endpoints
238239
for node in &nodes {
239-
let rpc = node
240-
.rpc_client()
241-
.ok_or_else(|| eyre!("Failed to create HTTP RPC client for node"))?;
242-
let auth = node.auth_server_handle();
243-
let url = node.rpc_url();
244-
245-
node_clients.push(crate::testsuite::NodeClient::new(rpc, auth, url));
240+
node_clients.push(node.to_node_client()?);
246241
}
247242

248243
// spawn a separate task just to handle the shutdown
@@ -274,7 +269,7 @@ where
274269
rlp_path: &Path,
275270
) -> Result<crate::setup_import::ChainImportResult>
276271
where
277-
N: NodeBuilderHelper,
272+
N: NodeBuilderHelper<Payload = I>,
278273
LocalPayloadAttributesBuilder<N::ChainSpec>: PayloadAttributesBuilder<
279274
<<N as NodeTypes>::Payload as PayloadTypes>::PayloadAttributes,
280275
>,
@@ -309,7 +304,7 @@ where
309304
&self,
310305
) -> impl Fn(u64) -> <<N as NodeTypes>::Payload as PayloadTypes>::PayloadBuilderAttributes + Copy
311306
where
312-
N: NodeBuilderHelper,
307+
N: NodeBuilderHelper<Payload = I>,
313308
LocalPayloadAttributesBuilder<N::ChainSpec>: PayloadAttributesBuilder<
314309
<<N as NodeTypes>::Payload as PayloadTypes>::PayloadAttributes,
315310
>,
@@ -332,7 +327,7 @@ where
332327
async fn finalize_setup(
333328
&self,
334329
env: &mut Environment<I>,
335-
node_clients: Vec<crate::testsuite::NodeClient>,
330+
node_clients: Vec<crate::testsuite::NodeClient<I>>,
336331
use_latest_block: bool,
337332
) -> Result<()> {
338333
if node_clients.is_empty() {
@@ -394,10 +389,13 @@ where
394389
}
395390

396391
/// Wait for all nodes to be ready to accept RPC requests
397-
async fn wait_for_nodes_ready(
392+
async fn wait_for_nodes_ready<P>(
398393
&self,
399-
node_clients: &[crate::testsuite::NodeClient],
400-
) -> Result<()> {
394+
node_clients: &[crate::testsuite::NodeClient<P>],
395+
) -> Result<()>
396+
where
397+
P: PayloadTypes,
398+
{
401399
for (idx, client) in node_clients.iter().enumerate() {
402400
let mut retry_count = 0;
403401
const MAX_RETRIES: usize = 10;
@@ -423,11 +421,14 @@ where
423421
}
424422

425423
/// Get block info for a given block number or tag
426-
async fn get_block_info(
424+
async fn get_block_info<P>(
427425
&self,
428-
client: &crate::testsuite::NodeClient,
426+
client: &crate::testsuite::NodeClient<P>,
429427
block: BlockNumberOrTag,
430-
) -> Result<crate::testsuite::BlockInfo> {
428+
) -> Result<crate::testsuite::BlockInfo>
429+
where
430+
P: PayloadTypes,
431+
{
431432
let block = client
432433
.get_block_by_number(block)
433434
.await?

0 commit comments

Comments
 (0)