mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
loopd: prefer stored destination in sweephtlc
This commit is contained in:
parent
6c57f05d8a
commit
33917e1dbd
2 changed files with 83 additions and 37 deletions
|
|
@ -106,8 +106,8 @@ func sweepHtlc(ctx context.Context, req *looprpc.SweepHtlcRequest,
|
||||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination address: honor a provided override or derive a fresh
|
// Destination address: honor a provided override immediately so request
|
||||||
// wallet address from the default account.
|
// validation stays independent from swap lookup.
|
||||||
var sweepAddr btcutil.Address
|
var sweepAddr btcutil.Address
|
||||||
if req.DestAddress != "" {
|
if req.DestAddress != "" {
|
||||||
sweepAddr, err = btcutil.DecodeAddress(
|
sweepAddr, err = btcutil.DecodeAddress(
|
||||||
|
|
@ -117,30 +117,10 @@ func sweepHtlc(ctx context.Context, req *looprpc.SweepHtlcRequest,
|
||||||
return nil, status.Errorf(codes.InvalidArgument,
|
return nil, status.Errorf(codes.InvalidArgument,
|
||||||
"invalid dest_address: %v", err)
|
"invalid dest_address: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
sweepAddr, err = wallet.NextAddr(
|
|
||||||
ctx, lnwallet.DefaultAccountName,
|
|
||||||
walletrpc.AddressType_TAPROOT_PUBKEY,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, status.Errorf(codes.Internal,
|
|
||||||
"derive sweep address: %v", err)
|
|
||||||
}
|
|
||||||
infof("sweephtlc: generated new destination address: %v",
|
|
||||||
sweepAddr.EncodeAddress())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sweepPkScript, err := txscript.PayToAddrScript(sweepAddr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
infof("sweephtlc: start sweep for %v -> %v", req.Outpoint,
|
|
||||||
sweepAddr.EncodeAddress())
|
|
||||||
|
|
||||||
// Locate the loop-out swap whose HTLC script matches the outpoint so
|
// Locate the loop-out swap whose HTLC script matches the outpoint so
|
||||||
// we can obtain keys and the stored preimage.
|
// we can obtain keys, the stored preimage, and the default destination.
|
||||||
swaps, err := store.FetchLoopOutSwaps(ctx)
|
swaps, err := store.FetchLoopOutSwaps(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -172,6 +152,34 @@ func sweepHtlc(ctx context.Context, req *looprpc.SweepHtlcRequest,
|
||||||
"no matching swap HTLC found")
|
"no matching swap HTLC found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prefer the stored swap destination for recovery sweeps and only
|
||||||
|
// derive a fresh wallet address when neither the request nor DB
|
||||||
|
// specifies one.
|
||||||
|
if sweepAddr == nil {
|
||||||
|
sweepAddr = targetSwap.Contract.DestAddr
|
||||||
|
}
|
||||||
|
if sweepAddr == nil {
|
||||||
|
sweepAddr, err = wallet.NextAddr(
|
||||||
|
ctx, lnwallet.DefaultAccountName,
|
||||||
|
walletrpc.AddressType_TAPROOT_PUBKEY,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal,
|
||||||
|
"derive sweep address: %v", err)
|
||||||
|
}
|
||||||
|
infof("sweephtlc: generated new destination address: %v",
|
||||||
|
sweepAddr.EncodeAddress())
|
||||||
|
}
|
||||||
|
|
||||||
|
sweepPkScript, err := txscript.PayToAddrScript(sweepAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
infof("sweephtlc: start sweep for %v -> %v", req.Outpoint,
|
||||||
|
sweepAddr.EncodeAddress())
|
||||||
|
|
||||||
infof("sweephtlc: matched swap %v at height hint %v",
|
infof("sweephtlc: matched swap %v at height hint %v",
|
||||||
targetSwap.Hash, targetSwap.Contract.InitiationHeight)
|
targetSwap.Hash, targetSwap.Contract.InitiationHeight)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
|
"github.com/btcsuite/btcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btclog/v2"
|
"github.com/btcsuite/btclog/v2"
|
||||||
"github.com/lightninglabs/loop/loopdb"
|
"github.com/lightninglabs/loop/loopdb"
|
||||||
|
|
@ -17,7 +18,9 @@ import (
|
||||||
"github.com/lightninglabs/loop/utils"
|
"github.com/lightninglabs/loop/utils"
|
||||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
|
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
@ -45,7 +48,6 @@ var sweepHtlcTests = []struct {
|
||||||
satPerVByte: 10,
|
satPerVByte: 10,
|
||||||
expectRegister: true,
|
expectRegister: true,
|
||||||
expectLogs: []string{
|
expectLogs: []string{
|
||||||
"sweephtlc: generated new destination address: %v",
|
|
||||||
"sweephtlc: start sweep for %v -> %v",
|
"sweephtlc: start sweep for %v -> %v",
|
||||||
"sweephtlc: matched swap %v at height hint %v",
|
"sweephtlc: matched swap %v at height hint %v",
|
||||||
"sweephtlc: registering conf ntfn for %v hint=%v",
|
"sweephtlc: registering conf ntfn for %v hint=%v",
|
||||||
|
|
@ -63,7 +65,6 @@ var sweepHtlcTests = []struct {
|
||||||
satPerVByte: 10,
|
satPerVByte: 10,
|
||||||
expectRegister: true,
|
expectRegister: true,
|
||||||
expectLogs: []string{
|
expectLogs: []string{
|
||||||
"sweephtlc: generated new destination address: %v",
|
|
||||||
"sweephtlc: start sweep for %v -> %v",
|
"sweephtlc: start sweep for %v -> %v",
|
||||||
"sweephtlc: matched swap %v at height hint %v",
|
"sweephtlc: matched swap %v at height hint %v",
|
||||||
"sweephtlc: registering conf ntfn for %v hint=%v",
|
"sweephtlc: registering conf ntfn for %v hint=%v",
|
||||||
|
|
@ -83,7 +84,6 @@ var sweepHtlcTests = []struct {
|
||||||
satPerVByte: 10,
|
satPerVByte: 10,
|
||||||
expectRegister: true,
|
expectRegister: true,
|
||||||
expectLogs: []string{
|
expectLogs: []string{
|
||||||
"sweephtlc: generated new destination address: %v",
|
|
||||||
"sweephtlc: start sweep for %v -> %v",
|
"sweephtlc: start sweep for %v -> %v",
|
||||||
"sweephtlc: matched swap %v at height hint %v",
|
"sweephtlc: matched swap %v at height hint %v",
|
||||||
"sweephtlc: registering conf ntfn for %v hint=%v",
|
"sweephtlc: registering conf ntfn for %v hint=%v",
|
||||||
|
|
@ -105,7 +105,6 @@ var sweepHtlcTests = []struct {
|
||||||
expectErrMsg: "fee exceeds",
|
expectErrMsg: "fee exceeds",
|
||||||
expectRegister: true,
|
expectRegister: true,
|
||||||
expectLogs: []string{
|
expectLogs: []string{
|
||||||
"sweephtlc: generated new destination address: %v",
|
|
||||||
"sweephtlc: start sweep for %v -> %v",
|
"sweephtlc: start sweep for %v -> %v",
|
||||||
"sweephtlc: matched swap %v at height hint %v",
|
"sweephtlc: matched swap %v at height hint %v",
|
||||||
"sweephtlc: registering conf ntfn for %v hint=%v",
|
"sweephtlc: registering conf ntfn for %v hint=%v",
|
||||||
|
|
@ -124,7 +123,6 @@ var sweepHtlcTests = []struct {
|
||||||
expectErrMsg: "fee too low for relay after clamp",
|
expectErrMsg: "fee too low for relay after clamp",
|
||||||
expectRegister: true,
|
expectRegister: true,
|
||||||
expectLogs: []string{
|
expectLogs: []string{
|
||||||
"sweephtlc: generated new destination address: %v",
|
|
||||||
"sweephtlc: start sweep for %v -> %v",
|
"sweephtlc: start sweep for %v -> %v",
|
||||||
"sweephtlc: matched swap %v at height hint %v",
|
"sweephtlc: matched swap %v at height hint %v",
|
||||||
"sweephtlc: registering conf ntfn for %v hint=%v",
|
"sweephtlc: registering conf ntfn for %v hint=%v",
|
||||||
|
|
@ -182,10 +180,7 @@ var sweepHtlcTests = []struct {
|
||||||
expectErrMsg: "no matching swap",
|
expectErrMsg: "no matching swap",
|
||||||
expectRegister: false,
|
expectRegister: false,
|
||||||
noSwap: true,
|
noSwap: true,
|
||||||
expectLogs: []string{
|
expectLogs: []string{},
|
||||||
"sweephtlc: generated new destination address: %v",
|
|
||||||
"sweephtlc: start sweep for %v -> %v",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid initiation height",
|
name: "invalid initiation height",
|
||||||
|
|
@ -197,7 +192,6 @@ var sweepHtlcTests = []struct {
|
||||||
contract.InitiationHeight = 0
|
contract.InitiationHeight = 0
|
||||||
},
|
},
|
||||||
expectLogs: []string{
|
expectLogs: []string{
|
||||||
"sweephtlc: generated new destination address: %v",
|
|
||||||
"sweephtlc: start sweep for %v -> %v",
|
"sweephtlc: start sweep for %v -> %v",
|
||||||
"sweephtlc: matched swap %v at height hint %v",
|
"sweephtlc: matched swap %v at height hint %v",
|
||||||
},
|
},
|
||||||
|
|
@ -212,7 +206,6 @@ var sweepHtlcTests = []struct {
|
||||||
reg.ErrChan <- errors.New("boom")
|
reg.ErrChan <- errors.New("boom")
|
||||||
},
|
},
|
||||||
expectLogs: []string{
|
expectLogs: []string{
|
||||||
"sweephtlc: generated new destination address: %v",
|
|
||||||
"sweephtlc: start sweep for %v -> %v",
|
"sweephtlc: start sweep for %v -> %v",
|
||||||
"sweephtlc: matched swap %v at height hint %v",
|
"sweephtlc: matched swap %v at height hint %v",
|
||||||
"sweephtlc: registering conf ntfn for %v hint=%v",
|
"sweephtlc: registering conf ntfn for %v hint=%v",
|
||||||
|
|
@ -230,7 +223,6 @@ var sweepHtlcTests = []struct {
|
||||||
txOut.PkScript = []byte{0x6a}
|
txOut.PkScript = []byte{0x6a}
|
||||||
},
|
},
|
||||||
expectLogs: []string{
|
expectLogs: []string{
|
||||||
"sweephtlc: generated new destination address: %v",
|
|
||||||
"sweephtlc: start sweep for %v -> %v",
|
"sweephtlc: start sweep for %v -> %v",
|
||||||
"sweephtlc: matched swap %v at height hint %v",
|
"sweephtlc: matched swap %v at height hint %v",
|
||||||
"sweephtlc: registering conf ntfn for %v hint=%v",
|
"sweephtlc: registering conf ntfn for %v hint=%v",
|
||||||
|
|
@ -245,7 +237,6 @@ var sweepHtlcTests = []struct {
|
||||||
expectErrMsg: "fee exceeds HTLC value",
|
expectErrMsg: "fee exceeds HTLC value",
|
||||||
expectRegister: true,
|
expectRegister: true,
|
||||||
expectLogs: []string{
|
expectLogs: []string{
|
||||||
"sweephtlc: generated new destination address: %v",
|
|
||||||
"sweephtlc: start sweep for %v -> %v",
|
"sweephtlc: start sweep for %v -> %v",
|
||||||
"sweephtlc: matched swap %v at height hint %v",
|
"sweephtlc: matched swap %v at height hint %v",
|
||||||
"sweephtlc: registering conf ntfn for %v hint=%v",
|
"sweephtlc: registering conf ntfn for %v hint=%v",
|
||||||
|
|
@ -264,6 +255,23 @@ var sweepHtlcTests = []struct {
|
||||||
modifyReq: func(req *looprpc.SweepHtlcRequest) {
|
modifyReq: func(req *looprpc.SweepHtlcRequest) {
|
||||||
req.Preimage = bytes.Repeat([]byte{9}, 32)
|
req.Preimage = bytes.Repeat([]byte{9}, 32)
|
||||||
},
|
},
|
||||||
|
expectLogs: []string{
|
||||||
|
"sweephtlc: start sweep for %v -> %v",
|
||||||
|
"sweephtlc: matched swap %v at height hint %v",
|
||||||
|
"sweephtlc: registering conf ntfn for %v hint=%v",
|
||||||
|
"sweephtlc: waiting for confirmation of %v",
|
||||||
|
"sweephtlc: funding confirmed at height %v",
|
||||||
|
"sweephtlc: swap hash validated for %v",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "fallback to generated destination",
|
||||||
|
amount: 100_000,
|
||||||
|
satPerVByte: 10,
|
||||||
|
expectRegister: true,
|
||||||
|
mutateSwap: func(contract *loopdb.LoopOutContract) {
|
||||||
|
contract.DestAddr = nil
|
||||||
|
},
|
||||||
expectLogs: []string{
|
expectLogs: []string{
|
||||||
"sweephtlc: generated new destination address: %v",
|
"sweephtlc: generated new destination address: %v",
|
||||||
"sweephtlc: start sweep for %v -> %v",
|
"sweephtlc: start sweep for %v -> %v",
|
||||||
|
|
@ -272,6 +280,9 @@ var sweepHtlcTests = []struct {
|
||||||
"sweephtlc: waiting for confirmation of %v",
|
"sweephtlc: waiting for confirmation of %v",
|
||||||
"sweephtlc: funding confirmed at height %v",
|
"sweephtlc: funding confirmed at height %v",
|
||||||
"sweephtlc: swap hash validated for %v",
|
"sweephtlc: swap hash validated for %v",
|
||||||
|
"sweephtlc: sweeping to %v with feerate %v sat/vbyte",
|
||||||
|
"sweephtlc: signing sweep spending %v",
|
||||||
|
"sweephtlc: witness assembled, tx size=%d vbytes",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -336,7 +347,7 @@ func TestSweepHtlc(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
destAddr, err := btcutil.NewAddressWitnessPubKeyHash(
|
destAddr, err := btcutil.NewAddressWitnessPubKeyHash(
|
||||||
make([]byte, 20), lnd.ChainParams,
|
bytes.Repeat([]byte{1}, 20), lnd.ChainParams,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|
@ -498,6 +509,33 @@ func TestSweepHtlc(t *testing.T) {
|
||||||
)
|
)
|
||||||
require.NotEmpty(t, sweepTx.TxIn[0].Witness)
|
require.NotEmpty(t, sweepTx.TxIn[0].Witness)
|
||||||
|
|
||||||
|
// Verify that the sweep uses the stored destination address and
|
||||||
|
// only falls back to wallet address generation when the swap
|
||||||
|
// record does not define one.
|
||||||
|
expectedAddr := loopOut.Contract.DestAddr
|
||||||
|
if req.DestAddress != "" {
|
||||||
|
expectedAddr, err = btcutil.DecodeAddress(
|
||||||
|
req.DestAddress, lnd.ChainParams,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
if expectedAddr == nil {
|
||||||
|
expectedAddr, err = lnd.WalletKit.NextAddr(
|
||||||
|
ctx, lnwallet.DefaultAccountName,
|
||||||
|
walletrpc.AddressType_TAPROOT_PUBKEY, false,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedPkScript, err := txscript.PayToAddrScript(
|
||||||
|
expectedAddr,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, sweepTx.TxOut, 1)
|
||||||
|
require.Equal(
|
||||||
|
t, expectedPkScript, sweepTx.TxOut[0].PkScript,
|
||||||
|
)
|
||||||
|
|
||||||
if tc.publish {
|
if tc.publish {
|
||||||
// For publish=true we should see a
|
// For publish=true we should see a
|
||||||
// publish (or a publish failure
|
// publish (or a publish failure
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue