Skip to content

Commit 32587a2

Browse files
committed
refactor test_l1_message_gap with test fixture
1 parent c19beb8 commit 32587a2

File tree

2 files changed

+66
-94
lines changed

2 files changed

+66
-94
lines changed

crates/node/src/test_utils/event_utils.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,39 @@ impl<'a> EventWaiter<'a> {
112112
Ok(())
113113
}
114114

115+
/// Wait for L1 message duplicate event on all specified nodes.
116+
pub async fn l1_message_duplicate(self, expected_queue_index: u64) -> eyre::Result<()> {
117+
self.wait_for_event_on_all(|e| {
118+
if let ChainOrchestratorEvent::L1MessageDuplicate(queue_index) = e {
119+
(*queue_index == expected_queue_index).then_some(())
120+
} else {
121+
None
122+
}
123+
})
124+
.await?;
125+
Ok(())
126+
}
127+
128+
/// Wait for L1 message gap event on all specified nodes.
129+
pub async fn l1_message_gap(
130+
self,
131+
expected_missing_index: u64,
132+
expected_l1_block_number_reset: u64,
133+
) -> eyre::Result<()> {
134+
self.wait_for_event_on_all(|e| {
135+
if let ChainOrchestratorEvent::L1MessageGap { missing_index, l1_block_number_reset } = e
136+
{
137+
(*missing_index == expected_missing_index
138+
&& *l1_block_number_reset == expected_l1_block_number_reset)
139+
.then_some(())
140+
} else {
141+
None
142+
}
143+
})
144+
.await?;
145+
Ok(())
146+
}
147+
115148
/// Wait for L1 reorg event to be received by all.
116149
pub async fn l1_reorg(self) -> eyre::Result<()> {
117150
self.wait_for_event_on_all(|e| {

crates/node/tests/e2e.rs

Lines changed: 33 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,100 +1849,39 @@ async fn test_batch_commit_gap() -> eyre::Result<()> {
18491849

18501850
// Test that the chain orchestrator detects gaps in L1 messages, triggers a reset command to the
18511851
// L1 watcher for self-healing and skips duplicate L1 messages received.
1852-
// #[tokio::test]
1853-
// async fn test_l1_message_gap() -> eyre::Result<()> {
1854-
// reth_tracing::init_test_tracing();
1855-
//
1856-
// let (mut nodes, _tasks, _wallet) = setup_engine(
1857-
// default_test_scroll_rollup_node_config(),
1858-
// 1,
1859-
// (*SCROLL_DEV).clone(),
1860-
// false,
1861-
// false,
1862-
// )
1863-
// .await?;
1864-
// let node = nodes.pop().unwrap();
1865-
//
1866-
// // Get handles for sending L1 notifications and receiving commands
1867-
// let l1_watcher_tx = node.inner.add_ons_handle.l1_watcher_tx.clone().unwrap();
1868-
// let l1_watcher_command_rx = node.inner.add_ons_handle.l1_watcher_command_rx.clone();
1869-
// let chain_orchestrator = node.inner.add_ons_handle.rollup_manager_handle.clone();
1870-
//
1871-
// // Get event listener to monitor chain orchestrator events
1872-
// let mut events = chain_orchestrator.get_event_listener().await?;
1873-
//
1874-
// // Node is unsynced initially -> does not derive batches (which is what we want)
1875-
//
1876-
// // Send L1 message 1 to populate the database
1877-
// let l1_message_0 = TxL1Message { queue_index: 0, ..Default::default() };
1878-
// let l1_message_0_block_info = BlockInfo { number: 1, hash: B256::random() };
1879-
// l1_watcher_tx
1880-
// .send(Arc::new(L1Notification::L1Message {
1881-
// message: l1_message_0.clone(),
1882-
// block_info: l1_message_0_block_info,
1883-
// block_timestamp: 0,
1884-
// }))
1885-
// .await?;
1886-
// wait_for_event_5s(
1887-
// &mut events,
1888-
// ChainOrchestratorEvent::L1MessageCommitted(l1_message_0.queue_index),
1889-
// )
1890-
// .await?;
1891-
//
1892-
// // Send duplicate L1 message 0 - should be skipped and duplicate detected
1893-
// l1_watcher_tx
1894-
// .send(Arc::new(L1Notification::L1Message {
1895-
// message: l1_message_0.clone(),
1896-
// block_info: l1_message_0_block_info,
1897-
// block_timestamp: 0,
1898-
// }))
1899-
// .await?;
1900-
// wait_for_event_5s(
1901-
// &mut events,
1902-
// ChainOrchestratorEvent::L1MessageDuplicate(l1_message_0.queue_index),
1903-
// )
1904-
// .await?;
1905-
//
1906-
// // Send L1 message 2 - should trigger reset due to gap (missing L1 message 1)
1907-
// let l1_message_3 = TxL1Message {
1908-
// queue_index: 2, // Gap! Missing index 2
1909-
// ..Default::default()
1910-
// };
1911-
// let l1_message_3_block_info = BlockInfo { number: 3, hash: B256::random() };
1912-
// l1_watcher_tx
1913-
// .send(Arc::new(L1Notification::L1Message {
1914-
// message: l1_message_3.clone(),
1915-
// block_info: l1_message_3_block_info,
1916-
// block_timestamp: 0,
1917-
// }))
1918-
// .await?;
1919-
// wait_for_event_5s(
1920-
// &mut events,
1921-
// ChainOrchestratorEvent::L1MessageGap {
1922-
// missing_index: l1_message_3.queue_index,
1923-
// l1_block_number_reset: l1_message_0_block_info.number,
1924-
// },
1925-
// )
1926-
// .await?;
1927-
//
1928-
// let mut command_rx = l1_watcher_command_rx.lock().await;
1929-
// let command = tokio::time::timeout(Duration::from_secs(5), command_rx.recv())
1930-
// .await
1931-
// .expect("should receive command within timeout")
1932-
// .expect("should receive Some(command)");
1933-
//
1934-
// // Verify it's a ResetToBlock command with the correct block number
1935-
// match command {
1936-
// L1WatcherCommand::ResetToBlock { block, .. } => {
1937-
// assert_eq!(
1938-
// block, l1_message_0_block_info.number,
1939-
// "Reset block should be the L1 block of the last known L1 message"
1940-
// );
1941-
// }
1942-
// }
1943-
//
1944-
// Ok(())
1945-
// }
1852+
#[tokio::test]
1853+
async fn test_l1_message_gap() -> eyre::Result<()> {
1854+
reth_tracing::init_test_tracing();
1855+
1856+
let mut fixture = TestFixture::builder().sequencer().build().await?;
1857+
1858+
// Node is unsynced initially -> does not derive batches (which is what we want)
1859+
1860+
let to_address = Address::random();
1861+
let sender = Address::random();
1862+
// Send L1 message 0 to populate the database
1863+
fixture.l1().add_message().queue_index(0).to(to_address).sender(sender).at_block(1).send().await?;
1864+
fixture.expect_event().l1_message_committed().await?;
1865+
1866+
// Send duplicate L1 message 0 - should be skipped and duplicate detected
1867+
fixture.l1().add_message().queue_index(0).to(to_address).sender(sender).at_block(1).send().await?;
1868+
fixture.expect_event().l1_message_duplicate(0).await?;
1869+
1870+
// Send L1 message 2 - should trigger reset due to gap (missing L1 message 1)
1871+
fixture.l1().add_message().queue_index(2).at_block(3).send().await?;
1872+
// Expect gap event: missing index 2, reset to L1 block 1 (where message 0 was committed)
1873+
fixture.expect_event().l1_message_gap(2, 1).await?;
1874+
1875+
// Verify that a ResetToBlock command was sent to the L1 watcher
1876+
let command = fixture.expect_l1_watcher_command().await?;
1877+
match command {
1878+
rollup_node_watcher::L1WatcherCommand::ResetToBlock { block, .. } => {
1879+
assert_eq!(block, 1, "Reset block should be the L1 block of the last known L1 message");
1880+
}
1881+
}
1882+
1883+
Ok(())
1884+
}
19461885

19471886
// #[tokio::test]
19481887
// async fn test_batch_revert_gap() -> eyre::Result<()> {

0 commit comments

Comments
 (0)