mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
sweep: make sure the full input is accounted
Fix the case where previously only the witness data is taken into account when calculating the fees.
This commit is contained in:
parent
17a089c899
commit
5e8452cc5d
@ -5,6 +5,8 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
)
|
)
|
||||||
@ -201,8 +203,8 @@ func (b *BudgetAggregator) filterInputs(inputs InputsMap) InputsMap {
|
|||||||
for _, pi := range inputs {
|
for _, pi := range inputs {
|
||||||
op := pi.OutPoint()
|
op := pi.OutPoint()
|
||||||
|
|
||||||
// Get the size and skip if there's an error.
|
// Get the size of the witness and skip if there's an error.
|
||||||
size, _, err := pi.WitnessType().SizeUpperBound()
|
witnessSize, _, err := pi.WitnessType().SizeUpperBound()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Skipped input=%v: cannot get its size: %v",
|
log.Warnf("Skipped input=%v: cannot get its size: %v",
|
||||||
op, err)
|
op, err)
|
||||||
@ -210,12 +212,27 @@ func (b *BudgetAggregator) filterInputs(inputs InputsMap) InputsMap {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
|
// Calculate the size if the input is included in the tx.
|
||||||
|
//
|
||||||
|
// NOTE: When including this input, we need to account the
|
||||||
|
// non-witness data which is expressed in vb.
|
||||||
|
//
|
||||||
|
// TODO(yy): This is not accurate for tapscript input. We need
|
||||||
|
// to unify calculations used in the `TxWeightEstimator` inside
|
||||||
|
// `input/size.go` and `weightEstimator` in
|
||||||
|
// `weight_estimator.go`. And calculate the expected weights
|
||||||
|
// similar to BOLT-3:
|
||||||
|
// https://github.com/lightning/bolts/blob/master/03-transactions.md#appendix-a-expected-weights
|
||||||
|
wu := lntypes.VByte(input.InputSize).ToWU() + witnessSize
|
||||||
|
|
||||||
// Skip inputs that has too little budget.
|
// Skip inputs that has too little budget.
|
||||||
minFee := minFeeRate.FeeForWeight(size)
|
minFee := minFeeRate.FeeForWeight(wu)
|
||||||
if pi.params.Budget < minFee {
|
if pi.params.Budget < minFee {
|
||||||
log.Warnf("Skipped input=%v: has budget=%v, but the "+
|
log.Warnf("Skipped input=%v: has budget=%v, but the "+
|
||||||
"min fee requires %v", op, pi.params.Budget,
|
"min fee requires %v (feerate=%v), size=%v", op,
|
||||||
minFee)
|
pi.params.Budget, minFee,
|
||||||
|
minFeeRate.FeePerVByte(), wu.ToVB())
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -224,11 +241,12 @@ func (b *BudgetAggregator) filterInputs(inputs InputsMap) InputsMap {
|
|||||||
startingFeeRate := pi.params.StartingFeeRate.UnwrapOr(
|
startingFeeRate := pi.params.StartingFeeRate.UnwrapOr(
|
||||||
chainfee.SatPerKWeight(0),
|
chainfee.SatPerKWeight(0),
|
||||||
)
|
)
|
||||||
startingFee := startingFeeRate.FeeForWeight(size)
|
startingFee := startingFeeRate.FeeForWeight(wu)
|
||||||
if pi.params.Budget < startingFee {
|
if pi.params.Budget < startingFee {
|
||||||
log.Errorf("Skipped input=%v: has budget=%v, but the "+
|
log.Errorf("Skipped input=%v: has budget=%v, but the "+
|
||||||
"starting fee requires %v", op,
|
"starting fee requires %v (feerate=%v), "+
|
||||||
pi.params.Budget, minFee)
|
"size=%v", op, pi.params.Budget, startingFee,
|
||||||
|
startingFeeRate.FeePerVByte(), wu.ToVB())
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,11 @@ func TestBudgetAggregatorFilterInputs(t *testing.T) {
|
|||||||
defer wt.AssertExpectations(t)
|
defer wt.AssertExpectations(t)
|
||||||
|
|
||||||
// Mock the `SizeUpperBound` method to return the size four times.
|
// Mock the `SizeUpperBound` method to return the size four times.
|
||||||
const wtSize lntypes.WeightUnit = 100
|
const wu lntypes.WeightUnit = 100
|
||||||
wt.On("SizeUpperBound").Return(wtSize, true, nil).Times(4)
|
wt.On("SizeUpperBound").Return(wu, true, nil).Times(4)
|
||||||
|
|
||||||
|
// Calculate the input size.
|
||||||
|
inpSize := lntypes.VByte(input.InputSize).ToWU() + wu
|
||||||
|
|
||||||
// Create a mock input that will be filtered out due to error.
|
// Create a mock input that will be filtered out due to error.
|
||||||
inpErr := &input.MockInput{}
|
inpErr := &input.MockInput{}
|
||||||
@ -64,9 +67,9 @@ func TestBudgetAggregatorFilterInputs(t *testing.T) {
|
|||||||
var (
|
var (
|
||||||
// Define three budget values, one below the min fee rate, one
|
// Define three budget values, one below the min fee rate, one
|
||||||
// above and one equal to it.
|
// above and one equal to it.
|
||||||
budgetLow = minFeeRate.FeeForWeight(wtSize) - 1
|
budgetLow = minFeeRate.FeeForWeight(inpSize) - 1
|
||||||
budgetEqual = minFeeRate.FeeForWeight(wtSize)
|
budgetEqual = minFeeRate.FeeForWeight(inpSize)
|
||||||
budgetHigh = minFeeRate.FeeForWeight(wtSize) + 1
|
budgetHigh = minFeeRate.FeeForWeight(inpSize) + 1
|
||||||
|
|
||||||
// Define three outpoints with different budget values.
|
// Define three outpoints with different budget values.
|
||||||
opLow = wire.OutPoint{Hash: chainhash.Hash{2}}
|
opLow = wire.OutPoint{Hash: chainhash.Hash{2}}
|
||||||
@ -398,8 +401,12 @@ func TestBudgetInputSetClusterInputs(t *testing.T) {
|
|||||||
|
|
||||||
// Mock the `SizeUpperBound` method to return the size 10 times since
|
// Mock the `SizeUpperBound` method to return the size 10 times since
|
||||||
// we are using ten inputs.
|
// we are using ten inputs.
|
||||||
const wtSize lntypes.WeightUnit = 100
|
const wu lntypes.WeightUnit = 100
|
||||||
wt.On("SizeUpperBound").Return(wtSize, true, nil).Times(10)
|
wt.On("SizeUpperBound").Return(wu, true, nil).Times(10)
|
||||||
|
|
||||||
|
// Calculate the input size.
|
||||||
|
inpSize := lntypes.VByte(input.InputSize).ToWU() + wu
|
||||||
|
|
||||||
wt.On("String").Return("mock witness type")
|
wt.On("String").Return("mock witness type")
|
||||||
|
|
||||||
// Mock the estimator to return a constant fee rate.
|
// Mock the estimator to return a constant fee rate.
|
||||||
@ -409,8 +416,8 @@ func TestBudgetInputSetClusterInputs(t *testing.T) {
|
|||||||
var (
|
var (
|
||||||
// Define two budget values, one below the min fee rate and one
|
// Define two budget values, one below the min fee rate and one
|
||||||
// above it.
|
// above it.
|
||||||
budgetLow = minFeeRate.FeeForWeight(wtSize) - 1
|
budgetLow = minFeeRate.FeeForWeight(inpSize) - 1
|
||||||
budgetHigh = minFeeRate.FeeForWeight(wtSize) + 1
|
budgetHigh = minFeeRate.FeeForWeight(inpSize) + 1
|
||||||
|
|
||||||
// Create three deadline heights, which means there are three
|
// Create three deadline heights, which means there are three
|
||||||
// groups of inputs to be expected.
|
// groups of inputs to be expected.
|
||||||
|
Loading…
Reference in New Issue
Block a user