diff --git a/itest/lnd_onchain_test.go b/itest/lnd_onchain_test.go index efd541bd3..d5d0a19f2 100644 --- a/itest/lnd_onchain_test.go +++ b/itest/lnd_onchain_test.go @@ -868,27 +868,33 @@ func testListSweeps(ht *lntest.HarnessTest) { ht.AssertNumTxsInMempool(1) // List all unconfirmed sweeps that alice's node had broadcast. - sweepResp := alice.RPC.ListSweeps(false, -1) - txIDs := sweepResp.GetTransactionIds().TransactionIds - require.Lenf(ht, txIDs, 1, "number of pending sweeps, starting from "+ - "height -1") + req1 := &walletrpc.ListSweepsRequest{ + Verbose: false, + StartHeight: -1, + } + ht.AssertNumSweeps(alice, req1, 1) // Now list sweeps from the closing of the first channel. We should // only see the sweep from the second channel and the pending one. - sweepResp = alice.RPC.ListSweeps(false, blockHeight) - txIDs = sweepResp.GetTransactionIds().TransactionIds - require.Lenf(ht, txIDs, 2, "number of sweeps, starting from height %d", - blockHeight) + req2 := &walletrpc.ListSweepsRequest{ + Verbose: false, + StartHeight: blockHeight, + } + ht.AssertNumSweeps(alice, req2, 2) // Finally list all sweeps from the closing of the second channel. We // should see all sweeps, including the pending one. - sweepResp = alice.RPC.ListSweeps(false, 0) - txIDs = sweepResp.GetTransactionIds().TransactionIds - require.Lenf(ht, txIDs, 3, "number of sweeps, starting from height 0") + req3 := &walletrpc.ListSweepsRequest{ + Verbose: false, + StartHeight: 0, + } + ht.AssertNumSweeps(alice, req3, 3) // Mine the pending sweep and make sure it is no longer returned. ht.MineBlocksAndAssertNumTxes(1, 1) - sweepResp = alice.RPC.ListSweeps(false, -1) - txIDs = sweepResp.GetTransactionIds().TransactionIds - require.Empty(ht, txIDs, "pending sweep should not be returned") + req4 := &walletrpc.ListSweepsRequest{ + Verbose: false, + StartHeight: -1, + } + ht.AssertNumSweeps(alice, req4, 0) } diff --git a/lntest/harness.go b/lntest/harness.go index 1d6aff553..cf948254b 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -2059,9 +2059,14 @@ func (h *HarnessTest) CalculateTxesFeeRate(txns []*wire.MsgTx) int64 { func (h *HarnessTest) AssertSweepFound(hn *node.HarnessNode, sweep string, verbose bool, startHeight int32) { + req := &walletrpc.ListSweepsRequest{ + Verbose: verbose, + StartHeight: startHeight, + } + err := wait.NoError(func() error { // List all sweeps that alice's node had broadcast. - sweepResp := hn.RPC.ListSweeps(verbose, startHeight) + sweepResp := hn.RPC.ListSweeps(req) var found bool if verbose { diff --git a/lntest/harness_assertion.go b/lntest/harness_assertion.go index 5a598033a..544576bef 100644 --- a/lntest/harness_assertion.go +++ b/lntest/harness_assertion.go @@ -2817,6 +2817,54 @@ func (h *HarnessTest) AssertAtLeastNumPendingSweeps(hn *node.HarnessNode, return results } +// AssertNumSweeps asserts the number of sweeps for the given node. +func (h *HarnessTest) AssertNumSweeps(hn *node.HarnessNode, + req *walletrpc.ListSweepsRequest, + n int) *walletrpc.ListSweepsResponse { + + var result *walletrpc.ListSweepsResponse + + // The ListSweeps call is wrapped in wait.NoError to handle potential + // timing issues. Sweep transactions might not be immediately reflected + // or processed by the node after an event (e.g., channel closure or + // block mining) due to propagation or processing delays. This ensures + // the system retries the call until the expected sweep is found, + // preventing test flakes caused by race conditions. + err := wait.NoError(func() error { + resp := hn.RPC.ListSweeps(req) + + var txIDs []string + if req.Verbose { + details := resp.GetTransactionDetails() + if details != nil { + for _, tx := range details.Transactions { + txIDs = append(txIDs, tx.TxHash) + } + } + } else { + ids := resp.GetTransactionIds() + if ids != nil { + txIDs = ids.TransactionIds + } + } + + num := len(txIDs) + + // Exit early if the num matches. + if num == n { + result = resp + return nil + } + + return fmt.Errorf("want %d, got %d, sweeps: %v, req: %v", n, + num, txIDs, req) + }, DefaultTimeout) + + require.NoErrorf(h, err, "%s: check num of sweeps timeout", hn.Name()) + + return result +} + // 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/lntest/rpc/wallet_kit.go b/lntest/rpc/wallet_kit.go index 02e449cd8..ffa5acdd0 100644 --- a/lntest/rpc/wallet_kit.go +++ b/lntest/rpc/wallet_kit.go @@ -169,16 +169,12 @@ func (h *HarnessRPC) VerifyMessageWithAddr( } // ListSweeps makes a ListSweeps RPC call to the node's WalletKit client. -func (h *HarnessRPC) ListSweeps(verbose bool, - startHeight int32) *walletrpc.ListSweepsResponse { +func (h *HarnessRPC) ListSweeps( + req *walletrpc.ListSweepsRequest) *walletrpc.ListSweepsResponse { ctxt, cancel := context.WithTimeout(h.runCtx, DefaultTimeout) defer cancel() - req := &walletrpc.ListSweepsRequest{ - Verbose: verbose, - StartHeight: startHeight, - } resp, err := h.WalletKit.ListSweeps(ctxt, req) h.NoError(err, "ListSweeps")