lnd/htlcswitch
ziggie f550ac1f7c
htlcswitch: fix hodlQueue deadlock by stopping htlcManager first
The channelLink.Stop() teardown had an inverted ordering that could
cause a permanent deadlock of the invoice registry under concurrent
peer disconnect.

The previous order was:
  1. HodlUnsubscribeAll  -- removes subscriptions
  2. hodlQueue.Stop()    -- kills the queue's internal goroutine
  3. cg.Quit()           -- signals htlcManager to stop
  4. cg.WgWait()         -- waits for htlcManager to exit

The race window between steps 2 and 4 left htlcManager alive. A
RevokeAndAck arriving during that window could drive processRemoteAdds
→ processExitHop → NotifyExitHopHtlc, registering a new hodl
subscription backed by a dead hodlQueue (ChanIn() has no reader).

Any subsequent call to notifyHodlSubscribers (e.g. MPP auto-release
timer, expiry watcher, or explicit settle/cancel) would then block
indefinitely on the unbuffered ChanIn(), holding hodlSubscriptionsMux.
Concurrent NotifyExitHopHtlc calls waiting for that lock, plus callers
holding the invoice-level lock waiting for those, produce a full
deadlock of the invoice registry with no recovery path short of a
daemon restart.

The fix is to stop htlcManager before touching the hodl subscription
state. htlcManager is the sole caller of NotifyExitHopHtlc, so once
cg.WgWait() returns no new subscriptions can be registered, making
HodlUnsubscribeAll and hodlQueue.Stop() race-free.
2026-04-09 10:02:30 +02:00
..
hodl multi: add golang 1.17 compatible build tags 2021-09-29 17:31:37 -07:00
hop go: update lightning-onion 2026-03-02 15:46:21 +01:00
testdata multi: update linter, fix new issues 2023-06-13 11:58:33 +02:00
circuit.go multi+refactor: move models package to graph/db 2024-11-28 13:34:33 +02:00
circuit_map.go multi: use the "errors" package everywhere 2025-06-30 09:46:55 +02:00
circuit_map_test.go multi: fix fmt.Errorf error wrapping 2024-02-27 11:13:40 +00:00
circuit_test.go multi: rename chan DB Open method to OpenForTesting 2024-11-28 13:51:15 +02:00
decayedlog.go htlcswitch: remove batchReplayBkt 2025-06-17 11:39:38 +08:00
decayedlog_test.go htlcswitch: use T.TempDir to create temporary test directory 2022-08-24 09:03:01 +08:00
failure.go htlcswitch: add linkError field to htlcpacket 2020-02-06 19:43:29 +02:00
failure_detail.go htlcswitch: add linkError field to htlcpacket 2020-02-06 19:43:29 +02:00
failure_test.go multi: update linter, fix new issues 2023-06-13 11:58:33 +02:00
held_htlc_set.go multi+refactor: move models package to graph/db 2024-11-28 13:34:33 +02:00
held_htlc_set_test.go multi+refactor: move models package to graph/db 2024-11-28 13:34:33 +02:00
htlcnotifier.go multi+refactor: move models package to graph/db 2024-11-28 13:34:33 +02:00
interceptable_switch.go multi: use the "errors" package everywhere 2025-06-30 09:46:55 +02:00
interfaces.go htlcswitch+routing: PaymentBandwidth accepts channel peer pubkey argument 2025-07-02 12:09:24 +02:00
link.go htlcswitch: fix hodlQueue deadlock by stopping htlcManager first 2026-04-09 10:02:30 +02:00
link_isolated_test.go multi: context.Background() -> t.Context() 2025-08-30 14:13:44 -03:00
link_test.go peer+htlcswitch: inject notification endpoint 2026-02-20 10:43:52 +01:00
linkfailure.go multi: use the "errors" package everywhere 2025-06-30 09:46:55 +02:00
log.go multi: start updating various loggers to use the new v2 type 2024-10-22 17:03:55 +02:00
mailbox.go htlcswitch: pass quit chans as unidirectional 2024-10-17 17:33:15 +02:00
mailbox_test.go htlcswitch: pass quit chans as unidirectional 2024-10-17 17:33:15 +02:00
mock.go multi: use the "errors" package everywhere 2025-06-30 09:46:55 +02:00
packet.go htlcswitch: handle nil circuit properly when settling 2024-12-16 15:58:23 +08:00
payment_result.go htlcswitch: rename paymentID to attemptID for clarity 2024-08-07 22:17:58 +08:00
payment_result_test.go multi: rename chan DB Open method to OpenForTesting 2024-11-28 13:51:15 +02:00
quiescer.go multi: add new config QuiescenceTimeout 2025-07-04 04:19:59 +08:00
quiescer_test.go multi: update to fn v2 2024-12-04 13:19:00 -07:00
resolution_store.go multi: use the "errors" package everywhere 2025-06-30 09:46:55 +02:00
resolution_store_test.go multi: update walletdb package 2025-04-09 18:47:53 +02:00
sequencer.go multi: use the "errors" package everywhere 2025-06-30 09:46:55 +02:00
switch.go routing+htlcswitch+discovery+peer+netann: optimize debug logging with lazy evaluation 2025-09-05 18:20:51 -07:00
switch_test.go multi: context.Background() -> t.Context() 2025-08-30 14:13:44 -03:00
test_utils.go peer+htlcswitch: inject notification endpoint 2026-02-20 10:43:52 +01:00