multi: coop close with active HTLCs on the channel

For the lncli cmd we now always initiate the coop close even if
there are active HTLCs on the channel. In case HTLCs are on the
channel and the coop close is initiated LND handles the closing
flow in the background and the lncli cmd will block until the
transaction is broadcasted to the mempool. In the background LND
disallows any new HTLCs and waits until all HTLCs are resolved
before kicking of the negotiation process.
Moreover if active HTLCs are present and the no_wait param is not
set the error msg is now highlightning it so the user can react
accordingly.
This commit is contained in:
ziggie committed 2025-02-20 17:43:18 +01:00
1 parent 319a0ee470
commit 59443faa36
6 files changed
+2353 -2273

No files matched your search

+18 -5
View File
@@ -2717,6 +2717,9 @@ func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest,
return err
}
// Retrieve the number of active HTLCs on the channel.
activeHtlcs := channel.ActiveHtlcs()
// If a force closure was requested, then we'll handle all the details
// around the creation and broadcast of the unilateral closure
// transaction here rather than going to the switch as we don't require
@@ -2833,9 +2836,12 @@ func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest,
// 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 {
return fmt.Errorf("cannot co-op close channel " +
"with active htlcs")
if !in.NoWait && len(activeHtlcs) != 0 {
return fmt.Errorf("cannot coop close channel with "+
"active htlcs (number of active htlcs: %d), "+
"bypass this check and initiate the coop "+
"close by setting no_wait=true",
len(activeHtlcs))
}
// Otherwise, the caller has requested a regular interactive
@@ -2879,12 +2885,19 @@ func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest,
}
// If the user doesn't want to wait for the txid to come back then we
// will send an empty update to kick off the stream.
// will send an empty update to kick off the stream. This is also used
// when active htlcs are still on the channel to give the client
// immediate feedback.
if in.NoWait {
rpcsLog.Trace("[closechannel] sending instant update")
if err := updateStream.Send(
//nolint:ll
&lnrpc.CloseStatusUpdate{
Update: &lnrpc.CloseStatusUpdate_CloseInstant{},
Update: &lnrpc.CloseStatusUpdate_CloseInstant{
CloseInstant: &lnrpc.InstantUpdate{
NumPendingHtlcs: int32(len(activeHtlcs)),
},
},
},
); err != nil {
return err