mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-26 01:33:02 +01:00
peer: add an implementation of chancloser.ChanObserver
In this commit, we add an implementation of a new interface the rbf coop state machine needs. We take care to accept interfaces everywhere, to make this easier to test, and decouple from the concrete types we'll end up using elsewhere.
This commit is contained in:
parent
1d2c22d140
commit
c32d4f9695
176
peer/chan_observer.go
Normal file
176
peer/chan_observer.go
Normal file
@ -0,0 +1,176 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chancloser"
|
||||
)
|
||||
|
||||
// channelView is a view into the current active/global channel state machine
|
||||
// for a given link.
|
||||
type channelView interface {
|
||||
// OweCommitment returns a boolean value reflecting whether we need to
|
||||
// send out a commitment signature because there are outstanding local
|
||||
// updates and/or updates in the local commit tx that aren't reflected
|
||||
// in the remote commit tx yet.
|
||||
OweCommitment() bool
|
||||
|
||||
// IsChannelClean returns true if neither side has pending commitments,
|
||||
// neither side has HTLC's, and all updates are locked in irrevocably.
|
||||
IsChannelClean() bool
|
||||
|
||||
// MarkCoopBroadcasted persistently marks that the channel close
|
||||
// transaction has been broadcast.
|
||||
MarkCoopBroadcasted(*wire.MsgTx, lntypes.ChannelParty) error
|
||||
|
||||
// StateSnapshot returns a snapshot of the current fully committed
|
||||
// state within the channel.
|
||||
StateSnapshot() *channeldb.ChannelSnapshot
|
||||
|
||||
// MarkShutdownSent persists the given ShutdownInfo. The existence of
|
||||
// the ShutdownInfo represents the fact that the Shutdown message has
|
||||
// been sent by us and so should be re-sent on re-establish.
|
||||
MarkShutdownSent(info *channeldb.ShutdownInfo) error
|
||||
}
|
||||
|
||||
// linkController is capable of controlling the flow out incoming/outgoing
|
||||
// HTLCs to/from the link.
|
||||
type linkController interface {
|
||||
// DisableAdds sets the ChannelUpdateHandler state to allow/reject
|
||||
// UpdateAddHtlc's in the specified direction. It returns true if the
|
||||
// state was changed and false if the desired state was already set
|
||||
// before the method was called.
|
||||
DisableAdds(outgoing bool) bool
|
||||
|
||||
// IsFlushing returns true when UpdateAddHtlc's are disabled in the
|
||||
// direction of the argument.
|
||||
IsFlushing(direction bool) bool
|
||||
}
|
||||
|
||||
// linkNetworkController is an interface that represents an object capable of
|
||||
// managing interactions with the active channel links from the PoV of the
|
||||
// gossip network.
|
||||
type linkNetworkController interface {
|
||||
// RequestDisable disables a channel by its channel point.
|
||||
RequestDisable(wire.OutPoint, bool) error
|
||||
}
|
||||
|
||||
// chanObserver implements the chancloser.ChanObserver interface for the
|
||||
// existing LightningChannel struct/instance.
|
||||
type chanObserver struct {
|
||||
chanView channelView
|
||||
link linkController
|
||||
linkNetwork linkNetworkController
|
||||
}
|
||||
|
||||
// newChanObserver creates a new instance of a chanObserver from an active
|
||||
// channelView.
|
||||
//
|
||||
//nolint:unused
|
||||
func newChanObserver(chanView channelView,
|
||||
link linkController, linkNetwork linkNetworkController) *chanObserver {
|
||||
|
||||
return &chanObserver{
|
||||
chanView: chanView,
|
||||
link: link,
|
||||
linkNetwork: linkNetwork,
|
||||
}
|
||||
}
|
||||
|
||||
// NoDanglingUpdates returns true if there are no dangling updates in the
|
||||
// channel. In other words, there are no active update messages that haven't
|
||||
// already been covered by a commit sig.
|
||||
func (l *chanObserver) NoDanglingUpdates() bool {
|
||||
return !l.chanView.OweCommitment()
|
||||
}
|
||||
|
||||
// DisableIncomingAdds instructs the channel link to disable process new
|
||||
// incoming add messages.
|
||||
func (l *chanObserver) DisableIncomingAdds() error {
|
||||
// If there's no link, then we don't need to disable any adds.
|
||||
if l.link == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
disabled := l.link.DisableAdds(htlcswitch.Incoming)
|
||||
if disabled {
|
||||
chanPoint := l.chanView.StateSnapshot().ChannelPoint
|
||||
peerLog.Debugf("ChannelPoint(%v): link already disabled",
|
||||
chanPoint)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DisableOutgoingAdds instructs the channel link to disable process new
|
||||
// outgoing add messages.
|
||||
func (l *chanObserver) DisableOutgoingAdds() error {
|
||||
// If there's no link, then we don't need to disable any adds.
|
||||
if l.link == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_ = l.link.DisableAdds(htlcswitch.Outgoing)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarkCoopBroadcasted persistently marks that the channel close transaction
|
||||
// has been broadcast.
|
||||
func (l *chanObserver) MarkCoopBroadcasted(tx *wire.MsgTx, local bool) error {
|
||||
return l.chanView.MarkCoopBroadcasted(tx, lntypes.Local)
|
||||
}
|
||||
|
||||
// MarkShutdownSent persists the given ShutdownInfo. The existence of the
|
||||
// ShutdownInfo represents the fact that the Shutdown message has been sent by
|
||||
// us and so should be re-sent on re-establish.
|
||||
func (l *chanObserver) MarkShutdownSent(deliveryAddr []byte,
|
||||
isInitiator bool) error {
|
||||
|
||||
shutdownInfo := channeldb.NewShutdownInfo(deliveryAddr, isInitiator)
|
||||
return l.chanView.MarkShutdownSent(shutdownInfo)
|
||||
}
|
||||
|
||||
// FinalBalances is the balances of the channel once it has been flushed. If
|
||||
// Some, then this indicates that the channel is now in a state where it's
|
||||
// always flushed, so we can accelerate the state transitions.
|
||||
func (l *chanObserver) FinalBalances() fn.Option[chancloser.ShutdownBalances] {
|
||||
chanClean := l.chanView.IsChannelClean()
|
||||
|
||||
switch {
|
||||
// If we have a link, then the balances are final if both the incoming
|
||||
// and outgoing adds are disabled _and_ the channel is clean.
|
||||
case l.link != nil && l.link.IsFlushing(htlcswitch.Incoming) &&
|
||||
l.link.IsFlushing(htlcswitch.Outgoing) && chanClean:
|
||||
|
||||
fallthrough
|
||||
|
||||
// If we don't have a link, then this is a restart case, so the
|
||||
// balances are final.
|
||||
case l.link == nil:
|
||||
snapshot := l.chanView.StateSnapshot()
|
||||
|
||||
return fn.Some(chancloser.ShutdownBalances{
|
||||
LocalBalance: snapshot.LocalBalance,
|
||||
RemoteBalance: snapshot.RemoteBalance,
|
||||
})
|
||||
|
||||
// Otherwise, the link is still active and not flushed, so the balances
|
||||
// aren't yet final.
|
||||
default:
|
||||
return fn.None[chancloser.ShutdownBalances]()
|
||||
}
|
||||
}
|
||||
|
||||
// DisableChannel disables the target channel.
|
||||
func (l *chanObserver) DisableChannel() error {
|
||||
op := l.chanView.StateSnapshot().ChannelPoint
|
||||
return l.linkNetwork.RequestDisable(op, false)
|
||||
}
|
||||
|
||||
// A compile-time assertion to ensure that chanObserver meets the
|
||||
// chancloser.ChanStateObserver interface.
|
||||
var _ chancloser.ChanStateObserver = (*chanObserver)(nil)
|
Loading…
x
Reference in New Issue
Block a user