mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-29 03:01:52 +01:00
sweep: increase delta fee rate precision in fee function
This commit adds a private type `mSatPerKWeight` that expresses a given fee rate in millisatoshi per kw. This is needed to increase the precision of the fee function. When sweeping anchor inputs, if using a deadline delta of over 1000, it's likely the delta will be 0 sat/kw due to precision.
This commit is contained in:
parent
23feef7e6c
commit
7fb18bc0d5
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -14,6 +15,17 @@ var (
|
|||||||
ErrMaxPosition = errors.New("position already at max")
|
ErrMaxPosition = errors.New("position already at max")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// mSatPerKWeight represents a fee rate in msat/kw.
|
||||||
|
//
|
||||||
|
// TODO(yy): unify all the units to be virtual bytes.
|
||||||
|
type mSatPerKWeight lnwire.MilliSatoshi
|
||||||
|
|
||||||
|
// String returns a human-readable string of the fee rate.
|
||||||
|
func (m mSatPerKWeight) String() string {
|
||||||
|
s := lnwire.MilliSatoshi(m)
|
||||||
|
return fmt.Sprintf("%v/kw", s)
|
||||||
|
}
|
||||||
|
|
||||||
// FeeFunction defines an interface that is used to calculate fee rates for
|
// FeeFunction defines an interface that is used to calculate fee rates for
|
||||||
// transactions. It's expected the implementations use three params, the
|
// transactions. It's expected the implementations use three params, the
|
||||||
// starting fee rate, the ending fee rate, and number of blocks till deadline
|
// starting fee rate, the ending fee rate, and number of blocks till deadline
|
||||||
@ -80,8 +92,10 @@ type LinearFeeFunction struct {
|
|||||||
// and the current block height.
|
// and the current block height.
|
||||||
position uint32
|
position uint32
|
||||||
|
|
||||||
// deltaFeeRate is the fee rate increase per block.
|
// deltaFeeRate is the fee rate (msat/kw) increase per block.
|
||||||
deltaFeeRate chainfee.SatPerKWeight
|
//
|
||||||
|
// NOTE: this is used to increase precision.
|
||||||
|
deltaFeeRate mSatPerKWeight
|
||||||
|
|
||||||
// estimator is the fee estimator used to estimate the fee rate. We use
|
// estimator is the fee estimator used to estimate the fee rate. We use
|
||||||
// it to get the initial fee rate and, use it as a benchmark to decide
|
// it to get the initial fee rate and, use it as a benchmark to decide
|
||||||
@ -121,21 +135,28 @@ func NewLinearFeeFunction(maxFeeRate chainfee.SatPerKWeight, confTarget uint32,
|
|||||||
|
|
||||||
// Calculate how much fee rate should be increased per block.
|
// Calculate how much fee rate should be increased per block.
|
||||||
end := l.endingFeeRate
|
end := l.endingFeeRate
|
||||||
delta := btcutil.Amount(end - start).MulF64(1 / float64(confTarget))
|
|
||||||
|
// The starting and ending fee rates are in sat/kw, so we need to
|
||||||
|
// convert them to msat/kw by multiplying by 1000.
|
||||||
|
delta := btcutil.Amount(end - start).MulF64(1000 / float64(confTarget))
|
||||||
|
l.deltaFeeRate = mSatPerKWeight(delta)
|
||||||
|
|
||||||
// We only allow the delta to be zero if the width is one - when the
|
// We only allow the delta to be zero if the width is one - when the
|
||||||
// delta is zero, it means the starting and ending fee rates are the
|
// delta is zero, it means the starting and ending fee rates are the
|
||||||
// same, which means there's nothing to increase, so any width greater
|
// same, which means there's nothing to increase, so any width greater
|
||||||
// than 1 doesn't provide any utility. This could happen when the
|
// than 1 doesn't provide any utility. This could happen when the
|
||||||
// sweeper is offered to sweep an input that has passed its deadline.
|
// sweeper is offered to sweep an input that has passed its deadline.
|
||||||
if delta == 0 && l.width != 1 {
|
if l.deltaFeeRate == 0 && l.width != 1 {
|
||||||
|
log.Errorf("Failed to init fee function: startingFeeRate=%v, "+
|
||||||
|
"endingFeeRate=%v, width=%v, delta=%v", start, end,
|
||||||
|
confTarget, l.deltaFeeRate)
|
||||||
|
|
||||||
return nil, fmt.Errorf("fee rate delta is zero")
|
return nil, fmt.Errorf("fee rate delta is zero")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach the calculated values to the fee function.
|
// Attach the calculated values to the fee function.
|
||||||
l.startingFeeRate = start
|
l.startingFeeRate = start
|
||||||
l.currentFeeRate = start
|
l.currentFeeRate = start
|
||||||
l.deltaFeeRate = chainfee.SatPerKWeight(delta)
|
|
||||||
|
|
||||||
log.Debugf("Linear fee function initialized with startingFeeRate=%v, "+
|
log.Debugf("Linear fee function initialized with startingFeeRate=%v, "+
|
||||||
"endingFeeRate=%v, width=%v, delta=%v", start, end,
|
"endingFeeRate=%v, width=%v, delta=%v", start, end,
|
||||||
@ -234,7 +255,9 @@ func (l *LinearFeeFunction) feeRateAtPosition(p uint32) chainfee.SatPerKWeight {
|
|||||||
return l.endingFeeRate
|
return l.endingFeeRate
|
||||||
}
|
}
|
||||||
|
|
||||||
feeRateDelta := btcutil.Amount(l.deltaFeeRate).MulF64(float64(p))
|
// deltaFeeRate is in msat/kw, so we need to divide by 1000 to get the
|
||||||
|
// fee rate in sat/kw.
|
||||||
|
feeRateDelta := btcutil.Amount(l.deltaFeeRate).MulF64(float64(p) / 1000)
|
||||||
|
|
||||||
feeRate := l.startingFeeRate + chainfee.SatPerKWeight(feeRateDelta)
|
feeRate := l.startingFeeRate + chainfee.SatPerKWeight(feeRateDelta)
|
||||||
if feeRate > l.endingFeeRate {
|
if feeRate > l.endingFeeRate {
|
||||||
|
@ -54,8 +54,8 @@ func TestLinearFeeFunctionNew(t *testing.T) {
|
|||||||
//
|
//
|
||||||
// Mock the fee estimator to return the fee rate.
|
// Mock the fee estimator to return the fee rate.
|
||||||
estimator.On("EstimateFeePerKW", confTarget).Return(
|
estimator.On("EstimateFeePerKW", confTarget).Return(
|
||||||
// The starting fee rate is 1 sat/kw less than the max fee rate.
|
// The starting fee rate is the max fee rate.
|
||||||
maxFeeRate-1, nil).Once()
|
maxFeeRate, nil).Once()
|
||||||
estimator.On("RelayFeePerKW").Return(estimatedFeeRate).Once()
|
estimator.On("RelayFeePerKW").Return(estimatedFeeRate).Once()
|
||||||
|
|
||||||
f, err = NewLinearFeeFunction(maxFeeRate, confTarget, estimator)
|
f, err = NewLinearFeeFunction(maxFeeRate, confTarget, estimator)
|
||||||
@ -96,7 +96,7 @@ func TestLinearFeeFunctionFeeRateAtPosition(t *testing.T) {
|
|||||||
startingFeeRate: 1000,
|
startingFeeRate: 1000,
|
||||||
endingFeeRate: 3000,
|
endingFeeRate: 3000,
|
||||||
position: 0,
|
position: 0,
|
||||||
deltaFeeRate: 1000,
|
deltaFeeRate: 1_000_000,
|
||||||
width: 3,
|
width: 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user