lnwallet/chancloser: remove the commit fee clamp, introduce max fee

In this commit, we stop clamping the ideal fee rate to the commitment
fee of the channel. This catches us up to this PR of the spec:
https://github.com/lightning/bolts/pull/847.

We also do away with the old 3x ideal fee "max fee", and replace that
with an explicit max fee. This new max fee will either be the default
multiplier of the ideal fee, or a new user specified max fee value.
This commit is contained in:
Olaoluwa Osuntokun committed 2022-07-26 17:20:23 -07:00
1 parent fec8fd9c63
commit c140da8f49
1 file changed
+33 -14
+33 -14
View File
@@ -35,6 +35,12 @@ var (
// shutdown script previously set for that party. // shutdown script previously set for that party.
ErrUpfrontShutdownScriptMismatch = fmt.Errorf("shutdown script does not " + ErrUpfrontShutdownScriptMismatch = fmt.Errorf("shutdown script does not " +
"match upfront shutdown script") "match upfront shutdown script")
// ErrProposalExeceedsMaxFee is returned when as the initiator, the
// latest fee proposal sent by the responder exceed our max fee.
// responder.
ErrProposalExeceedsMaxFee = fmt.Errorf("latest fee proposal exceeds " +
"max fee")
) )
// closeState represents all the possible states the channel closer state // closeState represents all the possible states the channel closer state
@@ -73,6 +79,14 @@ const (
closeFinished closeFinished
) )
const (
// defaultMaxFeeMultiplier is a multiplier we'll apply to the ideal fee
// of the initiator, to decide when the negotiated fee is too high. By
// default, we want to bail out if we attempt to negotiate a fee that's
// 3x higher than our max fee.
defaultMaxFeeMultiplier = 3
)
// ChanCloseCfg holds all the items that a ChanCloser requires to carry out its // ChanCloseCfg holds all the items that a ChanCloser requires to carry out its
// duties. // duties.
type ChanCloseCfg struct { type ChanCloseCfg struct {
@@ -89,6 +103,9 @@ type ChanCloseCfg struct {
// Disconnect will disconnect from the remote peer in this close. // Disconnect will disconnect from the remote peer in this close.
Disconnect func() error Disconnect func() error
// MaxFee, is non-zero represents the highest fee that the initiator is
// willing to pay to close the channel.
MaxFee chainfee.SatPerKWeight
// Quit is a channel that should be sent upon in the occasion the state // Quit is a channel that should be sent upon in the occasion the state
// machine should cease all progress and shutdown. // machine should cease all progress and shutdown.
Quit chan struct{} Quit chan struct{}
@@ -122,6 +139,11 @@ type ChanCloser struct {
// offer when starting negotiation. This will be used as a baseline. // offer when starting negotiation. This will be used as a baseline.
idealFeeSat btcutil.Amount idealFeeSat btcutil.Amount
// maxFee is the highest fee the initiator is willing to pay to close
// out the channel. This is either a use specified value, or a default
// multiplier based of the initial starting ideal fee.
maxFee btcutil.Amount
// lastFeeProposal is the last fee that we proposed to the remote party. // lastFeeProposal is the last fee that we proposed to the remote party.
// We'll use this as a pivot point to ratchet our next offer up, down, or // We'll use this as a pivot point to ratchet our next offer up, down, or
// simply accept the remote party's prior offer. // simply accept the remote party's prior offer.
@@ -168,17 +190,12 @@ func NewChanCloser(cfg ChanCloseCfg, deliveryScript []byte,
// TODO(roasbeef): should factor in minimal commit // TODO(roasbeef): should factor in minimal commit
idealFeeSat := cfg.Channel.CalcFee(idealFeePerKw) idealFeeSat := cfg.Channel.CalcFee(idealFeePerKw)
// If this fee is greater than the fee currently present within the // When we're the initiator, we'll want to also factor in the highest
// commitment transaction, then we'll clamp it down to be within the proper // fee we want to pay. This'll either be 3x the ideal fee, or the
// range. // specified explicit max fee.
// maxFee := idealFeeSat * defaultMaxFeeMultiplier
// TODO(roasbeef): clamp fee func? if cfg.MaxFee > 0 {
channelCommitFee := cfg.Channel.StateSnapshot().CommitFee maxFee = cfg.Channel.CalcFee(cfg.MaxFee)
if idealFeeSat > channelCommitFee {
chancloserLog.Infof("Ideal starting fee of %v is greater than commit "+
"fee of %v, clamping", int64(idealFeeSat), int64(channelCommitFee))
idealFeeSat = channelCommitFee
} }
chancloserLog.Infof("Ideal fee for closure of ChannelPoint(%v) is: %v sat", chancloserLog.Infof("Ideal fee for closure of ChannelPoint(%v) is: %v sat",
@@ -193,6 +210,7 @@ func NewChanCloser(cfg ChanCloseCfg, deliveryScript []byte,
cfg: cfg, cfg: cfg,
negotiationHeight: negotiationHeight, negotiationHeight: negotiationHeight,
idealFeeSat: idealFeeSat, idealFeeSat: idealFeeSat,
maxFee: maxFee,
localDeliveryScript: deliveryScript, localDeliveryScript: deliveryScript,
priorFeeOffers: make(map[btcutil.Amount]*lnwire.ClosingSigned), priorFeeOffers: make(map[btcutil.Amount]*lnwire.ClosingSigned),
locallyInitiated: locallyInitiated, locallyInitiated: locallyInitiated,
@@ -483,9 +501,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 { if c.cfg.Channel.IsInitiator() && feeProposal > c.maxFee {
return nil, false, fmt.Errorf("couldn't find" + return nil, false, fmt.Errorf("%w: %v > %v",
" compromise fee") ErrProposalExeceedsMaxFee, feeProposal,
c.maxFee)
} }
// With our new fee proposal calculated, we'll craft a new close // With our new fee proposal calculated, we'll craft a new close