Skip to content

Commit 33917e1

Browse files
committed
loopd: prefer stored destination in sweephtlc
1 parent 6c57f05 commit 33917e1

2 files changed

Lines changed: 83 additions & 37 deletions

File tree

loopd/sweep_htlc.go

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ func sweepHtlc(ctx context.Context, req *looprpc.SweepHtlcRequest,
106106
return nil, status.Error(codes.InvalidArgument, err.Error())
107107
}
108108

109-
// Destination address: honor a provided override or derive a fresh
110-
// wallet address from the default account.
109+
// Destination address: honor a provided override immediately so request
110+
// validation stays independent from swap lookup.
111111
var sweepAddr btcutil.Address
112112
if req.DestAddress != "" {
113113
sweepAddr, err = btcutil.DecodeAddress(
@@ -117,30 +117,10 @@ func sweepHtlc(ctx context.Context, req *looprpc.SweepHtlcRequest,
117117
return nil, status.Errorf(codes.InvalidArgument,
118118
"invalid dest_address: %v", err)
119119
}
120-
} else {
121-
sweepAddr, err = wallet.NextAddr(
122-
ctx, lnwallet.DefaultAccountName,
123-
walletrpc.AddressType_TAPROOT_PUBKEY,
124-
false,
125-
)
126-
if err != nil {
127-
return nil, status.Errorf(codes.Internal,
128-
"derive sweep address: %v", err)
129-
}
130-
infof("sweephtlc: generated new destination address: %v",
131-
sweepAddr.EncodeAddress())
132-
}
133-
134-
sweepPkScript, err := txscript.PayToAddrScript(sweepAddr)
135-
if err != nil {
136-
return nil, err
137120
}
138121

139-
infof("sweephtlc: start sweep for %v -> %v", req.Outpoint,
140-
sweepAddr.EncodeAddress())
141-
142122
// Locate the loop-out swap whose HTLC script matches the outpoint so
143-
// we can obtain keys and the stored preimage.
123+
// we can obtain keys, the stored preimage, and the default destination.
144124
swaps, err := store.FetchLoopOutSwaps(ctx)
145125
if err != nil {
146126
return nil, err
@@ -172,6 +152,34 @@ func sweepHtlc(ctx context.Context, req *looprpc.SweepHtlcRequest,
172152
"no matching swap HTLC found")
173153
}
174154

155+
// Prefer the stored swap destination for recovery sweeps and only
156+
// derive a fresh wallet address when neither the request nor DB
157+
// specifies one.
158+
if sweepAddr == nil {
159+
sweepAddr = targetSwap.Contract.DestAddr
160+
}
161+
if sweepAddr == nil {
162+
sweepAddr, err = wallet.NextAddr(
163+
ctx, lnwallet.DefaultAccountName,
164+
walletrpc.AddressType_TAPROOT_PUBKEY,
165+
false,
166+
)
167+
if err != nil {
168+
return nil, status.Errorf(codes.Internal,
169+
"derive sweep address: %v", err)
170+
}
171+
infof("sweephtlc: generated new destination address: %v",
172+
sweepAddr.EncodeAddress())
173+
}
174+
175+
sweepPkScript, err := txscript.PayToAddrScript(sweepAddr)
176+
if err != nil {
177+
return nil, err
178+
}
179+
180+
infof("sweephtlc: start sweep for %v -> %v", req.Outpoint,
181+
sweepAddr.EncodeAddress())
182+
175183
infof("sweephtlc: matched swap %v at height hint %v",
176184
targetSwap.Hash, targetSwap.Contract.InitiationHeight)
177185

loopd/sweep_htlc_test.go

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

1010
"github.com/btcsuite/btcd/btcutil"
11+
"github.com/btcsuite/btcd/txscript"
1112
"github.com/btcsuite/btcd/wire"
1213
"github.com/btcsuite/btclog/v2"
1314
"github.com/lightninglabs/loop/loopdb"
@@ -17,7 +18,9 @@ import (
1718
"github.com/lightninglabs/loop/utils"
1819
"github.com/lightningnetwork/lnd/chainntnfs"
1920
"github.com/lightningnetwork/lnd/keychain"
21+
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
2022
"github.com/lightningnetwork/lnd/lntypes"
23+
"github.com/lightningnetwork/lnd/lnwallet"
2124
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
2225
"github.com/stretchr/testify/require"
2326
)
@@ -45,7 +48,6 @@ var sweepHtlcTests = []struct {
4548
satPerVByte: 10,
4649
expectRegister: true,
4750
expectLogs: []string{
48-
"sweephtlc: generated new destination address: %v",
4951
"sweephtlc: start sweep for %v -> %v",
5052
"sweephtlc: matched swap %v at height hint %v",
5153
"sweephtlc: registering conf ntfn for %v hint=%v",
@@ -63,7 +65,6 @@ var sweepHtlcTests = []struct {
6365
satPerVByte: 10,
6466
expectRegister: true,
6567
expectLogs: []string{
66-
"sweephtlc: generated new destination address: %v",
6768
"sweephtlc: start sweep for %v -> %v",
6869
"sweephtlc: matched swap %v at height hint %v",
6970
"sweephtlc: registering conf ntfn for %v hint=%v",
@@ -83,7 +84,6 @@ var sweepHtlcTests = []struct {
8384
satPerVByte: 10,
8485
expectRegister: true,
8586
expectLogs: []string{
86-
"sweephtlc: generated new destination address: %v",
8787
"sweephtlc: start sweep for %v -> %v",
8888
"sweephtlc: matched swap %v at height hint %v",
8989
"sweephtlc: registering conf ntfn for %v hint=%v",
@@ -105,7 +105,6 @@ var sweepHtlcTests = []struct {
105105
expectErrMsg: "fee exceeds",
106106
expectRegister: true,
107107
expectLogs: []string{
108-
"sweephtlc: generated new destination address: %v",
109108
"sweephtlc: start sweep for %v -> %v",
110109
"sweephtlc: matched swap %v at height hint %v",
111110
"sweephtlc: registering conf ntfn for %v hint=%v",
@@ -124,7 +123,6 @@ var sweepHtlcTests = []struct {
124123
expectErrMsg: "fee too low for relay after clamp",
125124
expectRegister: true,
126125
expectLogs: []string{
127-
"sweephtlc: generated new destination address: %v",
128126
"sweephtlc: start sweep for %v -> %v",
129127
"sweephtlc: matched swap %v at height hint %v",
130128
"sweephtlc: registering conf ntfn for %v hint=%v",
@@ -182,10 +180,7 @@ var sweepHtlcTests = []struct {
182180
expectErrMsg: "no matching swap",
183181
expectRegister: false,
184182
noSwap: true,
185-
expectLogs: []string{
186-
"sweephtlc: generated new destination address: %v",
187-
"sweephtlc: start sweep for %v -> %v",
188-
},
183+
expectLogs: []string{},
189184
},
190185
{
191186
name: "invalid initiation height",
@@ -197,7 +192,6 @@ var sweepHtlcTests = []struct {
197192
contract.InitiationHeight = 0
198193
},
199194
expectLogs: []string{
200-
"sweephtlc: generated new destination address: %v",
201195
"sweephtlc: start sweep for %v -> %v",
202196
"sweephtlc: matched swap %v at height hint %v",
203197
},
@@ -212,7 +206,6 @@ var sweepHtlcTests = []struct {
212206
reg.ErrChan <- errors.New("boom")
213207
},
214208
expectLogs: []string{
215-
"sweephtlc: generated new destination address: %v",
216209
"sweephtlc: start sweep for %v -> %v",
217210
"sweephtlc: matched swap %v at height hint %v",
218211
"sweephtlc: registering conf ntfn for %v hint=%v",
@@ -230,7 +223,6 @@ var sweepHtlcTests = []struct {
230223
txOut.PkScript = []byte{0x6a}
231224
},
232225
expectLogs: []string{
233-
"sweephtlc: generated new destination address: %v",
234226
"sweephtlc: start sweep for %v -> %v",
235227
"sweephtlc: matched swap %v at height hint %v",
236228
"sweephtlc: registering conf ntfn for %v hint=%v",
@@ -245,7 +237,6 @@ var sweepHtlcTests = []struct {
245237
expectErrMsg: "fee exceeds HTLC value",
246238
expectRegister: true,
247239
expectLogs: []string{
248-
"sweephtlc: generated new destination address: %v",
249240
"sweephtlc: start sweep for %v -> %v",
250241
"sweephtlc: matched swap %v at height hint %v",
251242
"sweephtlc: registering conf ntfn for %v hint=%v",
@@ -264,6 +255,23 @@ var sweepHtlcTests = []struct {
264255
modifyReq: func(req *looprpc.SweepHtlcRequest) {
265256
req.Preimage = bytes.Repeat([]byte{9}, 32)
266257
},
258+
expectLogs: []string{
259+
"sweephtlc: start sweep for %v -> %v",
260+
"sweephtlc: matched swap %v at height hint %v",
261+
"sweephtlc: registering conf ntfn for %v hint=%v",
262+
"sweephtlc: waiting for confirmation of %v",
263+
"sweephtlc: funding confirmed at height %v",
264+
"sweephtlc: swap hash validated for %v",
265+
},
266+
},
267+
{
268+
name: "fallback to generated destination",
269+
amount: 100_000,
270+
satPerVByte: 10,
271+
expectRegister: true,
272+
mutateSwap: func(contract *loopdb.LoopOutContract) {
273+
contract.DestAddr = nil
274+
},
267275
expectLogs: []string{
268276
"sweephtlc: generated new destination address: %v",
269277
"sweephtlc: start sweep for %v -> %v",
@@ -272,6 +280,9 @@ var sweepHtlcTests = []struct {
272280
"sweephtlc: waiting for confirmation of %v",
273281
"sweephtlc: funding confirmed at height %v",
274282
"sweephtlc: swap hash validated for %v",
283+
"sweephtlc: sweeping to %v with feerate %v sat/vbyte",
284+
"sweephtlc: signing sweep spending %v",
285+
"sweephtlc: witness assembled, tx size=%d vbytes",
275286
},
276287
},
277288
}
@@ -336,7 +347,7 @@ func TestSweepHtlc(t *testing.T) {
336347
}
337348

338349
destAddr, err := btcutil.NewAddressWitnessPubKeyHash(
339-
make([]byte, 20), lnd.ChainParams,
350+
bytes.Repeat([]byte{1}, 20), lnd.ChainParams,
340351
)
341352
require.NoError(t, err)
342353

@@ -498,6 +509,33 @@ func TestSweepHtlc(t *testing.T) {
498509
)
499510
require.NotEmpty(t, sweepTx.TxIn[0].Witness)
500511

512+
// Verify that the sweep uses the stored destination address and
513+
// only falls back to wallet address generation when the swap
514+
// record does not define one.
515+
expectedAddr := loopOut.Contract.DestAddr
516+
if req.DestAddress != "" {
517+
expectedAddr, err = btcutil.DecodeAddress(
518+
req.DestAddress, lnd.ChainParams,
519+
)
520+
require.NoError(t, err)
521+
}
522+
if expectedAddr == nil {
523+
expectedAddr, err = lnd.WalletKit.NextAddr(
524+
ctx, lnwallet.DefaultAccountName,
525+
walletrpc.AddressType_TAPROOT_PUBKEY, false,
526+
)
527+
require.NoError(t, err)
528+
}
529+
530+
expectedPkScript, err := txscript.PayToAddrScript(
531+
expectedAddr,
532+
)
533+
require.NoError(t, err)
534+
require.Len(t, sweepTx.TxOut, 1)
535+
require.Equal(
536+
t, expectedPkScript, sweepTx.TxOut[0].PkScript,
537+
)
538+
501539
if tc.publish {
502540
// For publish=true we should see a
503541
// publish (or a publish failure

0 commit comments

Comments
 (0)