channeld: allow outgoing messages through even if they have send STFU.
What changed, and why it matters
This patch fixes a hang in Core Lightning's experimental splicing feature. Previously, once a node decided to enter 'quiet' mode (STFU) for splicing, it would stop sending all outgoing channel update messages, including the commitment_signed message the other side was waiting for. The fix lets messages that are already in flight go out, and only blocks brand-new activity once STFU has actually been sent. This prevents the two peers from deadlocking during a splice when a closing payment is still pending.
Treat as a bug-fix commit with limited denial-of-service security relevance. Users running experimental splicing should upgrade to avoid channel hangs. No immediate emergency response is warranted; review whether the hang is externally triggerable and could be abused to lock up liquidity.
Security signals we found
Denial-of-service-like hang in channel state machine
Protocol deadlock during experimental splicing
STFU/quiescence state machine logic error
Missing commitment_signed transmission
Evidence from the diff
The change refines the STFU (quiescence) logic in channeld. It introduces is_entering_stfu() (want_stfu or STFU sent by either side) to defer new master requests, fee updates, and blockheight updates while quiescence is being negotiated. It keeps is_stfu_active() (both sides have sent STFU) for full quiet mode. Crucially, send_commit_if_not_stfu() now only suppresses commitment_signed if the local node has itself sent STFU, rather than suppressing it whenever quiescence is desired or one-sided STFU is active. This avoids a deadlock where the local peer had sent STFU but still needed to send commitment_signed to satisfy the remote peer.
Changed components
channeld/channeld.cSTFU/quiescence handlingcommitment_signed sending logicsplicing code pathInspect captured patch +13 / −7
diff --git a/channeld/channeld.c b/channeld/channeld.c
index 9a8b95c0..9636008b 100644
--- a/channeld/channeld.c
+++ b/channeld/channeld.c
@@ -214,11 +214,18 @@ const u8 *hsm_req(const tal_t *ctx, const u8 *req TAKES)
return msg;
}
+/* We're in STFU mode now: must not send messages. */
static bool is_stfu_active(const struct peer *peer)
{
return peer->stfu_sent[LOCAL] && peer->stfu_sent[REMOTE];
}
+/* We're trying to enter STFU mode now: don't start *new* conversations */
+static bool is_entering_stfu(const struct peer *peer)
+{
+ return peer->want_stfu || peer->stfu_sent[LOCAL] || peer->stfu_sent[REMOTE];
+}
+
static void end_stfu_mode(struct peer *peer)
{
peer->want_stfu = false;
@@ -353,7 +360,7 @@ static void handle_stfu(struct peer *peer, const u8 *stfu)
/* Returns true if we queued this for later handling (steals if true) */
static bool handle_master_request_later(struct peer *peer, const u8 *msg)
{
- if (is_stfu_active(peer)) {
+ if (is_entering_stfu(peer)) {
msg_enqueue(peer->update_queue, take(msg));
return true;
}
@@ -1087,7 +1094,7 @@ static bool want_fee_update(const struct peer *peer, u32 *target)
return false;
/* No fee update while quiescing! */
- if (peer->want_stfu || is_stfu_active(peer))
+ if (is_entering_stfu(peer))
return false;
current = channel_feerate(peer->channel, REMOTE);
@@ -1125,8 +1132,8 @@ static bool want_blockheight_update(const struct peer *peer, u32 *height)
if (peer->channel->lease_expiry == 0)
return false;
- /* No fee update while quiescing! */
- if (peer->want_stfu || is_stfu_active(peer))
+ /* No block update while quiescing! */
+ if (is_entering_stfu(peer))
return false;
/* What's the current blockheight */
@@ -1509,10 +1516,9 @@ static void send_commit(struct peer *peer)
static void send_commit_if_not_stfu(struct peer *peer)
{
- if (!is_stfu_active(peer) && !peer->want_stfu) {
+ if (!peer->stfu_sent[LOCAL]) {
send_commit(peer);
- }
- else {
+ } else {
/* Timer now considered expired, you can add a new one. */
peer->commit_timer = NULL;
start_commit_timer(peer);
Why this scored 43/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.