lnd/peer/chan_observer.go
Oli 8047149c6a
multi: upgrade to btcd v2 modules
Migrate all btcd dependencies to the new per-package v2 modules (wire/v2,
txscript/v2, chaincfg/v2, chainhash/v2, btcutil/v2, psbt/v2, btcec/v2)
introduced by btcd v0.26.0, and pin the tagged ecosystem versions:
btcwallet v0.17.0, neutrino v0.18.0 and lightning-onion v1.4.0.

The bulk of the import rewrite was produced by the scripted diff from
https://github.com/btcsuite/btcd/pull/2547 (followed by 'make rpc'). The
address symbols that moved out of btcutil into the new address package
are imported as btcaddr where a local "address" variable would otherwise
shadow them. The go.mod/go.sum updates and the remaining manual
compilation fixes are folded into this single commit so it builds on its
own (the migration was previously split into a reproducible scripted-diff
plus follow-ups, intended to be squashed on merge).
2026-06-24 10:58:36 -07:00

179 lines
5.9 KiB
Go

package peer
import (
"github.com/btcsuite/btcd/wire/v2"
"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.
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 {
party := lntypes.Remote
if local {
party = lntypes.Local
}
return l.chanView.MarkCoopBroadcasted(tx, party)
}
// 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)