htlcswitch: asynchronously handle channel close requests
This commit modifies how the htlcswitch handles close requests. Previously it could be the case that a new channel was added, but at the same time a channel was requested to be closed. This would result in a circular waiting dependency: the peer contacts the switch, who tries to contact the peer. We eliminate this possibility by ensuring that the switch handles all close requests asynchronously. With this, the switch won't block indefinitely in the scenario described above.
This commit is contained in:
parent
d39410cc01
commit
0d4ee08372
@ -149,7 +149,7 @@ type Switch struct {
|
|||||||
// the channel close handler.
|
// the channel close handler.
|
||||||
chanCloseRequests chan *ChanClose
|
chanCloseRequests chan *ChanClose
|
||||||
|
|
||||||
// linkControl is a channel used to propogate add/remove/get htlc
|
// linkControl is a channel used to propagate add/remove/get htlc
|
||||||
// switch handler commands.
|
// switch handler commands.
|
||||||
linkControl chan interface{}
|
linkControl chan interface{}
|
||||||
}
|
}
|
||||||
@ -512,7 +512,9 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
|
|||||||
|
|
||||||
// If this is failure than we need to obfuscate the error.
|
// If this is failure than we need to obfuscate the error.
|
||||||
if htlc, ok := htlc.(*lnwire.UpdateFailHTLC); ok && !packet.isObfuscated {
|
if htlc, ok := htlc.(*lnwire.UpdateFailHTLC); ok && !packet.isObfuscated {
|
||||||
htlc.Reason = circuit.Obfuscator.BackwardObfuscate(htlc.Reason)
|
htlc.Reason = circuit.Obfuscator.BackwardObfuscate(
|
||||||
|
htlc.Reason,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Propagating settle/fail htlc back to src of add htlc packet.
|
// Propagating settle/fail htlc back to src of add htlc packet.
|
||||||
@ -542,7 +544,7 @@ func (s *Switch) CloseLink(chanPoint *wire.OutPoint,
|
|||||||
closeType ChannelCloseType) (chan *lnrpc.CloseStatusUpdate, chan error) {
|
closeType ChannelCloseType) (chan *lnrpc.CloseStatusUpdate, chan error) {
|
||||||
|
|
||||||
// TODO(roasbeef) abstract out the close updates.
|
// TODO(roasbeef) abstract out the close updates.
|
||||||
updateChan := make(chan *lnrpc.CloseStatusUpdate, 1)
|
updateChan := make(chan *lnrpc.CloseStatusUpdate, 2)
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
|
|
||||||
command := &ChanClose{
|
command := &ChanClose{
|
||||||
@ -564,34 +566,6 @@ func (s *Switch) CloseLink(chanPoint *wire.OutPoint,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleCloseLink sends a message to the peer responsible for the target
|
|
||||||
// channel point, instructing it to initiate a cooperative channel closure.
|
|
||||||
func (s *Switch) handleChanelClose(req *ChanClose) {
|
|
||||||
targetChanID := lnwire.NewChanIDFromOutPoint(req.ChanPoint)
|
|
||||||
|
|
||||||
var link ChannelLink
|
|
||||||
for chanID, l := range s.linkIndex {
|
|
||||||
if chanID == targetChanID {
|
|
||||||
link = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if link == nil {
|
|
||||||
req.Err <- errors.Errorf("channel with ChannelID(%v) not "+
|
|
||||||
"found", targetChanID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("requesting local channel close, peer(%v) channel(%v)",
|
|
||||||
link.Peer(), targetChanID)
|
|
||||||
|
|
||||||
// TODO(roasbeef): if type was CloseBreach initiate force closure with
|
|
||||||
// all other channels (if any) we have with the remote peer.
|
|
||||||
peerPub := link.Peer().PubKey()
|
|
||||||
s.cfg.LocalChannelClose(peerPub[:], req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// htlcForwarder is responsible for optimally forwarding (and possibly
|
// htlcForwarder is responsible for optimally forwarding (and possibly
|
||||||
// fragmenting) incoming/outgoing HTLCs amongst all active interfaces and their
|
// fragmenting) incoming/outgoing HTLCs amongst all active interfaces and their
|
||||||
// links. The duties of the forwarder are similar to that of a network switch,
|
// links. The duties of the forwarder are similar to that of a network switch,
|
||||||
@ -630,7 +604,19 @@ func (s *Switch) htlcForwarder() {
|
|||||||
// relevant link (if it exists) so the channel can be
|
// relevant link (if it exists) so the channel can be
|
||||||
// cooperatively closed (if possible).
|
// cooperatively closed (if possible).
|
||||||
case req := <-s.chanCloseRequests:
|
case req := <-s.chanCloseRequests:
|
||||||
s.handleChanelClose(req)
|
chanID := lnwire.NewChanIDFromOutPoint(req.ChanPoint)
|
||||||
|
link, ok := s.linkIndex[chanID]
|
||||||
|
if !ok {
|
||||||
|
req.Err <- errors.Errorf("channel with "+
|
||||||
|
"chan_id=%v not found", chanID[:])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
peerPub := link.Peer().PubKey()
|
||||||
|
log.Debugf("Requesting local channel close: peer=%v, "+
|
||||||
|
"chan_id=%x", link.Peer(), chanID[:])
|
||||||
|
|
||||||
|
go s.cfg.LocalChannelClose(peerPub[:], req)
|
||||||
|
|
||||||
// A new packet has arrived for forwarding, we'll interpret the
|
// A new packet has arrived for forwarding, we'll interpret the
|
||||||
// packet concretely, then either forward it along, or
|
// packet concretely, then either forward it along, or
|
||||||
|
Loading…
Reference in New Issue
Block a user