Skip to content

Commit f275fd6

Browse files
committed
Merge branch '0-19-3-branch-rc1-10117' into 0-19-3-branch-rc1
2 parents 558ea0f + b814428 commit f275fd6

File tree

7 files changed

+111
-74
lines changed

7 files changed

+111
-74
lines changed

contractcourt/anchor_resolver.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,10 @@ func (c *anchorResolver) Launch() error {
202202
// an output that we want to sweep only if it is economical to do so.
203203
//
204204
// An exclusive group is not necessary anymore, because we know that
205-
// this is the only anchor that can be swept.
205+
// this is the only anchor that can be swept. However, to avoid this
206+
// anchor input being group with other inputs, we still keep the
207+
// exclusive group here such that the anchor will be swept
208+
// independently.
206209
//
207210
// We also clear the parent tx information for cpfp, because the
208211
// commitment tx is confirmed.
@@ -222,6 +225,8 @@ func (c *anchorResolver) Launch() error {
222225
c.broadcastHeight, nil,
223226
)
224227

228+
exclusiveGroup := c.ShortChanID.ToUint64()
229+
225230
resultChan, err := c.Sweeper.SweepInput(
226231
&anchorInput,
227232
sweep.Params{
@@ -233,6 +238,10 @@ func (c *anchorResolver) Launch() error {
233238
// There's no rush to sweep the anchor, so we use a nil
234239
// deadline here.
235240
DeadlineHeight: fn.None[int32](),
241+
242+
// Use the chan id as the exclusive group. This prevents
243+
// any of the anchors from being batched together.
244+
ExclusiveGroup: &exclusiveGroup,
236245
},
237246
)
238247

docs/release-notes/release-notes-0.19.3.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@
4141
[increased](https://github.com/lightningnetwork/lnd/pull/10096) from 100KB to
4242
1MB, and `gossip.msg-burst-bytes` has been increased from 200KB to 2MB.
4343

44+
- Previously, when sweeping non-time sensitive anchor outputs, they might be
45+
grouped with other non-time sensitive outputs such as `to_local` outputs,
46+
which potentially allow the sweeping tx to be pinned. This is now
47+
[fixed](https://github.com/lightningnetwork/lnd/pull/10117) by moving sweeping
48+
anchors into its own tx, which means the anchor outputs won't be swept in a
49+
high fee environment.
50+
4451
## RPC Additions
4552

4653
## lncli Additions

itest/lnd_channel_force_close_test.go

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -978,15 +978,6 @@ func runChannelForceClosureTestRestart(ht *lntest.HarnessTest,
978978
Outpoint: commitSweep.Outpoint,
979979
AmountSat: uint64(aliceBalance),
980980
}
981-
op = fmt.Sprintf("%v:%v", anchorSweep.Outpoint.TxidStr,
982-
anchorSweep.Outpoint.OutputIndex)
983-
aliceReports[op] = &lnrpc.Resolution{
984-
ResolutionType: lnrpc.ResolutionType_ANCHOR,
985-
Outcome: lnrpc.ResolutionOutcome_CLAIMED,
986-
SweepTxid: sweepTxid.String(),
987-
Outpoint: anchorSweep.Outpoint,
988-
AmountSat: uint64(anchorSweep.AmountSat),
989-
}
990981

991982
// Check that we can find the commitment sweep in our set of known
992983
// sweeps, using the simple transaction id ListSweeps output.
@@ -1101,8 +1092,9 @@ func runChannelForceClosureTestRestart(ht *lntest.HarnessTest,
11011092

11021093
// Since Alice had numInvoices (6) htlcs extended to Carol before force
11031094
// closing, we expect Alice to broadcast an htlc timeout txn for each
1104-
// one.
1105-
ht.AssertNumPendingSweeps(alice, numInvoices)
1095+
// one. In addition, the anchor input is still pending due to it's
1096+
// uneconomical to sweep.
1097+
ht.AssertNumPendingSweeps(alice, numInvoices+1)
11061098

11071099
// Wait for them all to show up in the mempool
11081100
htlcTxid := ht.AssertNumTxsInMempool(1)[0]
@@ -1198,7 +1190,9 @@ func runChannelForceClosureTestRestart(ht *lntest.HarnessTest,
11981190
numBlocks := int(htlcCsvMaturityHeight - uint32(curHeight) - 1)
11991191
ht.MineEmptyBlocks(numBlocks)
12001192

1201-
ht.AssertNumPendingSweeps(alice, numInvoices)
1193+
// We should see numInvoices HTLC sweeps plus the uneconomical anchor
1194+
// sweep.
1195+
ht.AssertNumPendingSweeps(alice, numInvoices+1)
12021196

12031197
// Fetch the htlc sweep transaction from the mempool.
12041198
htlcSweepTx := ht.GetNumTxsFromMempool(1)[0]
@@ -1220,7 +1214,7 @@ func runChannelForceClosureTestRestart(ht *lntest.HarnessTest,
12201214
}, defaultTimeout)
12211215
require.NoError(ht, err, "timeout while checking force closed channel")
12221216

1223-
ht.AssertNumPendingSweeps(alice, numInvoices)
1217+
ht.AssertNumPendingSweeps(alice, numInvoices+1)
12241218

12251219
// Ensure the htlc sweep transaction only has one input for each htlc
12261220
// Alice extended before force closing.

itest/lnd_sweep_test.go

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,8 +1212,8 @@ func testSweepHTLCs(ht *lntest.HarnessTest) {
12121212
// 4. Alice force closes the channel.
12131213
//
12141214
// Test:
1215-
// 1. Alice's anchor sweeping is not attempted, instead, it should be swept
1216-
// together with her to_local output using the no deadline path.
1215+
// 1. Alice's CPFP-anchor sweeping is not attempted, instead, it should be
1216+
// swept using the no deadline path and failed due it's not economical.
12171217
// 2. Bob would also sweep his anchor and to_local outputs separately due to
12181218
// they have different deadline heights, which means only the to_local
12191219
// sweeping tx will succeed as the anchor sweeping is not economical.
@@ -1229,10 +1229,15 @@ func testSweepCommitOutputAndAnchor(ht *lntest.HarnessTest) {
12291229
// config.
12301230
deadline := uint32(1000)
12311231

1232-
// deadlineA is the deadline used for Alice, since her commit output is
1233-
// offered to the sweeper at CSV-1. With a deadline of 1000, her actual
1234-
// width of her fee func is CSV+1000-1. Given we are using a CSV of 2
1235-
// here, her fee func deadline then becomes 1001.
1232+
// deadlineA is the deadline used for Alice, given that,
1233+
// - the force close tx is broadcast at height 445, her inputs are
1234+
// registered at the same height, so her to_local and anchor outputs
1235+
// have a deadline height of 1445.
1236+
// - the force close tx is mined at 446, which means her anchor output
1237+
// now has a deadline delta of (1445-446) = 999 blocks.
1238+
// - for her to_local output, with a deadline of 1000, the width of the
1239+
// fee func is CSV+1000-1. Given we are using a CSV of 2 here, her fee
1240+
// func deadline then becomes 1001.
12361241
deadlineA := deadline + 1
12371242

12381243
// deadlineB is the deadline used for Bob, the actual deadline used by
@@ -1255,6 +1260,11 @@ func testSweepCommitOutputAndAnchor(ht *lntest.HarnessTest) {
12551260
// conf target is the deadline.
12561261
ht.SetFeeEstimateWithConf(startFeeRate, deadlineB)
12571262

1263+
// Set up the starting fee for Alice's anchor sweeping. With this low
1264+
// fee rate, her anchor sweeping should be attempted and failed due to
1265+
// dust output generated in the sweeping tx.
1266+
ht.SetFeeEstimateWithConf(startFeeRate, deadline-1)
1267+
12581268
// toLocalCSV is the CSV delay for Alice's to_local output. We use a
12591269
// small value to save us from mining blocks.
12601270
//
@@ -1415,10 +1425,10 @@ func testSweepCommitOutputAndAnchor(ht *lntest.HarnessTest) {
14151425
// With Alice's starting fee rate being validated, we now calculate her
14161426
// ending fee rate and fee rate delta.
14171427
//
1418-
// Alice sweeps two inputs - anchor and commit, so the starting budget
1419-
// should come from the sum of these two. However, due to the value
1420-
// being too large, the actual ending fee rate used should be the
1421-
// sweeper's max fee rate configured.
1428+
// Alice sweeps the to_local input, so the starting budget should come
1429+
// from the to_local balance. However, due to the value being too large,
1430+
// the actual ending fee rate used should be the sweeper's max fee rate
1431+
// configured.
14221432
aliceTxWeight := uint64(ht.CalculateTxWeight(aliceSweepTx))
14231433
aliceEndingFeeRate := sweep.DefaultMaxFeeRate.FeePerKWeight()
14241434
aliceFeeRateDelta := (aliceEndingFeeRate - aliceStartingFeeRate) /
@@ -1495,10 +1505,10 @@ func testSweepCommitOutputAndAnchor(ht *lntest.HarnessTest) {
14951505
}
14961506

14971507
// We should see two txns in the mempool:
1498-
// - Alice's sweeping tx, which sweeps both her anchor and
1499-
// commit outputs, using the increased fee rate.
1500-
// - Bob's previous sweeping tx, which sweeps both his anchor
1501-
// and commit outputs, at the possible increased fee rate.
1508+
// - Alice's sweeping tx, which sweeps her commit output, using
1509+
// the increased fee rate.
1510+
// - Bob's previous sweeping tx, which sweeps his commit output,
1511+
// at the possible increased fee rate.
15021512
txns := ht.GetNumTxsFromMempool(2)
15031513

15041514
// Assume the first tx is Alice's sweeping tx, if the second tx
@@ -1565,6 +1575,11 @@ func testSweepCommitOutputAndAnchor(ht *lntest.HarnessTest) {
15651575
// Mine a block to confirm both sweeping txns, this is needed to clean
15661576
// up the mempool.
15671577
ht.MineBlocksAndAssertNumTxes(1, 2)
1578+
1579+
// Finally, assert that both Alice and Bob still have the anchor
1580+
// outputs, which cannot be swept due to it being uneconomical.
1581+
ht.AssertNumPendingSweeps(alice, 1)
1582+
ht.AssertNumPendingSweeps(bob, 1)
15681583
}
15691584

15701585
// testBumpForceCloseFee tests that when a force close transaction, in

sweep/fee_bumper.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ const (
111111
// error, which means they cannot be retried with increased budget.
112112
TxFatal
113113

114-
// sentinalEvent is used to check if an event is unknown.
115-
sentinalEvent
114+
// sentinelEvent is used to check if an event is unknown.
115+
sentinelEvent
116116
)
117117

118118
// String returns a human-readable string for the event.
@@ -137,13 +137,13 @@ func (e BumpEvent) String() string {
137137

138138
// Unknown returns true if the event is unknown.
139139
func (e BumpEvent) Unknown() bool {
140-
return e >= sentinalEvent
140+
return e >= sentinelEvent
141141
}
142142

143143
// BumpRequest is used by the caller to give the Bumper the necessary info to
144144
// create and manage potential fee bumps for a set of inputs.
145145
type BumpRequest struct {
146-
// Budget givens the total amount that can be used as fees by these
146+
// Budget gives the total amount that can be used as fees by these
147147
// inputs.
148148
Budget btcutil.Amount
149149

@@ -589,7 +589,7 @@ func (t *TxPublisher) createRBFCompliantTx(
589589
// used up the budget, we will return an error
590590
// indicating this tx cannot be made. The
591591
// sweeper should handle this error and try to
592-
// cluster these inputs differetly.
592+
// cluster these inputs differently.
593593
increased, err = f.Increment()
594594
if err != nil {
595595
return nil, err
@@ -1332,7 +1332,7 @@ func (t *TxPublisher) createAndPublishTx(
13321332
// the fee bumper retry it at next block.
13331333
//
13341334
// NOTE: we may get this error if we've bypassed the mempool check,
1335-
// which means we are suing neutrino backend.
1335+
// which means we are using neutrino backend.
13361336
if errors.Is(result.Err, chain.ErrInsufficientFee) ||
13371337
errors.Is(result.Err, lnwallet.ErrMempoolFee) {
13381338

sweep/fee_bumper_test.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func TestBumpResultValidate(t *testing.T) {
7373
// Unknown event type will give an error.
7474
b = BumpResult{
7575
Tx: &wire.MsgTx{},
76-
Event: sentinalEvent,
76+
Event: sentinelEvent,
7777
}
7878
require.ErrorIs(t, b.Validate(), ErrInvalidBumpResult)
7979

@@ -457,7 +457,7 @@ func TestCreateAndCheckTx(t *testing.T) {
457457
//
458458
// NOTE: we are not testing the utility of creating valid txes here, so
459459
// this is fine to be mocked. This behaves essentially as skipping the
460-
// Signer check and alaways assume the tx has a valid sig.
460+
// Signer check and always assume the tx has a valid sig.
461461
script := &input.Script{}
462462
m.signer.On("ComputeInputScript", mock.Anything,
463463
mock.Anything).Return(script, nil)
@@ -550,7 +550,7 @@ func TestCreateRBFCompliantTx(t *testing.T) {
550550
//
551551
// NOTE: we are not testing the utility of creating valid txes here, so
552552
// this is fine to be mocked. This behaves essentially as skipping the
553-
// Signer check and alaways assume the tx has a valid sig.
553+
// Signer check and always assume the tx has a valid sig.
554554
script := &input.Script{}
555555
m.signer.On("ComputeInputScript", mock.Anything,
556556
mock.Anything).Return(script, nil)
@@ -1120,9 +1120,9 @@ func TestBroadcastImmediate(t *testing.T) {
11201120
require.Empty(t, tp.subscriberChans.Len())
11211121
}
11221122

1123-
// TestCreateAnPublishFail checks all the error cases are handled properly in
1124-
// the method createAndPublish.
1125-
func TestCreateAnPublishFail(t *testing.T) {
1123+
// TestCreateAndPublishFail checks all the error cases are handled properly in
1124+
// the method createAndPublishTx.
1125+
func TestCreateAndPublishFail(t *testing.T) {
11261126
t.Parallel()
11271127

11281128
// Create a publisher using the mocks.
@@ -1152,7 +1152,7 @@ func TestCreateAnPublishFail(t *testing.T) {
11521152
//
11531153
// NOTE: we are not testing the utility of creating valid txes here, so
11541154
// this is fine to be mocked. This behaves essentially as skipping the
1155-
// Signer check and alaways assume the tx has a valid sig.
1155+
// Signer check and always assume the tx has a valid sig.
11561156
script := &input.Script{}
11571157
m.signer.On("ComputeInputScript", mock.Anything,
11581158
mock.Anything).Return(script, nil)
@@ -1190,9 +1190,9 @@ func TestCreateAnPublishFail(t *testing.T) {
11901190
require.True(t, resultOpt.IsNone())
11911191
}
11921192

1193-
// TestCreateAnPublishSuccess checks the expected result is returned from the
1194-
// method createAndPublish.
1195-
func TestCreateAnPublishSuccess(t *testing.T) {
1193+
// TestCreateAndPublishSuccess checks the expected result is returned from the
1194+
// method createAndPublishTx.
1195+
func TestCreateAndPublishSuccess(t *testing.T) {
11961196
t.Parallel()
11971197

11981198
// Create a publisher using the mocks.
@@ -1218,7 +1218,7 @@ func TestCreateAnPublishSuccess(t *testing.T) {
12181218
//
12191219
// NOTE: we are not testing the utility of creating valid txes here, so
12201220
// this is fine to be mocked. This behaves essentially as skipping the
1221-
// Signer check and alaways assume the tx has a valid sig.
1221+
// Signer check and always assume the tx has a valid sig.
12221222
script := &input.Script{}
12231223
m.signer.On("ComputeInputScript", mock.Anything,
12241224
mock.Anything).Return(script, nil)
@@ -1445,7 +1445,7 @@ func TestHandleFeeBumpTx(t *testing.T) {
14451445
//
14461446
// NOTE: we are not testing the utility of creating valid txes here, so
14471447
// this is fine to be mocked. This behaves essentially as skipping the
1448-
// Signer check and alaways assume the tx has a valid sig.
1448+
// Signer check and always assume the tx has a valid sig.
14491449
script := &input.Script{}
14501450
m.signer.On("ComputeInputScript", mock.Anything,
14511451
mock.Anything).Return(script, nil)
@@ -1830,7 +1830,7 @@ func TestHandleInitialBroadcastSuccess(t *testing.T) {
18301830
//
18311831
// NOTE: we are not testing the utility of creating valid txes here, so
18321832
// this is fine to be mocked. This behaves essentially as skipping the
1833-
// Signer check and alaways assume the tx has a valid sig.
1833+
// Signer check and always assume the tx has a valid sig.
18341834
script := &input.Script{}
18351835
m.signer.On("ComputeInputScript", mock.Anything,
18361836
mock.Anything).Return(script, nil)
@@ -1916,7 +1916,7 @@ func TestHandleInitialBroadcastFail(t *testing.T) {
19161916
//
19171917
// NOTE: we are not testing the utility of creating valid txes here, so
19181918
// this is fine to be mocked. This behaves essentially as skipping the
1919-
// Signer check and alaways assume the tx has a valid sig.
1919+
// Signer check and always assume the tx has a valid sig.
19201920
script := &input.Script{}
19211921
m.signer.On("ComputeInputScript", mock.Anything,
19221922
mock.Anything).Return(script, nil)

0 commit comments

Comments
 (0)