diff --git a/crates/node/tests/e2e.rs b/crates/node/tests/e2e.rs index 304957be..c28adf91 100644 --- a/crates/node/tests/e2e.rs +++ b/crates/node/tests/e2e.rs @@ -988,6 +988,89 @@ async fn can_handle_l1_message_reorg() -> eyre::Result<()> { Ok(()) } +#[tokio::test] +async fn can_reject_l2_block_with_unknown_l1_message() -> eyre::Result<()> { + reth_tracing::init_test_tracing(); + color_eyre::install()?; + let chain_spec = (*SCROLL_DEV).clone(); + + // Launch 2 nodes: node0=sequencer and node1=follower. + let config = default_sequencer_test_scroll_rollup_node_config(); + let (mut nodes, _tasks, _) = setup_engine(config, 2, chain_spec.clone(), false, false).await?; + let node0 = nodes.remove(0); + let node1 = nodes.remove(0); + + // Get handles + let node0_rnm_handle = node0.inner.add_ons_handle.rollup_manager_handle.clone(); + let mut node0_rnm_events = node0_rnm_handle.get_event_listener().await?; + let node0_l1_watcher_tx = node0.inner.add_ons_handle.l1_watcher_tx.as_ref().unwrap(); + + let node1_rnm_handle = node1.inner.add_ons_handle.rollup_manager_handle.clone(); + let mut node1_rnm_events = node1_rnm_handle.get_event_listener().await?; + let node1_l1_watcher_tx = node1.inner.add_ons_handle.l1_watcher_tx.as_ref().unwrap(); + + // Let the sequencer build 10 blocks before performing the reorg process. + for i in 1..=10 { + node0_rnm_handle.build_block().await; + wait_for_block_sequenced_5s(&mut node0_rnm_events, i).await?; + } + + // Assert that the follower node has received all 10 blocks from the sequencer node. + wait_for_block_imported_5s(&mut node1_rnm_events, 10).await?; + + // Send a L1 message and wait for it to be indexed. + let l1_message_notification = L1Notification::L1Message { + message: TxL1Message { + queue_index: 0, + gas_limit: 21000, + to: Default::default(), + value: Default::default(), + sender: address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"), + input: Default::default(), + }, + block_number: 10, + block_timestamp: 0, + }; + + // Send the L1 message to the sequencer node but not to follower node. + node0_l1_watcher_tx.send(Arc::new(l1_message_notification.clone())).await?; + wait_for_event_5s(&mut node0_rnm_events, RollupManagerEvent::L1MessageIndexed(0)).await?; + node0_l1_watcher_tx.send(Arc::new(L1Notification::NewBlock(10))).await?; + + // TODO: which event should we wait for here? + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + + // Build block that contains the L1 message. + node0_rnm_handle.build_block().await; + wait_for_event_predicate_5s(&mut node0_rnm_events, |e| { + if let RollupManagerEvent::BlockImported(block) = e { + block.header.number == 11 && + block.body.transactions.len() == 1 && + block.body.transactions.iter().any(|tx| tx.is_l1_message()) + } else { + false + } + }) + .await?; + + for i in 12..=15 { + node0_rnm_handle.build_block().await; + wait_for_block_sequenced_5s(&mut node0_rnm_events, i).await?; + } + assert_eq!(latest_block(&node0).await?.header.number, 15); + + // TODO: follower node should not import block 15 + wait_for_block_imported_5s(&mut node1_rnm_events, 15).await?; + // follower node doesn't know about the L1 message so stops processing the chain + // TODO: currently this fails here + assert_eq!(latest_block(&node1).await?.header.number, 10); + + // TODO: let follower node receive the L1 message and process the chain after receiving a new + // block + + Ok(()) +} + #[tokio::test] async fn can_gossip_over_eth_wire() -> eyre::Result<()> { reth_tracing::init_test_tracing();