-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Allow coop closing a channel with HTLCs on it via lncli #9491
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1011,6 +1011,11 @@ var closeChannelCommand = cli.Command{ | |
comparison is the end boundary of the fee negotiation, if not specified | ||
it's always x3 of the starting value. Increasing this value increases | ||
the chance of a successful negotiation. | ||
Moreover if the channel has active HTLCs on it, the coop close will | ||
wait until all HTLCs are resolved and will not allow any new HTLCs on | ||
the channel. The channel will appear as disabled in the listchannels | ||
output. The command will block in that case until the channel close tx | ||
is broadcasted. | ||
|
||
In the case of a cooperative closure, one can manually set the address | ||
to deliver funds to upon closure. This is optional, and may only be used | ||
|
@@ -1042,8 +1047,10 @@ var closeChannelCommand = cli.Command{ | |
Usage: "attempt an uncooperative closure", | ||
}, | ||
cli.BoolFlag{ | ||
Name: "block", | ||
Usage: "block until the channel is closed", | ||
Name: "block", | ||
Usage: `block will wait for the channel to be closed, | ||
"meaning that it will wait for the channel close tx to | ||
get 1 confirmation.`, | ||
}, | ||
cli.Int64Flag{ | ||
Name: "conf_target", | ||
|
@@ -1117,6 +1124,9 @@ func closeChannel(ctx *cli.Context) error { | |
SatPerVbyte: ctx.Uint64(feeRateFlag), | ||
DeliveryAddress: ctx.String("delivery_addr"), | ||
MaxFeePerVbyte: ctx.Uint64("max_fee_rate"), | ||
// This makes sure that a coop close will also be executed if | ||
// active HTLCs are present on the channel. | ||
NoWait: true, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The effect of waiting for HTLCs is documented in rpcserver.go, but not in the schema. // If true, then the rpc call will not block while it awaits a closing txid.
// Consequently this RPC call will not return a closing txid if this value
// is set.
bool no_wait = 8; // If the user hasn't specified NoWait, then before we attempt
// to close the channel we ensure there are no active HTLCs on
// the link.
if !in.NoWait && len(channel.ActiveHtlcs()) != 0 { I propose to add this important detail to the schema as well and maybe rename the flag to Looking at the current name and the description of NoWait I thought originally, that it is a flag similar to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we cannot rename it because of backwards comp. issues. I think with a proper description we can keep it like this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The description is great! Thanks! Is it possible to decouple it into two flags? So NoWait only affects RPC behavior (whether or now to wait in RPC for transaction being broadcasted and return its txid) and a new flag would define what to do if there is a pending HTLC (force-close or wait-and-coop-close). In that case NoWait can be removed, since it can be implemented on the client side similar to What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah I think resolving this with 2 distinct flags is the way to go, but I keep it low priority for now. |
||
} | ||
|
||
// After parsing the request, we'll spin up a goroutine that will | ||
|
@@ -1154,7 +1164,9 @@ func closeChannel(ctx *cli.Context) error { | |
// executeChannelClose attempts to close the channel from a request. The closing | ||
// transaction ID is sent through `txidChan` as soon as it is broadcasted to the | ||
// network. The block boolean is used to determine if we should block until the | ||
// closing transaction receives all of its required confirmations. | ||
// closing transaction receives a confirmation of 1 block. The logging outputs | ||
// are sent to stderr to avoid conflicts with the JSON output of the command | ||
// and potential work flows which depend on a proper JSON output. | ||
func executeChannelClose(ctxc context.Context, client lnrpc.LightningClient, | ||
req *lnrpc.CloseChannelRequest, txidChan chan<- string, block bool) error { | ||
|
||
|
@@ -1173,22 +1185,40 @@ func executeChannelClose(ctxc context.Context, client lnrpc.LightningClient, | |
|
||
switch update := resp.Update.(type) { | ||
case *lnrpc.CloseStatusUpdate_CloseInstant: | ||
if req.NoWait { | ||
ziggie1984 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return nil | ||
fmt.Fprintln(os.Stderr, "Channel close successfully "+ | ||
"initiated") | ||
|
||
pendingHtlcs := update.CloseInstant.NumPendingHtlcs | ||
if pendingHtlcs > 0 { | ||
fmt.Fprintf(os.Stderr, "Cooperative channel "+ | ||
"close waiting for %d HTLCs to be "+ | ||
"resolved before the close process "+ | ||
"can kick off\n", pendingHtlcs) | ||
} | ||
|
||
case *lnrpc.CloseStatusUpdate_ClosePending: | ||
closingHash := update.ClosePending.Txid | ||
txid, err := chainhash.NewHash(closingHash) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Fprintf(os.Stderr, "Channel close transaction "+ | ||
"broadcasted: %v\n", txid) | ||
|
||
ziggie1984 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
txidChan <- txid.String() | ||
|
||
if !block { | ||
return nil | ||
} | ||
|
||
fmt.Fprintln(os.Stderr, "Waiting for channel close "+ | ||
"confirmation ...") | ||
|
||
case *lnrpc.CloseStatusUpdate_ChanClose: | ||
fmt.Fprintln(os.Stderr, "Channel close successfully "+ | ||
"confirmed") | ||
|
||
return nil | ||
} | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.