peer: ensure chan sends to breachArbiter can't block indefinitely

This commit fixes a possible deadlock bug that may arise during
shutdown due to an unconditional send on a channel to the breach
arbiter. We do this on two occasions within the peer: when loading a
new contract to give it the live version, and also when closing a
channel to ensure that it no longer watches over it.

Previously it was possible for these sends to block indefinitely in the
scenario that the server was shutting down (which means the breach
arbiter) is. As a result, the channel would never be drained, meaning
the server couldn’t complete shutdown as the peer hadn’t exited yet.
This commit is contained in:
Olaoluwa Osuntokun 2017-08-18 12:16:20 -07:00
parent f67ce4e6d7
commit 65dede2584
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2

22
peer.go
View File

@ -298,9 +298,15 @@ func (p *peer) loadActiveChannels(chans []*channeldb.OpenChannel) error {
p.activeChannels[chanID] = lnChan
p.activeChanMtx.Unlock()
peerLog.Infof("peerID(%v) loaded ChannelPoint(%v)", p.id, chanPoint)
peerLog.Infof("peerID(%v) loading ChannelPoint(%v)", p.id, chanPoint)
p.server.breachArbiter.newContracts <- lnChan
select {
case p.server.breachArbiter.newContracts <- lnChan:
case <-p.server.quit:
return fmt.Errorf("server shutting down")
case <-p.quit:
return fmt.Errorf("peer shutting down")
}
// Register this new channel link with the HTLC Switch. This is
// necessary to properly route multi-hop payments, and forward
@ -1369,6 +1375,16 @@ func (p *peer) handleClosingSigned(localReq *htlcswitch.ChanClose,
return ourSig, ourFee
}
chanPoint := channel.ChannelPoint()
select {
case p.server.breachArbiter.settledContracts <- chanPoint:
case <-p.server.quit:
return nil, 0
case <-p.quit:
return nil, 0
}
// We agreed on a fee, and we can broadcast the closure transaction to
// the network.
peerLog.Infof("Broadcasting cooperative close tx: %v",
@ -1376,7 +1392,6 @@ func (p *peer) handleClosingSigned(localReq *htlcswitch.ChanClose,
return spew.Sdump(closeTx)
}))
chanPoint := channel.ChannelPoint()
if err := p.server.cc.wallet.PublishTransaction(closeTx); err != nil {
// TODO(halseth): Add relevant error types to the
// WalletController interface as this is quite fragile.
@ -1397,7 +1412,6 @@ func (p *peer) handleClosingSigned(localReq *htlcswitch.ChanClose,
// Once we've completed the cooperative channel closure, we'll wipe the
// channel so we reject any incoming forward or payment requests via
// this channel.
p.server.breachArbiter.settledContracts <- chanPoint
if err := p.WipeChannel(channel); err != nil {
if localReq != nil {
localReq.Err <- err