rpc: disallow attempting a co-op close of a channel with active HTLCs

In this commit, we fix a bug that at times could cause any dangling
HTLC's to be sent to miner's fees if a user attempted to close out a
channel cooperatively that still had pending HTLC's. We'll first prevent
this at the RPC level by rejecting any attempts to trigger a co-op
channel closure while a channel still have dangling HTLC's.
This commit is contained in:
Olaoluwa Osuntokun 2018-03-30 12:51:01 -07:00
parent a0fe4fb716
commit ecbeca5f29
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21

@ -996,20 +996,19 @@ func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest,
// TODO(roasbeef): if force and peer online then don't force? // TODO(roasbeef): if force and peer online then don't force?
// If a force closure was requested, then we'll handle all the details // First, we'll fetch the channel as is, as we'll need to examine it
// around the creation and broadcast of the unilateral closure // regardless of if this is a force close or not.
// transaction here rather than going to the switch as we don't require
// interaction from the peer.
if force {
// As the first part of the force closure, we first fetch the
// channel from the database, then execute a direct force
// closure broadcasting our current commitment transaction.
channel, err := r.fetchActiveChannel(*chanPoint) channel, err := r.fetchActiveChannel(*chanPoint)
if err != nil { if err != nil {
return err return err
} }
channel.Stop() channel.Stop()
// 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
// interaction from the peer.
if force {
_, bestHeight, err := r.server.cc.chainIO.GetBestBlock() _, bestHeight, err := r.server.cc.chainIO.GetBestBlock()
if err != nil { if err != nil {
return err return err
@ -1092,6 +1091,14 @@ func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest,
} }
} }
// Before we attempt the cooperative channel closure, we'll
// examine the channel to ensure that it doesn't have a
// lingering HTLC.
if len(channel.localCommit.Htlcs) != 0 {
return nil, fmt.Errorf("cannot co-op close channel " +
"with active htlcs")
}
// Otherwise, the caller has requested a regular interactive // Otherwise, the caller has requested a regular interactive
// cooperative channel closure. So we'll forward the request to // cooperative channel closure. So we'll forward the request to
// the htlc switch which will handle the negotiation and // the htlc switch which will handle the negotiation and