Skip to content

Commit

Permalink
Merge pull request lightningnetwork#6274 from Roasbeef/anchor-utxos-u…
Browse files Browse the repository at this point in the history
…nconf

lnrpc+sweep: properly remove any unconfirmed descendant chains a to-be-swept input is spent
  • Loading branch information
Roasbeef authored Mar 17, 2022
2 parents d287884 + d164307 commit 3a04017
Show file tree
Hide file tree
Showing 16 changed files with 2,065 additions and 1,530 deletions.
3 changes: 3 additions & 0 deletions docs/release-notes/release-notes-0.15.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
* [Fixed deadlock in invoice
registry](https://github.com/lightningnetwork/lnd/pull/6332).

* [Fixed an issue that would cause wallet UTXO state to be incorrect if a 3rd
party sweeps our anchor
output](https://github.com/lightningnetwork/lnd/pull/6274).

## Misc

Expand Down
3,047 changes: 1,530 additions & 1,517 deletions lnrpc/lightning.pb.go

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions lnrpc/lightning.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2502,6 +2502,10 @@ message WalletBalanceResponse {
// The unconfirmed balance of a wallet(with 0 confirmations)
int64 unconfirmed_balance = 3;

// The total amount of wallet UTXOs held in outputs that are locked for
// other usage.
int64 locked_balance = 5;

// A mapping of each wallet account's name to its balance.
map<string, WalletAccountBalance> account_balance = 4;
}
Expand Down
5 changes: 5 additions & 0 deletions lnrpc/lightning.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -6540,6 +6540,11 @@
"format": "int64",
"title": "The unconfirmed balance of a wallet(with 0 confirmations)"
},
"locked_balance": {
"type": "string",
"format": "int64",
"description": "The total amount of wallet UTXOs held in outputs that are locked for\nother usage."
},
"account_balance": {
"type": "object",
"additionalProperties": {
Expand Down
67 changes: 67 additions & 0 deletions lntest/itest/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -1789,3 +1789,70 @@ func assertChannelPolicyUpdate(t *testing.T, node *lntest.HarnessNode,
), "error while waiting for channel update",
)
}

func transactionInWallet(node *lntest.HarnessNode, txid chainhash.Hash) bool {
txStr := txid.String()

txResp, err := node.GetTransactions(
context.Background(), &lnrpc.GetTransactionsRequest{},
)
if err != nil {
return false
}

for _, txn := range txResp.Transactions {
if txn.TxHash == txStr {
return true
}
}

return false
}

func assertTransactionInWallet(t *testing.T, node *lntest.HarnessNode, txID chainhash.Hash) {
t.Helper()

err := wait.Predicate(func() bool {
return transactionInWallet(node, txID)
}, defaultTimeout)
require.NoError(
t, err, fmt.Sprintf("transaction %v not found in wallet", txID),
)
}

func assertTransactionNotInWallet(t *testing.T, node *lntest.HarnessNode,
txID chainhash.Hash) {

t.Helper()

err := wait.Predicate(func() bool {
return !transactionInWallet(node, txID)
}, defaultTimeout)
require.NoError(
t, err, fmt.Sprintf("transaction %v found in wallet", txID),
)
}

func assertAnchorOutputLost(t *harnessTest, node *lntest.HarnessNode,
chanPoint wire.OutPoint) {

pendingChansRequest := &lnrpc.PendingChannelsRequest{}
err := wait.Predicate(func() bool {
resp, pErr := node.PendingChannels(
context.Background(), pendingChansRequest,
)
if pErr != nil {
return false
}

for _, pendingChan := range resp.PendingForceClosingChannels {
if pendingChan.Channel.ChannelPoint == chanPoint.String() {
return (pendingChan.Anchor ==
lnrpc.PendingChannelsResponse_ForceClosedChannel_LOST)
}
}

return false
}, defaultTimeout)
require.NoError(t.t, err, "anchor doesn't show as being lost")
}
12 changes: 6 additions & 6 deletions lntest/itest/lnd_channel_force_close_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
aliceReports[aliceAnchor.OutPoint.String()] = &lnrpc.Resolution{
ResolutionType: lnrpc.ResolutionType_ANCHOR,
Outcome: lnrpc.ResolutionOutcome_CLAIMED,
SweepTxid: aliceAnchor.SweepTx,
SweepTxid: aliceAnchor.SweepTx.TxHash().String(),
Outpoint: &lnrpc.OutPoint{
TxidBytes: aliceAnchor.OutPoint.Hash[:],
TxidStr: aliceAnchor.OutPoint.Hash.String(),
Expand Down Expand Up @@ -632,7 +632,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
carolReports[carolAnchor.OutPoint.String()] = &lnrpc.Resolution{
ResolutionType: lnrpc.ResolutionType_ANCHOR,
Outcome: lnrpc.ResolutionOutcome_CLAIMED,
SweepTxid: carolAnchor.SweepTx,
SweepTxid: carolAnchor.SweepTx.TxHash().String(),
AmountSat: anchorSize,
Outpoint: &lnrpc.OutPoint{
TxidBytes: carolAnchor.OutPoint.Hash[:],
Expand Down Expand Up @@ -770,7 +770,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest,
OutputIndex: carolCommit.OutPoint.Index,
},
AmountSat: uint64(pushAmt),
SweepTxid: carolCommit.SweepTx,
SweepTxid: carolCommit.SweepTx.TxHash().String(),
}

// Check that we can find the commitment sweep in our set of known
Expand Down Expand Up @@ -1337,7 +1337,7 @@ func padCLTV(cltv uint32) uint32 {

type sweptOutput struct {
OutPoint wire.OutPoint
SweepTx string
SweepTx *wire.MsgTx
}

// findCommitAndAnchor looks for a commitment sweep and anchor sweep in the
Expand All @@ -1364,7 +1364,7 @@ func findCommitAndAnchor(t *harnessTest, net *lntest.NetworkHarness,
if len(inputs) == 1 {
commitSweep = &sweptOutput{
OutPoint: inputs[0].PreviousOutPoint,
SweepTx: txHash.String(),
SweepTx: tx,
}
} else {
// Since we have more than one input, we run through
Expand All @@ -1375,7 +1375,7 @@ func findCommitAndAnchor(t *harnessTest, net *lntest.NetworkHarness,
if outpointStr == closeTx {
anchorSweep = &sweptOutput{
OutPoint: txin.PreviousOutPoint,
SweepTx: txHash.String(),
SweepTx: tx,
}
}
}
Expand Down
Loading

0 comments on commit 3a04017

Please sign in to comment.