From 4079f61d7e4aa207f16b603f9ebf0b667f72e4bb Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 May 2024 23:22:19 +0800 Subject: [PATCH] itest+sweep: fix current itest re anchor deadline --- itest/lnd_channel_force_close_test.go | 91 ++++++++++----------------- itest/lnd_multi-hop_test.go | 28 +++++---- itest/lnd_sweep_test.go | 16 ++--- sweep/fee_bumper.go | 4 +- 4 files changed, 59 insertions(+), 80 deletions(-) diff --git a/itest/lnd_channel_force_close_test.go b/itest/lnd_channel_force_close_test.go index dc28f034b..11dcd0acb 100644 --- a/itest/lnd_channel_force_close_test.go +++ b/itest/lnd_channel_force_close_test.go @@ -216,34 +216,17 @@ func channelForceClosureTest(ht *lntest.HarnessTest, // We expect to see Alice's force close tx in the mempool. ht.Miner.GetNumTxsFromMempool(1) - // Assert Alice's has the pending anchor outputs - one for local and - // the other for remote (invalid). - sweeps := ht.AssertNumPendingSweeps(alice, 2) - aliceAnchor := sweeps[0] - if aliceAnchor.Outpoint.TxidStr != waitingClose.Commitments.LocalTxid { - aliceAnchor = sweeps[1] - } - require.Equal(ht, aliceAnchor.Outpoint.TxidStr, - waitingClose.Commitments.LocalTxid) - // Mine a block which should confirm the commitment transaction // broadcast as a result of the force closure. Once mined, we also // expect Alice's anchor sweeping tx being published. ht.MineBlocksAndAssertNumTxes(1, 1) - // Assert Alice's anchor sweeping tx is found in the mempool. - aliceSweepTxid := ht.Miner.AssertNumTxsInMempool(1)[0] - - // Add alice's anchor to our expected set of reports. - op := fmt.Sprintf("%v:%v", aliceAnchor.Outpoint.TxidStr, - aliceAnchor.Outpoint.OutputIndex) - aliceReports[op] = &lnrpc.Resolution{ - ResolutionType: lnrpc.ResolutionType_ANCHOR, - Outcome: lnrpc.ResolutionOutcome_CLAIMED, - SweepTxid: aliceSweepTxid.String(), - Outpoint: aliceAnchor.Outpoint, - AmountSat: uint64(anchorSize), - } + // 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] + require.Equal(ht, aliceAnchor.Outpoint.TxidStr, + waitingClose.Commitments.LocalTxid) // Now that the commitment has been confirmed, the channel should be // marked as force closed. @@ -290,10 +273,8 @@ func channelForceClosureTest(ht *lntest.HarnessTest, } // Mine a block to trigger Carol's sweeper to make decisions on the - // anchor sweeping. This block will also confirm Alice's anchor - // sweeping tx as her anchor is used for CPFP due to there are - // time-sensitive HTLCs. - ht.MineBlocksAndAssertNumTxes(1, 1) + // anchor sweeping. + ht.MineEmptyBlocks(1) // Carol's sweep tx should be in the mempool already, as her output is // not timelocked. @@ -307,7 +288,7 @@ func channelForceClosureTest(ht *lntest.HarnessTest, totalFeeCarol := ht.CalculateTxFee(carolTx) // If we have anchors, add an anchor resolution for carol. - op = fmt.Sprintf("%v:%v", carolAnchor.Outpoint.TxidStr, + op := fmt.Sprintf("%v:%v", carolAnchor.Outpoint.TxidStr, carolAnchor.Outpoint.OutputIndex) carolReports[op] = &lnrpc.Resolution{ ResolutionType: lnrpc.ResolutionType_ANCHOR, @@ -336,27 +317,8 @@ func channelForceClosureTest(ht *lntest.HarnessTest, // commit and anchor outputs. ht.MineBlocksAndAssertNumTxes(1, 1) - // Once Alice's anchor sweeping is mined, she should have no pending - // sweep requests atm. - ht.AssertNumPendingSweeps(alice, 0) - - // TODO(yy): fix the case in 0.18.1 - the CPFP anchor sweeping may be - // replaced with a following request after the above restart - the - // anchor will be offered to the sweeper again with updated params, - // which cannot be swept due to it being uneconomical. - var anchorRecovered bool - err = wait.NoError(func() error { - sweepResp := alice.RPC.ListSweeps(false, 0) - txns := sweepResp.GetTransactionIds().TransactionIds - - if len(txns) >= 1 { - anchorRecovered = true - return nil - } - - return fmt.Errorf("expected 1 sweep tx, got %d", len(txns)) - }, wait.DefaultTimeout) - ht.Logf("waiting for Alice's anchor sweep to be broadcast: %v", err) + // Alice should still have the anchor sweeping request. + ht.AssertNumPendingSweeps(alice, 1) // The following restart checks to ensure that outputs in the // kindergarten bucket are persisted while waiting for the required @@ -399,12 +361,8 @@ func channelForceClosureTest(ht *lntest.HarnessTest, return errors.New("all funds should still be in " + "limbo") } - if !anchorRecovered { - return nil - } - if forceClose.RecoveredBalance != anchorSize { - return fmt.Errorf("expected %v to be recovered", - anchorSize) + if forceClose.RecoveredBalance != 0 { + return errors.New("no funds should be recovered") } return nil @@ -417,7 +375,11 @@ func channelForceClosureTest(ht *lntest.HarnessTest, // At this point, the CSV will expire in the next block, meaning that // the output should be offered to the sweeper. - aliceCommit := ht.AssertNumPendingSweeps(alice, 1)[0] + sweeps := ht.AssertNumPendingSweeps(alice, 2) + commitSweep, anchorSweep := sweeps[0], sweeps[1] + if commitSweep.AmountSat < anchorSweep.AmountSat { + commitSweep, anchorSweep = anchorSweep, commitSweep + } // Restart Alice to ensure that she resumes watching the finalized // commitment sweep txid. @@ -438,16 +400,27 @@ func channelForceClosureTest(ht *lntest.HarnessTest, } // We expect a resolution which spends our commit output. - op = fmt.Sprintf("%v:%v", aliceCommit.Outpoint.TxidStr, - aliceCommit.Outpoint.OutputIndex) + op = fmt.Sprintf("%v:%v", commitSweep.Outpoint.TxidStr, + commitSweep.Outpoint.OutputIndex) aliceReports[op] = &lnrpc.Resolution{ ResolutionType: lnrpc.ResolutionType_COMMIT, Outcome: lnrpc.ResolutionOutcome_CLAIMED, SweepTxid: sweepingTXID.String(), - Outpoint: aliceCommit.Outpoint, + Outpoint: commitSweep.Outpoint, AmountSat: uint64(aliceBalance), } + // Add alice's anchor to our expected set of reports. + op = fmt.Sprintf("%v:%v", aliceAnchor.Outpoint.TxidStr, + aliceAnchor.Outpoint.OutputIndex) + aliceReports[op] = &lnrpc.Resolution{ + ResolutionType: lnrpc.ResolutionType_ANCHOR, + Outcome: lnrpc.ResolutionOutcome_CLAIMED, + SweepTxid: sweepingTXID.String(), + Outpoint: aliceAnchor.Outpoint, + AmountSat: uint64(anchorSize), + } + // Check that we can find the commitment sweep in our set of known // sweeps, using the simple transaction id ListSweeps output. ht.AssertSweepFound(alice, sweepingTXID.String(), false, 0) diff --git a/itest/lnd_multi-hop_test.go b/itest/lnd_multi-hop_test.go index fa4590d04..7ff9f48b4 100644 --- a/itest/lnd_multi-hop_test.go +++ b/itest/lnd_multi-hop_test.go @@ -713,9 +713,11 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, // to be mined to trigger a force close later on. var blocksMined uint32 - // Increase the fee estimate so that the following force close tx will - // be cpfp'ed. - ht.SetFeeEstimate(30000) + // We need to mine a block otherwise `FindOutgoingHTLCDeadline` cannot + // find the incoming HTLC on Bob's ChainArbitrator. + // + // TODO(yy): Investigate and fix it! + ht.MineEmptyBlocks(1) // Now that all parties have the HTLC locked in, we'll immediately // force close the Bob -> Carol channel. This should trigger contract @@ -755,7 +757,7 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, ht.MineEmptyBlocks(int(defaultCSV - blocksMined)) blocksMined = defaultCSV - // Assert Bob has the sweep and trigger it.. + // Assert Bob has the sweep and trigger it. ht.AssertNumPendingSweeps(bob, 1) ht.MineEmptyBlocks(1) blocksMined++ @@ -1523,10 +1525,6 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, ht.AssertNumPendingSweeps(bob, 1) ht.AssertNumPendingSweeps(alice, 1) - // Mine a block to confirm Alice's CPFP anchor sweeping. - ht.MineBlocksAndAssertNumTxes(1, 1) - blocksMined++ - // Mine enough blocks for Alice to sweep her funds from the force // closed channel. AssertStreamChannelForceClosed() already mined a // block containing the commitment tx and the commit sweep tx will be @@ -1537,7 +1535,7 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, blocksMined = defaultCSV // Alice should now sweep her funds. - ht.AssertNumPendingSweeps(alice, 1) + ht.AssertNumPendingSweeps(alice, 2) // Mine a block to trigger the sweep. ht.MineEmptyBlocks(1) @@ -1690,7 +1688,7 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, ht.MineEmptyBlocks(numBlocks) // Both Alice and Bob should offer their commit sweeps. - ht.AssertNumPendingSweeps(alice, 1) + ht.AssertNumPendingSweeps(alice, 2) ht.AssertNumPendingSweeps(bob, 1) // Mine a block to trigger the sweeps. @@ -2472,7 +2470,6 @@ func runExtraPreimageFromRemoteCommit(ht *lntest.HarnessTest, if ht.IsNeutrinoBackend() { // Mine a block to confirm Carol's 2nd level success tx. ht.MineBlocksAndAssertNumTxes(1, 1) - numTxesMempool-- numBlocks-- } @@ -2503,6 +2500,15 @@ func runExtraPreimageFromRemoteCommit(ht *lntest.HarnessTest, case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: } + // For neutrino backend, Carol's second-stage sweep should be offered + // to her sweeper. + if ht.IsNeutrinoBackend() { + ht.AssertNumPendingSweeps(carol, 1) + + // Mine a block to trigger the sweep. + ht.MineEmptyBlocks(1) + } + // Mine a block to clean the mempool. ht.MineBlocksAndAssertNumTxes(1, numTxesMempool) diff --git a/itest/lnd_sweep_test.go b/itest/lnd_sweep_test.go index b79dda521..4702def38 100644 --- a/itest/lnd_sweep_test.go +++ b/itest/lnd_sweep_test.go @@ -874,9 +874,6 @@ func testSweepHTLCs(ht *lntest.HarnessTest) { )) ht.MineBlocks(numBlocks) - // Bob force closes the channel. - // ht.CloseChannelAssertPending(bob, bcChanPoint, true) - // Before we mine empty blocks to check the RBF behavior, we need to be // aware that Bob's incoming HTLC will expire before his outgoing HTLC // deadline is reached. This happens because the incoming HTLC is sent @@ -944,7 +941,7 @@ func testSweepHTLCs(ht *lntest.HarnessTest) { // Now the start fee rate is checked, we can calculate the fee rate // delta. outgoingFeeRateDelta := (outgoingEndFeeRate - outgoingStartFeeRate) / - chainfee.SatPerKWeight(outgoingHTLCDeadline) + chainfee.SatPerKWeight(outgoingHTLCDeadline-1) // outgoingFuncPosition records the position of Bob's fee function used // for his outgoing HTLC sweeping tx. @@ -1083,7 +1080,7 @@ func testSweepHTLCs(ht *lntest.HarnessTest) { // Now the start fee rate is checked, we can calculate the fee rate // delta. incomingFeeRateDelta := (incomingEndFeeRate - incomingStartFeeRate) / - chainfee.SatPerKWeight(incomingHTLCDeadline) + chainfee.SatPerKWeight(incomingHTLCDeadline-1) // incomingFuncPosition records the position of Bob's fee function used // for his incoming HTLC sweeping tx. @@ -1143,7 +1140,10 @@ func testSweepHTLCs(ht *lntest.HarnessTest) { // We now mine enough blocks till we reach the end of the outgoing // HTLC's deadline. Along the way, we check the expected fee rates are // used for both incoming and outgoing HTLC sweeping txns. - blocksLeft := outgoingHTLCDeadline - outgoingFuncPosition + // + // NOTE: We need to subtract 1 from the deadline as the budget must be + // used up before the deadline. + blocksLeft := outgoingHTLCDeadline - outgoingFuncPosition - 1 for i := int32(0); i < blocksLeft; i++ { // Mine an empty block. ht.MineEmptyBlocks(1) @@ -1418,7 +1418,7 @@ func testSweepCommitOutputAndAnchor(ht *lntest.HarnessTest) { bobTxWeight := uint64(ht.CalculateTxWeight(bobSweepTx)) bobEndingFeeRate := chainfee.NewSatPerKWeight(bobBudget, bobTxWeight) bobFeeRateDelta := (bobEndingFeeRate - bobStartFeeRate) / - chainfee.SatPerKWeight(deadlineB) + chainfee.SatPerKWeight(deadlineB-1) // Mine an empty block, which should trigger Alice's contractcourt to // offer her commit output to the sweeper. @@ -1550,7 +1550,7 @@ func testSweepCommitOutputAndAnchor(ht *lntest.HarnessTest) { aliceTxWeight := uint64(ht.CalculateTxWeight(aliceSweepTx)) aliceEndingFeeRate := sweep.DefaultMaxFeeRate.FeePerKWeight() aliceFeeRateDelta := (aliceEndingFeeRate - aliceStartingFeeRate) / - chainfee.SatPerKWeight(deadlineA) + chainfee.SatPerKWeight(deadlineA-1) aliceFeeRate := ht.CalculateTxFeeRate(aliceSweepTx) expectedFeeRateAlice := aliceStartingFeeRate + diff --git a/sweep/fee_bumper.go b/sweep/fee_bumper.go index a0e558cbb..dd471efff 100644 --- a/sweep/fee_bumper.go +++ b/sweep/fee_bumper.go @@ -1216,8 +1216,8 @@ func (t *TxPublisher) createSweepTx(inputs []input.Input, changePkScript []byte, } } - log.Debugf("Created sweep tx %v for %v inputs", sweepTx.TxHash(), - len(inputs)) + log.Debugf("Created sweep tx %v for inputs:\n%v", sweepTx.TxHash(), + inputTypeSummary(inputs)) return sweepTx, txFee, nil }