[Bug] Four-node reconnect can leave a channel TLC queue blocked
Corrected scope
This issue is narrowed to an observed channel-liveness failure after a reconnect in the four-node integration workload. It does not claim that every waiting_ack = false / verify nonce = None state is a protocol deadlock: that can be a normal commitment round in flight.
The earlier proposal to bypass is_waiting_tlc_ack() or to synthesize a local MuSig2 verify nonce is withdrawn; either would invalidate the nonce-pairing protocol.
Confirmed observation
During the ring workload in the reproduction comment, after disconnecting and reconnecting node2/node3, channel 0xe0f79f4c79692a382aa2680c6fd2420c366cd1f346c85fe735bb614eae464566 remained blocked:
- At
2026-07-15T05:33:56.244235Z, node3 persistedwaiting_ack=false, send=Some, verify=None, next=Some. - A local Hold TLC removal then failed with
Unable to handle TLC command in waiting TLC ACK state. - At
2026-07-15T05:34:56.471881Z, node3 still had 57 retryable TLC operations; the retry path stopped at the same gate. - The affected payment includes
0x867c50e6c4d49e3fb796b464943bb021ead0cb486367b0e7be3ae4e901ec0a3c.
is_waiting_tlc_ack() gates local TLC operations when the verify nonce is absent, while handle_revoke_and_ack_peer_message can clear the existing peer-response watchdog via set_waiting_ack(false) before leaving this state. The watchdog therefore does not cover an indefinitely missing next CommitmentSigned.
Tests withdrawn
The two Rust tests previously included here are withdrawn. Each injected the nonce state on one peer only, without the peer's matching waiting_ack and persisted CommitDiff; therefore they could not validate the actual reestablish/replay path. The first also incorrectly required local TLC removal to succeed during a possibly normal in-flight window.
Required follow-up
- Add a test transport hook to hold/drop a selected outbound
CommitmentSigned. - Reproduce the two-peer paired state, including the sender's persisted
CommitDiff, around the node2/node3 reconnect. - Determine why the expected
CommitmentSigneddid not arrive in the observed run and either restore valid protocol progress or cover this waiting window with the existing timeout/force-close mechanism.
The raw-log and workload background remain in the two earlier comments linked above.
Source: nervosnetwork/fiber