Skip to content

Commit 7eaf491

Browse files
committed
refactor test_batch_revert_gap with test fixture
1 parent 32587a2 commit 7eaf491

File tree

5 files changed

+218
-163
lines changed

5 files changed

+218
-163
lines changed

crates/chain-orchestrator/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -826,8 +826,7 @@ impl<
826826
missing_index,
827827
l1_block_number_reset
828828
);
829-
// TODO: getting channel closed here
830-
// self.l1_watcher_handle.trigger_gap_recovery(l1_block_number_reset).await;
829+
self.l1_watcher_handle.trigger_gap_recovery(l1_block_number_reset).await;
831830
}
832831
Some(BatchCommitDuplicate(index)) => {
833832
tracing::info!(

crates/node/src/test_utils/event_utils.rs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ impl<'a> EventWaiter<'a> {
134134
self.wait_for_event_on_all(|e| {
135135
if let ChainOrchestratorEvent::L1MessageGap { missing_index, l1_block_number_reset } = e
136136
{
137-
(*missing_index == expected_missing_index
138-
&& *l1_block_number_reset == expected_l1_block_number_reset)
137+
(*missing_index == expected_missing_index &&
138+
*l1_block_number_reset == expected_l1_block_number_reset)
139139
.then_some(())
140140
} else {
141141
None
@@ -177,10 +177,16 @@ impl<'a> EventWaiter<'a> {
177177
}
178178

179179
/// Wait for batch commit indexed event on all specified nodes.
180-
pub async fn batch_commit_indexed(self, target_batch_index: u64, target_l1_block_number: u64) -> eyre::Result<()> {
180+
pub async fn batch_commit_indexed(
181+
self,
182+
target_batch_index: u64,
183+
target_l1_block_number: u64,
184+
) -> eyre::Result<()> {
181185
self.wait_for_event_on_all(|e| {
182-
if let ChainOrchestratorEvent::BatchCommitIndexed {batch_info, l1_block_number} = e {
183-
(batch_info.index == target_batch_index && *l1_block_number == target_l1_block_number).then_some(())
186+
if let ChainOrchestratorEvent::BatchCommitIndexed { batch_info, l1_block_number } = e {
187+
(batch_info.index == target_batch_index &&
188+
*l1_block_number == target_l1_block_number)
189+
.then_some(())
184190
} else {
185191
None
186192
}
@@ -212,8 +218,42 @@ impl<'a> EventWaiter<'a> {
212218
if let ChainOrchestratorEvent::BatchCommitGap { missing_index, l1_block_number_reset } =
213219
e
214220
{
215-
(*missing_index == expected_missing_index
216-
&& *l1_block_number_reset == expected_l1_block_number_reset)
221+
(*missing_index == expected_missing_index &&
222+
*l1_block_number_reset == expected_l1_block_number_reset)
223+
.then_some(())
224+
} else {
225+
None
226+
}
227+
})
228+
.await?;
229+
Ok(())
230+
}
231+
232+
/// Wait for batch revert duplicate event on all specified nodes.
233+
pub async fn batch_revert_duplicate(self, expected_index: u64) -> eyre::Result<()> {
234+
self.wait_for_event_on_all(|e| {
235+
if let ChainOrchestratorEvent::BatchRevertDuplicate(index) = e {
236+
(*index == expected_index).then_some(())
237+
} else {
238+
None
239+
}
240+
})
241+
.await?;
242+
Ok(())
243+
}
244+
245+
/// Wait for batch revert gap event on all specified nodes.
246+
pub async fn batch_revert_gap(
247+
self,
248+
expected_missing_index: u64,
249+
expected_l1_block_number_reset: u64,
250+
) -> eyre::Result<()> {
251+
self.wait_for_event_on_all(|e| {
252+
if let ChainOrchestratorEvent::BatchRevertGap { missing_index, l1_block_number_reset } =
253+
e
254+
{
255+
(*missing_index == expected_missing_index &&
256+
*l1_block_number_reset == expected_l1_block_number_reset)
217257
.then_some(())
218258
} else {
219259
None

crates/node/src/test_utils/fixture.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ impl NodeHandle {
9898
pub const fn is_follower(&self) -> bool {
9999
matches!(self.typ, NodeType::Follower)
100100
}
101+
102+
/// Update the L1 watcher notification sender.
103+
///
104+
/// This is used after gap recovery to update the sender to the new channel
105+
/// that the `ChainOrchestrator` is now listening on.
106+
pub fn set_l1_watcher_tx(&mut self, tx: mpsc::Sender<Arc<L1Notification>>) {
107+
self.l1_watcher_tx = Some(tx);
108+
}
101109
}
102110

103111
impl Debug for NodeHandle {
@@ -225,6 +233,41 @@ impl TestFixture {
225233
.map_err(|_| eyre::eyre!("Timeout waiting for L1 watcher command"))?
226234
.ok_or_else(|| eyre::eyre!("L1 watcher command channel closed"))
227235
}
236+
237+
/// Process an L1 watcher reset command and update the notification sender.
238+
///
239+
/// After a gap is detected, the `ChainOrchestrator` calls `trigger_gap_recovery` which
240+
/// creates a new notification channel and sends the new sender via the command channel.
241+
/// This method reads that command and updates the test fixture's `l1_watcher_tx` so
242+
/// subsequent L1 notifications can be sent to the `ChainOrchestrator`.
243+
///
244+
/// Returns the block number that the L1 watcher should reset to.
245+
pub async fn process_gap_recovery_command(&mut self) -> eyre::Result<u64> {
246+
self.process_gap_recovery_command_on(0).await
247+
}
248+
249+
/// Process an L1 watcher reset command on a specific node.
250+
///
251+
/// See [`Self::process_gap_recovery_command`] for details.
252+
pub async fn process_gap_recovery_command_on(
253+
&mut self,
254+
node_index: usize,
255+
) -> eyre::Result<u64> {
256+
let command = {
257+
let mut command_rx = self.nodes[node_index].l1_watcher_command_rx.lock().await;
258+
tokio::time::timeout(Duration::from_secs(5), command_rx.recv())
259+
.await
260+
.map_err(|_| eyre::eyre!("Timeout waiting for L1 watcher command"))?
261+
.ok_or_else(|| eyre::eyre!("L1 watcher command channel closed"))?
262+
};
263+
264+
match command {
265+
L1WatcherCommand::ResetToBlock { block, new_sender } => {
266+
self.nodes[node_index].set_l1_watcher_tx(new_sender);
267+
Ok(block)
268+
}
269+
}
270+
}
228271
}
229272

230273
/// Builder for creating test fixtures with a fluent API.

crates/node/src/test_utils/l1_helpers.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ impl<'a> L1Helper<'a> {
9696
BatchRevertBuilder::new(self)
9797
}
9898

99+
/// Create a batch revert range builder.
100+
pub fn revert_batch_range(self) -> BatchRevertRangeBuilder<'a> {
101+
BatchRevertRangeBuilder::new(self)
102+
}
103+
99104
/// Send an L1 finalized block notification.
100105
pub async fn finalize_l1_block(self, block_number: u64) -> eyre::Result<()> {
101106
let notification = Arc::new(L1Notification::Finalized(block_number));
@@ -453,3 +458,58 @@ impl<'a> BatchRevertBuilder<'a> {
453458
self.l1_helper.send_to_nodes(notification).await
454459
}
455460
}
461+
462+
/// Builder for creating batch revert range notifications in tests.
463+
#[derive(Debug)]
464+
pub struct BatchRevertRangeBuilder<'a> {
465+
l1_helper: L1Helper<'a>,
466+
block_info: BlockInfo,
467+
start: u64,
468+
end: u64,
469+
}
470+
471+
impl<'a> BatchRevertRangeBuilder<'a> {
472+
fn new(l1_helper: L1Helper<'a>) -> Self {
473+
Self {
474+
l1_helper,
475+
block_info: BlockInfo { number: 0, hash: B256::random() },
476+
start: 0,
477+
end: 0,
478+
}
479+
}
480+
481+
/// Set the L1 block info for this batch revert range.
482+
pub const fn at_block(mut self, block_info: BlockInfo) -> Self {
483+
self.block_info = block_info;
484+
self
485+
}
486+
487+
/// Set the L1 block number for this batch revert range.
488+
pub const fn at_block_number(mut self, block_number: u64) -> Self {
489+
self.block_info.number = block_number;
490+
self
491+
}
492+
493+
/// Set the start batch index.
494+
pub const fn start(mut self, start: u64) -> Self {
495+
self.start = start;
496+
self
497+
}
498+
499+
/// Set the end batch index.
500+
pub const fn end(mut self, end: u64) -> Self {
501+
self.end = end;
502+
self
503+
}
504+
505+
/// Send the batch revert range notification.
506+
pub async fn send(self) -> eyre::Result<()> {
507+
let notification = Arc::new(L1Notification::BatchRevertRange {
508+
start: self.start,
509+
end: self.end,
510+
block_info: self.block_info,
511+
});
512+
513+
self.l1_helper.send_to_nodes(notification).await
514+
}
515+
}

0 commit comments

Comments
 (0)