Skip to content

Commit 4862251

Browse files
authored
Merge pull request #9750 from starius/fix-InternalKeyForAddr-for-imported-addresses
lnwallet: fix InternalKeyForAddr for imported addr
2 parents a35ace7 + dc2cad9 commit 4862251

File tree

5 files changed

+214
-71
lines changed

5 files changed

+214
-71
lines changed

docs/release-notes/release-notes-0.19.0.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ keysend payment validation is stricter.
118118
* [Fixed](https://github.com/lightningnetwork/lnd/pull/9746) a possible panic
119119
when running LND with an aux component injected (custom channels).
120120

121+
* [Fixed a bug](https://github.com/lightningnetwork/lnd/pull/9750): if a Taproot
122+
address is added to LND using the `ImportTapscript` RPC, LND previously failed
123+
to perform a cooperative close to that address.
124+
121125
# New Features
122126

123127
* Add support for [archiving channel backup](https://github.com/lightningnetwork/lnd/pull/9232)

itest/list_exclude_test.go

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
// be excluded from the test suite atm.
1414
//
1515
// TODO(yy): fix these tests and remove them from this list.
16-
var excludedTestsWindows = []string{
16+
var excludedTestsWindows = append(append([]string{
1717
"batch channel funding",
1818
"zero conf channel open",
1919
"open channel with unstable utxos",
@@ -45,26 +45,12 @@ var excludedTestsWindows = []string{
4545
"wipe forwarding packages",
4646

4747
"coop close with htlcs",
48-
"coop close with external delivery",
4948

5049
"forward interceptor restart",
5150
"forward interceptor dedup htlcs",
5251
"invoice HTLC modifier basic",
5352
"lookup htlc resolution",
5453

55-
"remote signer-taproot",
56-
"remote signer-account import",
57-
"remote signer-bump fee",
58-
"remote signer-funding input types",
59-
"remote signer-funding async payments taproot",
60-
"remote signer-funding async payments",
61-
"remote signer-random seed",
62-
"remote signer-verify msg",
63-
"remote signer-channel open",
64-
"remote signer-shared key",
65-
"remote signer-psbt",
66-
"remote signer-sign output raw",
67-
6854
"on chain to blinded",
6955
"query blinded route",
7056

@@ -76,7 +62,12 @@ var excludedTestsWindows = []string{
7662
// more investigation is needed.
7763
"channel force close-anchor restart",
7864
"channel force close-simple taproot restart",
79-
}
65+
}, extractNames(
66+
"coop close with external delivery",
67+
coopCloseWithExternalTestCases)...,
68+
),
69+
extractNames("remote signer", remoteSignerTestCases)...,
70+
)
8071

8172
// filterWindowsFlakyTests filters out the flaky tests that are excluded from
8273
// the test suite on Windows.

itest/list_on_test.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package itest
55
import (
66
"fmt"
77

8+
"github.com/lightningnetwork/lnd/fn/v2"
89
"github.com/lightningnetwork/lnd/lntest"
910
)
1011

@@ -642,10 +643,6 @@ var allTestCases = []*lntest.TestCase{
642643
Name: "sweep commit output and anchor",
643644
TestFunc: testSweepCommitOutputAndAnchor,
644645
},
645-
{
646-
Name: "coop close with external delivery",
647-
TestFunc: testCoopCloseWithExternalDelivery,
648-
},
649646
{
650647
Name: "payment failed htlc local swept",
651648
TestFunc: testPaymentFailedHTLCLocalSwept,
@@ -720,6 +717,13 @@ func appendPrefixed(prefix string, testCases,
720717
return testCases
721718
}
722719

720+
// extractNames is used to extract tests' names from a group of prefixed tests.
721+
func extractNames(prefix string, subtestCases []*lntest.TestCase) []string {
722+
return fn.Map(subtestCases, func(tc *lntest.TestCase) string {
723+
return fmt.Sprintf("%s-%s", prefix, tc.Name)
724+
})
725+
}
726+
723727
func init() {
724728
// Register subtests.
725729
allTestCases = appendPrefixed(
@@ -762,6 +766,10 @@ func init() {
762766
allTestCases = appendPrefixed(
763767
"wallet", allTestCases, walletTestCases,
764768
)
769+
allTestCases = appendPrefixed(
770+
"coop close with external delivery", allTestCases,
771+
coopCloseWithExternalTestCases,
772+
)
765773

766774
// Prepare the test cases for windows to exclude some of the flaky
767775
// ones.

itest/lnd_coop_close_external_delivery_test.go

Lines changed: 184 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,75 +2,209 @@ package itest
22

33
import (
44
"fmt"
5-
"testing"
65

76
"github.com/btcsuite/btcd/btcutil"
7+
"github.com/btcsuite/btcd/txscript"
88
"github.com/lightningnetwork/lnd/lnrpc"
9+
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
910
"github.com/lightningnetwork/lnd/lntest"
1011
"github.com/lightningnetwork/lnd/lntest/wait"
1112
"github.com/stretchr/testify/require"
1213
)
1314

14-
func testCoopCloseWithExternalDelivery(ht *lntest.HarnessTest) {
15-
ok := ht.Run("set P2WPKH delivery address at open", func(t *testing.T) {
16-
tt := ht.Subtest(t)
17-
testCoopCloseWithExternalDeliveryImpl(
18-
tt, true, lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
19-
)
20-
})
21-
// Abort the test if failed.
22-
if !ok {
23-
return
24-
}
25-
26-
ok = ht.Run("set P2WPKH delivery address at close", func(t *testing.T) {
27-
tt := ht.Subtest(t)
28-
testCoopCloseWithExternalDeliveryImpl(
29-
tt, false, lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
30-
)
31-
})
32-
// Abort the test if failed.
33-
if !ok {
34-
return
35-
}
36-
37-
ok = ht.Run("set P2TR delivery address at open", func(t *testing.T) {
38-
tt := ht.Subtest(t)
39-
testCoopCloseWithExternalDeliveryImpl(
40-
tt, true, lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
41-
)
42-
})
43-
// Abort the test if failed.
44-
if !ok {
45-
return
46-
}
47-
48-
ht.Run("set P2TR delivery address at close", func(t *testing.T) {
49-
tt := ht.Subtest(t)
50-
testCoopCloseWithExternalDeliveryImpl(
51-
tt, false, lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
52-
)
53-
})
15+
var coopCloseWithExternalTestCases = []*lntest.TestCase{
16+
{
17+
Name: "set P2WPKH delivery address at open",
18+
TestFunc: func(ht *lntest.HarnessTest) {
19+
testCoopCloseWithExternalDelivery(
20+
ht, true, false, false,
21+
lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
22+
)
23+
},
24+
},
25+
{
26+
Name: "set P2WPKH delivery address at close",
27+
TestFunc: func(ht *lntest.HarnessTest) {
28+
testCoopCloseWithExternalDelivery(
29+
ht, false, false, false,
30+
lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
31+
)
32+
},
33+
},
34+
{
35+
Name: "set P2TR delivery address at open",
36+
TestFunc: func(ht *lntest.HarnessTest) {
37+
testCoopCloseWithExternalDelivery(
38+
ht, true, false, false,
39+
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
40+
)
41+
},
42+
},
43+
{
44+
Name: "set P2TR delivery address at close",
45+
TestFunc: func(ht *lntest.HarnessTest) {
46+
testCoopCloseWithExternalDelivery(
47+
ht, false, false, false,
48+
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
49+
)
50+
},
51+
},
52+
{
53+
Name: "set imported P2TR address (ImportTapscript) at open",
54+
TestFunc: func(ht *lntest.HarnessTest) {
55+
testCoopCloseWithExternalDelivery(
56+
ht, true, true, false,
57+
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
58+
)
59+
},
60+
},
61+
{
62+
Name: "set imported P2TR address (ImportTapscript) at close",
63+
TestFunc: func(ht *lntest.HarnessTest) {
64+
testCoopCloseWithExternalDelivery(
65+
ht, false, true, false,
66+
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
67+
)
68+
},
69+
},
70+
{
71+
Name: "set imported P2WPKH address at open",
72+
TestFunc: func(ht *lntest.HarnessTest) {
73+
testCoopCloseWithExternalDelivery(
74+
ht, true, false, true,
75+
lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
76+
)
77+
},
78+
},
79+
{
80+
Name: "set imported P2WPKH address at close",
81+
TestFunc: func(ht *lntest.HarnessTest) {
82+
testCoopCloseWithExternalDelivery(
83+
ht, false, false, true,
84+
lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
85+
)
86+
},
87+
},
88+
{
89+
Name: "set imported P2TR address (ImportPublicKey) at open",
90+
TestFunc: func(ht *lntest.HarnessTest) {
91+
testCoopCloseWithExternalDelivery(
92+
ht, true, false, true,
93+
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
94+
)
95+
},
96+
},
97+
{
98+
Name: "set imported P2TR address (ImportPublicKey) at close",
99+
TestFunc: func(ht *lntest.HarnessTest) {
100+
testCoopCloseWithExternalDelivery(
101+
ht, false, false, true,
102+
lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
103+
)
104+
},
105+
},
54106
}
55107

56-
// testCoopCloseWithExternalDeliveryImpl ensures that we have a valid settled
108+
// testCoopCloseWithExternalDelivery ensures that we have a valid settled
57109
// balance irrespective of whether the delivery address is in LND's wallet or
58110
// not. Some users set this value to be an address in a different wallet and
59111
// this should not affect our ability to accurately report the settled balance.
60-
func testCoopCloseWithExternalDeliveryImpl(ht *lntest.HarnessTest,
61-
upfrontShutdown bool, deliveryAddressType lnrpc.AddressType) {
112+
//
113+
// If importTapscript is set, it imports a Taproot script and internal key to
114+
// Alice's LND using ImportTapscript to make sure it doesn't interfere with
115+
// delivery address. If importPubkey is set, the address is imported using
116+
// ImportPublicKey.
117+
func testCoopCloseWithExternalDelivery(ht *lntest.HarnessTest,
118+
upfrontShutdown, importTapscript, importPubkey bool,
119+
deliveryAddressType lnrpc.AddressType) {
62120

63121
alice := ht.NewNodeWithCoins("Alice", nil)
64122
bob := ht.NewNodeWithCoins("bob", nil)
65123
ht.ConnectNodes(alice, bob)
66124

125+
// Make fake taproot internal public key (equal to the final).
126+
// This is only used if importTapscript or importPubkey is set.
127+
taprootPubkey := [32]byte{1, 2, 3}
128+
if upfrontShutdown {
129+
// Make new address for second sub-test not to import
130+
// the same address twice causing an error.
131+
taprootPubkey[3] = 1
132+
}
133+
pkScriptBytes := append(
134+
[]byte{txscript.OP_1, txscript.OP_DATA_32},
135+
taprootPubkey[:]...,
136+
)
137+
pkScript, err := txscript.ParsePkScript(pkScriptBytes)
138+
require.NoError(ht, err)
139+
taprootAddress, err := pkScript.Address(harnessNetParams)
140+
require.NoError(ht, err)
141+
142+
var addr string
143+
switch {
144+
// Use ImportTapscript.
145+
case importTapscript:
146+
addr = taprootAddress.String()
147+
148+
// Import the taproot address to LND.
149+
req := &walletrpc.ImportTapscriptRequest{
150+
InternalPublicKey: taprootPubkey[:],
151+
Script: &walletrpc.ImportTapscriptRequest_FullKeyOnly{
152+
FullKeyOnly: true,
153+
},
154+
}
155+
res := alice.RPC.ImportTapscript(req)
156+
require.Equal(ht, addr, res.P2TrAddress)
157+
158+
// Use ImportPublicKey.
159+
case importPubkey:
160+
var (
161+
address btcutil.Address
162+
pubKey []byte
163+
addressType walletrpc.AddressType
164+
)
165+
switch deliveryAddressType {
166+
case lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH:
167+
// Make fake public key hash.
168+
pk := [33]byte{2, 3, 4}
169+
if upfrontShutdown {
170+
// Make new address for second sub-test.
171+
pk[1]++
172+
}
173+
address, err = btcutil.NewAddressWitnessPubKeyHash(
174+
btcutil.Hash160(pk[:]), harnessNetParams,
175+
)
176+
require.NoError(ht, err)
177+
pubKey = pk[:]
178+
addressType = walletrpc.AddressType_WITNESS_PUBKEY_HASH
179+
180+
case lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY:
181+
address = taprootAddress
182+
pubKey = taprootPubkey[:]
183+
addressType = walletrpc.AddressType_TAPROOT_PUBKEY
184+
185+
default:
186+
ht.Fatalf("not allowed address type: %v",
187+
deliveryAddressType)
188+
}
189+
190+
addr = address.String()
191+
192+
// Import the address to LND.
193+
alice.RPC.ImportPublicKey(&walletrpc.ImportPublicKeyRequest{
194+
PublicKey: pubKey,
195+
AddressType: addressType,
196+
})
197+
67198
// Here we generate a final delivery address in bob's wallet but set by
68199
// alice. We do this to ensure that the address is not in alice's LND
69200
// wallet. We already correctly track settled balances when the address
70201
// is in the LND wallet.
71-
addr := bob.RPC.NewAddress(&lnrpc.NewAddressRequest{
72-
Type: deliveryAddressType,
73-
})
202+
default:
203+
res := bob.RPC.NewAddress(&lnrpc.NewAddressRequest{
204+
Type: deliveryAddressType,
205+
})
206+
addr = res.Address
207+
}
74208

75209
// Prepare for channel open.
76210
openParams := lntest.OpenChannelParams{
@@ -80,7 +214,7 @@ func testCoopCloseWithExternalDeliveryImpl(ht *lntest.HarnessTest,
80214
// If we are testing the case where we set it on open then we'll set the
81215
// upfront shutdown script in the channel open parameters.
82216
if upfrontShutdown {
83-
openParams.CloseAddress = addr.Address
217+
openParams.CloseAddress = addr
84218
}
85219

86220
// Open the channel!
@@ -95,14 +229,14 @@ func testCoopCloseWithExternalDeliveryImpl(ht *lntest.HarnessTest,
95229
// If we are testing the case where we set the delivery address on
96230
// channel close then we will set it in the channel close parameters.
97231
if !upfrontShutdown {
98-
closeParams.DeliveryAddress = addr.Address
232+
closeParams.DeliveryAddress = addr
99233
}
100234

101235
// Close the channel!
102236
closeClient := alice.RPC.CloseChannel(&closeParams)
103237

104238
// Assert that we got a channel update when we get a closing txid.
105-
_, err := closeClient.Recv()
239+
_, err = closeClient.Recv()
106240
require.NoError(ht, err)
107241

108242
// Mine the closing transaction.

0 commit comments

Comments
 (0)