lnd icon indicating copy to clipboard operation
lnd copied to clipboard

[bug]: sweep: LinearFeeFunction off by one

Open morehouse opened this issue 9 months ago • 5 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.

morehouse avatar May 08 '24 22:05 morehouse

@saubyk add to 18.0?

Crypt-iQ avatar May 09 '24 15:05 Crypt-iQ

@saubyk add to 18.0?

makes sense. added.

saubyk avatar May 09 '24 20:05 saubyk

cc: @yyforyongyu

saubyk avatar May 09 '24 20:05 saubyk

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?

yyforyongyu avatar May 09 '24 20:05 yyforyongyu

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.

morehouse avatar May 09 '24 21:05 morehouse

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

ghost avatar May 13 '24 03:05 ghost