Skip to content

Commit 1499d7d

Browse files
cdeckercdecker
authored andcommitted
plugin: Add FORGET_CHANNEL to stuck HSM types
Type 34 (WIRE_HSMD_FORGET_CHANNEL) is sent synchronously by lightningd's delete_channel() once onchaind completes for a closed channel. In bgsync mode no signer is attached and the StagingHsmServer only answers the canned startup messages, so the request sits in the stager forever and blocks lightningd's main loop. Because the type was not sticky the node did not report itself as stuck, so update_state called getinfo on the blocked lightningd and the state poll stalled: no BlockSync self-preempt, no 60s stuck-grace kill and no stuck webhook to summon the signer. The session then idled until the 1h session wall. On EU bgsync this accounted for ~95% of the ~2,029 cap-hit sessions/day, with 1,936 "forgetting peer" events/day repeating on every visit to the same nodes (Loki, 2026-10-12). Marking the type stuck makes update_state skip the hanging getinfo, fires the stuck webhook so the signer gets summoned, and kills the session after ~60s instead of ~3,540s. The forget then commits for good once a user session attaches the signer.
1 parent 2239883 commit 1499d7d

1 file changed

Lines changed: 37 additions & 0 deletions

File tree

‎libs/gl-plugin/src/stager.rs‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ impl Stage {
109109
20, // WIRE_HSMD_SIGN_REMOTE_HTLC_TX
110110
21, // WIRE_HSMD_SIGN_MUTUAL_CLOSE_TX
111111
28, // WIRE_HSMD_CHECK_PUBKEY
112+
34, // WIRE_HSMD_FORGET_CHANNEL (lightningd delete_channel, sync)
112113
142, // WIRE_HSMD_SIGN_ANY_DELAYED_PAYMENT_TO_US
113114
143, // WIRE_HSMD_SIGN_ANY_REMOTE_HTLC_TO_US
114115
144, // WIRE_HSMD_SIGN_ANY_PENALTY_TO_US
@@ -260,4 +261,40 @@ mod test {
260261
f1.await.unwrap();
261262
f2.await.unwrap();
262263
}
264+
265+
#[tokio::test]
266+
async fn test_stuck_request_types() {
267+
// WIRE_HSMD_FORGET_CHANNEL (34) is queued but never answered: this is
268+
// the bgsync deadlock, lightningd's delete_channel() blocks on it
269+
// synchronously, so the node must report itself as stuck.
270+
let stage = Stage::new();
271+
stage
272+
.send(pb::HsmRequest {
273+
request_id: 0,
274+
context: None,
275+
raw: vec![0, 34, 0, 0, 0, 0, 0, 0, 0, 1],
276+
signer_state: vec![],
277+
requests: vec![],
278+
})
279+
.await
280+
.unwrap();
281+
assert_eq!(stage.stuck_request_types().await, vec![34]);
282+
assert!(stage.is_stuck().await);
283+
284+
// WIRE_HSMD_DERIVE_SECRET (27) is not on the sticky list, a queued
285+
// request of this type alone must not mark the node as stuck.
286+
let stage = Stage::new();
287+
stage
288+
.send(pb::HsmRequest {
289+
request_id: 0,
290+
context: None,
291+
raw: vec![0, 27, 0, 0, 0, 0, 0, 0, 0, 1],
292+
signer_state: vec![],
293+
requests: vec![],
294+
})
295+
.await
296+
.unwrap();
297+
assert_eq!(stage.stuck_request_types().await, Vec::<u16>::new());
298+
assert!(!stage.is_stuck().await);
299+
}
263300
}

0 commit comments

Comments
 (0)