mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-20 13:04:28 +02:00
peer+chancloser: allow restarting coop close process
On startup, we'll check whether we have the coop close chan status and have already broadcasted a coop close txn, and then make a decision on whether to restart the process based on that.
This commit is contained in:
@@ -483,6 +483,10 @@ func (c *ChanCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message,
|
|||||||
feeProposal := calcCompromiseFee(c.chanPoint, c.idealFeeSat,
|
feeProposal := calcCompromiseFee(c.chanPoint, c.idealFeeSat,
|
||||||
c.lastFeeProposal, remoteProposedFee,
|
c.lastFeeProposal, remoteProposedFee,
|
||||||
)
|
)
|
||||||
|
if feeProposal > c.idealFeeSat*3 {
|
||||||
|
return nil, false, fmt.Errorf("couldn't find" +
|
||||||
|
" compromise fee")
|
||||||
|
}
|
||||||
|
|
||||||
// With our new fee proposal calculated, we'll craft a new close
|
// With our new fee proposal calculated, we'll craft a new close
|
||||||
// signed signature to send to the other party so we can continue
|
// signed signature to send to the other party so we can continue
|
||||||
|
103
peer/brontide.go
103
peer/brontide.go
@@ -702,6 +702,30 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
msgs = append(msgs, chanSync)
|
msgs = append(msgs, chanSync)
|
||||||
|
|
||||||
|
// Check if this channel needs to have the cooperative
|
||||||
|
// close process restarted. If so, we'll need to send
|
||||||
|
// the Shutdown message that is returned.
|
||||||
|
if dbChan.HasChanStatus(
|
||||||
|
channeldb.ChanStatusCoopBroadcasted,
|
||||||
|
) {
|
||||||
|
shutdownMsg, err := p.restartCoopClose(lnChan)
|
||||||
|
if err != nil {
|
||||||
|
peerLog.Errorf("Unable to restart "+
|
||||||
|
"coop close for channel: %v",
|
||||||
|
err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if shutdownMsg == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the message to the set of messages to
|
||||||
|
// send.
|
||||||
|
msgs = append(msgs, shutdownMsg)
|
||||||
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2508,6 +2532,81 @@ func chooseDeliveryScript(upfront,
|
|||||||
return upfront, nil
|
return upfront, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restartCoopClose checks whether we need to restart the cooperative close
|
||||||
|
// process for a given channel.
|
||||||
|
func (p *Brontide) restartCoopClose(lnChan *lnwallet.LightningChannel) (
|
||||||
|
*lnwire.Shutdown, error) {
|
||||||
|
|
||||||
|
// If this channel has status ChanStatusCoopBroadcasted and does not
|
||||||
|
// have a closing transaction, then the cooperative close process was
|
||||||
|
// started but never finished. We'll re-create the chanCloser state
|
||||||
|
// machine and resend Shutdown. BOLT#2 requires that we retransmit
|
||||||
|
// Shutdown exactly, but doing so would mean persisting the RPC
|
||||||
|
// provided close script. Instead use the LocalUpfrontShutdownScript
|
||||||
|
// or generate a script.
|
||||||
|
c := lnChan.State()
|
||||||
|
_, err := c.BroadcastedCooperative()
|
||||||
|
if err != nil && err != channeldb.ErrNoCloseTx {
|
||||||
|
// An error other than ErrNoCloseTx was encountered.
|
||||||
|
return nil, err
|
||||||
|
} else if err == nil {
|
||||||
|
// This channel has already completed the coop close
|
||||||
|
// negotiation.
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// As mentioned above, we don't re-create the delivery script.
|
||||||
|
deliveryScript := c.LocalShutdownScript
|
||||||
|
if len(deliveryScript) == 0 {
|
||||||
|
var err error
|
||||||
|
deliveryScript, err = p.genDeliveryScript()
|
||||||
|
if err != nil {
|
||||||
|
peerLog.Errorf("unable to gen delivery script: %v",
|
||||||
|
err)
|
||||||
|
return nil, fmt.Errorf("close addr unavailable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute an ideal fee.
|
||||||
|
feePerKw, err := p.cfg.FeeEstimator.EstimateFeePerKW(
|
||||||
|
p.cfg.CoopCloseTargetConfs,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
peerLog.Errorf("unable to query fee estimator: %v", err)
|
||||||
|
return nil, fmt.Errorf("unable to estimate fee")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine whether we or the peer are the initiator of the coop
|
||||||
|
// close attempt by looking at the channel's status.
|
||||||
|
locallyInitiated := c.HasChanStatus(
|
||||||
|
channeldb.ChanStatusLocalCloseInitiator,
|
||||||
|
)
|
||||||
|
|
||||||
|
chanCloser, err := p.createChanCloser(
|
||||||
|
lnChan, deliveryScript, feePerKw, nil, locallyInitiated,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
peerLog.Errorf("unable to create chan closer: %v", err)
|
||||||
|
return nil, fmt.Errorf("unable to create chan closer")
|
||||||
|
}
|
||||||
|
|
||||||
|
// This does not need a mutex even though it is in a different
|
||||||
|
// goroutine since this is done before the channelManager goroutine is
|
||||||
|
// created.
|
||||||
|
chanID := lnwire.NewChanIDFromOutPoint(&c.FundingOutpoint)
|
||||||
|
p.activeChanCloses[chanID] = chanCloser
|
||||||
|
|
||||||
|
// Create the Shutdown message.
|
||||||
|
shutdownMsg, err := chanCloser.ShutdownChan()
|
||||||
|
if err != nil {
|
||||||
|
peerLog.Errorf("unable to create shutdown message: %v", err)
|
||||||
|
delete(p.activeChanCloses, chanID)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return shutdownMsg, nil
|
||||||
|
}
|
||||||
|
|
||||||
// createChanCloser constructs a ChanCloser from the passed parameters and is
|
// createChanCloser constructs a ChanCloser from the passed parameters and is
|
||||||
// used to de-duplicate code.
|
// used to de-duplicate code.
|
||||||
func (p *Brontide) createChanCloser(channel *lnwallet.LightningChannel,
|
func (p *Brontide) createChanCloser(channel *lnwallet.LightningChannel,
|
||||||
@@ -2788,6 +2887,10 @@ func (p *Brontide) finalizeChanClosure(chanCloser *chancloser.ChanCloser) {
|
|||||||
chanPoint := chanCloser.Channel().ChannelPoint()
|
chanPoint := chanCloser.Channel().ChannelPoint()
|
||||||
p.WipeChannel(chanPoint)
|
p.WipeChannel(chanPoint)
|
||||||
|
|
||||||
|
// Also clear the activeChanCloses map of this channel.
|
||||||
|
cid := lnwire.NewChanIDFromOutPoint(chanPoint)
|
||||||
|
delete(p.activeChanCloses, cid)
|
||||||
|
|
||||||
// Next, we'll launch a goroutine which will request to be notified by
|
// Next, we'll launch a goroutine which will request to be notified by
|
||||||
// the ChainNotifier once the closure transaction obtains a single
|
// the ChainNotifier once the closure transaction obtains a single
|
||||||
// confirmation.
|
// confirmation.
|
||||||
|
Reference in New Issue
Block a user