mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-26 01:33:02 +01:00
peer: add initial awareness of new rbf coop closer
In this commit, we use the interfaces we created in the prior commit to make a new method capable of spinning up the new rbf coop closer.
This commit is contained in:
parent
047d3532f9
commit
23a9a761e3
@ -9935,3 +9935,16 @@ func (lc *LightningChannel) FundingBlob() fn.Option[tlv.Blob] {
|
||||
return newBlob
|
||||
})(lc.channelState.CustomBlob)
|
||||
}
|
||||
|
||||
// ZeroConfRealScid returns an optional real scid for the channel. If this
|
||||
// returns None, then this isn't a zero conf channel. Otherwise, the real scid
|
||||
// value will be returned.
|
||||
//
|
||||
//nolint:ll
|
||||
func (lc *LightningChannel) ZeroConfRealScid() fn.Option[lnwire.ShortChannelID] {
|
||||
if lc.channelState.IsZeroConf() {
|
||||
return fn.Some(lc.channelState.ZeroConfRealScid())
|
||||
}
|
||||
|
||||
return fn.None[lnwire.ShortChannelID]()
|
||||
}
|
||||
|
158
peer/brontide.go
158
peer/brontide.go
@ -3,6 +3,7 @@ package peer
|
||||
import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
@ -46,6 +47,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/msgmux"
|
||||
"github.com/lightningnetwork/lnd/netann"
|
||||
"github.com/lightningnetwork/lnd/pool"
|
||||
"github.com/lightningnetwork/lnd/protofsm"
|
||||
"github.com/lightningnetwork/lnd/queue"
|
||||
"github.com/lightningnetwork/lnd/subscribe"
|
||||
"github.com/lightningnetwork/lnd/ticker"
|
||||
@ -913,6 +915,16 @@ func (p *Brontide) taprootShutdownAllowed() bool {
|
||||
p.LocalFeatures().HasFeature(lnwire.ShutdownAnySegwitOptional)
|
||||
}
|
||||
|
||||
// rbfCoopCloseAllowed returns true if both parties have negotiated the new RBF
|
||||
// coop close feature.
|
||||
func (p *Brontide) rbfCoopCloseAllowed() bool {
|
||||
return p.RemoteFeatures().HasFeature(
|
||||
lnwire.RbfCoopCloseOptionalStaging,
|
||||
) && p.LocalFeatures().HasFeature(
|
||||
lnwire.RbfCoopCloseOptionalStaging,
|
||||
)
|
||||
}
|
||||
|
||||
// QuitSignal is a method that should return a channel which will be sent upon
|
||||
// or closed once the backing peer exits. This allows callers using the
|
||||
// interface to cancel any processing in the event the backing implementation
|
||||
@ -3314,7 +3326,8 @@ func (p *Brontide) createChanCloser(channel *lnwallet.LightningChannel,
|
||||
}
|
||||
|
||||
// initNegotiateChanCloser initializes the channel closer for a channel that is
|
||||
// using the original "negotiation" based protocol.
|
||||
// using the original "negotiation" based protocol. This path is used when
|
||||
// we're the one initiating the channel close.
|
||||
//
|
||||
// TODO(roasbeef): can make a MsgEndpoint for existing handling logic to
|
||||
// further abstract.
|
||||
@ -3392,6 +3405,149 @@ func (p *Brontide) initNegotiateChanCloser(req *htlcswitch.ChanClose,
|
||||
return nil
|
||||
}
|
||||
|
||||
func chooseAddr(addr lnwire.DeliveryAddress) fn.Option[lnwire.DeliveryAddress] {
|
||||
if len(addr) == 0 {
|
||||
return fn.None[lnwire.DeliveryAddress]()
|
||||
}
|
||||
|
||||
return fn.Some(addr)
|
||||
}
|
||||
|
||||
// initRbfChanCloser initializes the channel closer for a channel that
|
||||
// is using the new RBF based co-op close protocol. This only creates the chan
|
||||
// closer, but doesn't attempt to trigger any manual state transitions.
|
||||
func (p *Brontide) initRbfChanCloser(
|
||||
channel *lnwallet.LightningChannel) (*chancloser.RbfChanCloser, error) {
|
||||
|
||||
chanID := lnwire.NewChanIDFromOutPoint(channel.ChannelPoint())
|
||||
|
||||
link := p.fetchLinkFromKeyAndCid(chanID)
|
||||
|
||||
_, startingHeight, err := p.cfg.ChainIO.GetBestBlock()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot obtain best block: %w", err)
|
||||
}
|
||||
|
||||
defaultFeePerKw, err := p.cfg.FeeEstimator.EstimateFeePerKW(
|
||||
p.cfg.CoopCloseTargetConfs,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to estimate fee: %w", err)
|
||||
}
|
||||
|
||||
thawHeight, err := channel.AbsoluteThawHeight()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get thaw height: %w", err)
|
||||
}
|
||||
|
||||
peerPub := *p.IdentityKey()
|
||||
|
||||
msgMapper := chancloser.NewRbfMsgMapper(uint32(startingHeight), chanID, peerPub)
|
||||
|
||||
initialState := chancloser.ChannelActive{}
|
||||
|
||||
scid := channel.ZeroConfRealScid().UnwrapOr(
|
||||
channel.ShortChanID(),
|
||||
)
|
||||
|
||||
env := chancloser.Environment{
|
||||
ChainParams: p.cfg.Wallet.Cfg.NetParams,
|
||||
ChanPeer: peerPub,
|
||||
ChanPoint: channel.ChannelPoint(),
|
||||
ChanID: chanID,
|
||||
Scid: scid,
|
||||
ChanType: channel.ChanType(),
|
||||
DefaultFeeRate: defaultFeePerKw.FeePerVByte(),
|
||||
ThawHeight: fn.Some(thawHeight),
|
||||
RemoteUpfrontShutdown: chooseAddr(
|
||||
channel.RemoteUpfrontShutdownScript(),
|
||||
),
|
||||
LocalUpfrontShutdown: chooseAddr(
|
||||
channel.LocalUpfrontShutdownScript(),
|
||||
),
|
||||
NewDeliveryScript: func() (lnwire.DeliveryAddress, error) {
|
||||
return p.genDeliveryScript()
|
||||
},
|
||||
FeeEstimator: &chancloser.SimpleCoopFeeEstimator{},
|
||||
ChanObserver: newChanObserver(
|
||||
channel, link, p.cfg.ChanStatusMgr,
|
||||
),
|
||||
}
|
||||
|
||||
spendEvent := protofsm.RegisterSpend[chancloser.ProtocolEvent]{
|
||||
OutPoint: channel.ChannelPoint(),
|
||||
PkScript: channel.FundingTxOut().PkScript,
|
||||
HeightHint: scid.BlockHeight,
|
||||
PostSpendEvent: fn.Some[chancloser.RbfSpendMapper](
|
||||
chancloser.SpendMapper,
|
||||
),
|
||||
}
|
||||
|
||||
// TODO(roasbeef): edge case here to re-enable a channel before both
|
||||
// shutdown sent?
|
||||
|
||||
daemonAdapters := NewLndDaemonAdapters(LndAdapterCfg{
|
||||
MsgSender: newPeerMsgSender(peerPub, p),
|
||||
TxBroadcaster: p.cfg.Wallet,
|
||||
ChainNotifier: p.cfg.ChainNotifier,
|
||||
})
|
||||
|
||||
protoCfg := chancloser.RbfChanCloserCfg{
|
||||
Daemon: daemonAdapters,
|
||||
InitialState: &initialState,
|
||||
Env: &env,
|
||||
InitEvent: fn.Some[protofsm.DaemonEvent](&spendEvent),
|
||||
MsgMapper: fn.Some[protofsm.MsgMapper[chancloser.ProtocolEvent]]( //nolint:ll
|
||||
msgMapper,
|
||||
),
|
||||
}
|
||||
|
||||
chanCloser := protofsm.NewStateMachine(protoCfg)
|
||||
|
||||
// Now that we've created the channel state machine, we'll register for
|
||||
// a hook to be sent once the channel has been flushed.
|
||||
link.OnFlushedOnce(func() {
|
||||
commitState := channel.StateSnapshot()
|
||||
|
||||
ctx := context.Background()
|
||||
chanCloser.SendEvent(ctx, &chancloser.ChannelFlushed{
|
||||
ShutdownBalances: chancloser.ShutdownBalances{
|
||||
LocalBalance: commitState.LocalBalance,
|
||||
RemoteBalance: commitState.RemoteBalance,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
return &chanCloser, nil
|
||||
}
|
||||
|
||||
// initAndStartRbfChanCloser initializes the channel closer for a channel that
|
||||
// is using the new RBF based co-op close protocol. This is called when we're
|
||||
// the one that's initiating the cooperative channel close.
|
||||
func (p *Brontide) initAndStartRbfChanCloser(req *htlcswitch.ChanClose,
|
||||
channel *lnwallet.LightningChannel) error {
|
||||
|
||||
// TODO(roasbeef): either kick off sent shutdown or shutdown recv'd
|
||||
// * can also send the NoDangling in as new event?
|
||||
|
||||
// First, we'll create the channel closer for this channel.
|
||||
chanCloser, err := p.initRbfChanCloser(channel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// With the chan closer created, we'll now kick off the co-op close
|
||||
// process by instructing it to send a shutdown message to the remote
|
||||
// party.
|
||||
ctx := context.Background()
|
||||
chanCloser.SendEvent(ctx, &chancloser.SendShutdown{
|
||||
IdealFeeRate: req.TargetFeePerKw.FeePerVByte(),
|
||||
DeliveryAddr: chooseAddr(req.DeliveryScript),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleLocalCloseReq kicks-off the workflow to execute a cooperative or
|
||||
// forced unilateral closure of the channel initiated by a local subsystem.
|
||||
func (p *Brontide) handleLocalCloseReq(req *htlcswitch.ChanClose) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user