diff --git a/itest/lnd_channel_backup_test.go b/itest/lnd_channel_backup_test.go index ea04a139a..8d0c00712 100644 --- a/itest/lnd_channel_backup_test.go +++ b/itest/lnd_channel_backup_test.go @@ -1266,6 +1266,12 @@ func testDataLossProtection(ht *lntest.HarnessTest) { // information Dave needs to sweep his funds. require.NoError(ht, restartDave(), "unable to restart Eve") + // Dave should have a pending sweep. + ht.AssertNumPendingSweeps(dave, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) + // Dave should sweep his funds. ht.Miner.AssertNumTxsInMempool(1) @@ -1417,6 +1423,11 @@ 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) + + // Mine a block to trigger the sweeps. + ht.MineBlocks(1) ht.Miner.AssertNumTxsInMempool(expectedTxes) // Carol should consider the channel pending force close (since she is @@ -1444,9 +1455,13 @@ func assertTimeLockSwept(ht *lntest.HarnessTest, carol, dave *node.HarnessNode, // After the Dave's output matures, he should reclaim his funds. // // The commit sweep resolver publishes the sweep tx at defaultCSV-1 and - // we already mined one block after the commitment was published, so - // take that into account. - ht.MineBlocks(defaultCSV - 1 - 1) + // we already mined one block after the commitment was published, and + // one block to trigger Carol's sweeps, so take that into account. + ht.MineBlocks(1) + ht.AssertNumPendingSweeps(dave, 1) + + // Mine a block to trigger the sweeps. + ht.MineBlocks(1) daveSweep := ht.Miner.AssertNumTxsInMempool(1)[0] block := ht.MineBlocksAndAssertNumTxes(1, 1)[0] ht.Miner.AssertTxInBlock(block, daveSweep) @@ -1526,6 +1541,12 @@ func assertDLPExecuted(ht *lntest.HarnessTest, // Dave should sweep his anchor only, since he still has the // lease CLTV constraint on his commitment output. We'd also // see Carol's anchor sweep here. + ht.AssertNumPendingSweeps(dave, 1) + ht.AssertNumPendingSweeps(carol, 1) + + // Mine a block to trigger the sweeps. + ht.MineBlocks(1) + blocksMined++ ht.Miner.AssertNumTxsInMempool(2) // Mine anchor sweep txes for Carol and Dave. @@ -1539,6 +1560,10 @@ func assertDLPExecuted(ht *lntest.HarnessTest, // defaultCSV-1 and we already mined one block after the // commitmment was published, so take that into account. ht.MineBlocks(defaultCSV - blocksMined) + ht.AssertNumPendingSweeps(carol, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) ht.MineBlocksAndAssertNumTxes(1, 1) // Now the channel should be fully closed also from Carol's POV. @@ -1552,6 +1577,10 @@ func assertDLPExecuted(ht *lntest.HarnessTest, require.Positive(ht, blocksTilMaturity) ht.MineBlocks(uint32(blocksTilMaturity)) + ht.AssertNumPendingSweeps(dave, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) ht.MineBlocksAndAssertNumTxes(1, 1) // Now Dave should consider the channel fully closed. @@ -1559,7 +1588,22 @@ func assertDLPExecuted(ht *lntest.HarnessTest, } else { // Dave should sweep his funds immediately, as they are not // timelocked. We also expect Carol and Dave sweep their - // anchors. + // anchors if it's an anchor channel. + if lntest.CommitTypeHasAnchors(commitType) { + ht.AssertNumPendingSweeps(carol, 1) + ht.AssertNumPendingSweeps(dave, 2) + } else { + ht.AssertNumPendingSweeps(dave, 1) + } + + // Mine one block to trigger the sweeper to sweep. + ht.MineBlocks(1) + blocksMined++ + + // For anchor channels, we expect three txns, + // 1. the anchor sweeping tx from Dave. + // 2. the anchor sweeping tx from Carol. + // 3. the commitment sweep from Dave. if lntest.CommitTypeHasAnchors(commitType) { ht.MineBlocksAndAssertNumTxes(1, 3) } else { @@ -1578,6 +1622,12 @@ func assertDLPExecuted(ht *lntest.HarnessTest, // defaultCSV-1 and we already have blocks mined after the // commitmment was published, so take that into account. ht.MineBlocks(defaultCSV - blocksMined) + + // Mine one block to trigger the sweeper to sweep. + ht.MineBlocks(1) + ht.AssertNumPendingSweeps(carol, 1) + + // Assert the sweeping tx is mined. ht.MineBlocksAndAssertNumTxes(1, 1) // Now the channel should be fully closed also from Carol's diff --git a/itest/lnd_channel_force_close_test.go b/itest/lnd_channel_force_close_test.go index b0aba4c07..3f73c17a8 100644 --- a/itest/lnd_channel_force_close_test.go +++ b/itest/lnd_channel_force_close_test.go @@ -179,12 +179,17 @@ func testCommitmentTransactionDeadline(ht *lntest.HarnessTest) { // Bob should now sweep his to_local output and anchor output. expectedNumTxes = 2 + ht.AssertNumPendingSweeps(bob, 2) // If Alice's anchor is not swept above, we should see it here. if !expectAnchor { expectedNumTxes = 3 + ht.AssertNumPendingSweeps(alice, 1) } + // Mine one block to trigger the sweeps. + ht.MineBlocks(1) + // Mine one more block to assert the sweep transactions. ht.MineBlocksAndAssertNumTxes(1, expectedNumTxes) @@ -386,16 +391,6 @@ func channelForceClosureTest(ht *lntest.HarnessTest, ) ) - // If we are dealing with an anchor channel type, the sweeper will - // sweep the HTLC second level output one block earlier (than the - // nursery that waits an additional block, and handles non-anchor - // channels). So we set a maturity height that is one less. - if lntest.CommitTypeHasAnchors(channelType) { - htlcCsvMaturityHeight = padCLTV( - startHeight + defaultCLTV + defaultCSV, - ) - } - aliceChan := ht.QueryChannelByChanPoint(alice, chanPoint) require.NotZero(ht, aliceChan.NumUpdates, "alice should see at least one update to her channel") @@ -523,6 +518,13 @@ func channelForceClosureTest(ht *lntest.HarnessTest, // (the "kindergarten" bucket.) ht.RestartNode(alice) + // Carol should have pending sweeps now. + ht.AssertNumPendingSweeps(carol, expectedTxes) + + // Mine a block to trigger the sweep transactions. + blocksMined := int32(1) + ht.MineBlocks(1) + // Carol's sweep tx should be in the mempool already, as her output is // not timelocked. If there are anchors, we also expect Carol's anchor // sweep now. @@ -560,7 +562,8 @@ func channelForceClosureTest(ht *lntest.HarnessTest, // For the persistence test, we generate two blocks, then trigger // a restart and then generate the final block that should trigger // the creation of the sweep transaction. - ht.MineBlocks(defaultCSV - 2) + ht.MineBlocks(1) + blocksMined++ // The following restart checks to ensure that outputs in the // kindergarten bucket are persisted while waiting for the required @@ -592,7 +595,8 @@ func channelForceClosureTest(ht *lntest.HarnessTest, // outputs should also reflect that this many blocks have // passed. err = checkCommitmentMaturity( - forceClose, commCsvMaturityHeight, 2, + forceClose, commCsvMaturityHeight, + defaultCSV-blocksMined, ) if err != nil { return err @@ -621,8 +625,13 @@ func channelForceClosureTest(ht *lntest.HarnessTest, ht.MineBlocks(1) // At this point, the CSV will expire in the next block, meaning that - // the sweeping transaction should now be broadcast. So we fetch the - // node's mempool to ensure it has been properly broadcast. + // the output should be offered to the sweeper. + ht.AssertNumPendingSweeps(alice, 1) + + // Mine one block and the sweeping transaction should now be broadcast. + // So we fetch the node's mempool to ensure it has been properly + // broadcast. + ht.MineBlocks(1) sweepingTXID := ht.Miner.AssertNumTxsInMempool(1)[0] // Fetch the sweep transaction, all input it's spending should be from @@ -729,7 +738,16 @@ func channelForceClosureTest(ht *lntest.HarnessTest, // number of blocks we have generated since adding it to the nursery, // and take an additional block off so that we end up one block shy of // the expiry height, and add the block padding. - cltvHeightDelta := padCLTV(defaultCLTV - defaultCSV - 1 - 1) + cltvHeightDelta := padCLTV(defaultCLTV - defaultCSV - 1 - 1 - 1) + + // NOTE: this rest of the test would only pass if we remove the `Force` + // flag used in sweeping HTLCs, otherwise an immediate sweep will be + // attempted due to being forced. This flag will be removed once we can + // conditionally cancel back upstream htlcs to avoid cascading FCs. + ht.Shutdown(alice) + ht.Shutdown(carol) + ht.MineBlocksAndAssertNumTxes(1, 0) + ht.Skip("Skipping due until force flags are removed") // Advance the blockchain until just before the CLTV expires, nothing // exciting should have happened during this time. @@ -773,20 +791,24 @@ func channelForceClosureTest(ht *lntest.HarnessTest, }, defaultTimeout) require.NoError(ht, err, "timeout while checking force closed channel") - // Now, generate the block which will cause Alice to broadcast the - // presigned htlc timeout txns. + // Now, generate the block which will cause Alice to offer the + // presigned htlc timeout txns to the sweeper. ht.MineBlocks(1) // Since Alice had numInvoices (6) htlcs extended to Carol before force // closing, we expect Alice to broadcast an htlc timeout txn for each // one. expectedTxes = numInvoices + ht.AssertNumPendingSweeps(alice, numInvoices) // In case of anchors, the timeout txs will be aggregated into one. if lntest.CommitTypeHasAnchors(channelType) { expectedTxes = 1 } + // Mine a block to trigger the sweeps. + ht.MineBlocks(1) + // Wait for them all to show up in the mempool. htlcTxIDs := ht.Miner.AssertNumTxsInMempool(expectedTxes) @@ -905,7 +927,7 @@ func channelForceClosureTest(ht *lntest.HarnessTest, ht.RestartNode(alice) // Advance the chain until just before the 2nd-layer CSV delays expire. - // For anchor channels thhis is one block earlier. + // For anchor channels this is one block earlier. numBlocks := uint32(defaultCSV - 1) if lntest.CommitTypeHasAnchors(channelType) { numBlocks = defaultCSV - 2 @@ -935,6 +957,10 @@ func channelForceClosureTest(ht *lntest.HarnessTest, // Generate a block that causes Alice to sweep the htlc outputs in the // kindergarten bucket. ht.MineBlocks(1) + ht.AssertNumPendingSweeps(alice, 6) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) // Wait for the single sweep txn to appear in the mempool. htlcSweepTxID := ht.Miner.AssertNumTxsInMempool(1)[0] @@ -1009,7 +1035,7 @@ func channelForceClosureTest(ht *lntest.HarnessTest, } err = checkPendingHtlcStageAndMaturity( - forceClose, 2, htlcCsvMaturityHeight, 0, + forceClose, 2, htlcCsvMaturityHeight, -1, ) if err != nil { return err @@ -1133,6 +1159,10 @@ func testFailingChannel(ht *lntest.HarnessTest) { // Mine enough blocks for Alice to sweep her funds from the force // closed channel. ht.MineBlocks(defaultCSV - 1) + ht.AssertNumPendingSweeps(alice, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) // Wait for the sweeping tx to be broadcast. ht.Miner.AssertNumTxsInMempool(1) diff --git a/itest/lnd_multi-hop_test.go b/itest/lnd_multi-hop_test.go index 1c0cd1007..b3abc79b9 100644 --- a/itest/lnd_multi-hop_test.go +++ b/itest/lnd_multi-hop_test.go @@ -236,7 +236,8 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest, ht.MineBlocks(numBlocks) // Bob's force close transaction should now be found in the mempool. If - // there are anchors, we also expect Bob's anchor sweep. + // there are anchors, we also expect Bob's anchor sweep as it's a + // forced sweep. expectedTxes := 1 hasAnchors := lntest.CommitTypeHasAnchors(c) if hasAnchors { @@ -256,10 +257,18 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest, ht.AssertActiveHtlcs(alice, payHash) // With the closing transaction confirmed, we should expect Bob's HTLC - // timeout transaction to be broadcast due to the expiry being reached. - // If there are anchors, we also expect Carol's anchor sweep now. - ht.Miner.AssertNumTxsInMempool(expectedTxes) + // timeout transaction to be offered to the sweeper due to the expiry + // being reached. If there are anchors, we also expect Carol's anchor + // sweep now. + ht.AssertNumPendingSweeps(bob, 1) + if hasAnchors { + ht.AssertNumPendingSweeps(carol, 1) + } + // Bob's HTLC timeout transaction should now be found in the mempool as + // it's a forced sweep, which means we don't need to mine a block to + // trigger it. + // // We'll also obtain the expected HTLC timeout transaction hash. htlcOutpoint := wire.OutPoint{Hash: closeTx.TxHash(), Index: 0} commitOutpoint := wire.OutPoint{Hash: closeTx.TxHash(), Index: 1} @@ -271,8 +280,15 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest, htlcOutpoint, ).TxHash() - // Mine a block to confirm the expected transactions. - ht.MineBlocksAndAssertNumTxes(1, expectedTxes) + // Mine a block to confirm Bob's sweep. + ht.MineBlocksAndAssertNumTxes(1, 1) + + // The above block will trigger Carol's sweeper to broadcast her anchor + // sweep. + if hasAnchors { + // Carol's anchor sweep should now be found in the mempool. + ht.Miner.AssertNumTxsInMempool(1) + } // With Bob's HTLC timeout transaction confirmed, there should be no // active HTLC's on the commitment transaction from Alice -> Bob. @@ -297,6 +313,12 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest, blocksTilMaturity := uint32(forceCloseChan.BlocksTilMaturity) ht.MineBlocks(blocksTilMaturity) + // Check that Bob has two pending sweeping txns. + ht.AssertNumPendingSweeps(bob, 2) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) + // Check that the sweep spends the expected inputs. ht.Miner.AssertOutpointInMempool(commitOutpoint) ht.Miner.AssertOutpointInMempool(htlcTimeoutOutpoint) @@ -308,6 +330,12 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest, numBlocks := uint32(forceCloseChan.BlocksTilMaturity - 1) ht.MineBlocks(numBlocks) + // Check that Bob has a pending sweeping tx. + ht.AssertNumPendingSweeps(bob, 1) + + // Mine a block the trigger the sweeping behavior. + ht.MineBlocks(1) + // Check that the sweep spends from the mined commitment. ht.Miner.AssertOutpointInMempool(commitOutpoint) @@ -427,7 +455,7 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest, // At this point, Carol should broadcast her active commitment // transaction in order to go to the chain and sweep her HTLC. If there - // are anchors, Carol also sweeps hers. + // are anchors, Carol also sweeps hers as it's a forced sweep. expectedTxes := 1 hasAnchors := lntest.CommitTypeHasAnchors(c) if hasAnchors { @@ -443,6 +471,10 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest, // Confirm the commitment. ht.MineBlocksAndAssertNumTxes(1, expectedTxes) + // After the force close transaction is mined, Carol should offer her + // second level HTLC tx to the sweeper. + ht.AssertNumPendingSweeps(carol, 1) + // Restart bob again. require.NoError(ht, restartBob()) @@ -456,12 +488,14 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest, // Carol. case lnrpc.CommitmentType_LEGACY: expectedTxes = 2 + ht.AssertNumPendingSweeps(bob, 1) // Carol should broadcast her second level HTLC transaction and Bob // should broadcast a sweep tx to sweep his output in the channel with // Carol, and another sweep tx to sweep his anchor output. case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT: expectedTxes = 3 + ht.AssertNumPendingSweeps(bob, 2) // Carol should broadcast her second level HTLC transaction and Bob // should broadcast a sweep tx to sweep his anchor output. Bob's commit @@ -469,11 +503,15 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest, // being the channel initiator of a script-enforced leased channel. case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: expectedTxes = 2 + ht.AssertNumPendingSweeps(bob, 1) default: ht.Fatalf("unhandled commitment type %v", c) } + // Mine one block to trigger the sweeper to sweep. + ht.MineEmptyBlocks(1) + // All transactions should be spending from the commitment transaction. txes := ht.Miner.GetNumTxsFromMempool(expectedTxes) ht.AssertAllTxesSpendFrom(txes, closingTxid) @@ -494,7 +532,12 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest, // If we mine 4 additional blocks, then Carol can sweep the second // level HTLC output once the CSV expires. - ht.MineEmptyBlocks(defaultCSV) + ht.MineEmptyBlocks(defaultCSV - 1) + + ht.AssertNumPendingSweeps(carol, 1) + + // Mine one block to trigger the sweeper to sweep. + ht.MineBlocks(1) // We should have a new transaction in the mempool. ht.Miner.AssertNumTxsInMempool(1) @@ -534,9 +577,13 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest, // and sweep it. numBlocks := uint32(forceCloseChan.BlocksTilMaturity) ht.MineBlocks(numBlocks) + + ht.AssertNumPendingSweeps(bob, 1) + ht.MineBlocks(1) + commitOutpoint := wire.OutPoint{Hash: closingTxid, Index: 3} ht.Miner.AssertOutpointInMempool(commitOutpoint) - ht.MineBlocks(1) + ht.MineBlocksAndAssertNumTxes(1, 1) } ht.AssertNumPendingForceClose(bob, 0) @@ -617,12 +664,20 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, bob, bobChanPoint, hasAnchors, stream, ) - // Increase the blocks mined. At this step + // Increase the blocks mined. At the step // AssertStreamChannelForceClosed mines one block. blocksMined++ - // If the channel closed has anchors, we should expect to see a sweep - // transaction for Carol's anchor. + // If the channel closed has anchors, we should expect to see a pending + // sweep request for Carol's anchor. + if hasAnchors { + ht.AssertNumPendingSweeps(carol, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) + blocksMined++ + } + htlcOutpoint := wire.OutPoint{Hash: *closeTx, Index: 0} bobCommitOutpoint := wire.OutPoint{Hash: *closeTx, Index: 1} if hasAnchors { @@ -640,7 +695,13 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, // CSV expires and the commitment was already mined inside // AssertStreamChannelForceClosed(), so mine one block less // than defaultCSV in order to perform mempool assertions. - ht.MineBlocks(defaultCSV - 1) + ht.MineBlocks(defaultCSV - blocksMined) + blocksMined = defaultCSV + + // Assert Bob has the sweep and trigger it.. + ht.AssertNumPendingSweeps(bob, 1) + ht.MineBlocks(1) + blocksMined++ commitSweepTx := ht.Miner.AssertOutpointInMempool( bobCommitOutpoint, @@ -649,7 +710,7 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, block := ht.MineBlocksAndAssertNumTxes(1, 1)[0] ht.Miner.AssertTxInBlock(block, &txid) - blocksMined += defaultCSV + blocksMined++ } // We'll now mine enough blocks for the HTLC to expire. After this, Bob @@ -697,16 +758,22 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, // either only sweep the HTLC timeout transaction, or sweep both the // HTLC timeout transaction and Bob's commit output depending on the // commitment type. - htlcTimeoutOutpoint := wire.OutPoint{Hash: timeoutTx, Index: 0} - sweepTx := ht.Miner.AssertOutpointInMempool( - htlcTimeoutOutpoint, - ).TxHash() if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { - ht.Miner.AssertOutpointInMempool(bobCommitOutpoint) + // Assert the expected number of pending sweeps are found. + ht.AssertNumPendingSweeps(bob, 2) + } else { + ht.AssertNumPendingSweeps(bob, 1) } - block = ht.MineBlocksAndAssertNumTxes(1, 1)[0] - ht.Miner.AssertTxInBlock(block, &sweepTx) + // Mine a block to trigger the sweep. + ht.MineBlocks(1) + + // Assert the sweeping tx is found in the mempool. + htlcTimeoutOutpoint := wire.OutPoint{Hash: timeoutTx, Index: 0} + ht.Miner.AssertOutpointInMempool(htlcTimeoutOutpoint) + + // Mine a block to confirm the sweep. + ht.MineBlocksAndAssertNumTxes(1, 1) // At this point, Bob should no longer show any channels as pending // close. @@ -809,25 +876,38 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, var expectedTxes int switch c { - // Bob can sweep his commit output immediately. + // Bob can sweep his commit output immediately, so we should see it + // being offer to the sweeper. case lnrpc.CommitmentType_LEGACY: + ht.AssertNumPendingSweeps(bob, 1) + expectedTxes = 1 // Bob can sweep his commit and anchor outputs immediately. Carol will // also sweep her anchor. case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT: + ht.AssertNumPendingSweeps(bob, 2) + ht.AssertNumPendingSweeps(carol, 1) + expectedTxes = 3 // Bob can't sweep his commit output yet as he was the initiator of a // script-enforced leased channel, so he'll always incur the additional // CLTV. He can still sweep his anchor output however. case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + ht.AssertNumPendingSweeps(bob, 1) + ht.AssertNumPendingSweeps(carol, 1) + expectedTxes = 2 default: ht.Fatalf("unhandled commitment type %v", c) } + // Mine one block to trigger the sweeps. + ht.MineBlocks(1) + blocksMined++ + // We now mine a block to clear up the mempool. ht.MineBlocksAndAssertNumTxes(1, expectedTxes) blocksMined++ @@ -875,6 +955,12 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, numBlocks := uint32(forceCloseChan.BlocksTilMaturity) ht.MineBlocks(numBlocks) + // Assert the commit output has been offered to the sweeper. + ht.AssertNumPendingSweeps(bob, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) + bobCommitOutpoint := wire.OutPoint{Hash: *closeTx, Index: 3} bobCommitSweep := ht.Miner.AssertOutpointInMempool( bobCommitOutpoint, @@ -988,23 +1074,35 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest, switch c { // Alice will sweep her commitment output immediately. case lnrpc.CommitmentType_LEGACY: + ht.AssertNumPendingSweeps(alice, 1) + expectedTxes = 1 // Alice will sweep her commitment and anchor output immediately. Bob // will also sweep his anchor. case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT: + ht.AssertNumPendingSweeps(alice, 2) + ht.AssertNumPendingSweeps(bob, 1) + expectedTxes = 3 // Alice will sweep her anchor output immediately. 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. case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + ht.AssertNumPendingSweeps(alice, 1) + ht.AssertNumPendingSweeps(bob, 1) + expectedTxes = 2 default: ht.Fatalf("unhandled commitment type %v", c) } + // Mine a block to trigger the sweeps. + ht.MineBlocks(1) + blocksMined++ + ht.Miner.AssertNumTxsInMempool(expectedTxes) // Suspend Bob to force Carol to go to chain. @@ -1025,7 +1123,8 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest, ht.MineBlocks(numBlocks - blocksMined) // Carol's commitment transaction should now be in the mempool. If - // there is an anchor, Carol will sweep that too. + // there is an anchor, Carol will sweep that too as it's forced sweep. + expectedTxes = 1 if lntest.CommitTypeHasAnchors(c) { expectedTxes = 2 } @@ -1043,15 +1142,20 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest, block := ht.MineBlocksAndAssertNumTxes(1, expectedTxes)[0] ht.Miner.AssertTxInBlock(block, &closingTxid) + // After the force close transaction is mined, Carol should offer her + // second-level success HTLC tx to the sweeper. + ht.AssertNumPendingSweeps(carol, 1) + // Restart bob again. require.NoError(ht, restartBob()) // After the force close transaction is mined, transactions will be // broadcast by both Bob and Carol. switch c { - // Carol will broadcast her second level HTLC transaction and Bob will + // Carol will sweep her second level HTLC transaction and Bob will // sweep his commitment output. case lnrpc.CommitmentType_LEGACY: + ht.AssertNumPendingSweeps(bob, 1) expectedTxes = 2 // Carol will broadcast her second level HTLC transaction and Bob will @@ -1062,6 +1166,7 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest, // - Bob's sweep tx spending two anchor outputs, one from channel Alice // to Bob and the other from channel Bob to Carol. case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT: + ht.AssertNumPendingSweeps(bob, 2) expectedTxes = 3 // Carol will broadcast her second level HTLC transaction, and Bob will @@ -1069,12 +1174,16 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest, // as it has incurred an additional CLTV due to being the initiator of // a script-enforced leased channel. case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + ht.AssertNumPendingSweeps(bob, 1) expectedTxes = 2 default: ht.Fatalf("unhandled commitment type %v", c) } + // Mine a block to trigger the sweeps. + ht.MineEmptyBlocks(1) + // Assert transactions can be found in the mempool. ht.Miner.AssertNumTxsInMempool(expectedTxes) @@ -1103,6 +1212,13 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest, // When Bob notices Carol's second level transaction 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. + ht.AssertNumPendingSweeps(bob, 1) + + // Mine a block to trigger the sweep of the second level tx. + ht.MineBlocks(1) + carolSecondLevelCSV-- + + // Check Bob's second level tx. bobSecondLvlTx := ht.Miner.GetNumTxsFromMempool(1)[0] bobSecondLvlTxid := bobSecondLvlTx.TxHash() @@ -1140,6 +1256,10 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest, // If we then mine 3 additional blocks, Carol's second level tx should // mature, and she can pull the funds from it with a sweep tx. ht.MineBlocks(carolSecondLevelCSV) + ht.AssertNumPendingSweeps(carol, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) carolSweep := ht.Miner.AssertNumTxsInMempool(1)[0] // Mining one additional block, Bob's second level tx is mature, and he @@ -1181,6 +1301,14 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest, numBlocks := uint32(forceCloseChan.BlocksTilMaturity) ht.MineBlocks(numBlocks) + // Both Alice and Bob should now offer their commit outputs to + // the sweeper. + ht.AssertNumPendingSweeps(alice, 1) + ht.AssertNumPendingSweeps(bob, 1) + + // Mine a block to trigger the sweeps. + ht.MineBlocks(1) + // Both Alice and Bob show broadcast their commit sweeps. aliceCommitOutpoint := wire.OutPoint{ Hash: *bobForceClose, Index: 3, @@ -1306,6 +1434,14 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, // so now bob will attempt to redeem his anchor commitment (if the // channel type is of that type). if hasAnchors { + // Check the anchor is offered to the sweeper. + ht.AssertNumPendingSweeps(bob, 1) + + // Mine a block to trigger the anchor sweep. + ht.MineBlocks(1) + blocksMined++ + + // Check that the anchor sweep is in the mempool. ht.Miner.AssertNumTxsInMempool(1) } @@ -1316,10 +1452,17 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, // commit sweep tx will be broadcast immediately before it can // be included in a block, so mine one less than defaultCSV in // order to perform mempool assertions. - ht.MineBlocks(defaultCSV - 1) - blocksMined += (defaultCSV - 1) + ht.MineBlocks(defaultCSV - blocksMined) + blocksMined += (defaultCSV - blocksMined) // Alice should now sweep her funds. + ht.AssertNumPendingSweeps(alice, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) + blocksMined++ + + // Assert the commitment sweep tx is in the mempool. ht.Miner.AssertNumTxsInMempool(1) } @@ -1346,7 +1489,8 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, } // Carol's commitment transaction should now be in the mempool. If - // there are anchors, Carol also sweeps her anchor. + // there are anchors, Carol also sweeps her anchor as it's a forced + // sweep. ht.Miner.AssertNumTxsInMempool(expectedTxes) // The closing transaction should be spending from the funding @@ -1361,6 +1505,10 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, block := ht.MineBlocksAndAssertNumTxes(1, expectedTxes)[0] ht.Miner.AssertTxInBlock(block, &closingTxid) + // After the force close transaction is mined, Carol should offer her + // second level HTLC tx to the sweeper. + ht.AssertNumPendingSweeps(carol, 1) + // Restart bob again. require.NoError(ht, restartBob()) @@ -1371,12 +1519,14 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, // Carol should broadcast her second level HTLC transaction and Bob // should broadcast a transaction to sweep his commitment output. case lnrpc.CommitmentType_LEGACY: + ht.AssertNumPendingSweeps(bob, 1) expectedTxes = 2 // Carol should broadcast her second level HTLC transaction and Bob // should broadcast a transaction to sweep his commitment output and // another to sweep his anchor output. case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT: + ht.AssertNumPendingSweeps(bob, 2) expectedTxes = 3 // Carol should broadcast her second level HTLC transaction and Bob @@ -1385,22 +1535,27 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, // due to being the channel initiator of a force closed script-enforced // leased channel. case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + ht.AssertNumPendingSweeps(bob, 1) expectedTxes = 2 default: ht.Fatalf("unhandled commitment type %v", c) } + + // Keep track of the second level tx maturity. + carolSecondLevelCSV := uint32(defaultCSV) + + // Mine a block to trigger the sweeps. + ht.MineBlocks(1) + carolSecondLevelCSV-- txes := ht.Miner.GetNumTxsFromMempool(expectedTxes) // All transactions should be pending from the commitment transaction. ht.AssertAllTxesSpendFrom(txes, closingTxid) - // Mine a block to confirm the two transactions (+ coinbase). + // Mine a block to confirm the expected transactions. ht.MineBlocksAndAssertNumTxes(1, expectedTxes) - // Keep track of the second level tx maturity. - carolSecondLevelCSV := uint32(defaultCSV) - // When Bob notices Carol's second level transaction in the block, he // will extract the preimage and broadcast a sweep tx to directly claim // the HTLC in his (already closed) channel with Alice. @@ -1432,6 +1587,10 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, // If we then mine 3 additional blocks, Carol's second level tx will // mature, and she should pull the funds. ht.MineEmptyBlocks(int(carolSecondLevelCSV)) + ht.AssertNumPendingSweeps(carol, 1) + + // Mine a block to trigger the sweep of the second level tx. + ht.MineBlocks(1) carolSweep := ht.Miner.AssertNumTxsInMempool(1)[0] // When Carol's sweep gets confirmed, she should have no more pending @@ -1457,7 +1616,14 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, numBlocks := uint32(forceCloseChan.BlocksTilMaturity) ht.MineBlocks(numBlocks) - // Both Alice and Bob show broadcast their commit sweeps. + // Both Alice and Bob should offer their commit sweeps. + ht.AssertNumPendingSweeps(alice, 1) + ht.AssertNumPendingSweeps(bob, 1) + + // Mine a block to trigger the sweeps. + ht.MineBlocks(1) + + // Both Alice and Bob should broadcast their commit sweeps. aliceCommitOutpoint := wire.OutPoint{ Hash: *aliceForceClose, Index: 3, } @@ -1499,6 +1665,11 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, // case of anchor channels, the second-level spends can also be aggregated and // properly feebumped, so we'll check that as well. func testMultiHopHtlcAggregation(ht *lntest.HarnessTest) { + // NOTE: this test would only pass if we remove the `Force` flag used + // in sweeping HTLCs, otherwise an immediate sweep will be attempted + // due to being forced. This flag will be removed once we can + // conditionally cancel back upstream htlcs to avoid cascading FCs. + ht.Skip("Skipping due until force flags are removed") runMultiHopHtlcClaimTest(ht, runMultiHopHtlcAggregation) } @@ -1659,7 +1830,8 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest, ht.MineBlocks(numBlocks) // Bob's force close transaction should now be found in the mempool. If - // there are anchors, we also expect Bob's anchor sweep. + // there are anchors, we also expect Bob's anchor sweep as it's a + // forced sweep. hasAnchors := lntest.CommitTypeHasAnchors(c) expectedTxes := 1 if hasAnchors { @@ -1672,12 +1844,6 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest, ) closeTxid := closeTx.TxHash() - // Restart Bob to increase the batch window duration so the sweeper - // will aggregate all the pending inputs. - ht.RestartNodeWithExtraArgs( - bob, []string{"--sweeper.batchwindowduration=15s"}, - ) - // Go through the closing transaction outputs, and make an index for // the HTLC outputs. successOuts := make(map[wire.OutPoint]struct{}) @@ -1724,6 +1890,9 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest, // preimages from Alice. We also expect Carol to sweep her commitment // output. case lnrpc.CommitmentType_LEGACY: + ht.AssertNumPendingSweeps(bob, numInvoices*2) + ht.AssertNumPendingSweeps(carol, 1) + expectedTxes = 2*numInvoices + 1 // In case of anchors, all success transactions will be aggregated into @@ -1734,11 +1903,18 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest, lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE, lnrpc.CommitmentType_SIMPLE_TAPROOT: + ht.AssertNumPendingSweeps(bob, numInvoices*2) + ht.AssertNumPendingSweeps(carol, 2) + expectedTxes = 4 default: ht.Fatalf("unhandled commitment type %v", c) } + + // Mine a block to trigger the sweeps. + ht.MineBlocks(1) + txes := ht.Miner.GetNumTxsFromMempool(expectedTxes) // Since Bob can aggregate the transactions, we expect a single @@ -1798,7 +1974,13 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest, if c != lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { // If we then mine additional blocks, Bob can sweep his // commitment output. - ht.MineBlocks(defaultCSV - 2) + ht.MineBlocks(1) + + // Assert the tx has been offered to the sweeper. + ht.AssertNumPendingSweeps(bob, 1) + + // Mine one block to trigger the sweep. + ht.MineBlocks(1) // Find the commitment sweep. bobCommitSweep := ht.Miner.GetNumTxsFromMempool(1)[0] @@ -1820,12 +2002,6 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest, } } - // We now restart Bob with a much larger batch window duration since it - // takes some time to aggregate all the 10 inputs below. - ht.RestartNodeWithExtraArgs( - bob, []string{"--sweeper.batchwindowduration=45s"}, - ) - switch c { // In case this is a non-anchor channel type, we must mine 2 blocks, as // the nursery waits an extra block before sweeping. Before the blocks @@ -1860,6 +2036,9 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest, ht.Fatalf("unhandled commitment type %v", c) } + // Mine one block to trigger the sweeps. + ht.MineBlocks(1) + // Make sure it spends from the second level tx. secondLevelSweep := ht.Miner.GetNumTxsFromMempool(1)[0] bobSweep := secondLevelSweep.TxHash() @@ -2021,12 +2200,6 @@ func createThreeHopNetwork(ht *lntest.HarnessTest, aliceChanPoint := resp[0] bobChanPoint := resp[1] - // Remove the ChannelAcceptor for Bob and Carol. - if zeroConf { - cancelBob() - cancelCarol() - } - // Make sure alice and carol know each other's channels. // // We'll only do this though if it wasn't a private channel we opened @@ -2041,6 +2214,12 @@ func createThreeHopNetwork(ht *lntest.HarnessTest, ht.AssertChannelExists(carol, bobChanPoint) } + // Remove the ChannelAcceptor for Bob and Carol. + if zeroConf { + cancelBob() + cancelCarol() + } + return aliceChanPoint, bobChanPoint, carol } @@ -2138,7 +2317,11 @@ func runExtraPreimageFromRemoteCommit(ht *lntest.HarnessTest, ht.MineClosingTx(bobChanPoint, c) // With the closing transaction confirmed, we should expect Carol's - // HTLC success transaction to be broadcast. + // HTLC success transaction to be offered to the sweeper. + ht.AssertNumPendingSweeps(carol, 1) + + // Mine a block to trigger the sweep. + ht.MineEmptyBlocks(1) ht.Miner.AssertNumTxsInMempool(1) // Restart Bob. Once he finishes syncing the channel state, he should @@ -2240,7 +2423,7 @@ func runExtraPreimageFromLocalCommit(ht *lntest.HarnessTest, Hash: payHash[:], RouteHints: routeHints, } - eveInvoice := carol.RPC.AddHoldInvoice(invoiceReq) + carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq) // Subscribe the invoice. stream := carol.RPC.SubscribeSingleInvoice(payHash[:]) @@ -2249,7 +2432,7 @@ func runExtraPreimageFromLocalCommit(ht *lntest.HarnessTest, // Alice to Carol. We won't wait for the response however, as Carol // will not immediately settle the payment. req := &routerrpc.SendPaymentRequest{ - PaymentRequest: eveInvoice.PaymentRequest, + PaymentRequest: carolInvoice.PaymentRequest, TimeoutSeconds: 60, FeeLimitMsat: noFeeLimitMsat, } @@ -2302,8 +2485,32 @@ func runExtraPreimageFromLocalCommit(ht *lntest.HarnessTest, invoiceReq.CltvExpiry - lncfg.DefaultIncomingBroadcastDelta - 1, )) + blocksMined := 0 + + // If this is a nont script-enforced channel, Bob will be able to sweep + // his commit output after 4 blocks. + if c != lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + // Mine 3 blocks so the output will be offered to the sweeper. + ht.MineBlocks(defaultCSV - 1) + + // Assert the commit output has been offered to the sweeper. + ht.AssertNumPendingSweeps(bob, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) + blocksMined = defaultCSV + } + // Mine empty blocks so it's easier to check Bob's sweeping txes below. - ht.MineEmptyBlocks(int(numBlocks)) + ht.MineEmptyBlocks(int(numBlocks) - blocksMined) + + // With the above blocks mined, we should expect Carol's to offer the + // htlc output on Bob's commitment to the sweeper. + // + // TODO(yy): it's not offered to the sweeper yet, instead, the utxo + // nursery is creating and broadcasting the sweep tx - we should unify + // this behavior and offer it to the sweeper. + // ht.AssertNumPendingSweeps(carol, 1) // Increase the fee rate used by the sweeper so Carol's direct spend tx // won't be replaced by Bob's timeout tx. diff --git a/itest/lnd_onchain_test.go b/itest/lnd_onchain_test.go index 9eac66cc3..dff7f996b 100644 --- a/itest/lnd_onchain_test.go +++ b/itest/lnd_onchain_test.go @@ -280,6 +280,8 @@ func runCPFP(ht *lntest.HarnessTest, alice, bob *node.HarnessNode) { // We use a higher fee rate than the default max and expect the // sweeper to cap the fee rate at the max value. SatPerVbyte: maxFeeRate * 2, + // We use a force param to create the sweeping tx immediately. + Force: true, } bob.RPC.BumpFee(bumpFeeReq) @@ -900,10 +902,14 @@ func testListSweeps(ht *lntest.HarnessTest) { ) // Mine enough blocks for the node to sweep its funds from the force - // closed channel. The commit sweep resolver is able to broadcast the - // sweep tx up to one block before the CSV elapses, so wait until + // closed channel. The commit sweep resolver offers the outputs to the + // sweeper up to one block before the CSV elapses, so wait until // defaulCSV-1. ht.MineEmptyBlocks(node.DefaultCSV - 1) + ht.AssertNumPendingSweeps(alice, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) // Now we can expect that the sweep has been broadcast. pendingTxHash := ht.Miner.AssertNumTxsInMempool(1) diff --git a/itest/lnd_revocation_test.go b/itest/lnd_revocation_test.go index d94fa7c43..2c4f5fd25 100644 --- a/itest/lnd_revocation_test.go +++ b/itest/lnd_revocation_test.go @@ -163,19 +163,23 @@ func breachRetributionTestCase(ht *lntest.HarnessTest, // again. ht.RestartNode(carol) - // Now mine a block, this transaction should include Carol's justice - // transaction which was just accepted into the mempool. - expectedNumTxes := 1 - - // For anchor channels, we'd also create the sweeping transaction. + // For anchor channels, we'd offer the anchor output to the sweeper. if lntest.CommitTypeHasAnchors(commitType) { - expectedNumTxes = 2 + ht.AssertNumPendingSweeps(carol, 1) } - block = ht.MineBlocksAndAssertNumTxes(1, expectedNumTxes)[0] + // Now mine a block, this transaction should include Carol's justice + // transaction which was just accepted into the mempool. + block = ht.MineBlocksAndAssertNumTxes(1, 1)[0] justiceTxid := justiceTx.TxHash() ht.Miner.AssertTxInBlock(block, &justiceTxid) + // The above mined block should trigger the sweeper to sweep the + // anchor. + if lntest.CommitTypeHasAnchors(commitType) { + ht.MineBlocksAndAssertNumTxes(1, 1) + } + ht.AssertNodeNumChannels(carol, 0) // Mine enough blocks for Bob's channel arbitrator to wrap up the @@ -354,19 +358,24 @@ func revokedCloseRetributionZeroValueRemoteOutputCase(ht *lntest.HarnessTest, // the justice transaction to confirm again. ht.RestartNode(dave) - // Now mine a block, this transaction should include Dave's justice - // transaction which was just accepted into the mempool. - expectedNumTxes := 1 - // For anchor channels, we'd also create the sweeping transaction. if lntest.CommitTypeHasAnchors(commitType) { - expectedNumTxes = 2 + ht.AssertNumPendingSweeps(dave, 1) } - block := ht.MineBlocksAndAssertNumTxes(1, expectedNumTxes)[0] + // Now mine a block, this transaction should include Dave's justice + // transaction which was just accepted into the mempool. + block := ht.MineBlocksAndAssertNumTxes(1, 1)[0] justiceTxid := justiceTx.TxHash() ht.Miner.AssertTxInBlock(block, &justiceTxid) + // The above mined block should trigger the sweeper to sweep the + // anchor. + if lntest.CommitTypeHasAnchors(commitType) { + ht.MineBlocksAndAssertNumTxes(1, 1) + } + + // At this point, Dave should have no pending channels. ht.AssertNodeNumChannels(dave, 0) } @@ -676,16 +685,20 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest, // waiting for the justice transaction to confirm again. ht.RestartNode(dave) - // Now mine a block, this transaction should include Dave's justice - // transaction which was just accepted into the mempool. - expectedNumTxes := 1 - // For anchor channels, we'd also create the sweeping transaction. if lntest.CommitTypeHasAnchors(commitType) { - expectedNumTxes = 2 + ht.AssertNumPendingSweeps(dave, 1) } - ht.MineBlocksAndAssertNumTxes(1, expectedNumTxes) + // Now mine a block, this transaction should include Dave's justice + // transaction which was just accepted into the mempool. + ht.MineBlocksAndAssertNumTxes(1, 1) + + // The above mined block should trigger the sweeper to sweep the + // anchor. + if lntest.CommitTypeHasAnchors(commitType) { + ht.MineBlocksAndAssertNumTxes(1, 1) + } // Dave should have no open channels. ht.AssertNodeNumChannels(dave, 0) diff --git a/itest/lnd_watchtower_test.go b/itest/lnd_watchtower_test.go index e97e604f4..af44f7b0f 100644 --- a/itest/lnd_watchtower_test.go +++ b/itest/lnd_watchtower_test.go @@ -581,6 +581,12 @@ func testRevokedCloseRetributionAltruistWatchtowerCase(ht *lntest.HarnessTest, // If this is an anchor channel, Dave would sweep the anchor. if lntest.CommitTypeHasAnchors(commitType) { + ht.AssertNumPendingSweeps(dave, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) + + // Mine a block to confirm the sweep. ht.MineBlocksAndAssertNumTxes(1, 1) } diff --git a/itest/lnd_wipe_fwdpkgs_test.go b/itest/lnd_wipe_fwdpkgs_test.go index a3632914b..cee1d8e76 100644 --- a/itest/lnd_wipe_fwdpkgs_test.go +++ b/itest/lnd_wipe_fwdpkgs_test.go @@ -114,6 +114,12 @@ func testWipeForwardingPackages(ht *lntest.HarnessTest) { pendingAB = pending.Channel require.Zero(ht, pendingAB.NumForwardingPackages) + // Alice should one pending sweep. + ht.AssertNumPendingSweeps(alice, 1) + + // Mine a block to trigger the sweep. + ht.MineBlocks(1) + // Mine 1 block to get Alice's sweeping tx confirmed. ht.MineBlocksAndAssertNumTxes(1, 1) diff --git a/lntest/harness.go b/lntest/harness.go index 6e0da417d..6960d06e1 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -1579,14 +1579,20 @@ func (h *HarnessTest) CleanupForceClose(hn *node.HarnessNode) { h.AssertNumPendingForceClose(hn, 1) // Mine enough blocks for the node to sweep its funds from the force - // closed channel. The commit sweep resolver is able to broadcast the - // sweep tx up to one block before the CSV elapses, so wait until - // defaulCSV-1. + // closed channel. The commit sweep resolver is able to offer the input + // to the sweeper at defaulCSV-1, and broadcast the sweep tx once one + // more block is mined. // // NOTE: we might empty blocks here as we don't know the exact number // of blocks to mine. This may end up mining more blocks than needed. h.MineEmptyBlocks(node.DefaultCSV - 1) + // Assert there is one pending sweep. + h.AssertNumPendingSweeps(hn, 1) + + // Mine a block to trigger the sweep. + h.MineEmptyBlocks(1) + // The node should now sweep the funds, clean up by mining the sweeping // tx. h.MineBlocksAndAssertNumTxes(1, 1) diff --git a/lntest/harness_assertion.go b/lntest/harness_assertion.go index 2f4ebeb7f..042cf3240 100644 --- a/lntest/harness_assertion.go +++ b/lntest/harness_assertion.go @@ -2591,3 +2591,20 @@ func (h *HarnessTest) AssertWalletLockedBalance(hn *node.HarnessNode, require.NoError(h, err, "%s: timeout checking locked balance", hn.Name()) } + +// AssertNumPendingSweeps asserts the number of pending sweeps for the given +// node. +func (h *HarnessTest) AssertNumPendingSweeps(hn *node.HarnessNode, n int) { + err := wait.NoError(func() error { + resp := hn.RPC.PendingSweeps() + num := len(resp.PendingSweeps) + + if num == n { + return nil + } + + return fmt.Errorf("want %d , got %d", n, num) + }, DefaultTimeout) + + require.NoErrorf(h, err, "%s: check pending sweeps timeout", hn.Name()) +} diff --git a/lntest/node/config.go b/lntest/node/config.go index 5a7013a21..d0de2fdd4 100644 --- a/lntest/node/config.go +++ b/lntest/node/config.go @@ -199,7 +199,7 @@ func (cfg *BaseNodeConfig) GenArgs() []string { nodeArgs := []string{ "--nobootstrap", - "--debuglevel=debug,DISC=trace", + "--debuglevel=debug", "--bitcoin.defaultchanconfs=1", "--accept-keysend", "--keep-failed-payment-attempts", @@ -217,10 +217,6 @@ func (cfg *BaseNodeConfig) GenArgs() []string { fmt.Sprintf("--trickledelay=%v", trickleDelay), fmt.Sprintf("--profile=%d", cfg.ProfilePort), - // Use a small batch window so we can broadcast our sweep - // transactions faster. - "--sweeper.batchwindowduration=5s", - // Use a small batch delay so we can broadcast the // announcements quickly in the tests. "--gossip.sub-batch-delay=5ms",