Skip to content

Commit e22524a

Browse files
committed
loopout: register for confirmation using htlc tx hash
1 parent 190caa4 commit e22524a

File tree

4 files changed

+42
-16
lines changed

4 files changed

+42
-16
lines changed

client_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"testing"
99

1010
"github.com/btcsuite/btcd/chaincfg"
11+
"github.com/btcsuite/btcd/chaincfg/chainhash"
1112
"github.com/btcsuite/btcutil"
1213
"github.com/lightninglabs/lndclient"
1314
"github.com/lightninglabs/loop/loopdb"
@@ -56,7 +57,7 @@ func TestSuccess(t *testing.T) {
5657
signalPrepaymentResult := ctx.AssertPaid(prepayInvoiceDesc)
5758

5859
// Expect client to register for conf.
59-
confIntent := ctx.AssertRegisterConf()
60+
confIntent := ctx.AssertRegisterConf(false)
6061

6162
testSuccess(ctx, testRequest.Amount, *hash,
6263
signalPrepaymentResult, signalSwapPaymentResult, false,
@@ -82,7 +83,7 @@ func TestFailOffchain(t *testing.T) {
8283
signalSwapPaymentResult := ctx.AssertPaid(swapInvoiceDesc)
8384
signalPrepaymentResult := ctx.AssertPaid(prepayInvoiceDesc)
8485

85-
ctx.AssertRegisterConf()
86+
ctx.AssertRegisterConf(false)
8687

8788
signalSwapPaymentResult(
8889
errors.New(lndclient.PaymentResultUnknownPaymentHash),
@@ -187,6 +188,7 @@ func testResume(t *testing.T, expired, preimageRevealed, expectSuccess bool) {
187188

188189
if preimageRevealed {
189190
update.State = loopdb.StatePreimageRevealed
191+
update.HtlcTxHash = &chainhash.Hash{1, 2, 6}
190192
}
191193

192194
pendingSwap := &loopdb.LoopOut{
@@ -230,7 +232,7 @@ func testResume(t *testing.T, expired, preimageRevealed, expectSuccess bool) {
230232
signalPrepaymentResult := ctx.AssertPaid(prepayInvoiceDesc)
231233

232234
// Expect client to register for conf.
233-
confIntent := ctx.AssertRegisterConf()
235+
confIntent := ctx.AssertRegisterConf(preimageRevealed)
234236

235237
signalSwapPaymentResult(nil)
236238
signalPrepaymentResult(nil)

loopout.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99
"time"
1010

11+
"github.com/btcsuite/btcd/chaincfg/chainhash"
1112
"github.com/btcsuite/btcd/wire"
1213
"github.com/btcsuite/btcutil"
1314
"github.com/lightninglabs/lndclient"
@@ -56,6 +57,9 @@ type loopOutSwap struct {
5657

5758
htlc *swap.Htlc
5859

60+
// htlcTxHash is the confirmed htlc tx id.
61+
htlcTxHash *chainhash.Hash
62+
5963
swapPaymentChan chan lndclient.PaymentResult
6064
prePaymentChan chan lndclient.PaymentResult
6165
}
@@ -210,6 +214,7 @@ func resumeLoopOutSwap(reqContext context.Context, cfg *swapConfig,
210214
} else {
211215
swap.state = lastUpdate.State
212216
swap.lastUpdateTime = lastUpdate.Time
217+
swap.htlcTxHash = lastUpdate.HtlcTxHash
213218
}
214219

215220
return swap, nil
@@ -376,6 +381,7 @@ func (s *loopOutSwap) executeSwap(globalCtx context.Context) error {
376381

377382
// Try to spend htlc and continue (rbf) until a spend has confirmed.
378383
spendDetails, err := s.waitForHtlcSpendConfirmed(globalCtx,
384+
*htlcOutpoint,
379385
func() error {
380386
return s.sweep(globalCtx, *htlcOutpoint, htlcValue)
381387
},
@@ -419,8 +425,9 @@ func (s *loopOutSwap) persistState(ctx context.Context) error {
419425
err := s.store.UpdateLoopOut(
420426
s.hash, updateTime,
421427
loopdb.SwapStateData{
422-
State: s.state,
423-
Cost: s.cost,
428+
State: s.state,
429+
Cost: s.cost,
430+
HtlcTxHash: s.htlcTxHash,
424431
},
425432
)
426433
if err != nil {
@@ -563,11 +570,21 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
563570
s.InitiationHeight,
564571
)
565572

573+
// If we've revealed the preimage in a previous run, we expect to have
574+
// recorded the htlc tx hash. We use this to re-register for
575+
// confirmation, to be sure that we'll keep tracking the same htlc. For
576+
// older swaps, this field may not be populated even though the preimage
577+
// has already been revealed.
578+
if s.state == loopdb.StatePreimageRevealed && s.htlcTxHash == nil {
579+
s.log.Warnf("No htlc tx hash available, registering with " +
580+
"just the pkscript")
581+
}
582+
566583
ctx, cancel := context.WithCancel(globalCtx)
567584
defer cancel()
568585
htlcConfChan, htlcErrChan, err :=
569586
s.lnd.ChainNotifier.RegisterConfirmationsNtfn(
570-
ctx, nil, s.htlc.PkScript, 1,
587+
ctx, s.htlcTxHash, s.htlc.PkScript, 1,
571588
s.InitiationHeight,
572589
)
573590
if err != nil {
@@ -680,8 +697,10 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
680697
}
681698
}
682699

683-
s.log.Infof("Htlc tx %v at height %v", txConf.Tx.TxHash(),
684-
txConf.BlockHeight)
700+
htlcTxHash := txConf.Tx.TxHash()
701+
s.log.Infof("Htlc tx %v at height %v", htlcTxHash, txConf.BlockHeight)
702+
703+
s.htlcTxHash = &htlcTxHash
685704

686705
return txConf, nil
687706
}
@@ -694,13 +713,14 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
694713
// sweep offchain. So we must make sure we sweep successfully before on-chain
695714
// timeout.
696715
func (s *loopOutSwap) waitForHtlcSpendConfirmed(globalCtx context.Context,
697-
spendFunc func() error) (*chainntnfs.SpendDetail, error) {
716+
htlc wire.OutPoint, spendFunc func() error) (*chainntnfs.SpendDetail,
717+
error) {
698718

699719
// Register the htlc spend notification.
700720
ctx, cancel := context.WithCancel(globalCtx)
701721
defer cancel()
702722
spendChan, spendErr, err := s.lnd.ChainNotifier.RegisterSpendNtfn(
703-
ctx, nil, s.htlc.PkScript, s.InitiationHeight,
723+
ctx, &htlc, s.htlc.PkScript, s.InitiationHeight,
704724
)
705725
if err != nil {
706726
return nil, fmt.Errorf("register spend ntfn: %v", err)

loopout_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ func TestLoopOutPaymentParameters(t *testing.T) {
115115

116116
// Swap is expected to register for confirmation of the htlc. Assert
117117
// this to prevent a blocked channel in the mock.
118-
ctx.AssertRegisterConf()
118+
ctx.AssertRegisterConf(false)
119119

120120
// Cancel the swap. There is nothing else we need to assert. The payment
121121
// parameters don't play a role in the remainder of the swap process.
@@ -187,7 +187,7 @@ func TestLateHtlcPublish(t *testing.T) {
187187
signalPrepaymentResult := ctx.AssertPaid(prepayInvoiceDesc)
188188

189189
// Expect client to register for conf
190-
ctx.AssertRegisterConf()
190+
ctx.AssertRegisterConf(false)
191191

192192
// // Wait too long before publishing htlc.
193193
blockEpochChan <- int32(swap.CltvExpiry - 10)
@@ -283,7 +283,7 @@ func TestCustomSweepConfTarget(t *testing.T) {
283283
signalPrepaymentResult(nil)
284284

285285
// Notify the confirmation notification for the HTLC.
286-
ctx.AssertRegisterConf()
286+
ctx.AssertRegisterConf(false)
287287

288288
blockEpochChan <- ctx.Lnd.Height + 1
289289

@@ -484,7 +484,7 @@ func TestPreimagePush(t *testing.T) {
484484
signalPrepaymentResult(nil)
485485

486486
// Notify the confirmation notification for the HTLC.
487-
ctx.AssertRegisterConf()
487+
ctx.AssertRegisterConf(false)
488488

489489
blockEpochChan <- ctx.Lnd.Height + 1
490490

test/context.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,18 @@ func (ctx *Context) AssertTrackPayment() TrackPaymentMessage {
113113
}
114114

115115
// AssertRegisterConf asserts that a register for conf has been received.
116-
func (ctx *Context) AssertRegisterConf() *ConfRegistration {
116+
func (ctx *Context) AssertRegisterConf(expectTxHash bool) *ConfRegistration {
117117
ctx.T.Helper()
118118

119119
// Expect client to register for conf
120120
var confIntent *ConfRegistration
121121
select {
122122
case confIntent = <-ctx.Lnd.RegisterConfChannel:
123-
if confIntent.TxID != nil {
123+
switch {
124+
case expectTxHash && confIntent.TxID == nil:
125+
ctx.T.Fatalf("expected tx id for registration")
126+
127+
case !expectTxHash && confIntent.TxID != nil:
124128
ctx.T.Fatalf("expected script only registration")
125129
}
126130
case <-time.After(Timeout):

0 commit comments

Comments
 (0)