mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 01:43:16 +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/wire"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
)
|
||||
@ -201,8 +203,8 @@ func (b *BudgetAggregator) filterInputs(inputs InputsMap) InputsMap {
|
||||
for _, pi := range inputs {
|
||||
op := pi.OutPoint()
|
||||
|
||||
// Get the size and skip if there's an error.
|
||||
size, _, err := pi.WitnessType().SizeUpperBound()
|
||||
// Get the size of the witness and skip if there's an error.
|
||||
witnessSize, _, err := pi.WitnessType().SizeUpperBound()
|
||||
if err != nil {
|
||||
log.Warnf("Skipped input=%v: cannot get its size: %v",
|
||||
op, err)
|
||||
@ -210,12 +212,27 @@ func (b *BudgetAggregator) filterInputs(inputs InputsMap) InputsMap {
|
||||
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.
|
||||
minFee := minFeeRate.FeeForWeight(size)
|
||||
minFee := minFeeRate.FeeForWeight(wu)
|
||||
if pi.params.Budget < minFee {
|
||||
log.Warnf("Skipped input=%v: has budget=%v, but the "+
|
||||
"min fee requires %v", op, pi.params.Budget,
|
||||
minFee)
|
||||
"min fee requires %v (feerate=%v), size=%v", op,
|
||||
pi.params.Budget, minFee,
|
||||
minFeeRate.FeePerVByte(), wu.ToVB())
|
||||
|
||||
continue
|
||||
}
|
||||
@ -224,11 +241,12 @@ func (b *BudgetAggregator) filterInputs(inputs InputsMap) InputsMap {
|
||||
startingFeeRate := pi.params.StartingFeeRate.UnwrapOr(
|
||||
chainfee.SatPerKWeight(0),
|
||||
)
|
||||
startingFee := startingFeeRate.FeeForWeight(size)
|
||||
startingFee := startingFeeRate.FeeForWeight(wu)
|
||||
if pi.params.Budget < startingFee {
|
||||
log.Errorf("Skipped input=%v: has budget=%v, but the "+
|
||||
"starting fee requires %v", op,
|
||||
pi.params.Budget, minFee)
|
||||
"starting fee requires %v (feerate=%v), "+
|
||||
"size=%v", op, pi.params.Budget, startingFee,
|
||||
startingFeeRate.FeePerVByte(), wu.ToVB())
|
||||
|
||||
continue
|
||||
}
|
||||
|
@ -43,8 +43,11 @@ func TestBudgetAggregatorFilterInputs(t *testing.T) {
|
||||
defer wt.AssertExpectations(t)
|
||||
|
||||
// Mock the `SizeUpperBound` method to return the size four times.
|
||||
const wtSize lntypes.WeightUnit = 100
|
||||
wt.On("SizeUpperBound").Return(wtSize, true, nil).Times(4)
|
||||
const wu lntypes.WeightUnit = 100
|
||||
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.
|
||||
inpErr := &input.MockInput{}
|
||||
@ -64,9 +67,9 @@ func TestBudgetAggregatorFilterInputs(t *testing.T) {
|
||||
var (
|
||||
// Define three budget values, one below the min fee rate, one
|
||||
// above and one equal to it.
|
||||
budgetLow = minFeeRate.FeeForWeight(wtSize) - 1
|
||||
budgetEqual = minFeeRate.FeeForWeight(wtSize)
|
||||
budgetHigh = minFeeRate.FeeForWeight(wtSize) + 1
|
||||
budgetLow = minFeeRate.FeeForWeight(inpSize) - 1
|
||||
budgetEqual = minFeeRate.FeeForWeight(inpSize)
|
||||
budgetHigh = minFeeRate.FeeForWeight(inpSize) + 1
|
||||
|
||||
// Define three outpoints with different budget values.
|
||||
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
|
||||
// we are using ten inputs.
|
||||
const wtSize lntypes.WeightUnit = 100
|
||||
wt.On("SizeUpperBound").Return(wtSize, true, nil).Times(10)
|
||||
const wu lntypes.WeightUnit = 100
|
||||
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")
|
||||
|
||||
// Mock the estimator to return a constant fee rate.
|
||||
@ -409,8 +416,8 @@ func TestBudgetInputSetClusterInputs(t *testing.T) {
|
||||
var (
|
||||
// Define two budget values, one below the min fee rate and one
|
||||
// above it.
|
||||
budgetLow = minFeeRate.FeeForWeight(wtSize) - 1
|
||||
budgetHigh = minFeeRate.FeeForWeight(wtSize) + 1
|
||||
budgetLow = minFeeRate.FeeForWeight(inpSize) - 1
|
||||
budgetHigh = minFeeRate.FeeForWeight(inpSize) + 1
|
||||
|
||||
// Create three deadline heights, which means there are three
|
||||
// groups of inputs to be expected.
|
||||
|
Loading…
Reference in New Issue
Block a user