From 8f936aa9ebc9586bf88f45db7b204dc42612b443 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Mon, 28 Apr 2025 15:43:19 +0800 Subject: [PATCH] itest: update num of sweeps in `AssertNumPendingSweeps` Since we now return all sweeps, we need to update the call to include immature sweeps. --- itest/lnd_channel_backup_test.go | 11 +- itest/lnd_channel_force_close_test.go | 48 ++++++--- itest/lnd_htlc_timeout_resolver_test.go | 5 +- itest/lnd_multi-hop_force_close_test.go | 129 +++++++++++++++--------- itest/lnd_onchain_test.go | 5 +- itest/lnd_sweep_test.go | 39 ++++--- lntest/harness_assertion.go | 53 +++++++++- lnwallet/channel.go | 2 +- 8 files changed, 201 insertions(+), 91 deletions(-) diff --git a/itest/lnd_channel_backup_test.go b/itest/lnd_channel_backup_test.go index f84b65ce3..d3daeb1df 100644 --- a/itest/lnd_channel_backup_test.go +++ b/itest/lnd_channel_backup_test.go @@ -1454,7 +1454,7 @@ func assertTimeLockSwept(ht *lntest.HarnessTest, carol, dave *node.HarnessNode, // Carol should sweep her funds immediately, as they are not // timelocked. ht.AssertNumPendingSweeps(carol, 2) - ht.AssertNumPendingSweeps(dave, 1) + ht.AssertNumPendingSweeps(dave, 2) // We expect Carol to sweep her funds and her anchor in a single sweep // tx. In addition, Dave will attempt to sweep his anchor output but @@ -1577,9 +1577,10 @@ func assertDLPExecuted(ht *lntest.HarnessTest, // Both Dave and Carol should have an anchor sweep request. // Note that they cannot sweep them as these anchor sweepings - // are uneconomical. - ht.AssertNumPendingSweeps(dave, 1) - ht.AssertNumPendingSweeps(carol, 1) + // are uneconomical. In addition, they should also have their + // leased to_local commit output. + ht.AssertNumPendingSweeps(dave, 2) + ht.AssertNumPendingSweeps(carol, 2) // After Carol's output matures, she should also reclaim her // funds. @@ -1620,7 +1621,7 @@ func assertDLPExecuted(ht *lntest.HarnessTest, // timelocked. We also expect Carol and Dave sweep their // anchors if it's an anchor channel. if lntest.CommitTypeHasAnchors(commitType) { - ht.AssertNumPendingSweeps(carol, 1) + ht.AssertNumPendingSweeps(carol, 2) ht.AssertNumPendingSweeps(dave, 2) } else { ht.AssertNumPendingSweeps(dave, 1) diff --git a/itest/lnd_channel_force_close_test.go b/itest/lnd_channel_force_close_test.go index 55bbc0c03..c04036a76 100644 --- a/itest/lnd_channel_force_close_test.go +++ b/itest/lnd_channel_force_close_test.go @@ -191,10 +191,18 @@ func runChannelForceClosureTest(ht *lntest.HarnessTest, // expect Alice's anchor sweeping tx being published. ht.MineBlocksAndAssertNumTxes(1, 1) - // Assert Alice's has one pending anchor output - because she doesn't - // have incoming HTLCs, her outgoing HTLC won't have a deadline, thus - // she won't use the anchor to perform CPFP. - aliceAnchor := ht.AssertNumPendingSweeps(alice, 1)[0] + // Assert Alice's has one pending anchor output and the commit output + // sweep - because she doesn't have incoming HTLCs, her outgoing HTLC + // won't have a deadline, thus she won't use the anchor to perform CPFP. + sweeps := ht.AssertNumPendingSweeps(alice, 2) + + // Find the anchor sweep - assume it's the first one, and change to the + // second one if the first one has a larger value. + aliceAnchor := sweeps[0] + if aliceAnchor.AmountSat > sweeps[1].AmountSat { + aliceAnchor = sweeps[1] + } + require.Equal(ht, aliceAnchor.Outpoint.TxidStr, waitingClose.Commitments.LocalTxid) @@ -250,8 +258,9 @@ func runChannelForceClosureTest(ht *lntest.HarnessTest, // commit and anchor outputs. ht.MineBlocksAndAssertNumTxes(1, 1) - // Alice should still have the anchor sweeping request. - ht.AssertNumPendingSweeps(alice, 1) + // Alice should still have the anchor and commit output sweeping + // requests. + ht.AssertNumPendingSweeps(alice, 2) // Alice should see the channel in her set of pending force closed // channels with her funds still in limbo. @@ -282,8 +291,8 @@ func runChannelForceClosureTest(ht *lntest.HarnessTest, // At this point, the CSV will expire in the next block, meaning that // the output should be offered to the sweeper. - sweeps := ht.AssertNumPendingSweeps(alice, 2) - commitSweep, anchorSweep := sweeps[0], sweeps[1] + aliceSweeps := ht.AssertNumPendingSweeps(alice, 2) + commitSweep, anchorSweep := aliceSweeps[0], aliceSweeps[1] if commitSweep.AmountSat < anchorSweep.AmountSat { commitSweep = anchorSweep } @@ -790,10 +799,18 @@ func runChannelForceClosureTestRestart(ht *lntest.HarnessTest, // expect Alice's anchor sweeping tx being published. ht.MineBlocksAndAssertNumTxes(1, 1) - // Assert Alice's has one pending anchor output - because she doesn't - // have incoming HTLCs, her outgoing HTLC won't have a deadline, thus - // she won't use the anchor to perform CPFP. - aliceAnchor := ht.AssertNumPendingSweeps(alice, 1)[0] + // Assert Alice's has one pending anchor output and the commit output + // sweep - because she doesn't have incoming HTLCs, her outgoing HTLC + // won't have a deadline, thus she won't use the anchor to perform CPFP. + sweeps := ht.AssertNumPendingSweeps(alice, 2) + + // Find the anchor sweep - assume it's the first one, and change to the + // second one if the first one has a larger value. + aliceAnchor := sweeps[0] + if aliceAnchor.AmountSat > sweeps[1].AmountSat { + aliceAnchor = sweeps[1] + } + require.Equal(ht, aliceAnchor.Outpoint.TxidStr, waitingClose.Commitments.LocalTxid) @@ -860,8 +877,9 @@ func runChannelForceClosureTestRestart(ht *lntest.HarnessTest, // commit and anchor outputs. ht.MineBlocksAndAssertNumTxes(1, 1) - // Alice should still have the anchor sweeping request. - ht.AssertNumPendingSweeps(alice, 1) + // Alice should still have the anchor and commit output sweeping + // requests. + ht.AssertNumPendingSweeps(alice, 2) // The following restart checks to ensure that outputs in the contract // court are persisted while waiting for the required number of @@ -918,7 +936,7 @@ func runChannelForceClosureTestRestart(ht *lntest.HarnessTest, // At this point, the CSV will expire in the next block, meaning that // the output should be offered to the sweeper. - sweeps := ht.AssertNumPendingSweeps(alice, 2) + sweeps = ht.AssertNumPendingSweeps(alice, 2) commitSweep, anchorSweep := sweeps[0], sweeps[1] if commitSweep.AmountSat < anchorSweep.AmountSat { commitSweep, anchorSweep = anchorSweep, commitSweep diff --git a/itest/lnd_htlc_timeout_resolver_test.go b/itest/lnd_htlc_timeout_resolver_test.go index 3ce3026eb..25aa0afcc 100644 --- a/itest/lnd_htlc_timeout_resolver_test.go +++ b/itest/lnd_htlc_timeout_resolver_test.go @@ -309,8 +309,9 @@ func testHtlcTimeoutResolverExtractPreimageLocal(ht *lntest.HarnessTest) { // Once Bob's force closing tx is confirmed, he will re-offer the // anchor output to his sweeper, which won't be swept due to it being - // uneconomical. - ht.AssertNumPendingSweeps(bob, 1) + // uneconomical. In addition, the to_local output should also be found + // although it's immature. + ht.AssertNumPendingSweeps(bob, 2) // Mine 3 blocks so the output will be offered to the sweeper. ht.MineBlocks(defaultCSV - 1) diff --git a/itest/lnd_multi-hop_force_close_test.go b/itest/lnd_multi-hop_force_close_test.go index c542c81ac..034a5641b 100644 --- a/itest/lnd_multi-hop_force_close_test.go +++ b/itest/lnd_multi-hop_force_close_test.go @@ -1,6 +1,8 @@ package itest import ( + "fmt" + "github.com/btcsuite/btcd/btcutil" "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc" @@ -10,6 +12,7 @@ import ( "github.com/lightningnetwork/lnd/lntest/node" "github.com/lightningnetwork/lnd/lntest/rpc" "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/routing" "github.com/stretchr/testify/require" ) @@ -438,7 +441,7 @@ func runLocalClaimOutgoingHTLC(ht *lntest.HarnessTest, // With the closing transaction confirmed, we should expect Bob's HTLC // timeout transaction to be offered to the sweeper due to the expiry // being reached. we also expect Carol's anchor sweeps. - ht.AssertNumPendingSweeps(bob, 1) + ht.AssertNumPendingSweeps(bob, 2) ht.AssertNumPendingSweeps(carol, 1) // Bob's sweeper should sweep his outgoing HTLC immediately since it's @@ -490,8 +493,9 @@ func runLocalClaimOutgoingHTLC(ht *lntest.HarnessTest, ht.MineBlocks(int(resp.BlocksTilMaturity - 1)) // Check that Bob has a pending sweeping tx which sweeps his - // to_local output. - ht.AssertNumPendingSweeps(bob, 1) + // to_local output. In addition, his immature outgoing HTLC + // should also be found. + ht.AssertNumPendingSweeps(bob, 2) // Mine a block to confirm the to_local sweeping tx, which also // triggers the sweeping of the second stage HTLC output. @@ -803,17 +807,12 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest, // off-chain. He will also try to sweep his anchor and to_local // outputs, with the anchor output being skipped due to it being // uneconomical. - if params.CommitmentType == leasedType { - // For leased channels, Bob cannot sweep his to_local output - // yet since it's timelocked, so we only see his anchor input. - ht.AssertNumPendingSweeps(bob, 1) - } else { - // For non-leased channels, Bob should have two pending sweeps, - // 1. to_local output. - // 2. anchor output, tho it won't be swept due to it being - // uneconomical. - ht.AssertNumPendingSweeps(bob, 2) - } + // + // Bob should have two pending sweeps, + // 1. to_local output - immature for leased channel. + // 2. anchor output, tho it won't be swept due to it being + // uneconomical. + ht.AssertNumPendingSweeps(bob, 2) flakeTxNotifierNeutrino(ht) @@ -1088,7 +1087,18 @@ func runLocalForceCloseBeforeHtlcTimeout(ht *lntest.HarnessTest, // The channel close has anchors, we should expect to see both Bob and // Carol has a pending sweep request for the anchor sweep. ht.AssertNumPendingSweeps(carol, 1) - anchorSweep := ht.AssertNumPendingSweeps(bob, 1)[0] + + // For Bob, we should see two pending sweep requests, + // 1. anchor output. + // 2. to_local output, immature. + sweeps := ht.AssertNumPendingSweeps(bob, 2) + + // Find the anchor sweep - assume it's the first one, and change to the + // second one if the first one has a larger value. + anchorSweep := sweeps[0] + if anchorSweep.AmountSat > sweeps[1].AmountSat { + anchorSweep = sweeps[1] + } // We expcet Bob's anchor sweep to be a non-CPFP anchor sweep now. // Although he has time-sensitive outputs, which means initially his @@ -1144,7 +1154,13 @@ func runLocalForceCloseBeforeHtlcTimeout(ht *lntest.HarnessTest, // Bob should have two pending sweep requests, // 1. the anchor sweep. // 2. the outgoing HTLC sweep. - ht.AssertNumPendingSweeps(bob, 2) + if params.CommitmentType != leasedType { + ht.AssertNumPendingSweeps(bob, 2) + } else { + // For leased channel, Bob still has the to_local output sweep + // request. + ht.AssertNumPendingSweeps(bob, 3) + } // Bob's outgoing HTLC sweep should be broadcast now. Mine a block to // confirm it. @@ -1209,7 +1225,16 @@ func testRemoteForceCloseBeforeTimeoutAnchor(ht *lntest.HarnessTest) { // Prepare params. params := lntest.OpenChannelParams{Amt: chanAmt} - cfg := node.CfgAnchor + cltvDelta := routing.MinCLTVDelta + cfg := []string{ + "--protocol.anchors", + // Use a small CLTV to mine less blocks. + fmt.Sprintf("--bitcoin.timelockdelta=%d", cltvDelta), + // Use a very large CSV, this way to_local outputs are never + // swept so we can focus on testing HTLCs. + fmt.Sprintf("--bitcoin.defaultremotedelay=%v", cltvDelta*10), + } + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) cfgs := [][]string{cfg, cfg, cfgCarol} @@ -1420,8 +1445,8 @@ func runRemoteForceCloseBeforeHtlcTimeout(ht *lntest.HarnessTest, // For script enforced lease channels, Bob can sweep his anchor // output immediately although it will be skipped due to it // being uneconomical. His to_local output is CLTV locked so it - // cannot be swept yet. - ht.AssertNumPendingSweeps(bob, 1) + // cannot be swept yet so it will show up as immature. + ht.AssertNumPendingSweeps(bob, 2) } else { // For non-leased channels, Bob can sweep his commit and anchor // outputs immediately. @@ -1455,7 +1480,13 @@ func runRemoteForceCloseBeforeHtlcTimeout(ht *lntest.HarnessTest, // Bob should have two pending sweep requests, // 1. the uneconomical anchor sweep. // 2. the direct timeout sweep. - ht.AssertNumPendingSweeps(bob, 2) + if params.CommitmentType != leasedType { + ht.AssertNumPendingSweeps(bob, 2) + } else { + // For leased channel, Bob should have the to_local output which + // is immature. + ht.AssertNumPendingSweeps(bob, 3) + } // Bob's sweeping tx should now be found in the mempool. sweepTx := ht.AssertNumTxsInMempool(1)[0] @@ -1953,12 +1984,13 @@ func runLocalClaimIncomingHTLCLeased(ht *lntest.HarnessTest, bob, aliceChanPoint, hasAnchorSweep, closeStream, ) - // Alice will offer her anchor output to her sweeper. Her commitment - // output cannot be swept yet as it has incurred an additional CLTV due - // to being the initiator of a script-enforced leased channel. + // Alice will offer her anchor output and to_local output to her + // sweeper. Her commitment output cannot be swept yet as it has incurred + // an additional CLTV due to being the initiator of a script-enforced + // leased channel. // // This anchor output cannot be swept due to it being uneconomical. - ht.AssertNumPendingSweeps(alice, 1) + ht.AssertNumPendingSweeps(alice, 2) // Bob will offer his anchor to his sweeper. // @@ -2003,10 +2035,11 @@ func runLocalClaimIncomingHTLCLeased(ht *lntest.HarnessTest, // Once Bob is online and sees the force close tx Bob=>Carol, he will // offer his commitment output to his sweeper, which will be skipped // due to it being timelocked. His anchor outputs will not be swept due - // to uneconomical. We expect to see two sweeping requests, + // to uneconomical. We expect to see three sweeping requests, // - the anchor output from channel Alice=>Bob. // - the anchor output from channel Bob=>Carol. - ht.AssertNumPendingSweeps(bob, 2) + // - to to_local output from channel Bob=>Carol, immature. + ht.AssertNumPendingSweeps(bob, 3) // Assert txns can be found in the mempool. // @@ -2024,11 +2057,12 @@ func runLocalClaimIncomingHTLCLeased(ht *lntest.HarnessTest, // When Bob notices Carol's second level tx in the block, he will // extract the preimage and broadcast a second level tx to claim the // HTLC in his (already closed) channel with Alice, which means Bob has - // three sweeping requests, + // four sweeping requests, // - the second level HTLC tx from channel Alice=>Bob. // - the anchor output from channel Alice=>Bob. // - the anchor output from channel Bob=>Carol. - ht.AssertNumPendingSweeps(bob, 3) + // - to to_local output from channel Bob=>Carol, immature. + ht.AssertNumPendingSweeps(bob, 4) flakePreimageSettlement(ht) @@ -2293,8 +2327,9 @@ func runLocalPreimageClaim(ht *lntest.HarnessTest, ht.AssertChannelPendingForceClose(alice, aliceChanPoint) // Once the force closing tx is mined, Alice should offer the anchor - // output to her sweeper. - ht.AssertNumPendingSweeps(alice, 1) + // output to her sweeper. In addition, the immature to_local output is + // also found in the pending sweeps. + ht.AssertNumPendingSweeps(alice, 2) // Bob should offer his anchor output to his sweeper. ht.AssertNumPendingSweeps(bob, 1) @@ -2544,8 +2579,8 @@ func runLocalPreimageClaimLeased(ht *lntest.HarnessTest, ht.AssertChannelPendingForceClose(alice, aliceChanPoint) // Once the force closing tx is mined, Alice should offer the anchor - // output to her sweeper. - ht.AssertNumPendingSweeps(alice, 1) + // output and to_local output (immature) to her sweeper. + ht.AssertNumPendingSweeps(alice, 2) // Bob should offer his anchor output to his sweeper. ht.AssertNumPendingSweeps(bob, 1) @@ -2601,8 +2636,8 @@ func runLocalPreimageClaimLeased(ht *lntest.HarnessTest, // - the anchor output from channel Alice=>Bob, uneconomical. // - the anchor output from channel Bob=>Carol, uneconomical. // - the commit output sweep from the channel with Carol, which is CLTV - // locked so it won't show up the pending sweeps. - ht.AssertNumPendingSweeps(bob, 2) + // locked so it's immature. + ht.AssertNumPendingSweeps(bob, 3) // We mine one block to confirm, // - Carol's sweeping tx of the incoming HTLC. @@ -2613,7 +2648,8 @@ func runLocalPreimageClaimLeased(ht *lntest.HarnessTest, // - the anchor output from channel Alice=>Bob, uneconomical. // - the anchor output from channel Bob=>Carol, uneconomical. // - the htlc sweeping tx. - ht.AssertNumPendingSweeps(bob, 3) + // - the to_local output sweep, immature. + ht.AssertNumPendingSweeps(bob, 4) flakePreimageSettlement(ht) @@ -2999,8 +3035,9 @@ func runHtlcAggregation(ht *lntest.HarnessTest, // Mine a block to confirm Bob's force close tx and anchor sweeping tx. ht.MineBlocksAndAssertNumTxes(1, 2) - // Bob should have `numInvoices` for HTLC timeout txns. - ht.AssertNumPendingSweeps(bob, numInvoices) + // Bob should have `numInvoices` for HTLC timeout txns. In addition he + // should have a local commit sweep. + ht.AssertNumPendingSweeps(bob, numInvoices+1) // Once bob has force closed, we can restart carol. require.NoError(ht, restartCarol()) @@ -3015,8 +3052,8 @@ func runHtlcAggregation(ht *lntest.HarnessTest, } // Bob should have `numInvoices` for both HTLC success and timeout - // txns. - ht.AssertNumPendingSweeps(bob, numInvoices*2) + // txns. In addition he should have a local commit sweep. + ht.AssertNumPendingSweeps(bob, numInvoices*2+1) flakePreimageSettlement(ht) @@ -3038,7 +3075,7 @@ func runHtlcAggregation(ht *lntest.HarnessTest, ht.MineBlocks(1) // Bob should offer the to_local output to his sweeper now. - ht.AssertNumPendingSweeps(bob, 1) + ht.AssertNumPendingSweeps(bob, numInvoices*2+1) // Mine a block to confirm Bob's sweeping of his to_local // output. @@ -3056,14 +3093,12 @@ func runHtlcAggregation(ht *lntest.HarnessTest, ht.MineBlocks(int(resp.PendingHtlcs[0].BlocksTilMaturity)) // With the above mined block, Bob's HTLCs should now all be offered to - // his sweeper since the CSV lock is now expired. - // - // For leased channel, due to the test setup, Bob's to_local output is - // now also mature and can be swept together with his HTLCs. - if params.CommitmentType == leasedType { - ht.AssertNumPendingSweeps(bob, numInvoices*2+1) - } else { + // his sweeper since the CSV lock is now expired. In addition he should + // have a local commit sweep if this is a leased channel. + if params.CommitmentType != leasedType { ht.AssertNumPendingSweeps(bob, numInvoices*2) + } else { + ht.AssertNumPendingSweeps(bob, numInvoices*2+1) } // When we mine one additional block, that will confirm Bob's second diff --git a/itest/lnd_onchain_test.go b/itest/lnd_onchain_test.go index e5d3db134..efd541bd3 100644 --- a/itest/lnd_onchain_test.go +++ b/itest/lnd_onchain_test.go @@ -463,8 +463,9 @@ func testAnchorThirdPartySpend(ht *lntest.HarnessTest) { ht.MineBlocksAndAssertNumTxes(1, 1) forceCloseTxID, _ := chainhash.NewHashFromStr(aliceCloseTx) - // Alice's should have the anchor sweep request. - ht.AssertNumPendingSweeps(alice, 1) + // Alice's should have the anchor sweep request. In addition, she should + // see her immature to_local output sweep. + ht.AssertNumPendingSweeps(alice, 2) // Mine 3 blocks so Alice will sweep her commit output. forceClose := ht.AssertChannelPendingForceClose(alice, aliceChanPoint1) diff --git a/itest/lnd_sweep_test.go b/itest/lnd_sweep_test.go index d5c16b0bd..a74726488 100644 --- a/itest/lnd_sweep_test.go +++ b/itest/lnd_sweep_test.go @@ -346,7 +346,7 @@ func testSweepCPFPAnchorOutgoingTimeout(ht *lntest.HarnessTest) { // contractcourt will offer the HTLC to his sweeper. We are not testing // the HTLC sweeping behaviors so we just perform a simple check and // exit the test. - ht.AssertNumPendingSweeps(bob, 1) + ht.AssertNumPendingSweeps(bob, 2) ht.MineBlocksAndAssertNumTxes(1, 1) // Finally, clean the mempool for the next test. @@ -901,8 +901,9 @@ func testSweepHTLCs(ht *lntest.HarnessTest) { // Update the blocks left till Bob force closes Alice->Bob. blocksTillIncomingSweep-- - // Bob should have one pending sweep for the outgoing HTLC. - ht.AssertNumPendingSweeps(bob, 1) + // Bob should have one pending sweep for the outgoing HTLC and another + // one for his to_local output. + ht.AssertNumPendingSweeps(bob, 2) // Bob should have one sweeping tx in the mempool. outgoingSweep := ht.GetNumTxsFromMempool(1)[0] @@ -975,8 +976,9 @@ func testSweepHTLCs(ht *lntest.HarnessTest) { // mempool. ht.AssertTxNotInMempool(outgoingSweep.TxHash()) - // Bob should still have the outgoing HTLC sweep. - ht.AssertNumPendingSweeps(bob, 1) + // Bob should still have the outgoing HTLC sweep and the + // to_local output. + ht.AssertNumPendingSweeps(bob, 2) // We should see Bob's replacement tx in the mempool. outgoingSweep = ht.GetNumTxsFromMempool(1)[0] @@ -999,12 +1001,13 @@ func testSweepHTLCs(ht *lntest.HarnessTest) { // Bob should now have two pending sweeps: // 1. the outgoing HTLC output. // 2. the anchor output from his local commitment. - expectedNumSweeps = 2 + // 3. the to_local output, which is not matured yet. + expectedNumSweeps = 3 // For neutrino backend, we expect the anchor output from his remote // commitment to be present. if ht.IsNeutrinoBackend() { - expectedNumSweeps = 3 + expectedNumSweeps = 4 } ht.AssertNumPendingSweeps(bob, expectedNumSweeps) @@ -1033,11 +1036,12 @@ func testSweepHTLCs(ht *lntest.HarnessTest) { // Update Bob's fee function position. outgoingFuncPosition++ - // Bob should now have three pending sweeps: + // Bob should now have four pending sweeps: // 1. the outgoing HTLC output on Bob->Carol. // 2. the incoming HTLC output on Alice->Bob. // 3. the anchor sweeping on Alice-> Bob. - ht.AssertNumPendingSweeps(bob, 3) + // 4. the to_local output, immature. + ht.AssertNumPendingSweeps(bob, 4) // We should see three txns in the mempool: // 1. the outgoing HTLC sweeping tx. @@ -1163,7 +1167,8 @@ func testSweepHTLCs(ht *lntest.HarnessTest) { // Bob should have two pending sweeps: // 1. the outgoing HTLC output on Bob->Carol. // 2. the incoming HTLC output on Alice->Bob. - ht.AssertNumPendingSweeps(bob, 2) + // 3. the to_local output, immature. + ht.AssertNumPendingSweeps(bob, 3) // We should see Bob's replacement txns in the mempool. incomingSweep, outgoingSweep = identifySweepTxns() @@ -1347,9 +1352,10 @@ func testSweepCommitOutputAndAnchor(ht *lntest.HarnessTest) { // to their sweepers. ht.MineBlocksAndAssertNumTxes(1, 1) - // Alice should have one pending sweep, + // Alice should have two pending sweeps, // - anchor sweeping from her local commitment. - ht.AssertNumPendingSweeps(alice, 1) + // - to_local output from her local commitment. + ht.AssertNumPendingSweeps(alice, 2) // Bob should have two pending sweeps, // - anchor sweeping from the remote anchor on Alice's commit tx. @@ -2301,8 +2307,9 @@ func testFeeReplacement(ht *lntest.HarnessTest) { // so we can focus on testing his outgoing HTLCs. ht.MineBlocksAndAssertNumTxes(1, 2) - // Bob should have numPayments pending sweep for the outgoing HTLCs. - ht.AssertNumPendingSweeps(bob, numPayments) + // Bob should have numPayments pending sweep for the outgoing HTLCs. In + // addition, he should see his immature to_local output sweep. + ht.AssertNumPendingSweeps(bob, numPayments+1) // Bob should have one sweeping tx in the mempool, which sweeps all his // outgoing HTLCs. @@ -2356,7 +2363,9 @@ func testFeeReplacement(ht *lntest.HarnessTest) { // sweeping tx and broadcast it using the remaining outgoing HTLC. // // Bob should have numPayments-1 pending sweep for the outgoing HTLCs. - ht.AssertNumPendingSweeps(bob, numPayments-1) + // In addition, he should have his to_local output sweep which is + // immature. + ht.AssertNumPendingSweeps(bob, numPayments) // Assert Bob immediately sweeps his remaining HTLC with the previous // fee rate. diff --git a/lntest/harness_assertion.go b/lntest/harness_assertion.go index 8cdbb4ad8..e8082bdba 100644 --- a/lntest/harness_assertion.go +++ b/lntest/harness_assertion.go @@ -711,8 +711,11 @@ func (h *HarnessTest) AssertStreamChannelForceClosed(hn *node.HarnessNode, } // Assert there's a pending anchor sweep. + // + // NOTE: We may have a local sweep here, that's why we use + // AssertAtLeastNumPendingSweeps instead of AssertNumPendingSweeps. if anchorSweep { - h.AssertNumPendingSweeps(hn, 1) + h.AssertAtLeastNumPendingSweeps(hn, 1) } return closingTxid @@ -2723,9 +2726,10 @@ func (h *HarnessTest) AssertNumPendingSweeps(hn *node.HarnessNode, numDesc := "\n" for _, s := range resp.PendingSweeps { desc := fmt.Sprintf("op=%v:%v, amt=%v, type=%v, "+ - "deadline=%v\n", s.Outpoint.TxidStr, - s.Outpoint.OutputIndex, s.AmountSat, - s.WitnessType, s.DeadlineHeight) + "deadline=%v, maturityHeight=%v\n", + s.Outpoint.TxidStr, s.Outpoint.OutputIndex, + s.AmountSat, s.WitnessType, s.DeadlineHeight, + s.MaturityHeight) numDesc += desc // The deadline height must be set, otherwise the @@ -2749,6 +2753,47 @@ func (h *HarnessTest) AssertNumPendingSweeps(hn *node.HarnessNode, return results } +// AssertAtLeastNumPendingSweeps asserts there are at least n pending sweeps for +// the given node. +func (h *HarnessTest) AssertAtLeastNumPendingSweeps(hn *node.HarnessNode, + n int) []*walletrpc.PendingSweep { + + results := make([]*walletrpc.PendingSweep, 0, n) + + err := wait.NoError(func() error { + resp := hn.RPC.PendingSweeps() + num := len(resp.PendingSweeps) + + numDesc := "\n" + for _, s := range resp.PendingSweeps { + desc := fmt.Sprintf("op=%v:%v, amt=%v, type=%v, "+ + "deadline=%v, maturityHeight=%v\n", + s.Outpoint.TxidStr, s.Outpoint.OutputIndex, + s.AmountSat, s.WitnessType, s.DeadlineHeight, + s.MaturityHeight) + numDesc += desc + + // The deadline height must be set, otherwise the + // pending input response is not update-to-date. + if s.DeadlineHeight == 0 { + return fmt.Errorf("input not updated: %s", desc) + } + } + + if num >= n { + results = resp.PendingSweeps + return nil + } + + return fmt.Errorf("want %d , got %d, sweeps: %s", n, num, + numDesc) + }, DefaultTimeout) + + require.NoErrorf(h, err, "%s: check pending sweeps timeout", hn.Name()) + + return results +} + // FindSweepingTxns asserts the expected number of sweeping txns are found in // the txns specified and return them. func (h *HarnessTest) FindSweepingTxns(txns []*wire.MsgTx, diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 05cd23c32..545c4ccb8 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -7180,7 +7180,7 @@ func newOutgoingHtlcResolution(signer input.Signer, Expiry: htlc.RefundTimeout, ClaimOutpoint: op, SweepSignDesc: signDesc, - CsvDelay: csvDelay, + CsvDelay: htlcCsvDelay, ResolutionBlob: resolutionBlob, }, nil }