Skip to content

Commit 5d92172

Browse files
authored
Merge pull request #9609 from yyforyongyu/fix-listunspent
Fix inaccurate `listunspent` result
2 parents e8875e0 + bdcd980 commit 5d92172

File tree

15 files changed

+85
-257
lines changed

15 files changed

+85
-257
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@
9191
* [Pass through](https://github.com/lightningnetwork/lnd/pull/9601) the unused
9292
`MaxPeers` configuration variable for neutrino mode.
9393

94+
* [Fixed](https://github.com/lightningnetwork/lnd/pull/9609) a bug that may
95+
cause `listunspent` to give inaccurate wallet UTXOs.
96+
9497
# New Features
9598

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

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0
1212
github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c
1313
github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318
14-
github.com/btcsuite/btcwallet v0.16.10
14+
github.com/btcsuite/btcwallet v0.16.11
1515
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5
1616
github.com/btcsuite/btcwallet/wallet/txrules v1.2.2
1717
github.com/btcsuite/btcwallet/walletdb v1.4.4

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c/go.mod h1:w7xnGOhw
9595
github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318 h1:oCjIcinPt7XQ644MP/22JcjYEC84qRc3bRBH0d7Hhd4=
9696
github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318/go.mod h1:XItGUfVOxotJL8kkuk2Hj3EVow5KCugXl3wWfQ6K0AE=
9797
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
98-
github.com/btcsuite/btcwallet v0.16.10 h1:SDMS0Gp7oEJVvyZNQ6gDYkpkvp/cSMRcAAy3fvO3vTk=
99-
github.com/btcsuite/btcwallet v0.16.10/go.mod h1:1HJXYbjJzgumlnxOC2+ViR1U+gnHWoOn7WeK5OfY1eU=
98+
github.com/btcsuite/btcwallet v0.16.11 h1:c8RgW/HO79if8P+KFQLQE00ITmFnLPKAzIy9FwxE37A=
99+
github.com/btcsuite/btcwallet v0.16.11/go.mod h1:1HJXYbjJzgumlnxOC2+ViR1U+gnHWoOn7WeK5OfY1eU=
100100
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 h1:Rr0njWI3r341nhSPesKQ2JF+ugDSzdPoeckS75SeDZk=
101101
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5/go.mod h1:+tXJ3Ym0nlQc/iHSwW1qzjmPs3ev+UVWMbGgfV1OZqU=
102102
github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 h1:YEO+Lx1ZJJAtdRrjuhXjWrYsmAk26wLTlNzxt2q0lhk=

itest/flakes.go

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package itest
33
import (
44
"time"
55

6-
"github.com/btcsuite/btcd/btcutil"
76
"github.com/lightningnetwork/lnd/lntest"
8-
"github.com/lightningnetwork/lnd/lntest/node"
97
)
108

119
// flakePreimageSettlement documents a flake found when testing the preimage
@@ -34,19 +32,6 @@ func flakePreimageSettlement(ht *lntest.HarnessTest) {
3432
time.Sleep(2 * time.Second)
3533
}
3634

37-
// flakeFundExtraUTXO documents a flake found when testing the sweeping behavior
38-
// of the given node, which would fail due to no wallet UTXO available, while
39-
// there should be enough.
40-
//
41-
// TODO(yy): remove it once the issue is resolved.
42-
func flakeFundExtraUTXO(ht *lntest.HarnessTest, node *node.HarnessNode) {
43-
// The node should have enough wallet UTXOs here to sweep the HTLC in
44-
// the end of this test. However, due to a known issue, the node's
45-
// wallet may report there's no UTXO available. For details,
46-
// - https://github.com/lightningnetwork/lnd/issues/8786
47-
ht.FundCoins(btcutil.SatoshiPerBitcoin, node)
48-
}
49-
5035
// flakeTxNotifierNeutrino documents a flake found when running force close
5136
// tests using neutrino backend, which is a race between two notifications - one
5237
// for the spending notification, the other for the block which contains the
@@ -127,3 +112,28 @@ func flakePaymentStreamReturnEarly() {
127112
// commitment.
128113
time.Sleep(2 * time.Second)
129114
}
115+
116+
// flakeRaceInBitcoinClientNotifications documents a bug found that the
117+
// `ListUnspent` gives inaccurate results. In specific,
118+
// - an output is confirmed in block X, which is under the process of being
119+
// credited to our wallet.
120+
// - `ListUnspent` is called between the above process, returning an
121+
// inaccurate result, causing the sweeper to think there's no wallet utxo.
122+
// - the sweeping will fail at block X due to not enough inputs.
123+
//
124+
// Under the hood, the RPC client created for handling wallet txns and handling
125+
// block notifications are independent. For the block notification, which is
126+
// registered via `RegisterBlockEpochNtfn`, is managed by the `chainntnfs`,
127+
// which is hooked to a bitcoind client created at startup. For the wallet, it
128+
// uses another bitcoind client to receive online events. Although they share
129+
// the same bitcoind RPC conn, these two clients are acting independently.
130+
// With this setup, it means there's no coordination between the two system -
131+
// `lnwallet` and `chainntnfs` can disagree on the latest onchain state for a
132+
// short period, causing an inconsistent state which leads to the failed
133+
// sweeping attempt.
134+
//
135+
// TODO(yy): We need to adhere to the SSOT principle, and make the effort to
136+
// ensure the whole system only uses one bitcoind client.
137+
func flakeRaceInBitcoinClientNotifications(ht *lntest.HarnessTest) {
138+
ht.MineEmptyBlocks(1)
139+
}

itest/list_exclude_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ var excludedTestsWindows = []string{
6969
"query blinded route",
7070

7171
"data loss protection",
72+
73+
// The following restart cases will fail in windows due to aggregation
74+
// can sometimes miss grouping one or two inputs in the same sweeping
75+
// tx, which is likely caused by how the blocks are notified in windows,
76+
// more investigation is needed.
77+
"channel force close-anchor restart",
78+
"channel force close-simple taproot restart",
7279
}
7380

7481
// filterWindowsFlakyTests filters out the flaky tests that are excluded from

itest/lnd_multi-hop_force_close_test.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,6 @@ func runLocalClaimOutgoingHTLC(ht *lntest.HarnessTest,
341341
ht.FundCoins(btcutil.SatoshiPerBitcoin, bob)
342342
}
343343

344-
flakeFundExtraUTXO(ht, bob)
345-
346344
// Now that our channels are set up, we'll send two HTLC's from Alice
347345
// to Carol. The first HTLC will be universally considered "dust",
348346
// while the second will be a proper fully valued HTLC.
@@ -685,7 +683,6 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest,
685683

686684
// Fund Carol one UTXO so she can sweep outputs.
687685
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
688-
flakeFundExtraUTXO(ht, carol)
689686

690687
// If this is a taproot channel, then we'll need to make some manual
691688
// route hints so Alice can actually find a route.
@@ -1601,8 +1598,6 @@ func runLocalClaimIncomingHTLC(ht *lntest.HarnessTest,
16011598

16021599
// Fund Carol one UTXO so she can sweep outputs.
16031600
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
1604-
flakeFundExtraUTXO(ht, carol)
1605-
flakeFundExtraUTXO(ht, bob)
16061601

16071602
// If this is a taproot channel, then we'll need to make some manual
16081603
// route hints so Alice can actually find a route.
@@ -1897,7 +1892,6 @@ func runLocalClaimIncomingHTLCLeased(ht *lntest.HarnessTest,
18971892

18981893
// Fund Carol one UTXO so she can sweep outputs.
18991894
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
1900-
flakeFundExtraUTXO(ht, carol)
19011895

19021896
// With the network active, we'll now add a new hodl invoice at Carol's
19031897
// end. Make sure the cltv expiry delta is large enough, otherwise Bob
@@ -2230,7 +2224,6 @@ func runLocalPreimageClaim(ht *lntest.HarnessTest,
22302224

22312225
// Fund Carol one UTXO so she can sweep outputs.
22322226
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
2233-
flakeFundExtraUTXO(ht, carol)
22342227

22352228
// If this is a taproot channel, then we'll need to make some manual
22362229
// route hints so Alice can actually find a route.
@@ -2490,7 +2483,6 @@ func runLocalPreimageClaimLeased(ht *lntest.HarnessTest,
24902483

24912484
// Fund Carol one UTXO so she can sweep outputs.
24922485
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
2493-
flakeFundExtraUTXO(ht, carol)
24942486

24952487
// With the network active, we'll now add a new hodl invoice at Carol's
24962488
// end. Make sure the cltv expiry delta is large enough, otherwise Bob
@@ -2842,7 +2834,6 @@ func runHtlcAggregation(ht *lntest.HarnessTest,
28422834
// We need one additional UTXO to create the sweeping tx for the
28432835
// second-level success txes.
28442836
ht.FundCoins(btcutil.SatoshiPerBitcoin, bob)
2845-
flakeFundExtraUTXO(ht, bob)
28462837

28472838
// If this is a taproot channel, then we'll need to make some manual
28482839
// route hints so Alice+Carol can actually find a route.

itest/lnd_sweep_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,6 @@ func testSweepCPFPAnchorOutgoingTimeout(ht *lntest.HarnessTest) {
115115
ht.FundCoins(btcutil.SatoshiPerBitcoin, bob)
116116
}
117117

118-
flakeFundExtraUTXO(ht, bob)
119-
120118
// Subscribe the invoice.
121119
streamCarol := carol.RPC.SubscribeSingleInvoice(payHash[:])
122120

@@ -342,6 +340,8 @@ func testSweepCPFPAnchorOutgoingTimeout(ht *lntest.HarnessTest) {
342340
// needed to clean up the mempool.
343341
ht.MineBlocksAndAssertNumTxes(1, 2)
344342

343+
flakeRaceInBitcoinClientNotifications(ht)
344+
345345
// The above mined block should confirm Bob's force close tx, and his
346346
// contractcourt will offer the HTLC to his sweeper. We are not testing
347347
// the HTLC sweeping behaviors so we just perform a simple check and
@@ -435,8 +435,6 @@ func testSweepCPFPAnchorIncomingTimeout(ht *lntest.HarnessTest) {
435435
ht.FundCoins(btcutil.SatoshiPerBitcoin, bob)
436436
}
437437

438-
flakeFundExtraUTXO(ht, bob)
439-
440438
// Subscribe the invoice.
441439
streamCarol := carol.RPC.SubscribeSingleInvoice(payHash[:])
442440

0 commit comments

Comments
 (0)