Skip to content

Commit ce8cde6

Browse files
authored
Merge pull request #9470 from ziggie1984/fix-sweepInput-bug
Make BumpFee RPC user inputs more stricter.
2 parents 3c0350e + 022b358 commit ce8cde6

File tree

8 files changed

+632
-465
lines changed

8 files changed

+632
-465
lines changed

cmd/commands/walletrpc_active.go

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,10 @@ var bumpFeeCommand = cli.Command{
268268
cli.Uint64Flag{
269269
Name: "conf_target",
270270
Usage: `
271-
The deadline in number of blocks that the input should be spent within.
272-
When not set, for new inputs, the default value (1008) is used; for
273-
exiting inputs, their current values will be retained.`,
271+
The conf target is the starting fee rate of the fee function expressed
272+
in number of blocks. So instead of using sat_per_vbyte the conf target
273+
can be specified and LND will query its fee estimator for the current
274+
fee rate for the given target.`,
274275
},
275276
cli.Uint64Flag{
276277
Name: "sat_per_byte",
@@ -307,6 +308,14 @@ var bumpFeeCommand = cli.Command{
307308
the budget for fee bumping; for existing inputs, their current budgets
308309
will be retained.`,
309310
},
311+
cli.Uint64Flag{
312+
Name: "deadline_delta",
313+
Usage: `
314+
The deadline delta in number of blocks that this input should be spent
315+
within to bump the transaction. When specified also a budget value is
316+
required. When the deadline is reached, ALL the budget will be spent as
317+
fee.`,
318+
},
310319
},
311320
Action: actionDecorator(bumpFee),
312321
}
@@ -344,11 +353,12 @@ func bumpFee(ctx *cli.Context) error {
344353
}
345354

346355
resp, err := client.BumpFee(ctxc, &walletrpc.BumpFeeRequest{
347-
Outpoint: protoOutPoint,
348-
TargetConf: uint32(ctx.Uint64("conf_target")),
349-
Immediate: immediate,
350-
Budget: ctx.Uint64("budget"),
351-
SatPerVbyte: ctx.Uint64("sat_per_vbyte"),
356+
Outpoint: protoOutPoint,
357+
TargetConf: uint32(ctx.Uint64("conf_target")),
358+
Immediate: immediate,
359+
Budget: ctx.Uint64("budget"),
360+
SatPerVbyte: ctx.Uint64("sat_per_vbyte"),
361+
DeadlineDelta: uint32(ctx.Uint64("deadline_delta")),
352362
})
353363
if err != nil {
354364
return err
@@ -377,9 +387,10 @@ var bumpCloseFeeCommand = cli.Command{
377387
cli.Uint64Flag{
378388
Name: "conf_target",
379389
Usage: `
380-
The deadline in number of blocks that the input should be spent within.
381-
When not set, for new inputs, the default value (1008) is used; for
382-
exiting inputs, their current values will be retained.`,
390+
The conf target is the starting fee rate of the fee function expressed
391+
in number of blocks. So instead of using sat_per_vbyte the conf target
392+
can be specified and LND will query its fee estimator for the current
393+
fee rate for the given target.`,
383394
},
384395
cli.Uint64Flag{
385396
Name: "sat_per_byte",
@@ -435,8 +446,17 @@ var bumpForceCloseFeeCommand = cli.Command{
435446
cli.Uint64Flag{
436447
Name: "conf_target",
437448
Usage: `
438-
The deadline in number of blocks that the anchor output should be spent
439-
within to bump the closing transaction.`,
449+
The conf target is the starting fee rate of the fee function expressed
450+
in number of blocks. So instead of using sat_per_vbyte the conf target
451+
can be specified and LND will query its fee estimator for the current
452+
fee rate for the given target.`,
453+
},
454+
cli.Uint64Flag{
455+
Name: "deadline_delta",
456+
Usage: `
457+
The deadline delta in number of blocks that the anchor output should
458+
be spent within to bump the closing transaction. When the deadline is
459+
reached, ALL the budget will be spent as fees.`,
440460
},
441461
cli.Uint64Flag{
442462
Name: "sat_per_byte",
@@ -513,10 +533,11 @@ func bumpForceCloseFee(ctx *cli.Context) error {
513533
resp, err := walletClient.BumpForceCloseFee(
514534
ctxc, &walletrpc.BumpForceCloseFeeRequest{
515535
ChanPoint: rpcChannelPoint,
516-
DeadlineDelta: uint32(ctx.Uint64("conf_target")),
517536
Budget: ctx.Uint64("budget"),
518537
Immediate: immediate,
519538
StartingFeerate: ctx.Uint64("sat_per_vbyte"),
539+
TargetConf: uint32(ctx.Uint64("conf_target")),
540+
DeadlineDelta: uint32(ctx.Uint64("deadline_delta")),
520541
})
521542
if err != nil {
522543
return err

docs/release-notes/release-notes-0.18.5.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@
5050

5151
* [Improved user experience](https://github.com/lightningnetwork/lnd/pull/9454)
5252
by returning a custom error code when HTLC carries incorrect custom records.
53+
54+
* [Make input validation stricter](https://github.com/lightningnetwork/lnd/pull/9470)
55+
when using the `BumpFee`, `BumpCloseFee(deprecated)` and `BumpForceCloseFee`
56+
RPCs. For the `BumpFee` RPC the new param `deadline_delta` is introduced. For
57+
the `BumpForceCloseFee` RPC the param `conf_target` was added. The conf_target
58+
changed in its meaning for all the RPCs which had it before. Now it is used
59+
for estimating the starting fee rate instead of being treated as the deadline,
60+
and it cannot be set together with `StartingFeeRate`. Moreover if the user now
61+
specifies the `deadline_delta` param, the budget value has to be set as well.
5362

5463
## Tooling and Documentation
5564

itest/lnd_onchain_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -490,12 +490,12 @@ func testAnchorThirdPartySpend(ht *lntest.HarnessTest) {
490490
commit.DeadlineHeight, anchor.DeadlineHeight)
491491

492492
// Update the anchor sweep's deadline and budget so it will always be
493-
// swpet.
493+
// swept.
494494
bumpFeeReq := &walletrpc.BumpFeeRequest{
495-
Outpoint: anchor.Outpoint,
496-
TargetConf: uint32(deadline + 100),
497-
Budget: uint64(anchor.AmountSat * 10),
498-
Immediate: true,
495+
Outpoint: anchor.Outpoint,
496+
DeadlineDelta: uint32(deadline + 100),
497+
Budget: uint64(anchor.AmountSat * 10),
498+
Immediate: true,
499499
}
500500
alice.RPC.BumpFee(bumpFeeReq)
501501

itest/lnd_sweep_test.go

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,11 +1723,42 @@ func runBumpFee(ht *lntest.HarnessTest, alice *node.HarnessNode) {
17231723
// min relay fee rate is used as the current fee rate.
17241724
assertFeeRateEqual(startFeeRate)
17251725

1726+
// First we test the case where we specify the conf target to increase
1727+
// the starting fee rate of the fee function.
1728+
confTargetFeeRate := chainfee.SatPerVByte(50)
1729+
ht.SetFeeEstimateWithConf(confTargetFeeRate.FeePerKWeight(), 3)
1730+
1731+
// Second bump request - we will specify the conf target and expect a
1732+
// starting fee rate that is estimated using the provided estimator.
1733+
// - starting fee rate: 50 sat/vbyte (conf target 3).
1734+
// - deadline: 1008 (default deadline).
1735+
// - budget: 50% of the input value.
1736+
bumpFeeReq = &walletrpc.BumpFeeRequest{
1737+
Outpoint: op,
1738+
// We use a force param to create the sweeping tx immediately.
1739+
Immediate: true,
1740+
TargetConf: 3,
1741+
}
1742+
1743+
alice.RPC.BumpFee(bumpFeeReq)
1744+
1745+
// Alice's old sweeping tx should be replaced.
1746+
ht.AssertTxNotInMempool(sweepTx1.TxHash())
1747+
1748+
// Assert the pending sweep is created with the expected values:
1749+
// - broadcast attempts: 2.
1750+
// - starting fee rate: 50 sat/vbyte (conf target 3).
1751+
// - deadline: 1008 (default deadline).
1752+
// - budget: 50% of the input value.
1753+
sweepTx2 := assertPendingSweepResp(
1754+
2, uint64(value/2), deadline, uint64(confTargetFeeRate),
1755+
)
1756+
17261757
// testFeeRate sepcifies a starting fee rate in sat/vbyte.
17271758
const testFeeRate = uint64(100)
17281759

1729-
// Second bump request - we will specify the fee rate and expect a fee
1730-
// func that has,
1760+
// Third bump request - we will specify the fee rate and expect a fee
1761+
// func to change the starting fee rate of the fee function,
17311762
// - starting fee rate: 100 sat/vbyte.
17321763
// - deadline: 1008 (default deadline).
17331764
// - budget: 50% of the input value.
@@ -1740,15 +1771,15 @@ func runBumpFee(ht *lntest.HarnessTest, alice *node.HarnessNode) {
17401771
alice.RPC.BumpFee(bumpFeeReq)
17411772

17421773
// Alice's old sweeping tx should be replaced.
1743-
ht.AssertTxNotInMempool(sweepTx1.TxHash())
1774+
ht.AssertTxNotInMempool(sweepTx2.TxHash())
17441775

17451776
// Assert the pending sweep is created with the expected values:
1746-
// - broadcast attempts: 2.
1777+
// - broadcast attempts: 3.
17471778
// - starting fee rate: 100 sat/vbyte.
17481779
// - deadline: 1008 (default deadline).
17491780
// - budget: 50% of the input value.
1750-
sweepTx2 := assertPendingSweepResp(
1751-
2, uint64(value/2), deadline, testFeeRate,
1781+
sweepTx3 := assertPendingSweepResp(
1782+
3, uint64(value/2), deadline, testFeeRate,
17521783
)
17531784

17541785
// We expect the requested starting fee rate to be the current fee
@@ -1758,7 +1789,7 @@ func runBumpFee(ht *lntest.HarnessTest, alice *node.HarnessNode) {
17581789
// testBudget specifies a budget in sats.
17591790
testBudget := uint64(float64(value) * 0.1)
17601791

1761-
// Third bump request - we will specify the budget and expect a fee
1792+
// Fourth bump request - we will specify the budget and expect a fee
17621793
// func that has,
17631794
// - starting fee rate: 100 sat/vbyte, stays unchanged.
17641795
// - deadline: 1008 (default deadline).
@@ -1772,14 +1803,14 @@ func runBumpFee(ht *lntest.HarnessTest, alice *node.HarnessNode) {
17721803
alice.RPC.BumpFee(bumpFeeReq)
17731804

17741805
// Alice's old sweeping tx should be replaced.
1775-
ht.AssertTxNotInMempool(sweepTx2.TxHash())
1806+
ht.AssertTxNotInMempool(sweepTx3.TxHash())
17761807

17771808
// Assert the pending sweep is created with the expected values:
1778-
// - broadcast attempts: 3.
1809+
// - broadcast attempts: 4.
17791810
// - starting fee rate: 100 sat/vbyte, stays unchanged.
17801811
// - deadline: 1008 (default deadline).
17811812
// - budget: 10% of the input value.
1782-
sweepTx3 := assertPendingSweepResp(3, testBudget, deadline, 0)
1813+
sweepTx4 := assertPendingSweepResp(4, testBudget, deadline, testFeeRate)
17831814

17841815
// We expect the current fee rate to be increased because we ensure the
17851816
// initial broadcast always succeeds.
@@ -1789,34 +1820,37 @@ func runBumpFee(ht *lntest.HarnessTest, alice *node.HarnessNode) {
17891820
testDeadlineDelta := uint32(100)
17901821
deadlineHeight := uint32(currentHeight) + testDeadlineDelta
17911822

1792-
// Fourth bump request - we will specify the deadline and expect a fee
1823+
// Fifth bump request - we will specify the deadline and expect a fee
17931824
// func that has,
17941825
// - starting fee rate: 100 sat/vbyte, stays unchanged.
17951826
// - deadline: 100.
17961827
// - budget: 10% of the input value, stays unchanged.
17971828
bumpFeeReq = &walletrpc.BumpFeeRequest{
17981829
Outpoint: op,
17991830
// We use a force param to create the sweeping tx immediately.
1800-
Immediate: true,
1801-
TargetConf: testDeadlineDelta,
1831+
Immediate: true,
1832+
DeadlineDelta: testDeadlineDelta,
1833+
Budget: testBudget,
18021834
}
18031835
alice.RPC.BumpFee(bumpFeeReq)
18041836

18051837
// Alice's old sweeping tx should be replaced.
1806-
ht.AssertTxNotInMempool(sweepTx3.TxHash())
1838+
ht.AssertTxNotInMempool(sweepTx4.TxHash())
18071839

18081840
// Assert the pending sweep is created with the expected values:
1809-
// - broadcast attempts: 4.
1841+
// - broadcast attempts: 5.
18101842
// - starting fee rate: 100 sat/vbyte, stays unchanged.
18111843
// - deadline: 100.
18121844
// - budget: 10% of the input value, stays unchanged.
1813-
sweepTx4 := assertPendingSweepResp(4, testBudget, deadlineHeight, 0)
1845+
sweepTx5 := assertPendingSweepResp(
1846+
5, testBudget, deadlineHeight, testFeeRate,
1847+
)
18141848

18151849
// We expect the current fee rate to be increased because we ensure the
18161850
// initial broadcast always succeeds.
18171851
assertFeeRateGreater(testFeeRate)
18181852

1819-
// Fifth bump request - we test the behavior of `Immediate` - every
1853+
// Sixth bump request - we test the behavior of `Immediate` - every
18201854
// time it's called, the fee function will keep increasing the fee rate
18211855
// until the broadcast can succeed. The fee func that has,
18221856
// - starting fee rate: 100 sat/vbyte, stays unchanged.
@@ -1830,14 +1864,16 @@ func runBumpFee(ht *lntest.HarnessTest, alice *node.HarnessNode) {
18301864
alice.RPC.BumpFee(bumpFeeReq)
18311865

18321866
// Alice's old sweeping tx should be replaced.
1833-
ht.AssertTxNotInMempool(sweepTx4.TxHash())
1867+
ht.AssertTxNotInMempool(sweepTx5.TxHash())
18341868

18351869
// Assert the pending sweep is created with the expected values:
1836-
// - broadcast attempts: 5.
1870+
// - broadcast attempts: 6.
18371871
// - starting fee rate: 100 sat/vbyte, stays unchanged.
18381872
// - deadline: 100, stays unchanged.
18391873
// - budget: 10% of the input value, stays unchanged.
1840-
sweepTx5 := assertPendingSweepResp(5, testBudget, deadlineHeight, 0)
1874+
sweepTx6 := assertPendingSweepResp(
1875+
6, testBudget, deadlineHeight, testFeeRate,
1876+
)
18411877

18421878
// We expect the current fee rate to be increased because we ensure the
18431879
// initial broadcast always succeeds.
@@ -1855,26 +1891,27 @@ func runBumpFee(ht *lntest.HarnessTest, alice *node.HarnessNode) {
18551891
// We use a force param to create the sweeping tx immediately.
18561892
Immediate: true,
18571893
SatPerVbyte: startFeeRate,
1858-
Budget: smallBudget,
1859-
TargetConf: uint32(sweep.DefaultDeadlineDelta),
1894+
// The budget and the deadline delta must be set together.
1895+
Budget: smallBudget,
1896+
DeadlineDelta: uint32(sweep.DefaultDeadlineDelta),
18601897
}
18611898
alice.RPC.BumpFee(bumpFeeReq)
18621899

18631900
// Assert the pending sweep is created with the expected values:
1864-
// - broadcast attempts: 6.
1901+
// - broadcast attempts: 7.
18651902
// - starting fee rate: 1 sat/vbyte.
18661903
// - deadline: 1008.
18671904
// - budget: 1000 sats.
1868-
sweepTx6 := assertPendingSweepResp(
1869-
6, smallBudget, deadline, startFeeRate,
1905+
sweepTx7 := assertPendingSweepResp(
1906+
7, smallBudget, deadline, startFeeRate,
18701907
)
18711908

18721909
// Since this budget is too small to cover the RBF, we expect the
18731910
// sweeping attempt to fail.
18741911
//
1875-
require.Equal(ht, sweepTx5.TxHash(), sweepTx6.TxHash(), "tx5 should "+
1876-
"not be replaced: tx5=%v, tx6=%v", sweepTx5.TxHash(),
1877-
sweepTx6.TxHash())
1912+
require.Equal(ht, sweepTx6.TxHash(), sweepTx7.TxHash(), "tx6 should "+
1913+
"not be replaced: tx6=%v, tx7=%v", sweepTx6.TxHash(),
1914+
sweepTx7.TxHash())
18781915

18791916
// We expect the current fee rate to be increased because we ensure the
18801917
// initial broadcast always succeeds.

0 commit comments

Comments
 (0)