From 0fc5301d12d267f2f316a43e65fdf3809e69bec0 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Mon, 18 Mar 2024 10:56:41 +0800 Subject: [PATCH] lnwallet+sweep: cap conf target used in fee estimator --- lnwallet/chainfee/estimator.go | 14 +++++++------- sweep/fee_function.go | 10 ++++++++++ sweep/fee_function_test.go | 18 ++++++++++++++++++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/lnwallet/chainfee/estimator.go b/lnwallet/chainfee/estimator.go index fa5e04ba1..76c235d1b 100644 --- a/lnwallet/chainfee/estimator.go +++ b/lnwallet/chainfee/estimator.go @@ -17,11 +17,11 @@ import ( ) const ( - // maxBlockTarget is the highest number of blocks confirmations that + // MaxBlockTarget is the highest number of blocks confirmations that // a WebAPIEstimator will cache fees for. This number is chosen // because it's the highest number of confs bitcoind will return a fee // estimate for. - maxBlockTarget uint32 = 1008 + MaxBlockTarget uint32 = 1008 // minBlockTarget is the lowest number of blocks confirmations that // a WebAPIEstimator will cache fees for. Requesting an estimate for @@ -463,11 +463,11 @@ func (b *BitcoindEstimator) Stop() error { func (b *BitcoindEstimator) EstimateFeePerKW( numBlocks uint32) (SatPerKWeight, error) { - if numBlocks > maxBlockTarget { + if numBlocks > MaxBlockTarget { log.Debugf("conf target %d exceeds the max value, "+ - "use %d instead.", numBlocks, maxBlockTarget, + "use %d instead.", numBlocks, MaxBlockTarget, ) - numBlocks = maxBlockTarget + numBlocks = MaxBlockTarget } feeEstimate, err := b.fetchEstimate(numBlocks, b.feeMode) @@ -761,8 +761,8 @@ func NewWebAPIEstimator(api WebAPIFeeSource, noCache bool) *WebAPIEstimator { func (w *WebAPIEstimator) EstimateFeePerKW(numBlocks uint32) ( SatPerKWeight, error) { - if numBlocks > maxBlockTarget { - numBlocks = maxBlockTarget + if numBlocks > MaxBlockTarget { + numBlocks = MaxBlockTarget } else if numBlocks < minBlockTarget { return 0, fmt.Errorf("conf target of %v is too low, minimum "+ "accepted is %v", numBlocks, minBlockTarget) diff --git a/sweep/fee_function.go b/sweep/fee_function.go index 955ca43a6..59da96d78 100644 --- a/sweep/fee_function.go +++ b/sweep/fee_function.go @@ -276,6 +276,16 @@ func (l *LinearFeeFunction) estimateFeeRate( ConfTarget: confTarget, } + // If the conf target is greater or equal to the max allowed value + // (1008), we will use the min relay fee instead. + if confTarget >= chainfee.MaxBlockTarget { + minFeeRate := l.estimator.RelayFeePerKW() + log.Debugf("Conf target %v is greater than max block target, "+ + "using min relay fee rate %v", confTarget, minFeeRate) + + return minFeeRate, nil + } + // endingFeeRate comes from budget/txWeight, which means the returned // fee rate will always be capped by this value, hence we don't need to // worry about overpay. diff --git a/sweep/fee_function_test.go b/sweep/fee_function_test.go index e549d8d64..fb75bcc1c 100644 --- a/sweep/fee_function_test.go +++ b/sweep/fee_function_test.go @@ -19,6 +19,7 @@ func TestLinearFeeFunctionNew(t *testing.T) { // Create testing params. maxFeeRate := chainfee.SatPerKWeight(10000) estimatedFeeRate := chainfee.SatPerKWeight(500) + minRelayFeeRate := chainfee.SatPerKWeight(100) confTarget := uint32(6) // Assert init fee function with zero conf value returns an error. @@ -62,6 +63,23 @@ func TestLinearFeeFunctionNew(t *testing.T) { rt.ErrorContains(err, "fee rate delta is zero") rt.Nil(f) + // When the conf target is >= 1008, the min relay fee should be used. + // + // Mock the fee estimator to reutrn the fee rate. + estimator.On("RelayFeePerKW").Return(minRelayFeeRate).Once() + + largeConf := uint32(1008) + f, err = NewLinearFeeFunction(maxFeeRate, largeConf, estimator) + rt.NoError(err) + rt.NotNil(f) + + // Assert the internal state. + rt.Equal(minRelayFeeRate, f.startingFeeRate) + rt.Equal(maxFeeRate, f.endingFeeRate) + rt.Equal(minRelayFeeRate, f.currentFeeRate) + rt.NotZero(f.deltaFeeRate) + rt.Equal(largeConf, f.width) + // Check a successfully created fee function. // // Mock the fee estimator to return the fee rate.