lightningnetwork/lnd

[bug]: sweep: LinearFeeFunction off by one

morehouse opened this issue · 6 comments

LinearFeeFunction doesn't return the max fee rate until after the deadline has been missed.

Example

Current block height is H. An incoming HTLC has a cltv_expiry of H + 10, so the contractcourt sets deadline := H + 10 for the HTLC input.

We need to confirm our HTLC-Preimage no later than block H + 10, or else we'll get into a bidding war with the channel peer since they can spend the timeout path after block H + 10 confirms.

LinearFeeFunction should max out its fee rate after block H + 9 confirms since this is the last shot at meeting the deadline. Instead, LinearFeeFunction waits to max out the fee rate until block H + 10.

Severity

For typical deadlines 10+ blocks away, this is a minor problem. But in the extreme case of a next-block deadline, LinearFeeFunction will return the min feerate instead of the max, which is quite bad.

@saubyk add to 18.0?

@saubyk add to 18.0?

makes sense. added.

But in the extreme case of a next-block deadline, LinearFeeFunction will return the min feerate instead of the max, which is quite bad.

What do you mean by saying next-block deadline? That we only have 1 block left till it times out? What is this min feerate?

What do you mean by saying next-block deadline? That we only have 1 block left till it times out? What is this min feerate?

Here's an example graph of the LinearFeeFunction. The min feerate is the starting feerate. The max feerate is the ending feerate.

image

Now imagine we call SweepInput with a deadline 1 block away. The fee function will be initialized with a width of 1 and starting feerate at the minimum of the feerate line. After 1 block (i.e. deadline missed), the feerate will be immediately bumped to the maximum of the feerate line.

But for this next-block deadline case, we really don't want a sloped line at all -- we want to start right at the maximum.

func (l *LinearFeeFunction) feeRateAtPosition(p uint32) chainfee.SatPerKWeight {
if p >= l.width - 1 {
return l.endingFeeRate
}
...
}
does this suggestion fix the issue located in /sweep/fee_function.go