lnwallet+sweep: calculate max allowed feerate on BumpResult

This commit adds the method `MaxFeeRateAllowed` to calculate the max fee
rate. The caller may specify a large MaxFeeRate value, which cannot be
cover by the budget. In that case, we default to use the max feerate
calculated using `budget/weight`.
This commit is contained in:
yyforyongyu
2024-02-29 13:18:23 +08:00
parent f85661d94a
commit ecd471ac75
3 changed files with 183 additions and 0 deletions

View File

@@ -3,10 +3,24 @@ package sweep
import (
"testing"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/stretchr/testify/require"
)
var (
// Create a taproot change script.
changePkScript = []byte{
0x51, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}
)
// TestBumpResultValidate tests the validate method of the BumpResult struct.
func TestBumpResultValidate(t *testing.T) {
t.Parallel()
@@ -50,3 +64,110 @@ func TestBumpResultValidate(t *testing.T) {
}
require.NoError(t, b.Validate())
}
// TestCalcSweepTxWeight checks that the weight of the sweep tx is calculated
// correctly.
func TestCalcSweepTxWeight(t *testing.T) {
t.Parallel()
// Create an input.
inp := createTestInput(100, input.WitnessKeyHash)
// Use a wrong change script to test the error case.
weight, err := calcSweepTxWeight([]input.Input{&inp}, []byte{0})
require.Error(t, err)
require.Zero(t, weight)
// Use a correct change script to test the success case.
weight, err = calcSweepTxWeight([]input.Input{&inp}, changePkScript)
require.NoError(t, err)
// BaseTxSize 8 bytes
// InputSize 1+41 bytes
// One P2TROutputSize 1+43 bytes
// One P2WKHWitnessSize 2+109 bytes
// Total weight = (8+42+44) * 4 + 111 = 487
require.EqualValuesf(t, 487, weight, "unexpected weight %v", weight)
}
// TestBumpRequestMaxFeeRateAllowed tests the max fee rate allowed for a bump
// request.
func TestBumpRequestMaxFeeRateAllowed(t *testing.T) {
t.Parallel()
// Create a test input.
inp := createTestInput(100, input.WitnessKeyHash)
// The weight is 487.
weight, err := calcSweepTxWeight([]input.Input{&inp}, changePkScript)
require.NoError(t, err)
// Define a test budget and calculates its fee rate.
budget := btcutil.Amount(1000)
budgetFeeRate := chainfee.NewSatPerKWeight(budget, weight)
testCases := []struct {
name string
req *BumpRequest
expectedMaxFeeRate chainfee.SatPerKWeight
expectedErr bool
}{
{
// Use a wrong change script to test the error case.
name: "error calc weight",
req: &BumpRequest{
DeliveryAddress: []byte{1},
},
expectedMaxFeeRate: 0,
expectedErr: true,
},
{
// When the budget cannot give a fee rate that matches
// the supplied MaxFeeRate, the max allowed feerate is
// capped by the budget.
name: "use budget as max fee rate",
req: &BumpRequest{
DeliveryAddress: changePkScript,
Inputs: []input.Input{&inp},
Budget: budget,
MaxFeeRate: budgetFeeRate + 1,
},
expectedMaxFeeRate: budgetFeeRate,
},
{
// When the budget can give a fee rate that matches the
// supplied MaxFeeRate, the max allowed feerate is
// capped by the MaxFeeRate.
name: "use config as max fee rate",
req: &BumpRequest{
DeliveryAddress: changePkScript,
Inputs: []input.Input{&inp},
Budget: budget,
MaxFeeRate: budgetFeeRate - 1,
},
expectedMaxFeeRate: budgetFeeRate - 1,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
// Check the method under test.
maxFeeRate, err := tc.req.MaxFeeRateAllowed()
// If we expect an error, check the error is returned
// and the feerate is empty.
if tc.expectedErr {
require.Error(t, err)
require.Zero(t, maxFeeRate)
return
}
// Otherwise, check the max fee rate is as expected.
require.NoError(t, err)
require.Equal(t, tc.expectedMaxFeeRate, maxFeeRate)
})
}
}