mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-08-25 05:02:32 +02:00
Make sure that an address imported to LND via ImportTapscript or ImportPublicKey can be used as a delivery address in coop close. New test cases: - P2TR address imported with ImportTapscript - P2TR address imported with ImportPublicKey - P2WPKH address imported with ImportPublicKey Safeguard against https://github.com/lightninglabs/loop/issues/923
270 lines
7.4 KiB
Go
270 lines
7.4 KiB
Go
package itest
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/btcsuite/btcd/btcutil"
|
|
"github.com/btcsuite/btcd/txscript"
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
|
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
|
"github.com/lightningnetwork/lnd/lntest"
|
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
var coopCloseWithExternalTestCases = []*lntest.TestCase{
|
|
{
|
|
Name: "set P2WPKH delivery address at open",
|
|
TestFunc: func(ht *lntest.HarnessTest) {
|
|
testCoopCloseWithExternalDelivery(
|
|
ht, true, false, false,
|
|
lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
|
|
)
|
|
},
|
|
},
|
|
{
|
|
Name: "set P2WPKH delivery address at close",
|
|
TestFunc: func(ht *lntest.HarnessTest) {
|
|
testCoopCloseWithExternalDelivery(
|
|
ht, false, false, false,
|
|
lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
|
|
)
|
|
},
|
|
},
|
|
{
|
|
Name: "set P2TR delivery address at open",
|
|
TestFunc: func(ht *lntest.HarnessTest) {
|
|
testCoopCloseWithExternalDelivery(
|
|
ht, true, false, false,
|
|
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
|
|
)
|
|
},
|
|
},
|
|
{
|
|
Name: "set P2TR delivery address at close",
|
|
TestFunc: func(ht *lntest.HarnessTest) {
|
|
testCoopCloseWithExternalDelivery(
|
|
ht, false, false, false,
|
|
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
|
|
)
|
|
},
|
|
},
|
|
{
|
|
Name: "set imported P2TR address (ImportTapscript) at open",
|
|
TestFunc: func(ht *lntest.HarnessTest) {
|
|
testCoopCloseWithExternalDelivery(
|
|
ht, true, true, false,
|
|
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
|
|
)
|
|
},
|
|
},
|
|
{
|
|
Name: "set imported P2TR address (ImportTapscript) at close",
|
|
TestFunc: func(ht *lntest.HarnessTest) {
|
|
testCoopCloseWithExternalDelivery(
|
|
ht, false, true, false,
|
|
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
|
|
)
|
|
},
|
|
},
|
|
{
|
|
Name: "set imported P2WPKH address at open",
|
|
TestFunc: func(ht *lntest.HarnessTest) {
|
|
testCoopCloseWithExternalDelivery(
|
|
ht, true, false, true,
|
|
lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
|
|
)
|
|
},
|
|
},
|
|
{
|
|
Name: "set imported P2WPKH address at close",
|
|
TestFunc: func(ht *lntest.HarnessTest) {
|
|
testCoopCloseWithExternalDelivery(
|
|
ht, false, false, true,
|
|
lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
|
|
)
|
|
},
|
|
},
|
|
{
|
|
Name: "set imported P2TR address (ImportPublicKey) at open",
|
|
TestFunc: func(ht *lntest.HarnessTest) {
|
|
testCoopCloseWithExternalDelivery(
|
|
ht, true, false, true,
|
|
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
|
|
)
|
|
},
|
|
},
|
|
{
|
|
Name: "set imported P2TR address (ImportPublicKey) at close",
|
|
TestFunc: func(ht *lntest.HarnessTest) {
|
|
testCoopCloseWithExternalDelivery(
|
|
ht, false, false, true,
|
|
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
|
|
)
|
|
},
|
|
},
|
|
}
|
|
|
|
// testCoopCloseWithExternalDelivery ensures that we have a valid settled
|
|
// balance irrespective of whether the delivery address is in LND's wallet or
|
|
// not. Some users set this value to be an address in a different wallet and
|
|
// this should not affect our ability to accurately report the settled balance.
|
|
//
|
|
// If importTapscript is set, it imports a Taproot script and internal key to
|
|
// Alice's LND using ImportTapscript to make sure it doesn't interfere with
|
|
// delivery address. If importPubkey is set, the address is imported using
|
|
// ImportPublicKey.
|
|
func testCoopCloseWithExternalDelivery(ht *lntest.HarnessTest,
|
|
upfrontShutdown, importTapscript, importPubkey bool,
|
|
deliveryAddressType lnrpc.AddressType) {
|
|
|
|
alice := ht.NewNodeWithCoins("Alice", nil)
|
|
bob := ht.NewNodeWithCoins("bob", nil)
|
|
ht.ConnectNodes(alice, bob)
|
|
|
|
// Make fake taproot internal public key (equal to the final).
|
|
// This is only used if importTapscript or importPubkey is set.
|
|
taprootPubkey := [32]byte{1, 2, 3}
|
|
if upfrontShutdown {
|
|
// Make new address for second sub-test not to import
|
|
// the same address twice causing an error.
|
|
taprootPubkey[3] = 1
|
|
}
|
|
pkScriptBytes := append(
|
|
[]byte{txscript.OP_1, txscript.OP_DATA_32},
|
|
taprootPubkey[:]...,
|
|
)
|
|
pkScript, err := txscript.ParsePkScript(pkScriptBytes)
|
|
require.NoError(ht, err)
|
|
taprootAddress, err := pkScript.Address(harnessNetParams)
|
|
require.NoError(ht, err)
|
|
|
|
var addr string
|
|
switch {
|
|
// Use ImportTapscript.
|
|
case importTapscript:
|
|
addr = taprootAddress.String()
|
|
|
|
// Import the taproot address to LND.
|
|
req := &walletrpc.ImportTapscriptRequest{
|
|
InternalPublicKey: taprootPubkey[:],
|
|
Script: &walletrpc.ImportTapscriptRequest_FullKeyOnly{
|
|
FullKeyOnly: true,
|
|
},
|
|
}
|
|
res := alice.RPC.ImportTapscript(req)
|
|
require.Equal(ht, addr, res.P2TrAddress)
|
|
|
|
// Use ImportPublicKey.
|
|
case importPubkey:
|
|
var (
|
|
address btcutil.Address
|
|
pubKey []byte
|
|
addressType walletrpc.AddressType
|
|
)
|
|
switch deliveryAddressType {
|
|
case lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH:
|
|
// Make fake public key hash.
|
|
pk := [33]byte{2, 3, 4}
|
|
if upfrontShutdown {
|
|
// Make new address for second sub-test.
|
|
pk[1]++
|
|
}
|
|
address, err = btcutil.NewAddressWitnessPubKeyHash(
|
|
btcutil.Hash160(pk[:]), harnessNetParams,
|
|
)
|
|
require.NoError(ht, err)
|
|
pubKey = pk[:]
|
|
addressType = walletrpc.AddressType_WITNESS_PUBKEY_HASH
|
|
|
|
case lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY:
|
|
address = taprootAddress
|
|
pubKey = taprootPubkey[:]
|
|
addressType = walletrpc.AddressType_TAPROOT_PUBKEY
|
|
|
|
default:
|
|
ht.Fatalf("not allowed address type: %v",
|
|
deliveryAddressType)
|
|
}
|
|
|
|
addr = address.String()
|
|
|
|
// Import the address to LND.
|
|
alice.RPC.ImportPublicKey(&walletrpc.ImportPublicKeyRequest{
|
|
PublicKey: pubKey,
|
|
AddressType: addressType,
|
|
})
|
|
|
|
// Here we generate a final delivery address in bob's wallet but set by
|
|
// alice. We do this to ensure that the address is not in alice's LND
|
|
// wallet. We already correctly track settled balances when the address
|
|
// is in the LND wallet.
|
|
default:
|
|
res := bob.RPC.NewAddress(&lnrpc.NewAddressRequest{
|
|
Type: deliveryAddressType,
|
|
})
|
|
addr = res.Address
|
|
}
|
|
|
|
// Prepare for channel open.
|
|
openParams := lntest.OpenChannelParams{
|
|
Amt: btcutil.Amount(1000000),
|
|
}
|
|
|
|
// If we are testing the case where we set it on open then we'll set the
|
|
// upfront shutdown script in the channel open parameters.
|
|
if upfrontShutdown {
|
|
openParams.CloseAddress = addr
|
|
}
|
|
|
|
// Open the channel!
|
|
chanPoint := ht.OpenChannel(alice, bob, openParams)
|
|
|
|
// Prepare for channel close.
|
|
closeParams := lnrpc.CloseChannelRequest{
|
|
ChannelPoint: chanPoint,
|
|
TargetConf: 6,
|
|
}
|
|
|
|
// If we are testing the case where we set the delivery address on
|
|
// channel close then we will set it in the channel close parameters.
|
|
if !upfrontShutdown {
|
|
closeParams.DeliveryAddress = addr
|
|
}
|
|
|
|
// Close the channel!
|
|
closeClient := alice.RPC.CloseChannel(&closeParams)
|
|
|
|
// Assert that we got a channel update when we get a closing txid.
|
|
_, err = closeClient.Recv()
|
|
require.NoError(ht, err)
|
|
|
|
// Mine the closing transaction.
|
|
ht.MineClosingTx(chanPoint)
|
|
|
|
// Assert that we got a channel update when the closing tx was mined.
|
|
_, err = closeClient.Recv()
|
|
require.NoError(ht, err)
|
|
|
|
// Here we query our closed channels to conduct the final test
|
|
// assertion. We want to ensure that even though alice's delivery
|
|
// address is set to an address in bob's wallet, we should still show
|
|
// the balance as settled.
|
|
err = wait.NoError(func() error {
|
|
closed := alice.RPC.ClosedChannels(&lnrpc.ClosedChannelsRequest{
|
|
Cooperative: true,
|
|
})
|
|
|
|
if len(closed.Channels) == 0 {
|
|
return fmt.Errorf("expected closed channel not found")
|
|
}
|
|
|
|
if closed.Channels[0].SettledBalance == 0 {
|
|
return fmt.Errorf("expected settled balance to be zero")
|
|
}
|
|
|
|
return nil
|
|
}, defaultTimeout)
|
|
require.NoError(ht, err, "timeout checking closed channels")
|
|
}
|