Skip to content

Commit c7f22b7

Browse files
committed
loopout: wait for full confirmation when sweeping
1 parent c0da5fe commit c7f22b7

File tree

3 files changed

+41
-12
lines changed

3 files changed

+41
-12
lines changed

client_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,8 @@ func testLoopOutSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash,
411411

412412
ctx.AssertRegisterConf(true, 3)
413413

414+
ctx.NotifyConf(sweepTx)
415+
414416
ctx.assertStatus(loopdb.StateSuccess)
415417

416418
ctx.assertStoreFinished(loopdb.StateSuccess)

loopout.go

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -596,33 +596,34 @@ func (s *loopOutSwap) executeSwap(globalCtx context.Context) error {
596596
return nil
597597
}
598598

599-
// Try to spend htlc and continue (rbf) until a spend has confirmed.
600-
spend, err := s.waitForHtlcSpendConfirmedV2(
599+
// Try to spend htlc and continue (rbf) until a spend has fully
600+
// confirmed.
601+
conf, err := s.waitForHtlcSpendConfirmedV2(
601602
globalCtx, *htlcOutpoint, htlcValue,
602603
)
603604
if err != nil {
604605
return err
605606
}
606607

607-
// If spend details are nil, we resolved the swap without waiting for
608-
// its spend, so we can exit.
609-
if spend == nil {
608+
// If conf details are nil, we resolved the swap without waiting for
609+
// its confirmation, so we can exit.
610+
if conf == nil {
610611
return nil
611612
}
612613

613614
// Inspect witness stack to see if it is a success transaction. We
614615
// don't just try to match with the hash of our sweep tx, because it
615616
// may be swept by a different (fee) sweep tx from a previous run.
616617
htlcInput, err := swap.GetTxInputByOutpoint(
617-
spend.Tx, htlcOutpoint,
618+
conf.Tx, htlcOutpoint,
618619
)
619620
if err != nil {
620621
return err
621622
}
622623

623624
sweepSuccessful := s.htlc.IsSuccessWitness(htlcInput.Witness)
624625
if sweepSuccessful {
625-
s.cost.Onchain = spend.OnChainFeePortion
626+
s.cost.Onchain = conf.OnChainFeePortion
626627
s.state = loopdb.StateSuccess
627628
} else {
628629
s.state = loopdb.StateFailSweepTimeout
@@ -1140,10 +1141,12 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
11401141
// sweep or a server revocation tx.
11411142
func (s *loopOutSwap) waitForHtlcSpendConfirmedV2(globalCtx context.Context,
11421143
htlcOutpoint wire.OutPoint, htlcValue btcutil.Amount) (
1143-
*sweepbatcher.SpendDetail, error) {
1144+
*sweepbatcher.ConfDetail, error) {
11441145

11451146
spendChan := make(chan *sweepbatcher.SpendDetail)
11461147
spendErrChan := make(chan error, 1)
1148+
confChan := make(chan *sweepbatcher.ConfDetail, 1)
1149+
confErrChan := make(chan error, 1)
11471150
quitChan := make(chan bool, 1)
11481151

11491152
defer func() {
@@ -1153,6 +1156,8 @@ func (s *loopOutSwap) waitForHtlcSpendConfirmedV2(globalCtx context.Context,
11531156
notifier := sweepbatcher.SpendNotifier{
11541157
SpendChan: spendChan,
11551158
SpendErrChan: spendErrChan,
1159+
ConfChan: confChan,
1160+
ConfErrChan: confErrChan,
11561161
QuitChan: quitChan,
11571162
}
11581163

@@ -1192,15 +1197,28 @@ func (s *loopOutSwap) waitForHtlcSpendConfirmedV2(globalCtx context.Context,
11921197

11931198
for {
11941199
select {
1195-
// Htlc spend, break loop.
1200+
// Htlc spend, but waiting for more confirmations in case of
1201+
// a reorg.
11961202
case spend := <-spendChan:
11971203
s.log.Infof("Htlc spend by tx: %v", spend.Tx.TxHash())
11981204

1199-
return spend, nil
1200-
12011205
// Spend notification error.
12021206
case err := <-spendErrChan:
1203-
return nil, err
1207+
return nil, fmt.Errorf("spend notification error: %w",
1208+
err)
1209+
1210+
// Htlc was spent and the sweep transaction is fully confirmed.
1211+
// Break from loop.
1212+
case conf := <-confChan:
1213+
s.log.Infof("Sweep tx %v fully confirmed in block %d",
1214+
conf.Tx.TxHash(), conf.BlockHeight)
1215+
1216+
return conf, nil
1217+
1218+
// Conf notification error.
1219+
case err := <-confErrChan:
1220+
return nil, fmt.Errorf("conf notification error: %w",
1221+
err)
12041222

12051223
// Receive status updates for our payment so that we can detect
12061224
// whether we've successfully pushed our preimage.

loopout_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ func testCustomSweepConfTarget(t *testing.T) {
472472
// confirmations.
473473
ctx.AssertRegisterConf(true, 3)
474474

475+
// Notify the batch for the confirmation.
476+
ctx.NotifyConf(sweepTx)
477+
475478
cfg.store.(*loopdb.StoreMock).AssertLoopOutState(loopdb.StateSuccess)
476479
status = <-statusChan
477480
require.Equal(t, loopdb.StateSuccess, status.State)
@@ -747,6 +750,9 @@ func testPreimagePush(t *testing.T) {
747750
// confs.
748751
ctx.AssertRegisterConf(true, 3)
749752

753+
// Notify the batch for the confirmation.
754+
ctx.NotifyConf(sweepTx)
755+
750756
cfg.store.(*loopdb.StoreMock).AssertLoopOutState(loopdb.StateSuccess)
751757
status := <-statusChan
752758
require.Equal(t, loopdb.StateSuccess, status.State)
@@ -1105,6 +1111,9 @@ func TestLoopOutMuSig2Sweep(t *testing.T) {
11051111
// confs.
11061112
ctx.AssertRegisterConf(true, 3)
11071113

1114+
// Notify the batch for the confirmation.
1115+
ctx.NotifyConf(sweepTx)
1116+
11081117
cfg.store.(*loopdb.StoreMock).AssertLoopOutState(loopdb.StateSuccess)
11091118
status = <-statusChan
11101119
require.Equal(t, status.State, loopdb.StateSuccess)

0 commit comments

Comments
 (0)