sweepbatcher: fix height hint for confirmations

Previously, we passed the current best block height as the height hint to
RegisterConfirmationsNtfn. If Loop was shut down when a sweep was confirmed
and restarted later, it would use the current best height as the hint. This
caused the confirmation to be missed, since it had already occurred before
that height.

This commit fixes the issue by passing the initiation height of the swap as the
height hint instead. This is consistent with what we do in other places where
we use RegisterConfirmationsNtfn.

Since LND caches previously passed height hints for RegisterConfirmationsNtfn
and uses maximum passed value, to actually recover in such a condition, one has
to restart LND passing the option --height-hint-cache-query-disable and then
restart Loop applying this fix. If a pruned bitcoind backend is used, this might
not work.
This commit is contained in:
Boris Nagaev 2025-04-04 23:49:53 -03:00
parent ec2bf44e46
commit 4c26aefe80
No known key found for this signature in database
2 changed files with 20 additions and 7 deletions

View file

@ -1707,13 +1707,20 @@ func (b *batch) monitorSpend(ctx context.Context, primarySweep sweep) error {
// monitorConfirmations monitors the batch transaction for confirmations.
func (b *batch) monitorConfirmations(ctx context.Context) error {
// Find initiationHeight.
primarySweep, ok := b.sweeps[b.primarySweepID]
if !ok {
return fmt.Errorf("can't find primarySweep")
}
reorgChan := make(chan struct{})
confCtx, cancel := context.WithCancel(ctx)
confChan, errChan, err := b.chainNotifier.RegisterConfirmationsNtfn(
confCtx, b.batchTxid, b.batchPkScript, batchConfHeight,
b.currentHeight, lndclient.WithReOrgChan(reorgChan),
primarySweep.initiationHeight,
lndclient.WithReOrgChan(reorgChan),
)
if err != nil {
cancel()

View file

@ -781,12 +781,15 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
Notifier: &dummyNotifier,
}
const initiationHeight = 550
swap1 := &loopdb.LoopOutContract{
SwapContract: loopdb.SwapContract{
CltvExpiry: 111,
AmountRequested: 111,
ProtocolVersion: loopdb.ProtocolVersionMuSig2,
HtlcKeys: htlcKeys,
CltvExpiry: 111,
AmountRequested: 111,
ProtocolVersion: loopdb.ProtocolVersionMuSig2,
HtlcKeys: htlcKeys,
InitiationHeight: initiationHeight,
},
DestAddr: destAddr,
@ -871,14 +874,17 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
SpendingTx: spendingTx,
SpenderTxHash: &spendingTxHash,
SpenderInputIndex: 0,
SpendingHeight: 601,
}
// We notify the spend.
lnd.SpendChannel <- spendDetail
// After receiving the spend, the batch is now monitoring for confs.
<-lnd.RegisterConfChannel
confReg := <-lnd.RegisterConfChannel
// Make sure the confirmation has proper height hint. It should pass
// the swap initiation height, not the current height.
require.Equal(t, int32(initiationHeight), confReg.HeightHint)
// The batch should eventually read the spend notification and progress
// its state to closed.