diff --git a/htlcswitch/interfaces.go b/htlcswitch/interfaces.go index b899e6a90..e12825c53 100644 --- a/htlcswitch/interfaces.go +++ b/htlcswitch/interfaces.go @@ -7,6 +7,7 @@ import ( "github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwallet" + "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/record" ) @@ -57,6 +58,21 @@ type packetHandler interface { handleLocalAddPacket(*htlcPacket) error } +// dustHandler is an interface used exclusively by the Switch to evaluate +// whether a link has too much dust exposure. +type dustHandler interface { + // getDustSum returns the dust sum on either the local or remote + // commitment. + getDustSum(remote bool) lnwire.MilliSatoshi + + // getFeeRate returns the current channel feerate. + getFeeRate() chainfee.SatPerKWeight + + // getDustClosure returns a closure that can evaluate whether a passed + // HTLC is dust. + getDustClosure() dustClosure +} + // ChannelUpdateHandler is an interface that provides methods that allow // sending lnwire.Message to the underlying link as well as querying state. type ChannelUpdateHandler interface { @@ -122,6 +138,9 @@ type ChannelLink interface { // Embed the ChannelUpdateHandler interface. ChannelUpdateHandler + // Embed the dustHandler interface. + dustHandler + // ChannelPoint returns the channel outpoint for the channel link. ChannelPoint() *wire.OutPoint diff --git a/htlcswitch/link.go b/htlcswitch/link.go index f82327b2b..00197d2b3 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -1930,6 +1930,10 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) { "error receiving fee update: %v", err) return } + + // Update the mailbox's feerate as well. + l.mailBox.SetFeeRate(fee) + case *lnwire.Error: // Error received from remote, MUST fail channel, but should // only print the contents of the error message if all @@ -2193,6 +2197,34 @@ func (l *channelLink) MayAddOutgoingHtlc() error { return l.channel.MayAddOutgoingHtlc() } +// getDustSum is a wrapper method that calls the underlying channel's dust sum +// method. +// +// NOTE: Part of the dustHandler interface. +func (l *channelLink) getDustSum(remote bool) lnwire.MilliSatoshi { + return l.channel.GetDustSum(remote) +} + +// getFeeRate is a wrapper method that retrieves the underlying channel's +// feerate. +// +// NOTE: Part of the dustHandler interface. +func (l *channelLink) getFeeRate() chainfee.SatPerKWeight { + return l.channel.CommitFeeRate() +} + +// getDustClosure returns a closure that can be used by the switch or mailbox +// to evaluate whether a given HTLC is dust. +// +// NOTE: Part of the dustHandler interface. +func (l *channelLink) getDustClosure() dustClosure { + localDustLimit := l.channel.State().LocalChanCfg.DustLimit + remoteDustLimit := l.channel.State().RemoteChanCfg.DustLimit + chanType := l.channel.State().ChanType + + return dustHelper(chanType, localDustLimit, remoteDustLimit) +} + // dustClosure is a function that evaluates whether an HTLC is dust. It returns // true if the HTLC is dust. It takes in a feerate, a boolean denoting whether // the HTLC is incoming (i.e. one that the remote sent), a boolean denoting @@ -2232,6 +2264,14 @@ func (l *channelLink) AttachMailBox(mailbox MailBox) { l.upstream = mailbox.MessageOutBox() l.downstream = mailbox.PacketOutBox() l.Unlock() + + // Set the mailbox's fee rate. This may be refreshing a feerate that was + // never committed. + l.mailBox.SetFeeRate(l.getFeeRate()) + + // Also set the mailbox's dust closure so that it can query whether HTLC's + // are dust given the current feerate. + l.mailBox.SetDustClosure(l.getDustClosure()) } // UpdateForwardingPolicy updates the forwarding policy for the target @@ -2532,6 +2572,10 @@ func (l *channelLink) updateChannelFee(feePerKw chainfee.SatPerKWeight) error { return err } + // The fee passed the channel's validation checks, so we update the + // mailbox feerate. + l.mailBox.SetFeeRate(feePerKw) + // We'll then attempt to send a new UpdateFee message, and also lock it // in immediately by triggering a commitment update. msg := lnwire.NewUpdateFee(l.ChanID(), uint32(feePerKw)) diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index ce9b0f838..cda704ce5 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -16,6 +16,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" "github.com/go-errors/errors" sphinx "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/chainntnfs" @@ -717,6 +718,21 @@ func (f *mockChannelLink) handleLocalAddPacket(pkt *htlcPacket) error { return nil } +func (f *mockChannelLink) getDustSum(remote bool) lnwire.MilliSatoshi { + return 0 +} + +func (f *mockChannelLink) getFeeRate() chainfee.SatPerKWeight { + return 0 +} + +func (f *mockChannelLink) getDustClosure() dustClosure { + dustLimit := btcutil.Amount(400) + return dustHelper( + channeldb.SingleFunderTweaklessBit, dustLimit, dustLimit, + ) +} + func (f *mockChannelLink) HandleChannelUpdate(lnwire.Message) { } @@ -742,6 +758,7 @@ func (f *mockChannelLink) Stats() (uint64, lnwire.MilliSatoshi, lnwire.MilliSato func (f *mockChannelLink) AttachMailBox(mailBox MailBox) { f.mailBox = mailBox f.packets = mailBox.PacketOutBox() + mailBox.SetDustClosure(f.getDustClosure()) } func (f *mockChannelLink) Start() error {