Merge pull request #5618 from Crypt-iQ/coop_switch_sync_08092021

multi: optimistically shutdown link during coop close
This commit is contained in:
Olaoluwa Osuntokun authored and GitHub committed 2021-09-20 18:09:07 -07:00
commit ac5f88bae8
12 files changed
+490 -57

No files matched your search

+70 -27
View File
@@ -1184,11 +1184,9 @@ func waitUntilLinkActive(p *Brontide,
// The link may already be active by this point, and we may have missed the
// ActiveLinkEvent. Check if the link exists.
links, _ := p.cfg.Switch.GetLinksByInterface(p.cfg.PubKeyBytes)
for _, link := range links {
if link.ChanID() == cid {
return link
}
link := p.fetchLinkFromKeyAndCid(cid)
if link != nil {
return link
}
// If the link is nil, we must wait for it to be active.
@@ -1216,16 +1214,7 @@ func waitUntilLinkActive(p *Brontide,
// The link shouldn't be nil as we received an
// ActiveLinkEvent. If it is nil, we return nil and the
// calling function should catch it.
links, _ = p.cfg.Switch.GetLinksByInterface(
p.cfg.PubKeyBytes,
)
for _, link := range links {
if link.ChanID() == cid {
return link
}
}
return nil
return p.fetchLinkFromKeyAndCid(cid)
case <-p.quit:
return nil
@@ -2409,12 +2398,11 @@ func (p *Brontide) fetchActiveChanCloser(chanID lnwire.ChannelID) (
// cooperative channel closure.
chanCloser, ok := p.activeChanCloses[chanID]
if !ok {
// If we need to create a chan closer for the first time, then
// we'll check to ensure that the channel is even in the proper
// state to allow a co-op channel closure.
if len(channel.ActiveHtlcs()) != 0 {
return nil, fmt.Errorf("cannot co-op close " +
"channel w/ active htlcs")
// Optimistically try a link shutdown, erroring out if it
// failed.
if err := p.tryLinkShutdown(chanID); err != nil {
peerLog.Errorf("failed link shutdown: %v", err)
return nil, err
}
// We'll create a valid closing state machine in order to
@@ -2454,9 +2442,8 @@ func (p *Brontide) fetchActiveChanCloser(chanID lnwire.ChannelID) (
chanCloser = chancloser.NewChanCloser(
chancloser.ChanCloseCfg{
Channel: channel,
UnregisterChannel: p.cfg.Switch.RemoveLink,
BroadcastTx: p.cfg.Wallet.PublishTransaction,
Channel: channel,
BroadcastTx: p.cfg.Wallet.PublishTransaction,
DisableChannel: func(chanPoint wire.OutPoint) error {
return p.cfg.ChanStatusMgr.RequestDisable(chanPoint, false)
},
@@ -2570,11 +2557,18 @@ func (p *Brontide) handleLocalCloseReq(req *htlcswitch.ChanClose) {
return
}
// Optimistically try a link shutdown, erroring out if it
// failed.
if err := p.tryLinkShutdown(chanID); err != nil {
peerLog.Errorf("failed link shutdown: %v", err)
req.Err <- err
return
}
chanCloser := chancloser.NewChanCloser(
chancloser.ChanCloseCfg{
Channel: channel,
UnregisterChannel: p.cfg.Switch.RemoveLink,
BroadcastTx: p.cfg.Wallet.PublishTransaction,
Channel: channel,
BroadcastTx: p.cfg.Wallet.PublishTransaction,
DisableChannel: func(chanPoint wire.OutPoint) error {
return p.cfg.ChanStatusMgr.RequestDisable(chanPoint, false)
},
@@ -2701,6 +2695,55 @@ func (p *Brontide) handleLinkFailure(failure linkFailureReport) {
}
}
// tryLinkShutdown attempts to fetch a target link from the switch, calls
// ShutdownIfChannelClean to optimistically trigger a link shutdown, and
// removes the link from the switch. It returns an error if any step failed.
func (p *Brontide) tryLinkShutdown(cid lnwire.ChannelID) error {
// Fetch the appropriate link and call ShutdownIfChannelClean to ensure
// no other updates can occur.
chanLink := p.fetchLinkFromKeyAndCid(cid)
// If the link happens to be nil, return ErrChannelNotFound so we can
// ignore the close message.
if chanLink == nil {
return ErrChannelNotFound
}
// Else, the link exists, so attempt to trigger shutdown. If this
// fails, we'll send an error message to the remote peer.
if err := chanLink.ShutdownIfChannelClean(); err != nil {
return err
}
// Next, we remove the link from the switch to shut down all of the
// link's goroutines and remove it from the switch's internal maps. We
// don't call WipeChannel as the channel must still be in the
// activeChannels map to process coop close messages.
p.cfg.Switch.RemoveLink(cid)
return nil
}
// fetchLinkFromKeyAndCid fetches a link from the switch via the remote's
// public key and the channel id.
func (p *Brontide) fetchLinkFromKeyAndCid(
cid lnwire.ChannelID) htlcswitch.ChannelUpdateHandler {
var chanLink htlcswitch.ChannelUpdateHandler
// We don't need to check the error here, and can instead just loop
// over the slice and return nil.
links, _ := p.cfg.Switch.GetLinksByInterface(p.cfg.PubKeyBytes)
for _, link := range links {
if link.ChanID() == cid {
chanLink = link
break
}
}
return chanLink
}
// finalizeChanClosure performs the final clean up steps once the cooperative
// closure transaction has been fully broadcast. The finalized closing state
// machine should be passed in. Once the transaction has been sufficiently