Skip to content

Commit bdaa9f4

Browse files
committed
sweep: ensure we factor in extra change addrs in MaxFeeRateAllowed
1 parent f2adabb commit bdaa9f4

File tree

4 files changed

+48
-10
lines changed

4 files changed

+48
-10
lines changed

sweep/fee_bumper.go

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/lightningnetwork/lnd/lnutils"
2121
"github.com/lightningnetwork/lnd/lnwallet"
2222
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
23+
"github.com/lightningnetwork/lnd/tlv"
2324
)
2425

2526
var (
@@ -43,6 +44,19 @@ var (
4344
ErrThirdPartySpent = errors.New("third party spent the output")
4445
)
4546

47+
var (
48+
// dummyChangePkScript is a dummy tapscript change script that's used
49+
// when we don't need a real address, just something that can be used
50+
// for fee estimation.
51+
dummyChangePkScript = []byte{
52+
0x51, 0x20,
53+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57+
}
58+
)
59+
4660
// Bumper defines an interface that can be used by other subsystems for fee
4761
// bumping.
4862
type Bumper interface {
@@ -129,12 +143,33 @@ type BumpRequest struct {
129143
// compares it with the specified MaxFeeRate, and returns the smaller of the
130144
// two.
131145
func (r *BumpRequest) MaxFeeRateAllowed() (chainfee.SatPerKWeight, error) {
146+
// We'll want to know if we have any blobs, as we need to factor this
147+
// into the max fee rate for this bump request.
148+
hasBlobs := fn.Any(func(i input.Input) bool {
149+
return fn.MapOptionZ(
150+
i.ResolutionBlob(), func(b tlv.Blob) bool {
151+
return len(b) > 0
152+
},
153+
)
154+
}, r.Inputs)
155+
156+
sweepAddrs := [][]byte{
157+
r.DeliveryAddress.DeliveryAddress,
158+
}
159+
160+
// If we have blobs, then we'll add an extra sweep addr for the size
161+
// estimate below. We know that these blobs will also always be based on
162+
// p2tr addrs.
163+
if hasBlobs {
164+
// We need to pass in a real address, so we'll use a dummy
165+
// tapscript change script that's used elsewhere for tests.
166+
sweepAddrs = append(sweepAddrs, dummyChangePkScript)
167+
}
168+
132169
// Get the size of the sweep tx, which will be used to calculate the
133170
// budget fee rate.
134-
//
135-
// TODO(roasbeef): also wants the extra change output?
136171
size, err := calcSweepTxWeight(
137-
r.Inputs, r.DeliveryAddress.DeliveryAddress,
172+
r.Inputs, sweepAddrs,
138173
)
139174
if err != nil {
140175
return 0, err
@@ -163,7 +198,7 @@ func (r *BumpRequest) MaxFeeRateAllowed() (chainfee.SatPerKWeight, error) {
163198
// calcSweepTxWeight calculates the weight of the sweep tx. It assumes a
164199
// sweeping tx always has a single output(change).
165200
func calcSweepTxWeight(inputs []input.Input,
166-
outputPkScript []byte) (lntypes.WeightUnit, error) {
201+
outputPkScript [][]byte) (lntypes.WeightUnit, error) {
167202

168203
// Use a const fee rate as we only use the weight estimator to
169204
// calculate the size.
@@ -177,7 +212,7 @@ func calcSweepTxWeight(inputs []input.Input,
177212
// TODO(yy): we should refactor the weight estimator to not require a
178213
// fee rate and max fee rate and make it a pure tx weight calculator.
179214
_, estimator, err := getWeightEstimate(
180-
inputs, nil, feeRate, 0, [][]byte{outputPkScript},
215+
inputs, nil, feeRate, 0, outputPkScript,
181216
)
182217
if err != nil {
183218
return 0, err

sweep/fee_bumper_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,15 @@ func TestCalcSweepTxWeight(t *testing.T) {
115115
inp := createTestInput(100, input.WitnessKeyHash)
116116

117117
// Use a wrong change script to test the error case.
118-
weight, err := calcSweepTxWeight([]input.Input{&inp}, []byte{0})
118+
weight, err := calcSweepTxWeight(
119+
[]input.Input{&inp}, [][]byte{{0x00}},
120+
)
119121
require.Error(t, err)
120122
require.Zero(t, weight)
121123

122124
// Use a correct change script to test the success case.
123125
weight, err = calcSweepTxWeight(
124-
[]input.Input{&inp}, changePkScript.DeliveryAddress,
126+
[]input.Input{&inp}, [][]byte{changePkScript.DeliveryAddress},
125127
)
126128
require.NoError(t, err)
127129

@@ -143,7 +145,7 @@ func TestBumpRequestMaxFeeRateAllowed(t *testing.T) {
143145

144146
// The weight is 487.
145147
weight, err := calcSweepTxWeight(
146-
[]input.Input{&inp}, changePkScript.DeliveryAddress,
148+
[]input.Input{&inp}, [][]byte{changePkScript.DeliveryAddress},
147149
)
148150
require.NoError(t, err)
149151

sweep/tx_input_set_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func TestNewBudgetInputSet(t *testing.T) {
9292
rt.ErrorContains(err, "duplicate inputs")
9393
rt.Nil(set)
9494

95-
// Pass a slice of inputs that only one input has the deadline height,
95+
// Pass a slice of inputs that only one input has the deadline height.
9696
set, err = NewBudgetInputSet(
9797
[]SweeperInput{input0, input3}, testHeight,
9898
fn.None[AuxSweeper](),

sweep/txgenerator.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,8 @@ func getWeightEstimate(inputs []input.Input, outputs []*wire.TxOut,
262262

263263
default:
264264
// Unknown script type.
265-
return nil, nil, errors.New("unknown script type")
265+
return nil, nil, fmt.Errorf("unknown script "+
266+
"type: %x", outputPkScript)
266267
}
267268
}
268269

0 commit comments

Comments
 (0)