Skip to content

Commit

Permalink
Merge pull request #8426 from breez/expose-closing-tx
Browse files Browse the repository at this point in the history
Expose closing tx in waiting_close_channels
  • Loading branch information
yyforyongyu authored Jan 30, 2024
2 parents b76d3e6 + 172e836 commit dd7b186
Show file tree
Hide file tree
Showing 9 changed files with 2,019 additions and 1,899 deletions.
14 changes: 12 additions & 2 deletions cmd/lncli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -1445,15 +1445,25 @@ var pendingChannelsCommand = cli.Command{
Name: "pendingchannels",
Category: "Channels",
Usage: "Display information pertaining to pending channels.",
Action: actionDecorator(pendingChannels),
Flags: []cli.Flag{
cli.BoolFlag{
Name: "include_raw_tx",
Usage: "include the raw transaction hex for " +
"waiting_close_channels.",
},
},
Action: actionDecorator(pendingChannels),
}

func pendingChannels(ctx *cli.Context) error {
ctxc := getContext()
client, cleanUp := getClient(ctx)
defer cleanUp()

req := &lnrpc.PendingChannelsRequest{}
includeRawTx := ctx.Bool("include_raw_tx")
req := &lnrpc.PendingChannelsRequest{
IncludeRawTx: includeRawTx,
}
resp, err := client.PendingChannels(ctxc, req)
if err != nil {
return err
Expand Down
9 changes: 9 additions & 0 deletions docs/release-notes/release-notes-0.18.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@
[MinConf](https://github.com/lightningnetwork/lnd/pull/8097)(minimum number
of confirmations) has been added to the `WalletBalance` RPC call.

* `PendingChannels` now optionally returns the
[raw hex of the closing tx](https://github.com/lightningnetwork/lnd/pull/8426)
in `waiting_close_channels`.

## lncli Updates

* [Documented all available lncli commands](https://github.com/lightningnetwork/lnd/pull/8181).
Expand All @@ -202,6 +206,10 @@
* [Use the default LND value in the buildroute rpc command for the
final cltv delta](https://github.com/lightningnetwork/lnd/pull/8387).

* `pendingchannels` now optionally returns the
[raw hex of the closing tx](https://github.com/lightningnetwork/lnd/pull/8426)
in `waiting_close_channels`.

## Code Health

* [Remove Litecoin code](https://github.com/lightningnetwork/lnd/pull/7867).
Expand Down Expand Up @@ -287,6 +295,7 @@
* Carla Kirk-Cohen
* Elle Mouton
* ErikEk
* Jesse de Wit
* Keagan McClelland
* Marcos Fernandez Perez
* Matt Morehouse
Expand Down
20 changes: 19 additions & 1 deletion itest/lnd_channel_force_close_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package itest

import (
"bytes"
"encoding/hex"
"fmt"
"testing"

Expand Down Expand Up @@ -141,7 +142,24 @@ func testCommitmentTransactionDeadline(ht *lntest.HarnessTest) {
// Now that the channel has been force closed, it should show
// up in the PendingChannels RPC under the waiting close
// section.
ht.AssertChannelWaitingClose(alice, chanPoint)
waitingClose := ht.AssertChannelWaitingClose(alice, chanPoint)

// The waiting close channel closing tx hex should be set and
// be valid.
require.NotEmpty(ht, waitingClose.ClosingTxHex)
rawTxBytes, err := hex.DecodeString(waitingClose.ClosingTxHex)
require.NoError(
ht, err,
"waiting close channel closingTxHex invalid hex",
)
rawTx := &wire.MsgTx{}
err = rawTx.Deserialize(bytes.NewReader(rawTxBytes))
require.NoError(
ht, err, "waiting close channel ClosingTxHex invalid",
)
require.Equal(
ht, waitingClose.ClosingTxid, rawTx.TxHash().String(),
)

// We should see Alice's force closing tx in the mempool.
expectedNumTxes := 1
Expand Down
3,770 changes: 1,898 additions & 1,872 deletions lnrpc/lightning.pb.go

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions lnrpc/lightning.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions lnrpc/lightning.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2636,6 +2636,9 @@ message PendingHTLC {
}

message PendingChannelsRequest {
// Indicates whether to include the raw transaction hex for
// waiting_close_channels.
bool include_raw_tx = 1;
}
message PendingChannelsResponse {
message PendingChannel {
Expand Down Expand Up @@ -2733,6 +2736,10 @@ message PendingChannelsResponse {

// The transaction id of the closing transaction
string closing_txid = 4;

// The raw hex encoded bytes of the closing transaction. Included if
// include_raw_tx in the request is true.
string closing_tx_hex = 5;
}

message Commitments {
Expand Down
13 changes: 13 additions & 0 deletions lnrpc/lightning.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,15 @@
}
}
},
"parameters": [
{
"name": "include_raw_tx",
"description": "Indicates whether to include the raw transaction hex for\nwaiting_close_channels.",
"in": "query",
"required": false,
"type": "boolean"
}
],
"tags": [
"Lightning"
]
Expand Down Expand Up @@ -3140,6 +3149,10 @@
"closing_txid": {
"type": "string",
"title": "The transaction id of the closing transaction"
},
"closing_tx_hex": {
"type": "string",
"description": "The raw hex encoded bytes of the closing transaction. Included if\ninclude_raw_tx in the request is true."
}
}
},
Expand Down
4 changes: 3 additions & 1 deletion lntest/rpc/lnd.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ func (h *HarnessRPC) PendingChannels() *lnrpc.PendingChannelsResponse {
ctxt, cancel := context.WithTimeout(h.runCtx, DefaultTimeout)
defer cancel()

pendingChansRequest := &lnrpc.PendingChannelsRequest{}
pendingChansRequest := &lnrpc.PendingChannelsRequest{
IncludeRawTx: true,
}
resp, err := h.LN.PendingChannels(ctxt, pendingChansRequest)

// TODO(yy): We may get a `unable to find arbitrator` error from the
Expand Down
63 changes: 40 additions & 23 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3718,8 +3718,8 @@ func (r *rpcServer) fetchPendingForceCloseChannels() (pendingForceClose,
// fetchWaitingCloseChannels queries the database for a list of channels
// that have their closing transactions broadcast but not confirmed yet.
// The returned result is used in the response of the PendingChannels RPC.
func (r *rpcServer) fetchWaitingCloseChannels() (waitingCloseChannels,
int64, error) {
func (r *rpcServer) fetchWaitingCloseChannels(
includeRawTx bool) (waitingCloseChannels, int64, error) {

// We'll also fetch all channels that are open, but have had their
// commitment broadcasted, meaning they are waiting for the closing
Expand All @@ -3734,43 +3734,42 @@ func (r *rpcServer) fetchWaitingCloseChannels() (waitingCloseChannels,
result := make(waitingCloseChannels, 0)
limboBalance := int64(0)

// getClosingTx is a helper closure that tries to find the closing txid
// of a given waiting close channel. Notice that if the remote closes
// the channel, we may not have the closing txid.
getClosingTx := func(c *channeldb.OpenChannel) (string, error) {
// getClosingTx is a helper closure that tries to find the closing tx of
// a given waiting close channel. Notice that if the remote closes the
// channel, we may not have the closing tx.
getClosingTx := func(c *channeldb.OpenChannel) (*wire.MsgTx, error) {
var (
tx *wire.MsgTx
err error
)

// First, we try to locate the force closing txid. If not
// found, we will then try to find its coop closing txid.
// First, we try to locate the force closing tx. If not found,
// we will then try to find its coop closing tx.
tx, err = c.BroadcastedCommitment()
if err == nil {
return tx.TxHash().String(), nil
return tx, nil
}

// If the error returned is not ErrNoCloseTx, something
// unexpected happened and we will return the error.
if err != channeldb.ErrNoCloseTx {
return "", err
return nil, err
}

// Otherwise, we continue to locate its coop closing txid.
// Otherwise, we continue to locate its coop closing tx.
tx, err = c.BroadcastedCooperative()
if err == nil {
return tx.TxHash().String(), nil
return tx, nil
}

// Return the error if it's not ErrNoCloseTx.
if err != channeldb.ErrNoCloseTx {
return "", err
return nil, err
}

// Otherwise return an empty txid. This can happen if the
// remote broadcast the closing txid and we haven't recorded it
// yet.
return "", nil
// Otherwise return an empty tx. This can happen if the remote
// broadcast the closing tx and we haven't recorded it yet.
return nil, nil
}

for _, waitingClose := range channels {
Expand Down Expand Up @@ -3830,12 +3829,12 @@ func (r *rpcServer) fetchWaitingCloseChannels() (waitingCloseChannels,
return nil, 0, err
}

// Get the closing txid.
// NOTE: the closing txid could be empty here if it's the
// remote broadcasted the closing tx.
closingTxid, err := getClosingTx(waitingClose)
// Get the closing tx.
// NOTE: the closing tx could be nil here if it's the remote
// that broadcasted the closing tx.
closingTx, err := getClosingTx(waitingClose)
if err != nil {
rpcsLog.Errorf("unable to find closing txid for "+
rpcsLog.Errorf("unable to find closing tx for "+
"channel:%s, %v",
waitingClose.ShortChannelID, err)
return nil, 0, err
Expand All @@ -3857,11 +3856,27 @@ func (r *rpcServer) fetchWaitingCloseChannels() (waitingCloseChannels,
Memo: string(waitingClose.Memo),
}

var closingTxid, closingTxHex string
if closingTx != nil {
closingTxid = closingTx.TxHash().String()
if includeRawTx {
var txBuf bytes.Buffer
err = closingTx.Serialize(&txBuf)
if err != nil {
return nil, 0, fmt.Errorf("failed to "+
"serialize closing transaction"+
": %w", err)
}
closingTxHex = hex.EncodeToString(txBuf.Bytes())
}
}

waitingCloseResp := &lnrpc.PendingChannelsResponse_WaitingCloseChannel{
Channel: channel,
LimboBalance: channel.LocalBalance,
Commitments: &commitments,
ClosingTxid: closingTxid,
ClosingTxHex: closingTxHex,
}

// A close tx has been broadcasted, all our balance will be in
Expand Down Expand Up @@ -3904,7 +3919,9 @@ func (r *rpcServer) PendingChannels(ctx context.Context,
// Third, we fetch all channels that are open, but have had their
// commitment broadcasted, meaning they are waiting for the closing
// transaction to confirm.
waitingCloseChannels, limbo, err := r.fetchWaitingCloseChannels()
waitingCloseChannels, limbo, err := r.fetchWaitingCloseChannels(
in.IncludeRawTx,
)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit dd7b186

Please sign in to comment.