Add quiescence test of disconnecting waiting on the next step
What changed, and why it matters
This commit only adds a new automated test to the rust-lightning project. It does not change any production code. The test verifies that a Lightning node will disconnect a peer if the peer fails to send a required follow-up message after both sides have agreed to pause (quiesce) a channel. Because no actual behavior is modified, this commit does not introduce or fix a security vulnerability on its own.
No action required. Review the test for correctness if desired, but it does not alter runtime security posture.
Security signals we found
No production code changes
Purely additive test coverage
Tests existing disconnect-on-timeout behavior in quiescence protocol
Evidence from the diff
The diff adds a single unit test, test_quiescence_timeout_while_waiting_for_counterparty_something_fundamental, in lightning/src/ln/quiescence_tests.rs. The test sets up two nodes, has one propose quiescence, processes only one direction of the stfu message, advances the timer past DISCONNECT_PEER_AWAITING_RESPONSE_TICKS, and asserts that both nodes emit a DisconnectPeerWithWarning error event. This is purely test coverage for an existing timeout/disconnect behavior; no implementation code is changed.
Changed components
lightning/src/ln/quiescence_tests.rsInspect captured patch +42 / −0
diff --git a/lightning/src/ln/quiescence_tests.rs b/lightning/src/ln/quiescence_tests.rs
index c13f9e7..983fd8b 100644
--- a/lightning/src/ln/quiescence_tests.rs
+++ b/lightning/src/ln/quiescence_tests.rs
@@ -549,6 +549,48 @@ fn test_quiescence_timeout_while_waiting_for_counterparty_stfu() {
assert!(nodes[1].node.get_and_clear_pending_msg_events().iter().find_map(f).is_some());
}
+#[test]
+fn test_quiescence_timeout_while_waiting_for_counterparty_something_fundamental() {
+ // Test that we'll disconnect if the counterparty does not send their "something fundamental"
+ // within a reasonable time if we've reached quiescence.
+ let chanmon_cfgs = create_chanmon_cfgs(2);
+ let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+ let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+ let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+ let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1).2;
+
+ let node_id_0 = nodes[0].node.get_our_node_id();
+ let node_id_1 = nodes[1].node.get_our_node_id();
+
+ nodes[1].node.maybe_propose_quiescence(&node_id_0, &chan_id).unwrap();
+ let stfu = get_event_msg!(nodes[1], MessageSendEvent::SendStfu, node_id_0);
+
+ nodes[0].node.handle_stfu(node_id_1, &stfu);
+ let _stfu = get_event_msg!(nodes[0], MessageSendEvent::SendStfu, node_id_1);
+
+ for _ in 0..DISCONNECT_PEER_AWAITING_RESPONSE_TICKS {
+ nodes[0].node.timer_tick_occurred();
+ nodes[1].node.timer_tick_occurred();
+ }
+
+ // Node B didn't receive node A's stfu within the timeout so it'll disconnect.
+ let f = |event| {
+ if let MessageSendEvent::HandleError { action, .. } = event {
+ if let msgs::ErrorAction::DisconnectPeerWithWarning { .. } = action {
+ Some(())
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ };
+ // At this point, node A is waiting on B to do something fundamental, and node B is waiting on
+ // A's stfu that we never delivered. Thus both should disconnect each other.
+ assert!(nodes[0].node.get_and_clear_pending_msg_events().into_iter().find_map(&f).is_some());
+ assert!(nodes[1].node.get_and_clear_pending_msg_events().into_iter().find_map(&f).is_some());
+}
+
fn do_test_quiescence_during_disconnection(with_pending_claim: bool, propose_disconnected: bool) {
// Test that we'll start trying for quiescence immediately after reconnection if we're waiting
// to do some quiescence-required action.
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.