Skip to content

Commit 342b828

Browse files
prestwichclaude
andcommitted
fix(node-tests): adapt test infra to HostNotifier trait
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6663b5e commit 342b828

7 files changed

Lines changed: 147 additions & 174 deletions

File tree

crates/node-tests/Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ homepage.workspace = true
99
repository.workspace = true
1010

1111
[dependencies]
12+
signet-blobber = { workspace = true, features = ["test-utils"] }
1213
signet-node.workspace = true
1314
signet-node-config = { workspace = true, features = ["test_utils"] }
15+
signet-node-types.workspace = true
1416

1517
signet-cold = { workspace = true, features = ["in-memory"] }
1618
signet-constants.workspace = true
17-
signet-evm.workspace = true
1819
signet-genesis.workspace = true
1920
signet-hot = { workspace = true, features = ["in-memory"] }
2021
signet-storage.workspace = true
@@ -26,11 +27,11 @@ signet-zenith.workspace = true
2627
alloy.workspace = true
2728

2829
reth.workspace = true
29-
reth-exex.workspace = true
3030
reth-exex-test-utils.workspace = true
31-
reth-node-api.workspace = true
3231

3332
eyre.workspace = true
33+
reqwest.workspace = true
34+
signet-rpc.workspace = true
3435
tokio.workspace = true
3536
tracing.workspace = true
3637
tracing-subscriber.workspace = true

crates/node-tests/src/context.rs

Lines changed: 87 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
HostBlockSpec, NotificationSpec, NotificationWithSidecars, RuBlockSpec,
3-
convert::ToRethPrimitive,
3+
convert::to_host_notification,
44
types::{CtxProvider, Log, TestCounterInstance, TestErc20Instance, TestLogInstance},
55
};
66
use alloy::{
@@ -14,36 +14,79 @@ use alloy::{
1414
},
1515
rpc::types::eth::{TransactionReceipt, TransactionRequest},
1616
};
17-
use reth::transaction_pool::{TransactionOrigin, TransactionPool, test_utils::MockTransaction};
18-
use reth_exex_test_utils::{Adapter, TestExExHandle};
19-
use reth_node_api::FullNodeComponents;
17+
use reth::{
18+
api::FullNodeComponents,
19+
transaction_pool::{TransactionOrigin, TransactionPool, test_utils::MockTransaction},
20+
};
21+
use reth_exex_test_utils::Adapter;
2022
use signet_cold::{ColdStorageReadHandle, mem::MemColdBackend};
2123
use signet_hot::{
2224
db::{HotDbRead, UnsafeDbWrite},
2325
mem::MemKv,
2426
};
2527
use signet_node::{NodeStatus, SignetNodeBuilder};
2628
use signet_node_config::test_utils::test_config;
29+
use signet_node_types::{HostNotification, HostNotifier};
30+
use signet_rpc::{ServeConfig, StorageRpcConfig};
2731
use signet_storage::{CancellationToken, HistoryRead, HistoryWrite, HotKv, UnifiedStorage};
2832
use signet_storage_types::{Account, BlockNumberList, DbSignetEvent, RecoveredTx, SealedHeader};
29-
use signet_test_utils::contracts::counter::COUNTER_DEPLOY_CODE;
33+
use signet_test_utils::{chain::Chain, contracts::counter::COUNTER_DEPLOY_CODE};
3034
use signet_types::constants::{HostPermitted, RollupPermitted, SignetSystemConstants};
3135
use signet_zenith::{HostOrders::OrdersInstance, RollupPassage::RollupPassageInstance};
3236
use std::sync::{
3337
Arc, Mutex,
3438
atomic::{AtomicU64, Ordering},
3539
};
36-
use tokio::{sync::watch, task::JoinHandle};
40+
use tokio::sync::{mpsc, watch};
41+
use tokio::task::JoinHandle;
3742
use tracing::instrument;
3843

44+
/// A channel-backed [`HostNotifier`] for integration tests.
45+
///
46+
/// Receives [`HostNotification`]s from the test harness and yields them
47+
/// to the signet node's main loop.
48+
pub struct TestHostNotifier {
49+
receiver: mpsc::UnboundedReceiver<HostNotification<Chain>>,
50+
}
51+
52+
impl TestHostNotifier {
53+
/// Create a new test notifier from a receiver.
54+
pub const fn new(receiver: mpsc::UnboundedReceiver<HostNotification<Chain>>) -> Self {
55+
Self { receiver }
56+
}
57+
}
58+
59+
impl core::fmt::Debug for TestHostNotifier {
60+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
61+
f.debug_struct("TestHostNotifier").finish_non_exhaustive()
62+
}
63+
}
64+
65+
impl HostNotifier for TestHostNotifier {
66+
type Chain = Chain;
67+
type Error = core::convert::Infallible;
68+
69+
async fn next_notification(
70+
&mut self,
71+
) -> Option<Result<HostNotification<Self::Chain>, Self::Error>> {
72+
self.receiver.recv().await.map(Ok)
73+
}
74+
75+
fn set_head(&mut self, _block_number: u64) {}
76+
77+
fn set_backfill_thresholds(&mut self, _max_blocks: Option<u64>) {}
78+
79+
fn send_finished_height(&self, _block_number: u64) -> Result<(), Self::Error> {
80+
Ok(())
81+
}
82+
}
83+
3984
/// Signet Node test context
4085
///
4186
/// This contains the following:
4287
///
43-
/// - Reth/ExEx context info
44-
/// - The test exex handle, which is used to send notifications to the signet
45-
/// instance.
46-
/// - The components for the Signet Node instance
88+
/// - A channel sender for host notifications
89+
/// - The reth test components (for pool access)
4790
/// - A receiver for the node status (latest block processed)
4891
/// - Unified storage backed by in-memory hot and cold storage
4992
/// - An alloy provider connected to the Signet Node RPC,
@@ -52,10 +95,10 @@ use tracing::instrument;
5295
/// - A set of addresses for testing, each of which has a pre-existing balance
5396
/// on the Signet Node chain.
5497
pub struct SignetTestContext {
55-
/// The test exex handle
56-
pub handle: TestExExHandle,
98+
/// The notification sender for the test host notifier.
99+
pub sender: mpsc::UnboundedSender<HostNotification<Chain>>,
57100

58-
/// The components for the Signet Node instance
101+
/// The reth test components (for pool access).
59102
pub components: Adapter,
60103

61104
/// The Signet Node status receiver
@@ -101,7 +144,7 @@ impl SignetTestContext {
101144
#[instrument]
102145
pub async fn new() -> (Self, JoinHandle<eyre::Result<()>>) {
103146
let cfg = test_config();
104-
let (ctx, handle) = reth_exex_test_utils::test_exex_context().await.unwrap();
147+
let (ctx, _handle) = reth_exex_test_utils::test_exex_context().await.unwrap();
105148
let components = ctx.components.clone();
106149

107150
// set up Signet Node storage
@@ -148,10 +191,36 @@ impl SignetTestContext {
148191

149192
let alias_oracle: Arc<Mutex<HashSet<Address>>> = Arc::new(Mutex::new(HashSet::default()));
150193

194+
// Create the test host notifier channel
195+
let (sender, receiver) = mpsc::unbounded_channel();
196+
let notifier = TestHostNotifier { receiver };
197+
198+
// Build the blob cacher from the reth test pool
199+
let blob_cacher = signet_blobber::BlobFetcher::builder()
200+
.with_config(cfg.block_extractor())
201+
.unwrap()
202+
.with_pool(components.pool().clone())
203+
.with_client(reqwest::Client::new())
204+
.build_cache()
205+
.unwrap()
206+
.spawn();
207+
208+
// Build ServeConfig from the test config's IPC endpoint
209+
let serve_config = ServeConfig {
210+
http: vec![],
211+
http_cors: None,
212+
ws: vec![],
213+
ws_cors: None,
214+
ipc: cfg.ipc_endpoint().map(ToOwned::to_owned),
215+
};
216+
151217
let (node, mut node_status) = SignetNodeBuilder::new(cfg.clone())
152-
.with_ctx(ctx)
218+
.with_notifier(notifier)
153219
.with_storage(Arc::clone(&storage))
154220
.with_alias_oracle(Arc::clone(&alias_oracle))
221+
.with_blob_cacher(blob_cacher)
222+
.with_serve_config(serve_config)
223+
.with_rpc_config(StorageRpcConfig::default())
155224
.build()
156225
.await
157226
.unwrap();
@@ -179,7 +248,7 @@ impl SignetTestContext {
179248
.unwrap();
180249

181250
let this = Self {
182-
handle,
251+
sender,
183252
components,
184253
node_status,
185254
storage,
@@ -284,7 +353,8 @@ impl SignetTestContext {
284353
assert!(pool.get_blob(tx_hash).unwrap().is_some(), "Missing blob we just inserted");
285354
}
286355

287-
self.handle.notifications_tx.send(notification.notification.to_reth()).await.unwrap();
356+
let host_notification = to_host_notification(&notification.notification);
357+
self.sender.send(host_notification).unwrap();
288358
}
289359

290360
/// Send a notification to the Signet Node instance and wait for it to be

crates/node-tests/src/convert.rs

Lines changed: 21 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,26 @@
1-
use alloy::consensus::ReceiptEnvelope;
2-
use signet_evm::ExecutionOutcome;
3-
use signet_types::primitives::{RecoveredBlock, SealedBlock};
1+
use signet_node_types::{HostNotification, HostNotificationKind};
2+
use signet_test_utils::chain::Chain;
43
use std::sync::Arc;
54

6-
/// Utility trait to convert a type to a Reth primitive type.
7-
/// This is used mainly where we need to convert to a reth primitive type
8-
/// because reth does not support the alloy equivalents.
9-
pub trait ToRethPrimitive {
10-
/// The Reth primitive type that the type can be converted to.
11-
type RethPrimitive;
12-
13-
/// Convert the type to a Reth primitive type.
14-
fn to_reth(self) -> Self::RethPrimitive;
15-
}
16-
17-
// Reth does not preserve envelope status for receipts, so
18-
// the DB model will not support envelopes.
19-
impl ToRethPrimitive for ReceiptEnvelope {
20-
type RethPrimitive = reth::primitives::Receipt;
21-
22-
fn to_reth(self) -> Self::RethPrimitive {
23-
let success = self.is_success();
24-
let cumulative_gas_used = self.cumulative_gas_used();
25-
let tx_type = match self.tx_type() {
26-
alloy::consensus::TxType::Legacy => reth::primitives::TxType::Legacy,
27-
alloy::consensus::TxType::Eip2930 => reth::primitives::TxType::Eip2930,
28-
alloy::consensus::TxType::Eip1559 => reth::primitives::TxType::Eip1559,
29-
alloy::consensus::TxType::Eip4844 => reth::primitives::TxType::Eip4844,
30-
alloy::consensus::TxType::Eip7702 => reth::primitives::TxType::Eip7702,
31-
};
32-
33-
let r = match self {
34-
ReceiptEnvelope::Legacy(r)
35-
| ReceiptEnvelope::Eip2930(r)
36-
| ReceiptEnvelope::Eip1559(r)
37-
| ReceiptEnvelope::Eip4844(r) => r,
38-
_ => panic!("unsupported receipt type"),
39-
};
40-
41-
reth::primitives::Receipt { tx_type, success, cumulative_gas_used, logs: r.receipt.logs }
42-
}
43-
}
44-
45-
impl ToRethPrimitive for SealedBlock {
46-
type RethPrimitive = reth::primitives::SealedBlock<reth::primitives::Block>;
47-
48-
fn to_reth(self) -> Self::RethPrimitive {
49-
let hash = self.header.hash();
50-
let header = self.header.into_inner();
51-
let body = reth::primitives::BlockBody {
52-
transactions: self.transactions,
53-
ommers: vec![],
54-
withdrawals: None,
55-
};
56-
reth::primitives::SealedBlock::new_unchecked(
57-
reth::primitives::Block::new(header, body),
58-
hash,
59-
)
60-
}
61-
}
62-
63-
impl ToRethPrimitive for RecoveredBlock {
64-
type RethPrimitive = reth::primitives::RecoveredBlock<reth::primitives::Block>;
65-
66-
fn to_reth(self) -> Self::RethPrimitive {
67-
let hash = self.header.hash();
68-
let senders: Vec<_> = self.senders().collect();
69-
let header = self.header.into_inner();
70-
let transactions = self.transactions.into_iter().map(|r| r.into_inner()).collect();
71-
let body = reth::primitives::BlockBody { transactions, ommers: vec![], withdrawals: None };
72-
let block = reth::primitives::Block::new(header, body);
73-
reth::primitives::RecoveredBlock::new(block, senders, hash)
74-
}
75-
}
76-
77-
impl ToRethPrimitive for signet_test_utils::chain::Chain {
78-
type RethPrimitive = reth::providers::Chain;
79-
80-
fn to_reth(self) -> Self::RethPrimitive {
81-
reth::providers::Chain::new(
82-
self.blocks.to_reth(),
83-
self.execution_outcome.to_reth(),
84-
Default::default(),
85-
)
86-
}
87-
}
88-
89-
impl<T> ToRethPrimitive for Vec<T>
90-
where
91-
T: ToRethPrimitive,
92-
{
93-
type RethPrimitive = Vec<T::RethPrimitive>;
94-
95-
fn to_reth(self) -> Self::RethPrimitive {
96-
self.into_iter().map(ToRethPrimitive::to_reth).collect()
97-
}
98-
}
99-
100-
impl ToRethPrimitive for ExecutionOutcome {
101-
type RethPrimitive = reth::providers::ExecutionOutcome;
102-
103-
fn to_reth(self) -> Self::RethPrimitive {
104-
let (bundle, receipts, first_block) = self.into_parts();
105-
106-
reth::providers::ExecutionOutcome {
107-
bundle,
108-
receipts: receipts.into_iter().map(ToRethPrimitive::to_reth).collect(),
109-
first_block,
110-
requests: vec![],
5+
/// Convert a test [`ExExNotification`] into a [`HostNotification`].
6+
///
7+
/// Safe and finalized block numbers are set to `None` since the test
8+
/// harness does not exercise block tag logic.
9+
///
10+
/// [`ExExNotification`]: signet_test_utils::specs::ExExNotification
11+
pub fn to_host_notification(
12+
notif: &signet_test_utils::specs::ExExNotification,
13+
) -> HostNotification<Chain> {
14+
let kind = match notif {
15+
signet_test_utils::specs::ExExNotification::Committed { new } => {
16+
HostNotificationKind::ChainCommitted { new: Arc::clone(new) }
11117
}
112-
}
113-
}
114-
115-
impl ToRethPrimitive for signet_test_utils::specs::ExExNotification {
116-
type RethPrimitive = reth_exex::ExExNotification;
117-
118-
fn to_reth(self) -> Self::RethPrimitive {
119-
match self {
120-
signet_test_utils::specs::ExExNotification::Committed { new } => {
121-
reth_exex::ExExNotification::ChainCommitted { new: new.to_reth() }
122-
}
123-
signet_test_utils::specs::ExExNotification::Reorged { old, new } => {
124-
reth_exex::ExExNotification::ChainReorged { old: old.to_reth(), new: new.to_reth() }
125-
}
126-
signet_test_utils::specs::ExExNotification::Reverted { old } => {
127-
reth_exex::ExExNotification::ChainReverted { old: old.to_reth() }
128-
}
18+
signet_test_utils::specs::ExExNotification::Reorged { old, new } => {
19+
HostNotificationKind::ChainReorged { old: Arc::clone(old), new: Arc::clone(new) }
12920
}
130-
}
131-
}
132-
133-
impl<T: ToRethPrimitive + Clone> ToRethPrimitive for Arc<T> {
134-
type RethPrimitive = Arc<T::RethPrimitive>;
135-
136-
fn to_reth(self) -> Self::RethPrimitive {
137-
Arc::new(ToRethPrimitive::to_reth((*self).clone()))
138-
}
139-
}
140-
141-
impl<T: Clone + ToRethPrimitive> ToRethPrimitive for &T {
142-
type RethPrimitive = T::RethPrimitive;
143-
144-
fn to_reth(self) -> Self::RethPrimitive {
145-
ToRethPrimitive::to_reth(self.clone())
146-
}
21+
signet_test_utils::specs::ExExNotification::Reverted { old } => {
22+
HostNotificationKind::ChainReverted { old: Arc::clone(old) }
23+
}
24+
};
25+
HostNotification { kind, safe_block_number: None, finalized_block_number: None }
14726
}

crates/node-tests/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ pub mod constants;
1616

1717
/// Test context.
1818
mod context;
19-
pub use context::{BalanceChecks, NonceChecks, SignetTestContext};
19+
pub use context::{BalanceChecks, NonceChecks, SignetTestContext, TestHostNotifier};
2020

21-
/// Bespoke conversion utilities for converting between alloy and reth types.
21+
/// Conversion utilities for test notifications.
2222
pub mod convert;
2323

2424
/// Signet node RPC server utilities and helpers.
@@ -32,7 +32,7 @@ pub mod types;
3232
pub mod utils;
3333
pub use utils::run_test;
3434

35-
pub use reth_exex_test_utils::{Adapter, TestExExContext};
35+
pub use reth_exex_test_utils::Adapter;
3636
pub use signet_test_utils::specs::{
3737
HostBlockSpec, NotificationSpec, NotificationWithSidecars, RuBlockSpec,
3838
};

0 commit comments

Comments
 (0)