From 2c27df6c30d743d6a54133c32ca3d4f1781c9cda Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 26 Oct 2024 03:29:12 +0800 Subject: [PATCH 01/64] itest: print num of blocks for debugging --- itest/lnd_test.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/itest/lnd_test.go b/itest/lnd_test.go index 5b9105694d..cb0871b963 100644 --- a/itest/lnd_test.go +++ b/itest/lnd_test.go @@ -106,6 +106,9 @@ func TestLightningNetworkDaemon(t *testing.T) { // among all the test cases. harnessTest.SetupStandbyNodes() + // Get the current block height. + height := harnessTest.CurrentHeight() + // Run the subset of the test cases selected in this tranche. for idx, testCase := range testCases { testCase := testCase @@ -151,9 +154,10 @@ func TestLightningNetworkDaemon(t *testing.T) { } } - height := harnessTest.CurrentHeight() - t.Logf("=========> tests finished for tranche: %v, tested %d "+ - "cases, end height: %d\n", trancheIndex, len(testCases), height) + //nolint:forbidigo + fmt.Printf("=========> tranche %v finished, tested %d cases, mined "+ + "blocks: %d\n", trancheIndex, len(testCases), + harnessTest.CurrentHeight()-height) } // getTestCaseSplitTranche returns the sub slice of the test cases that should From 88bd0cb806faafacc6df4356cd40c916977e2151 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 25 Oct 2024 03:33:37 +0800 Subject: [PATCH 02/64] itest: shuffle test cases to even out blocks mined in tranches This commit adds a new flag to shuffle all the test cases before running them so tests which require lots of blocks to be mined are less likely to be run in the same tranch. The other benefit is this approach provides a more efficient way to figure which tests are broken since all the differnet backends are running different tranches in their builds, we can identify more failed tests in one push. --- Makefile | 4 ++-- itest/list_on_test.go | 4 +++- itest/lnd_test.go | 37 +++++++++++++++++++++++++++++++++++++ make/testing_flags.mk | 6 ++++++ scripts/itest_parallel.sh | 7 ++++--- scripts/itest_part.sh | 10 +++++----- 6 files changed, 57 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 6b28bcc491..2f0c8c9bae 100644 --- a/Makefile +++ b/Makefile @@ -220,7 +220,7 @@ clean-itest-logs: itest-only: clean-itest-logs db-instance @$(call print, "Running integration tests with ${backend} backend.") date - EXEC_SUFFIX=$(EXEC_SUFFIX) scripts/itest_part.sh 0 1 $(TEST_FLAGS) $(ITEST_FLAGS) -test.v + EXEC_SUFFIX=$(EXEC_SUFFIX) scripts/itest_part.sh 0 1 $(SHUFFLE_SEED) $(TEST_FLAGS) $(ITEST_FLAGS) -test.v $(COLLECT_ITEST_COVERAGE) #? itest: Build and run integration tests @@ -233,7 +233,7 @@ itest-race: build-itest-race itest-only itest-parallel: clean-itest-logs build-itest db-instance @$(call print, "Running tests") date - EXEC_SUFFIX=$(EXEC_SUFFIX) scripts/itest_parallel.sh $(ITEST_PARALLELISM) $(NUM_ITEST_TRANCHES) $(TEST_FLAGS) $(ITEST_FLAGS) + EXEC_SUFFIX=$(EXEC_SUFFIX) scripts/itest_parallel.sh $(ITEST_PARALLELISM) $(NUM_ITEST_TRANCHES) $(SHUFFLE_SEED) $(TEST_FLAGS) $(ITEST_FLAGS) $(COLLECT_ITEST_COVERAGE) #? itest-clean: Kill all running itest processes diff --git a/itest/list_on_test.go b/itest/list_on_test.go index a192a423f4..67915dee8f 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -2,7 +2,9 @@ package itest -import "github.com/lightningnetwork/lnd/lntest" +import ( + "github.com/lightningnetwork/lnd/lntest" +) var allTestCases = []*lntest.TestCase{ { diff --git a/itest/lnd_test.go b/itest/lnd_test.go index cb0871b963..f2a345fa11 100644 --- a/itest/lnd_test.go +++ b/itest/lnd_test.go @@ -20,6 +20,7 @@ import ( "github.com/lightningnetwork/lnd/lntest/port" "github.com/lightningnetwork/lnd/lntest/wait" "github.com/stretchr/testify/require" + "golang.org/x/exp/rand" "google.golang.org/grpc/grpclog" ) @@ -61,6 +62,13 @@ var ( "0-based index specified by the -runtranche flag", ) + // shuffleSeedFlag is the source of randomness used to shuffle the test + // cases. If not specified, the test cases won't be shuffled. + shuffleSeedFlag = flag.Uint64( + "shuffleseed", 0, "if set, shuffles the test cases using this "+ + "as the source of randomness", + ) + // testCasesRunTranche is the 0-based index of the split test cases // tranche to run in the current invocation. testCasesRunTranche = flag.Uint( @@ -160,6 +168,32 @@ func TestLightningNetworkDaemon(t *testing.T) { harnessTest.CurrentHeight()-height) } +// maybeShuffleTestCases shuffles the test cases if the flag `shuffleseed` is +// set and not 0. In parallel tests we want to shuffle the test cases so they +// are executed in a random order. This is done to even out the blocks mined in +// each test tranche so they can run faster. +// +// NOTE: Because the parallel tests are initialized with the same seed (job +// ID), they will always have the same order. +func maybeShuffleTestCases() { + // Exit if not set. + if shuffleSeedFlag == nil { + return + } + + // Exit if set to 0. + if *shuffleSeedFlag == 0 { + return + } + + // Init the seed and shuffle the test cases. + rand.Seed(*shuffleSeedFlag) + rand.Shuffle(len(allTestCases), func(i, j int) { + allTestCases[i], allTestCases[j] = + allTestCases[j], allTestCases[i] + }) +} + // getTestCaseSplitTranche returns the sub slice of the test cases that should // be run as the current split tranche as well as the index and slice offset of // the tranche. @@ -182,6 +216,9 @@ func getTestCaseSplitTranche() ([]*lntest.TestCase, uint, uint) { runTranche = 0 } + // Shuffle the test cases if the `shuffleseed` flag is set. + maybeShuffleTestCases() + numCases := uint(len(allTestCases)) testsPerTranche := numCases / numTranches trancheOffset := runTranche * testsPerTranche diff --git a/make/testing_flags.mk b/make/testing_flags.mk index b2db6861c3..ba5b3fb378 100644 --- a/make/testing_flags.mk +++ b/make/testing_flags.mk @@ -10,6 +10,7 @@ COVER_PKG = $$(go list -deps -tags="$(DEV_TAGS)" ./... | grep '$(PKG)' | grep -v NUM_ITEST_TRANCHES = 4 ITEST_PARALLELISM = $(NUM_ITEST_TRANCHES) POSTGRES_START_DELAY = 5 +SHUFFLE_SEED = 0 # If rpc option is set also add all extra RPC tags to DEV_TAGS ifneq ($(with-rpc),) @@ -27,6 +28,11 @@ ifneq ($(parallel),) ITEST_PARALLELISM = $(parallel) endif +# Set the seed for shuffling the test cases. +ifneq ($(shuffleseed),) +SHUFFLE_SEED = $(shuffleseed) +endif + # Windows needs to append a .exe suffix to all executable files, otherwise it # won't run them. ifneq ($(windows),) diff --git a/scripts/itest_parallel.sh b/scripts/itest_parallel.sh index 2ae7f3f531..ab1b3efa28 100755 --- a/scripts/itest_parallel.sh +++ b/scripts/itest_parallel.sh @@ -3,9 +3,10 @@ # Get all the variables. PROCESSES=$1 TRANCHES=$2 +SHUFFLE_SEED=$3 -# Here we also shift 2 times and get the rest of our flags to pass on in $@. -shift 2 +# Here we also shift 3 times and get the rest of our flags to pass on in $@. +shift 3 # Create a variable to hold the final exit code. exit_code=0 @@ -13,7 +14,7 @@ exit_code=0 # Run commands using xargs in parallel and capture their PIDs pids=() for ((i=0; i Date: Thu, 7 Nov 2024 12:50:40 +0800 Subject: [PATCH 03/64] workflows: pass action ID as the shuffle seed To make sure each run is shuffled, we use the action ID as the seed. --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c89df089d3..ad5748e5c3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -316,7 +316,7 @@ jobs: run: ./scripts/install_bitcoind.sh $BITCOIN_VERSION - name: run ${{ matrix.name }} - run: make itest-parallel tranches=${{ env.TRANCHES }} ${{ matrix.args }} + run: make itest-parallel tranches=${{ env.TRANCHES }} ${{ matrix.args }} shuffleseed=${{ github.run_id }}${{ strategy.job-index }} - name: Send coverage if: ${{ contains(matrix.args, 'cover=1') }} @@ -364,7 +364,7 @@ jobs: key-prefix: integration-test - name: run itest - run: make itest-parallel tranches=${{ env.TRANCHES }} windows=1 + run: make itest-parallel tranches=${{ env.TRANCHES }} windows=1 shuffleseed=${{ github.run_id }} - name: kill any remaining lnd processes if: ${{ failure() }} @@ -414,7 +414,7 @@ jobs: mv bitcoin-${BITCOIN_VERSION}.0 /tmp/bitcoin - name: run itest - run: PATH=$PATH:/tmp/bitcoin/bin make itest-parallel tranches=${{ env.TRANCHES }} backend=bitcoind + run: PATH=$PATH:/tmp/bitcoin/bin make itest-parallel tranches=${{ env.TRANCHES }} backend=bitcoind shuffleseed=${{ github.run_id }} - name: Zip log files on failure if: ${{ failure() }} From 3eda87fff95ef25b01436a2a182cfb19981b0824 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 26 Oct 2024 16:24:44 +0800 Subject: [PATCH 04/64] itest: remove direct reference to stanby nodes Prepares the upcoming refactor. We now never call `ht.Alice` directly, instead, we always init `alice := ht.Alice` so it's easier to see how they are removed in a following commit. --- itest/lnd_custom_features.go | 22 +++++----- itest/lnd_estimate_route_fee_test.go | 2 +- itest/lnd_funding_test.go | 6 ++- itest/lnd_misc_test.go | 4 +- itest/lnd_neutrino_test.go | 8 ++-- itest/lnd_onchain_test.go | 20 ++++++--- itest/lnd_open_channel_test.go | 4 +- itest/lnd_psbt_test.go | 41 +++++++++-------- itest/lnd_quiescence_test.go | 4 +- itest/lnd_rest_api_test.go | 4 +- itest/lnd_route_blinding_test.go | 66 ++++++++++++++++------------ itest/lnd_routing_test.go | 12 ++--- itest/lnd_signer_test.go | 12 +++-- itest/lnd_sweep_test.go | 4 +- itest/lnd_taproot_test.go | 34 +++++++------- itest/lnd_watchtower_test.go | 22 ++++++---- 16 files changed, 157 insertions(+), 108 deletions(-) diff --git a/itest/lnd_custom_features.go b/itest/lnd_custom_features.go index 4867ca2d11..c7cec8f1dd 100644 --- a/itest/lnd_custom_features.go +++ b/itest/lnd_custom_features.go @@ -13,6 +13,8 @@ import ( // sets. For completeness, it also asserts that features aren't set in places // where they aren't intended to be. func testCustomFeatures(ht *lntest.HarnessTest) { + alice, bob := ht.Alice, ht.Bob + var ( // Odd custom features so that we don't need to worry about // issues connecting to peers. @@ -27,20 +29,20 @@ func testCustomFeatures(ht *lntest.HarnessTest) { fmt.Sprintf("--protocol.custom-nodeann=%v", customNodeAnn), fmt.Sprintf("--protocol.custom-invoice=%v", customInvoice), } - ht.RestartNodeWithExtraArgs(ht.Alice, extraArgs) + ht.RestartNodeWithExtraArgs(alice, extraArgs) // Connect nodes and open a channel so that Alice will be included // in Bob's graph. - ht.ConnectNodes(ht.Alice, ht.Bob) + ht.ConnectNodes(alice, bob) chanPoint := ht.OpenChannel( - ht.Alice, ht.Bob, lntest.OpenChannelParams{Amt: 1000000}, + alice, bob, lntest.OpenChannelParams{Amt: 1000000}, ) // Check that Alice's custom feature bit was sent to Bob in her init // message. - peers := ht.Bob.RPC.ListPeers() + peers := bob.RPC.ListPeers() require.Len(ht, peers.Peers, 1) - require.Equal(ht, peers.Peers[0].PubKey, ht.Alice.PubKeyStr) + require.Equal(ht, peers.Peers[0].PubKey, alice.PubKeyStr) _, customInitSet := peers.Peers[0].Features[customInit] require.True(ht, customInitSet) @@ -51,7 +53,7 @@ func testCustomFeatures(ht *lntest.HarnessTest) { // Assert that Alice's custom feature bit is contained in the node // announcement sent to Bob. - updates := ht.AssertNumNodeAnns(ht.Bob, ht.Alice.PubKeyStr, 1) + updates := ht.AssertNumNodeAnns(bob, alice.PubKeyStr, 1) features := updates[len(updates)-1].Features _, customFeature := features[customNodeAnn] require.True(ht, customFeature) @@ -60,8 +62,8 @@ func testCustomFeatures(ht *lntest.HarnessTest) { ) // Assert that Alice's custom feature bit is included in invoices. - invoice := ht.Alice.RPC.AddInvoice(&lnrpc.Invoice{}) - payReq := ht.Alice.RPC.DecodePayReq(invoice.PaymentRequest) + invoice := alice.RPC.AddInvoice(&lnrpc.Invoice{}) + payReq := alice.RPC.DecodePayReq(invoice.PaymentRequest) _, customInvoiceSet := payReq.Features[customInvoice] require.True(ht, customInvoiceSet) assertFeatureNotInSet( @@ -79,9 +81,9 @@ func testCustomFeatures(ht *lntest.HarnessTest) { }, }, } - ht.Alice.RPC.UpdateNodeAnnouncementErr(nodeAnnReq) + alice.RPC.UpdateNodeAnnouncementErr(nodeAnnReq) - ht.CloseChannel(ht.Alice, chanPoint) + ht.CloseChannel(alice, chanPoint) } // assertFeatureNotInSet checks that the features provided aren't contained in diff --git a/itest/lnd_estimate_route_fee_test.go b/itest/lnd_estimate_route_fee_test.go index ffff5accaa..0286976851 100644 --- a/itest/lnd_estimate_route_fee_test.go +++ b/itest/lnd_estimate_route_fee_test.go @@ -109,7 +109,7 @@ func testEstimateRouteFee(ht *lntest.HarnessTest) { }, ) - bobsPrivChannels := ht.Bob.RPC.ListChannels(&lnrpc.ListChannelsRequest{ + bobsPrivChannels := mts.bob.RPC.ListChannels(&lnrpc.ListChannelsRequest{ PrivateOnly: true, }) require.Len(ht, bobsPrivChannels.Channels, 1) diff --git a/itest/lnd_funding_test.go b/itest/lnd_funding_test.go index 4c045776e0..5f2c60a1b3 100644 --- a/itest/lnd_funding_test.go +++ b/itest/lnd_funding_test.go @@ -402,14 +402,16 @@ func testUnconfirmedChannelFunding(ht *lntest.HarnessTest) { // testChannelFundingInputTypes tests that any type of supported input type can // be used to fund channels. func testChannelFundingInputTypes(ht *lntest.HarnessTest) { + alice := ht.Alice + // We'll start off by creating a node for Carol. carol := ht.NewNode("Carol", nil) // Now, we'll connect her to Alice so that they can open a // channel together. - ht.ConnectNodes(carol, ht.Alice) + ht.ConnectNodes(carol, alice) - runChannelFundingInputTypes(ht, ht.Alice, carol) + runChannelFundingInputTypes(ht, alice, carol) } // runChannelFundingInputTypes tests that any type of supported input type can diff --git a/itest/lnd_misc_test.go b/itest/lnd_misc_test.go index 33a7067552..21873109ff 100644 --- a/itest/lnd_misc_test.go +++ b/itest/lnd_misc_test.go @@ -763,6 +763,8 @@ func testAbandonChannel(ht *lntest.HarnessTest) { // testSendAllCoins tests that we're able to properly sweep all coins from the // wallet into a single target address at the specified fee rate. func testSendAllCoins(ht *lntest.HarnessTest) { + alice := ht.Alice + // First, we'll make a new node, Ainz who'll we'll use to test wallet // sweeping. // @@ -789,7 +791,7 @@ func testSendAllCoins(ht *lntest.HarnessTest) { // Ensure that we can't send coins to another user's Pubkey. err = ainz.RPC.SendCoinsAssertErr(&lnrpc.SendCoinsRequest{ - Addr: ht.Alice.RPC.GetInfo().IdentityPubkey, + Addr: alice.RPC.GetInfo().IdentityPubkey, SendAll: true, Label: sendCoinsLabel, TargetConf: 6, diff --git a/itest/lnd_neutrino_test.go b/itest/lnd_neutrino_test.go index 2c551362a2..39531bb84c 100644 --- a/itest/lnd_neutrino_test.go +++ b/itest/lnd_neutrino_test.go @@ -13,8 +13,10 @@ func testNeutrino(ht *lntest.HarnessTest) { ht.Skipf("skipping test for non neutrino backends") } + alice := ht.Alice + // Check if the neutrino sub server is running. - statusRes := ht.Alice.RPC.Status(nil) + statusRes := alice.RPC.Status(nil) require.True(ht, statusRes.Active) require.Len(ht, statusRes.Peers, 1, "unable to find a peer") @@ -22,11 +24,11 @@ func testNeutrino(ht *lntest.HarnessTest) { cFilterReq := &neutrinorpc.GetCFilterRequest{ Hash: statusRes.GetBlockHash(), } - ht.Alice.RPC.GetCFilter(cFilterReq) + alice.RPC.GetCFilter(cFilterReq) // Try to reconnect to a connected peer. addPeerReq := &neutrinorpc.AddPeerRequest{ PeerAddrs: statusRes.Peers[0], } - ht.Alice.RPC.AddPeer(addPeerReq) + alice.RPC.AddPeer(addPeerReq) } diff --git a/itest/lnd_onchain_test.go b/itest/lnd_onchain_test.go index a34b9a2e47..704676d56b 100644 --- a/itest/lnd_onchain_test.go +++ b/itest/lnd_onchain_test.go @@ -33,8 +33,10 @@ func testChainKit(ht *lntest.HarnessTest) { // testChainKitGetBlock ensures that given a block hash, the RPC endpoint // returns the correct target block. func testChainKitGetBlock(ht *lntest.HarnessTest) { + alice := ht.Alice + // Get best block hash. - bestBlockRes := ht.Alice.RPC.GetBestBlock(nil) + bestBlockRes := alice.RPC.GetBestBlock(nil) var bestBlockHash chainhash.Hash err := bestBlockHash.SetBytes(bestBlockRes.BlockHash) @@ -44,7 +46,7 @@ func testChainKitGetBlock(ht *lntest.HarnessTest) { getBlockReq := &chainrpc.GetBlockRequest{ BlockHash: bestBlockHash[:], } - getBlockRes := ht.Alice.RPC.GetBlock(getBlockReq) + getBlockRes := alice.RPC.GetBlock(getBlockReq) // Deserialize the block which was retrieved by hash. msgBlock := &wire.MsgBlock{} @@ -61,8 +63,10 @@ func testChainKitGetBlock(ht *lntest.HarnessTest) { // testChainKitGetBlockHeader ensures that given a block hash, the RPC endpoint // returns the correct target block header. func testChainKitGetBlockHeader(ht *lntest.HarnessTest) { + alice := ht.Alice + // Get best block hash. - bestBlockRes := ht.Alice.RPC.GetBestBlock(nil) + bestBlockRes := alice.RPC.GetBestBlock(nil) var ( bestBlockHash chainhash.Hash @@ -76,7 +80,7 @@ func testChainKitGetBlockHeader(ht *lntest.HarnessTest) { getBlockReq := &chainrpc.GetBlockRequest{ BlockHash: bestBlockHash[:], } - getBlockRes := ht.Alice.RPC.GetBlock(getBlockReq) + getBlockRes := alice.RPC.GetBlock(getBlockReq) // Deserialize the block which was retrieved by hash. blockReader := bytes.NewReader(getBlockRes.RawBlock) @@ -87,7 +91,7 @@ func testChainKitGetBlockHeader(ht *lntest.HarnessTest) { getBlockHeaderReq := &chainrpc.GetBlockHeaderRequest{ BlockHash: bestBlockHash[:], } - getBlockHeaderRes := ht.Alice.RPC.GetBlockHeader(getBlockHeaderReq) + getBlockHeaderRes := alice.RPC.GetBlockHeader(getBlockHeaderReq) // Deserialize the block header which was retrieved by hash. blockHeaderReader := bytes.NewReader(getBlockHeaderRes.RawBlockHeader) @@ -104,14 +108,16 @@ func testChainKitGetBlockHeader(ht *lntest.HarnessTest) { // testChainKitGetBlockHash ensures that given a block height, the RPC endpoint // returns the correct target block hash. func testChainKitGetBlockHash(ht *lntest.HarnessTest) { + alice := ht.Alice + // Get best block hash. - bestBlockRes := ht.Alice.RPC.GetBestBlock(nil) + bestBlockRes := alice.RPC.GetBestBlock(nil) // Retrieve the block hash at best block height. req := &chainrpc.GetBlockHashRequest{ BlockHeight: int64(bestBlockRes.BlockHeight), } - getBlockHashRes := ht.Alice.RPC.GetBlockHash(req) + getBlockHashRes := alice.RPC.GetBlockHash(req) // Ensure best block hash is the same as retrieved block hash. expected := bestBlockRes.BlockHash diff --git a/itest/lnd_open_channel_test.go b/itest/lnd_open_channel_test.go index a4134abcaf..b47a766d53 100644 --- a/itest/lnd_open_channel_test.go +++ b/itest/lnd_open_channel_test.go @@ -315,7 +315,9 @@ func testOpenChannelUpdateFeePolicy(ht *lntest.HarnessTest) { // closing, and ensures that if a node is subscribed to channel updates they // will be received correctly for both cooperative and force closed channels. func testBasicChannelCreationAndUpdates(ht *lntest.HarnessTest) { - runBasicChannelCreationAndUpdates(ht, ht.Alice, ht.Bob) + alice, bob := ht.Alice, ht.Bob + + runBasicChannelCreationAndUpdates(ht, alice, bob) } // runBasicChannelCreationAndUpdates tests multiple channel opening and closing, diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go index a774b3aa70..deecbdbf22 100644 --- a/itest/lnd_psbt_test.go +++ b/itest/lnd_psbt_test.go @@ -1088,6 +1088,8 @@ func runFundAndSignPsbt(ht *lntest.HarnessTest, alice *node.HarnessNode) { // a PSBT that already specifies an input but where the user still wants the // wallet to perform coin selection. func testFundPsbt(ht *lntest.HarnessTest) { + alice, bob := ht.Alice, ht.Bob + // We test a pay-join between Alice and Bob. Bob wants to send Alice // 5 million Satoshis in a non-obvious way. So Bob selects a UTXO that's // bigger than 5 million Satoshis and expects the change minus the send @@ -1095,20 +1097,20 @@ func testFundPsbt(ht *lntest.HarnessTest) { // combines her change with the 5 million Satoshis from Bob. With this // Alice ends up paying the fees for a transfer to her. const sendAmount = 5_000_000 - aliceAddr := ht.Alice.RPC.NewAddress(&lnrpc.NewAddressRequest{ + aliceAddr := alice.RPC.NewAddress(&lnrpc.NewAddressRequest{ Type: lnrpc.AddressType_TAPROOT_PUBKEY, }) - bobAddr := ht.Bob.RPC.NewAddress(&lnrpc.NewAddressRequest{ + bobAddr := bob.RPC.NewAddress(&lnrpc.NewAddressRequest{ Type: lnrpc.AddressType_TAPROOT_PUBKEY, }) - ht.Alice.UpdateState() - ht.Bob.UpdateState() - aliceStartBalance := ht.Alice.State.Wallet.TotalBalance - bobStartBalance := ht.Bob.State.Wallet.TotalBalance + alice.UpdateState() + bob.UpdateState() + aliceStartBalance := alice.State.Wallet.TotalBalance + bobStartBalance := bob.State.Wallet.TotalBalance var bobUtxo *lnrpc.Utxo - bobUnspent := ht.Bob.RPC.ListUnspent(&walletrpc.ListUnspentRequest{}) + bobUnspent := bob.RPC.ListUnspent(&walletrpc.ListUnspentRequest{}) for _, utxo := range bobUnspent.Utxos { if utxo.AmountSat > sendAmount { bobUtxo = utxo @@ -1145,7 +1147,7 @@ func testFundPsbt(ht *lntest.HarnessTest) { require.NoError(ht, err) derivation, trDerivation := getAddressBip32Derivation( - ht, bobUtxo.Address, ht.Bob, + ht, bobUtxo.Address, bob, ) bobUtxoPkScript, _ := hex.DecodeString(bobUtxo.PkScript) @@ -1165,31 +1167,31 @@ func testFundPsbt(ht *lntest.HarnessTest) { // We have the template now. Bob basically funds the 5 million Sats to // send to Alice and Alice now only needs to coin select to pay for the // fees. - fundedPacket := fundPsbtCoinSelect(ht, ht.Alice, packet, 1) + fundedPacket := fundPsbtCoinSelect(ht, alice, packet, 1) txFee, err := fundedPacket.GetTxFee() require.NoError(ht, err) // We now let Bob sign the transaction. - signedPacket := signPacket(ht, ht.Bob, fundedPacket) + signedPacket := signPacket(ht, bob, fundedPacket) // And then Alice, which should give us a fully signed TX. - signedPacket = signPacket(ht, ht.Alice, signedPacket) + signedPacket = signPacket(ht, alice, signedPacket) // We should be able to finalize the PSBT and extract the final TX now. - extractPublishAndMine(ht, ht.Alice, signedPacket) + extractPublishAndMine(ht, alice, signedPacket) // Make sure the new wallet balances are reflected correctly. ht.AssertActiveNodesSynced() - ht.Alice.UpdateState() - ht.Bob.UpdateState() + alice.UpdateState() + bob.UpdateState() require.Equal( ht, aliceStartBalance+sendAmount-int64(txFee), - ht.Alice.State.Wallet.TotalBalance, + alice.State.Wallet.TotalBalance, ) require.Equal( ht, bobStartBalance-sendAmount, - ht.Bob.State.Wallet.TotalBalance, + bob.State.Wallet.TotalBalance, ) } @@ -1596,6 +1598,9 @@ func sendAllCoinsToAddrType(ht *lntest.HarnessTest, // the channel opening. The psbt funding flow is used to simulate this behavior // because we can easily let the remote peer run into the timeout. func testPsbtChanFundingFailFlow(ht *lntest.HarnessTest) { + alice := ht.Alice + bob := ht.Bob + const chanSize = funding.MaxBtcFundingAmount // Decrease the timeout window for the remote peer to accelerate the @@ -1604,12 +1609,10 @@ func testPsbtChanFundingFailFlow(ht *lntest.HarnessTest) { "--dev.reservationtimeout=1s", "--dev.zombiesweeperinterval=1s", } - ht.RestartNodeWithExtraArgs(ht.Bob, args) + ht.RestartNodeWithExtraArgs(bob, args) // Before we start the test, we'll ensure both sides are connected so // the funding flow can be properly executed. - alice := ht.Alice - bob := ht.Bob ht.EnsureConnected(alice, bob) // At this point, we can begin our PSBT channel funding workflow. We'll diff --git a/itest/lnd_quiescence_test.go b/itest/lnd_quiescence_test.go index 7c2c274a21..3ce508e568 100644 --- a/itest/lnd_quiescence_test.go +++ b/itest/lnd_quiescence_test.go @@ -30,7 +30,7 @@ func testQuiescence(ht *lntest.HarnessTest) { require.True(ht, res.Initiator) req := &routerrpc.SendPaymentRequest{ - Dest: ht.Alice.PubKey[:], + Dest: alice.PubKey[:], Amt: 100, PaymentHash: ht.Random32Bytes(), FinalCltvDelta: finalCltvDelta, @@ -39,7 +39,7 @@ func testQuiescence(ht *lntest.HarnessTest) { } ht.SendPaymentAssertFail( - ht.Bob, req, + bob, req, // This fails with insufficient balance because the bandwidth // manager reports 0 bandwidth if a link is not eligible for // forwarding, which is the case during quiescence. diff --git a/itest/lnd_rest_api_test.go b/itest/lnd_rest_api_test.go index ce2884e776..42a4783c21 100644 --- a/itest/lnd_rest_api_test.go +++ b/itest/lnd_rest_api_test.go @@ -237,6 +237,8 @@ func testRestAPI(ht *lntest.HarnessTest) { } func wsTestCaseSubscription(ht *lntest.HarnessTest) { + alice := ht.Alice + // Find out the current best block so we can subscribe to the next one. hash, height := ht.GetBestBlock() @@ -246,7 +248,7 @@ func wsTestCaseSubscription(ht *lntest.HarnessTest) { Height: uint32(height), } url := "/v2/chainnotifier/register/blocks" - c, err := openWebSocket(ht.Alice, url, "POST", req, nil) + c, err := openWebSocket(alice, url, "POST", req, nil) require.NoError(ht, err, "websocket") defer func() { err := c.WriteMessage(websocket.CloseMessage, closeMsg) diff --git a/itest/lnd_route_blinding_test.go b/itest/lnd_route_blinding_test.go index 85690da7d3..f09d5dc35d 100644 --- a/itest/lnd_route_blinding_test.go +++ b/itest/lnd_route_blinding_test.go @@ -556,22 +556,24 @@ func (b *blindedForwardTest) drainCarolLiquidity(incoming bool) { func setupFourHopNetwork(ht *lntest.HarnessTest, carol, dave *node.HarnessNode) []*lnrpc.ChannelPoint { + alice, bob := ht.Alice, ht.Bob + const chanAmt = btcutil.Amount(100000) var networkChans []*lnrpc.ChannelPoint // Open a channel with 100k satoshis between Alice and Bob with Alice // being the sole funder of the channel. chanPointAlice := ht.OpenChannel( - ht.Alice, ht.Bob, lntest.OpenChannelParams{ + alice, bob, lntest.OpenChannelParams{ Amt: chanAmt, }, ) networkChans = append(networkChans, chanPointAlice) // Create a channel between bob and carol. - ht.EnsureConnected(ht.Bob, carol) + ht.EnsureConnected(bob, carol) chanPointBob := ht.OpenChannel( - ht.Bob, carol, lntest.OpenChannelParams{ + bob, carol, lntest.OpenChannelParams{ Amt: chanAmt, }, ) @@ -590,7 +592,7 @@ func setupFourHopNetwork(ht *lntest.HarnessTest, networkChans = append(networkChans, chanPointCarol) // Wait for all nodes to have seen all channels. - nodes := []*node.HarnessNode{ht.Alice, ht.Bob, carol, dave} + nodes := []*node.HarnessNode{alice, bob, carol, dave} for _, chanPoint := range networkChans { for _, node := range nodes { ht.AssertChannelInGraph(node, chanPoint) @@ -609,6 +611,8 @@ func setupFourHopNetwork(ht *lntest.HarnessTest, // path and forward payments in a blinded route and finally, receiving the // payment. func testBlindedRouteInvoices(ht *lntest.HarnessTest) { + alice := ht.Alice + ctx, testCase := newBlindedForwardTest(ht) defer testCase.cleanup() @@ -634,7 +638,7 @@ func testBlindedRouteInvoices(ht *lntest.HarnessTest) { }) // Now let Alice pay the invoice. - ht.CompletePaymentRequests(ht.Alice, []string{invoice.PaymentRequest}) + ht.CompletePaymentRequests(alice, []string{invoice.PaymentRequest}) // Let Dave add a blinded invoice. // Once again let Dave create a blinded invoice. @@ -661,7 +665,7 @@ func testBlindedRouteInvoices(ht *lntest.HarnessTest) { require.EqualValues(ht, path.IntroductionNode, testCase.dave.PubKey[:]) // Now let Alice pay the invoice. - ht.CompletePaymentRequests(ht.Alice, []string{invoice.PaymentRequest}) + ht.CompletePaymentRequests(alice, []string{invoice.PaymentRequest}) } // testReceiverBlindedError tests handling of errors from the receiving node in @@ -733,6 +737,8 @@ func testRelayingBlindedError(ht *lntest.HarnessTest) { // over Alice -- Bob -- Carol -- Dave, where Bob is the introduction node and // has insufficient outgoing liquidity to forward on to carol. func testIntroductionNodeError(ht *lntest.HarnessTest) { + bob := ht.Bob + ctx, testCase := newBlindedForwardTest(ht) defer testCase.cleanup() testCase.setupNetwork(ctx, false) @@ -746,7 +752,7 @@ func testIntroductionNodeError(ht *lntest.HarnessTest) { // Subscribe to Bob's HTLC events so that we can observe the payment // coming in. - bobEvents := ht.Bob.RPC.SubscribeHtlcEvents() + bobEvents := bob.RPC.SubscribeHtlcEvents() // Once subscribed, the first event will be UNKNOWN. ht.AssertHtlcEventType(bobEvents, routerrpc.HtlcEvent_UNKNOWN) @@ -764,6 +770,8 @@ func testIntroductionNodeError(ht *lntest.HarnessTest) { // testDisableIntroductionNode tests disabling of blinded forwards for the // introduction node. func testDisableIntroductionNode(ht *lntest.HarnessTest) { + alice, bob := ht.Alice, ht.Bob + // First construct a blinded route while Bob is still advertising the // route blinding feature bit to ensure that Bob is included in the // blinded path that Dave selects. @@ -774,10 +782,10 @@ func testDisableIntroductionNode(ht *lntest.HarnessTest) { route := testCase.createRouteToBlinded(10_000_000, blindedPaymentPath) // Now, disable route blinding for Bob, then re-connect to Alice. - ht.RestartNodeWithExtraArgs(ht.Bob, []string{ + ht.RestartNodeWithExtraArgs(bob, []string{ "--protocol.no-route-blinding", }) - ht.EnsureConnected(ht.Alice, ht.Bob) + ht.EnsureConnected(alice, bob) // Assert that this fails. testCase.sendToRoute(route, false) @@ -788,6 +796,8 @@ func testDisableIntroductionNode(ht *lntest.HarnessTest) { // to resolve blinded HTLCs on chain between restarts, as we've got all the // infrastructure in place already for error testing. func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { + alice, bob := ht.Alice, ht.Bob + // Setup a test case, note that we don't use its built in clean up // because we're going to close a channel, so we'll close out the // rest manually. @@ -807,8 +817,8 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { // Wait for the HTLC to be active on Alice and Bob's channels. hash := sha256.Sum256(testCase.preimage[:]) - ht.AssertOutgoingHTLCActive(ht.Alice, testCase.channels[0], hash[:]) - ht.AssertOutgoingHTLCActive(ht.Bob, testCase.channels[1], hash[:]) + ht.AssertOutgoingHTLCActive(alice, testCase.channels[0], hash[:]) + ht.AssertOutgoingHTLCActive(bob, testCase.channels[1], hash[:]) // Intercept the forward on Carol's link, but do not take any action // so that we have the chance to force close with this HTLC in flight. @@ -817,11 +827,11 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { // Force close Bob <-> Carol. closeStream, _ := ht.CloseChannelAssertPending( - ht.Bob, testCase.channels[1], true, + bob, testCase.channels[1], true, ) ht.AssertStreamChannelForceClosed( - ht.Bob, testCase.channels[1], false, closeStream, + bob, testCase.channels[1], false, closeStream, ) // SuspendCarol so that she can't interfere with the resolution of the @@ -831,32 +841,32 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { // Mine blocks so that Bob will claim his CSV delayed local commitment, // we've already mined 1 block so we need one less than our CSV. ht.MineBlocks(node.DefaultCSV - 1) - ht.AssertNumPendingSweeps(ht.Bob, 1) + ht.AssertNumPendingSweeps(bob, 1) ht.MineBlocksAndAssertNumTxes(1, 1) // Restart bob so that we can test that he's able to recover everything // he needs to claim a blinded HTLC. - ht.RestartNode(ht.Bob) + ht.RestartNode(bob) // Mine enough blocks for Bob to trigger timeout of his outgoing HTLC. // Carol's incoming expiry height is Bob's outgoing so we can use this // value. - info := ht.Bob.RPC.GetInfo() + info := bob.RPC.GetInfo() target := carolHTLC.IncomingExpiry - info.BlockHeight ht.MineBlocks(int(target)) // Wait for Bob's timeout transaction in the mempool, since we've // suspended Carol we don't need to account for her commitment output // claim. - ht.AssertNumPendingSweeps(ht.Bob, 0) + ht.AssertNumPendingSweeps(bob, 0) ht.MineBlocksAndAssertNumTxes(1, 1) // Assert that the HTLC has cleared. - ht.AssertHTLCNotActive(ht.Bob, testCase.channels[0], hash[:]) - ht.AssertHTLCNotActive(ht.Alice, testCase.channels[0], hash[:]) + ht.AssertHTLCNotActive(bob, testCase.channels[0], hash[:]) + ht.AssertHTLCNotActive(alice, testCase.channels[0], hash[:]) // Wait for the HTLC to reflect as failed for Alice. - paymentStream := ht.Alice.RPC.TrackPaymentV2(hash[:]) + paymentStream := alice.RPC.TrackPaymentV2(hash[:]) htlcs := ht.ReceiveTrackPayment(paymentStream).Htlcs require.Len(ht, htlcs, 1) require.NotNil(ht, htlcs[0].Failure) @@ -868,7 +878,7 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { // Clean up the rest of our force close: mine blocks so that Bob's CSV // expires to trigger his sweep and then mine it. ht.MineBlocks(node.DefaultCSV) - ht.AssertNumPendingSweeps(ht.Bob, 1) + ht.AssertNumPendingSweeps(bob, 1) ht.MineBlocksAndAssertNumTxes(1, 1) // Bring carol back up so that we can close out the rest of our @@ -885,7 +895,7 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { // Manually close out the rest of our channels and cancel (don't use // built in cleanup which will try close the already-force-closed // channel). - ht.CloseChannel(ht.Alice, testCase.channels[0]) + ht.CloseChannel(alice, testCase.channels[0]) ht.CloseChannel(testCase.carol, testCase.channels[2]) testCase.cancel() } @@ -1191,7 +1201,7 @@ func testBlindedRouteDummyHops(ht *lntest.HarnessTest) { // Now let Alice pay the invoice. ht.CompletePaymentRequests( - ht.Alice, []string{invoiceResp.PaymentRequest}, + alice, []string{invoiceResp.PaymentRequest}, ) // Make sure Dave show the invoice as settled. @@ -1233,7 +1243,7 @@ func testBlindedRouteDummyHops(ht *lntest.HarnessTest) { // Now let Alice pay the invoice. ht.CompletePaymentRequests( - ht.Alice, []string{invoiceResp.PaymentRequest}, + alice, []string{invoiceResp.PaymentRequest}, ) // Make sure Dave show the invoice as settled. @@ -1430,6 +1440,8 @@ func testMPPToMultipleBlindedPaths(ht *lntest.HarnessTest) { // UpdateAddHTLC which we need to ensure gets included in the message on // restart. func testBlindedPaymentHTLCReForward(ht *lntest.HarnessTest) { + alice, bob := ht.Alice, ht.Bob + // Setup a test case. ctx, testCase := newBlindedForwardTest(ht) defer testCase.cleanup() @@ -1464,8 +1476,8 @@ func testBlindedPaymentHTLCReForward(ht *lntest.HarnessTest) { }() // Wait for the HTLC to be active on Alice and Bob's channels. - ht.AssertOutgoingHTLCActive(ht.Alice, testCase.channels[0], hash[:]) - ht.AssertOutgoingHTLCActive(ht.Bob, testCase.channels[1], hash[:]) + ht.AssertOutgoingHTLCActive(alice, testCase.channels[0], hash[:]) + ht.AssertOutgoingHTLCActive(bob, testCase.channels[1], hash[:]) // Intercept the forward on Carol's link. At this point, we know she // has received the HTLC and so will persist this packet. @@ -1493,7 +1505,7 @@ func testBlindedPaymentHTLCReForward(ht *lntest.HarnessTest) { // Nodes need to be connected otherwise the forwarding of the // intercepted htlc will fail. - ht.EnsureConnected(ht.Bob, testCase.carol) + ht.EnsureConnected(bob, testCase.carol) ht.EnsureConnected(testCase.carol, testCase.dave) // Now that carol and dave are connected signal the forwarding of the diff --git a/itest/lnd_routing_test.go b/itest/lnd_routing_test.go index 07adcf559c..04500a47cd 100644 --- a/itest/lnd_routing_test.go +++ b/itest/lnd_routing_test.go @@ -750,6 +750,8 @@ func testInvoiceRoutingHints(ht *lntest.HarnessTest) { // testScidAliasRoutingHints tests that dynamically created aliases via the RPC // are properly used when routing. func testScidAliasRoutingHints(ht *lntest.HarnessTest) { + bob := ht.Bob + const chanAmt = btcutil.Amount(800000) // Option-scid-alias is opt-in, as is anchors. @@ -866,8 +868,8 @@ func testScidAliasRoutingHints(ht *lntest.HarnessTest) { }) // Connect the existing Bob node with Carol via a public channel. - ht.ConnectNodes(ht.Bob, carol) - chanPointBC := ht.OpenChannel(ht.Bob, carol, lntest.OpenChannelParams{ + ht.ConnectNodes(bob, carol) + chanPointBC := ht.OpenChannel(bob, carol, lntest.OpenChannelParams{ Amt: chanAmt, PushAmt: chanAmt / 2, }) @@ -902,7 +904,7 @@ func testScidAliasRoutingHints(ht *lntest.HarnessTest) { // Now Alice will try to pay to that payment request. timeout := time.Second * 15 - stream := ht.Bob.RPC.SendPayment(&routerrpc.SendPaymentRequest{ + stream := bob.RPC.SendPayment(&routerrpc.SendPaymentRequest{ PaymentRequest: payReq, TimeoutSeconds: int32(timeout.Seconds()), FeeLimitSat: math.MaxInt64, @@ -924,7 +926,7 @@ func testScidAliasRoutingHints(ht *lntest.HarnessTest) { AliasMaps: ephemeralAliasMap, }) payReq2 := dave.RPC.AddInvoice(invoice).PaymentRequest - stream2 := ht.Bob.RPC.SendPayment(&routerrpc.SendPaymentRequest{ + stream2 := bob.RPC.SendPayment(&routerrpc.SendPaymentRequest{ PaymentRequest: payReq2, TimeoutSeconds: int32(timeout.Seconds()), FeeLimitSat: math.MaxInt64, @@ -932,7 +934,7 @@ func testScidAliasRoutingHints(ht *lntest.HarnessTest) { ht.AssertPaymentStatusFromStream(stream2, lnrpc.Payment_FAILED) ht.CloseChannel(carol, chanPointCD) - ht.CloseChannel(ht.Bob, chanPointBC) + ht.CloseChannel(bob, chanPointBC) } // testMultiHopOverPrivateChannels tests that private channels can be used as diff --git a/itest/lnd_signer_test.go b/itest/lnd_signer_test.go index 9310699887..2858e771c5 100644 --- a/itest/lnd_signer_test.go +++ b/itest/lnd_signer_test.go @@ -25,7 +25,9 @@ import ( // the node's pubkey and a customized public key to check the validity of the // result. func testDeriveSharedKey(ht *lntest.HarnessTest) { - runDeriveSharedKey(ht, ht.Alice) + alice := ht.Alice + + runDeriveSharedKey(ht, alice) } // runDeriveSharedKey checks the ECDH performed by the endpoint @@ -197,7 +199,9 @@ func runDeriveSharedKey(ht *lntest.HarnessTest, alice *node.HarnessNode) { // testSignOutputRaw makes sure that the SignOutputRaw RPC can be used with all // custom ways of specifying the signing key in the key descriptor/locator. func testSignOutputRaw(ht *lntest.HarnessTest) { - runSignOutputRaw(ht, ht.Alice) + alice := ht.Alice + + runSignOutputRaw(ht, alice) } // runSignOutputRaw makes sure that the SignOutputRaw RPC can be used with all @@ -377,7 +381,9 @@ func assertSignOutputRaw(ht *lntest.HarnessTest, // all custom flags by verifying with VerifyMessage. Tests both ECDSA and // Schnorr signatures. func testSignVerifyMessage(ht *lntest.HarnessTest) { - runSignVerifyMessage(ht, ht.Alice) + alice := ht.Alice + + runSignVerifyMessage(ht, alice) } // runSignVerifyMessage makes sure that the SignMessage RPC can be used with diff --git a/itest/lnd_sweep_test.go b/itest/lnd_sweep_test.go index 130b8202d0..d86b382dd9 100644 --- a/itest/lnd_sweep_test.go +++ b/itest/lnd_sweep_test.go @@ -1558,7 +1558,9 @@ func testSweepCommitOutputAndAnchor(ht *lntest.HarnessTest) { // CPFP, then RBF. Along the way, we check the `BumpFee` can properly update // the fee function used by supplying new params. func testBumpFee(ht *lntest.HarnessTest) { - runBumpFee(ht, ht.Alice) + alice := ht.Alice + + runBumpFee(ht, alice) } // runBumpFee checks the `BumpFee` RPC can properly bump the fee of a given diff --git a/itest/lnd_taproot_test.go b/itest/lnd_taproot_test.go index b30f8cdaab..d2dd35b528 100644 --- a/itest/lnd_taproot_test.go +++ b/itest/lnd_taproot_test.go @@ -49,34 +49,36 @@ var ( // testTaproot ensures that the daemon can send to and spend from taproot (p2tr) // outputs. func testTaproot(ht *lntest.HarnessTest) { - testTaprootSendCoinsKeySpendBip86(ht, ht.Alice) - testTaprootComputeInputScriptKeySpendBip86(ht, ht.Alice) - testTaprootSignOutputRawScriptSpend(ht, ht.Alice) + alice := ht.Alice + + testTaprootSendCoinsKeySpendBip86(ht, alice) + testTaprootComputeInputScriptKeySpendBip86(ht, alice) + testTaprootSignOutputRawScriptSpend(ht, alice) testTaprootSignOutputRawScriptSpend( - ht, ht.Alice, txscript.SigHashSingle, + ht, alice, txscript.SigHashSingle, ) - testTaprootSignOutputRawKeySpendBip86(ht, ht.Alice) + testTaprootSignOutputRawKeySpendBip86(ht, alice) testTaprootSignOutputRawKeySpendBip86( - ht, ht.Alice, txscript.SigHashSingle, + ht, alice, txscript.SigHashSingle, ) - testTaprootSignOutputRawKeySpendRootHash(ht, ht.Alice) + testTaprootSignOutputRawKeySpendRootHash(ht, alice) muSig2Versions := []signrpc.MuSig2Version{ signrpc.MuSig2Version_MUSIG2_VERSION_V040, signrpc.MuSig2Version_MUSIG2_VERSION_V100RC2, } for _, version := range muSig2Versions { - testTaprootMuSig2KeySpendBip86(ht, ht.Alice, version) - testTaprootMuSig2KeySpendRootHash(ht, ht.Alice, version) - testTaprootMuSig2ScriptSpend(ht, ht.Alice, version) - testTaprootMuSig2CombinedLeafKeySpend(ht, ht.Alice, version) - testMuSig2CombineKey(ht, ht.Alice, version) + testTaprootMuSig2KeySpendBip86(ht, alice, version) + testTaprootMuSig2KeySpendRootHash(ht, alice, version) + testTaprootMuSig2ScriptSpend(ht, alice, version) + testTaprootMuSig2CombinedLeafKeySpend(ht, alice, version) + testMuSig2CombineKey(ht, alice, version) } - testTaprootImportTapscriptFullTree(ht, ht.Alice) - testTaprootImportTapscriptPartialReveal(ht, ht.Alice) - testTaprootImportTapscriptRootHashOnly(ht, ht.Alice) - testTaprootImportTapscriptFullKey(ht, ht.Alice) + testTaprootImportTapscriptFullTree(ht, alice) + testTaprootImportTapscriptPartialReveal(ht, alice) + testTaprootImportTapscriptRootHashOnly(ht, alice) + testTaprootImportTapscriptFullKey(ht, alice) } // testTaprootSendCoinsKeySpendBip86 tests sending to and spending from diff --git a/itest/lnd_watchtower_test.go b/itest/lnd_watchtower_test.go index a68df852bc..272d19d19d 100644 --- a/itest/lnd_watchtower_test.go +++ b/itest/lnd_watchtower_test.go @@ -39,6 +39,8 @@ var watchtowerTestCases = []*lntest.TestCase{ // testTowerClientTowerAndSessionManagement tests the various control commands // that a user has over the client's set of active towers and sessions. func testTowerClientTowerAndSessionManagement(ht *lntest.HarnessTest) { + alice := ht.Alice + const ( chanAmt = funding.MaxBtcFundingAmount externalIP = "1.2.3.4" @@ -104,13 +106,13 @@ func testTowerClientTowerAndSessionManagement(ht *lntest.HarnessTest) { ht.FundCoins(btcutil.SatoshiPerBitcoin, dave) // Connect Dave and Alice. - ht.ConnectNodes(dave, ht.Alice) + ht.ConnectNodes(dave, alice) // Open a channel between Dave and Alice. params := lntest.OpenChannelParams{ Amt: chanAmt, } - chanPoint := ht.OpenChannel(dave, ht.Alice, params) + chanPoint := ht.OpenChannel(dave, alice, params) // Show that the Wallis tower is currently seen as an active session // candidate. @@ -122,7 +124,7 @@ func testTowerClientTowerAndSessionManagement(ht *lntest.HarnessTest) { // Make some back-ups and assert that they are added to a session with // the tower. - generateBackups(ht, dave, ht.Alice, 4) + generateBackups(ht, dave, alice, 4) // Assert that one of the sessions now has 4 backups. assertNumBackups(ht, dave.RPC, wallisPk, 4, false) @@ -139,7 +141,7 @@ func testTowerClientTowerAndSessionManagement(ht *lntest.HarnessTest) { require.False(ht, info.SessionInfo[0].ActiveSessionCandidate) // Back up a few more states. - generateBackups(ht, dave, ht.Alice, 4) + generateBackups(ht, dave, alice, 4) // These should _not_ be on the tower. Therefore, the number of // back-ups on the tower should be the same as before. @@ -163,7 +165,7 @@ func testTowerClientTowerAndSessionManagement(ht *lntest.HarnessTest) { }) // Generate some more back-ups. - generateBackups(ht, dave, ht.Alice, 4) + generateBackups(ht, dave, alice, 4) // Assert that they get added to the first tower (Wallis) and that the // number of sessions with Wallis has not changed - in other words, the @@ -205,7 +207,7 @@ func testTowerClientTowerAndSessionManagement(ht *lntest.HarnessTest) { assertNumSessions(wallisPk, 4, false) // Any new back-ups should now be backed up on a different session. - generateBackups(ht, dave, ht.Alice, 2) + generateBackups(ht, dave, alice, 2) assertNumBackups(ht, dave.RPC, wallisPk, 10, false) findSession(wallisPk, 2) @@ -238,6 +240,8 @@ func testTowerClientTowerAndSessionManagement(ht *lntest.HarnessTest) { // testTowerClientSessionDeletion tests that sessions are correctly deleted // when they are deemed closable. func testTowerClientSessionDeletion(ht *lntest.HarnessTest) { + alice := ht.Alice + const ( chanAmt = funding.MaxBtcFundingAmount numInvoices = 5 @@ -290,18 +294,18 @@ func testTowerClientSessionDeletion(ht *lntest.HarnessTest) { ht.FundCoins(btcutil.SatoshiPerBitcoin, dave) // Connect Dave and Alice. - ht.ConnectNodes(dave, ht.Alice) + ht.ConnectNodes(dave, alice) // Open a channel between Dave and Alice. params := lntest.OpenChannelParams{ Amt: chanAmt, } - chanPoint := ht.OpenChannel(dave, ht.Alice, params) + chanPoint := ht.OpenChannel(dave, alice, params) // Since there are 2 updates made for every payment and the maximum // number of updates per session has been set to 10, make 5 payments // between the pair so that the session is exhausted. - generateBackups(ht, dave, ht.Alice, maxUpdates) + generateBackups(ht, dave, alice, maxUpdates) // Assert that one of the sessions now has 10 backups. assertNumBackups(ht, dave.RPC, wallisPk, 10, false) From de8f14bed2fce06e357870578e816346805644af Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 20 Nov 2024 14:46:59 +0800 Subject: [PATCH 05/64] itest: remove the use of standby nodes This commit removes the usage of the standby nodes and uses `CreateSimpleNetwork` when applicable. Also introduces a helper method `NewNodeWithCoins` to quickly start a node with funds. --- itest/lnd_channel_backup_test.go | 4 +- itest/lnd_channel_balance_test.go | 5 +- itest/lnd_channel_force_close_test.go | 2 +- itest/lnd_channel_graph_test.go | 21 ++--- itest/lnd_channel_policy_test.go | 28 +++--- .../lnd_coop_close_external_delivery_test.go | 3 +- itest/lnd_coop_close_with_htlcs_test.go | 6 +- itest/lnd_custom_features.go | 13 ++- itest/lnd_custom_message_test.go | 5 +- itest/lnd_experimental_endorsement.go | 3 +- itest/lnd_forward_interceptor_test.go | 4 +- itest/lnd_funding_test.go | 11 ++- itest/lnd_hold_invoice_force_test.go | 7 +- itest/lnd_hold_persistence_test.go | 4 +- itest/lnd_htlc_test.go | 2 +- itest/lnd_invoice_acceptor_test.go | 3 +- itest/lnd_macaroons_test.go | 6 +- itest/lnd_max_htlcs_test.go | 22 ++--- itest/lnd_misc_test.go | 59 +++++++------ itest/lnd_mpp_test.go | 4 +- itest/lnd_multi-hop-error-propagation_test.go | 4 +- itest/lnd_multi-hop-payments_test.go | 4 +- itest/lnd_network_test.go | 4 +- itest/lnd_neutrino_test.go | 2 +- itest/lnd_onchain_test.go | 15 ++-- itest/lnd_open_channel_test.go | 28 +++--- itest/lnd_payment_test.go | 16 +++- itest/lnd_psbt_test.go | 17 ++-- itest/lnd_quiescence_test.go | 3 +- itest/lnd_res_handoff_test.go | 3 +- itest/lnd_rest_api_test.go | 20 ++--- itest/lnd_route_blinding_test.go | 85 +++++++++++-------- itest/lnd_routing_test.go | 39 ++++++--- itest/lnd_signer_test.go | 6 +- itest/lnd_single_hop_invoice_test.go | 7 +- itest/lnd_sweep_test.go | 2 +- itest/lnd_switch_test.go | 4 +- itest/lnd_taproot_test.go | 2 +- itest/lnd_trackpayments_test.go | 25 +++--- itest/lnd_wallet_import_test.go | 4 +- itest/lnd_watchtower_test.go | 10 +-- itest/lnd_wipe_fwdpkgs_test.go | 23 ++--- itest/lnd_zero_conf_test.go | 2 +- lntest/harness.go | 36 ++++++++ 44 files changed, 322 insertions(+), 251 deletions(-) diff --git a/itest/lnd_channel_backup_test.go b/itest/lnd_channel_backup_test.go index 4ea5f6933b..7691fdd194 100644 --- a/itest/lnd_channel_backup_test.go +++ b/itest/lnd_channel_backup_test.go @@ -844,7 +844,7 @@ func runChanRestoreScenarioForceClose(ht *lntest.HarnessTest, zeroConf bool) { // and the on-disk channel.backup are updated each time a channel is // opened/closed. func testChannelBackupUpdates(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) // First, we'll make a temp directory that we'll use to store our // backup file, so we can check in on it during the test easily. @@ -1052,7 +1052,7 @@ func testExportChannelBackup(ht *lntest.HarnessTest) { // With Carol up, we'll now connect her to Alice, and open a channel // between them. - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) ht.ConnectNodes(carol, alice) // Next, we'll open two channels between Alice and Carol back to back. diff --git a/itest/lnd_channel_balance_test.go b/itest/lnd_channel_balance_test.go index 8ab276d2e6..82382e9110 100644 --- a/itest/lnd_channel_balance_test.go +++ b/itest/lnd_channel_balance_test.go @@ -48,7 +48,8 @@ func testChannelBalance(ht *lntest.HarnessTest) { } // Before beginning, make sure alice and bob are connected. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) ht.EnsureConnected(alice, bob) chanPoint := ht.OpenChannel( @@ -118,7 +119,7 @@ func testChannelUnsettledBalance(ht *lntest.HarnessTest) { carol := ht.NewNode("Carol", []string{"--hodl.exit-settle"}) // Connect Alice to Carol. - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) ht.ConnectNodes(alice, carol) // Open a channel between Alice and Carol. diff --git a/itest/lnd_channel_force_close_test.go b/itest/lnd_channel_force_close_test.go index e5ef6b7cab..7c047fbcdb 100644 --- a/itest/lnd_channel_force_close_test.go +++ b/itest/lnd_channel_force_close_test.go @@ -771,7 +771,7 @@ func testFailingChannel(ht *lntest.HarnessTest) { // totally unrelated preimage. carol := ht.NewNode("Carol", []string{"--hodl.bogus-settle"}) - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) ht.ConnectNodes(alice, carol) // Let Alice connect and open a channel to Carol, diff --git a/itest/lnd_channel_graph_test.go b/itest/lnd_channel_graph_test.go index 0cd5fcf2e2..e6b3c77370 100644 --- a/itest/lnd_channel_graph_test.go +++ b/itest/lnd_channel_graph_test.go @@ -218,7 +218,9 @@ func testUpdateChanStatus(ht *lntest.HarnessTest) { // describeGraph RPC request unless explicitly asked for. func testUnannouncedChannels(ht *lntest.HarnessTest) { amount := funding.MaxBtcFundingAmount - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) + ht.EnsureConnected(alice, bob) // Open a channel between Alice and Bob, ensuring the // channel has been opened properly. @@ -267,14 +269,10 @@ func testGraphTopologyNtfns(ht *lntest.HarnessTest, pinned bool) { // Spin up Bob first, since we will need to grab his pubkey when // starting Alice to test pinned syncing. - bob := ht.Bob + bob := ht.NewNodeWithCoins("Bob", nil) bobInfo := bob.RPC.GetInfo() bobPubkey := bobInfo.IdentityPubkey - // Restart Bob as he may have leftover announcements from previous - // tests, causing the graph to be unsynced. - ht.RestartNodeWithExtraArgs(bob, nil) - // For unpinned syncing, start Alice as usual. Otherwise grab Bob's // pubkey to include in his pinned syncer set. var aliceArgs []string @@ -285,8 +283,7 @@ func testGraphTopologyNtfns(ht *lntest.HarnessTest, pinned bool) { } } - alice := ht.Alice - ht.RestartNodeWithExtraArgs(alice, aliceArgs) + alice := ht.NewNodeWithCoins("Alice", aliceArgs) // Connect Alice and Bob. ht.EnsureConnected(alice, bob) @@ -379,7 +376,9 @@ func testGraphTopologyNtfns(ht *lntest.HarnessTest, pinned bool) { // external IP addresses specified on the command line, that those addresses // announced to the network and reported in the network graph. func testNodeAnnouncement(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNode("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) + ht.EnsureConnected(alice, bob) advertisedAddrs := []string{ "192.168.1.1:8333", @@ -434,7 +433,9 @@ func testNodeAnnouncement(ht *lntest.HarnessTest) { // the requests correctly and that the new node announcement is broadcast // with the right information after updating our node. func testUpdateNodeAnnouncement(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNode("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) + ht.EnsureConnected(alice, bob) var lndArgs []string diff --git a/itest/lnd_channel_policy_test.go b/itest/lnd_channel_policy_test.go index 9aa0f09b88..3031296c1c 100644 --- a/itest/lnd_channel_policy_test.go +++ b/itest/lnd_channel_policy_test.go @@ -30,19 +30,16 @@ func testUpdateChannelPolicy(ht *lntest.HarnessTest) { chanAmt := funding.MaxBtcFundingAmount pushAmt := chanAmt / 2 - alice, bob := ht.Alice, ht.Bob - // Create a channel Alice->Bob. - chanPoint := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{ + chanPoints, nodes := ht.CreateSimpleNetwork( + [][]string{nil, nil}, lntest.OpenChannelParams{ Amt: chanAmt, PushAmt: pushAmt, }, ) - // We add all the nodes' update channels to a slice, such that we can - // make sure they all receive the expected updates. - nodes := []*node.HarnessNode{alice, bob} + alice, bob := nodes[0], nodes[1] + chanPoint := chanPoints[0] // Alice and Bob should see each other's ChannelUpdates, advertising the // default routing policies. We do not currently set any inbound fees. @@ -441,7 +438,8 @@ func testUpdateChannelPolicy(ht *lntest.HarnessTest) { func testSendUpdateDisableChannel(ht *lntest.HarnessTest) { const chanAmt = 100000 - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) // Create a new node Eve, which will be restarted later with a config // that has an inactive channel timeout of just 6 seconds (down from @@ -678,7 +676,9 @@ func testUpdateChannelPolicyForPrivateChannel(ht *lntest.HarnessTest) { // We'll create the following topology first, // Alice <--public:100k--> Bob <--private:100k--> Carol - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) + ht.EnsureConnected(alice, bob) // Open a channel with 100k satoshis between Alice and Bob. chanPointAliceBob := ht.OpenChannel( @@ -787,16 +787,14 @@ func testUpdateChannelPolicyFeeRateAccuracy(ht *lntest.HarnessTest) { pushAmt := chanAmt / 2 // Create a channel Alice -> Bob. - alice, bob := ht.Alice, ht.Bob - chanPoint := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{ + chanPoints, nodes := ht.CreateSimpleNetwork( + [][]string{nil, nil}, lntest.OpenChannelParams{ Amt: chanAmt, PushAmt: pushAmt, }, ) - - // Nodes that we need to make sure receive the channel updates. - nodes := []*node.HarnessNode{alice, bob} + alice := nodes[0] + chanPoint := chanPoints[0] baseFee := int64(1500) timeLockDelta := uint32(66) diff --git a/itest/lnd_coop_close_external_delivery_test.go b/itest/lnd_coop_close_external_delivery_test.go index 57c2da2f4f..8341a2f650 100644 --- a/itest/lnd_coop_close_external_delivery_test.go +++ b/itest/lnd_coop_close_external_delivery_test.go @@ -58,7 +58,8 @@ func testCoopCloseWithExternalDelivery(ht *lntest.HarnessTest) { func testCoopCloseWithExternalDeliveryImpl(ht *lntest.HarnessTest, upfrontShutdown bool, deliveryAddressType lnrpc.AddressType) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("bob", nil) ht.ConnectNodes(alice, bob) // Here we generate a final delivery address in bob's wallet but set by diff --git a/itest/lnd_coop_close_with_htlcs_test.go b/itest/lnd_coop_close_with_htlcs_test.go index 2b7bcad729..b5d5f516b9 100644 --- a/itest/lnd_coop_close_with_htlcs_test.go +++ b/itest/lnd_coop_close_with_htlcs_test.go @@ -37,7 +37,8 @@ func testCoopCloseWithHtlcs(ht *lntest.HarnessTest) { // channel party initiates a channel shutdown while an HTLC is still pending on // the channel. func coopCloseWithHTLCs(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("bob", nil) ht.ConnectNodes(alice, bob) // Here we set up a channel between Alice and Bob, beginning with a @@ -128,7 +129,8 @@ func coopCloseWithHTLCs(ht *lntest.HarnessTest) { // process continues as expected even if a channel re-establish happens after // one party has already initiated the shutdown. func coopCloseWithHTLCsWithRestart(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("bob", nil) ht.ConnectNodes(alice, bob) // Open a channel between Alice and Bob with the balance split equally. diff --git a/itest/lnd_custom_features.go b/itest/lnd_custom_features.go index c7cec8f1dd..cba6ee4aaf 100644 --- a/itest/lnd_custom_features.go +++ b/itest/lnd_custom_features.go @@ -13,8 +13,6 @@ import ( // sets. For completeness, it also asserts that features aren't set in places // where they aren't intended to be. func testCustomFeatures(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob - var ( // Odd custom features so that we don't need to worry about // issues connecting to peers. @@ -29,14 +27,13 @@ func testCustomFeatures(ht *lntest.HarnessTest) { fmt.Sprintf("--protocol.custom-nodeann=%v", customNodeAnn), fmt.Sprintf("--protocol.custom-invoice=%v", customInvoice), } - ht.RestartNodeWithExtraArgs(alice, extraArgs) + cfgs := [][]string{extraArgs, nil} - // Connect nodes and open a channel so that Alice will be included - // in Bob's graph. - ht.ConnectNodes(alice, bob) - chanPoint := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{Amt: 1000000}, + chanPoints, nodes := ht.CreateSimpleNetwork( + cfgs, lntest.OpenChannelParams{Amt: 1000000}, ) + alice, bob := nodes[0], nodes[1] + chanPoint := chanPoints[0] // Check that Alice's custom feature bit was sent to Bob in her init // message. diff --git a/itest/lnd_custom_message_test.go b/itest/lnd_custom_message_test.go index 14a4e79493..93a92a2d66 100644 --- a/itest/lnd_custom_message_test.go +++ b/itest/lnd_custom_message_test.go @@ -14,8 +14,6 @@ import ( // types (within the message type range usually reserved for protocol messages) // via the send and subscribe custom message APIs. func testCustomMessage(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob - var ( overrideType1 uint32 = 554 overrideType2 uint32 = 555 @@ -27,7 +25,8 @@ func testCustomMessage(ht *lntest.HarnessTest) { extraArgs := []string{ fmt.Sprintf(msgOverrideArg, overrideType1), } - ht.RestartNodeWithExtraArgs(alice, extraArgs) + alice := ht.NewNode("Alice", extraArgs) + bob := ht.NewNode("Bob", nil) // Subscribe Alice to custom messages before we send any, so that we // don't miss any. diff --git a/itest/lnd_experimental_endorsement.go b/itest/lnd_experimental_endorsement.go index 6b89f1ada2..d537715ed6 100644 --- a/itest/lnd_experimental_endorsement.go +++ b/itest/lnd_experimental_endorsement.go @@ -24,7 +24,8 @@ func testExperimentalEndorsement(ht *lntest.HarnessTest) { // testEndorsement sets up a 5 hop network and tests propagation of // experimental endorsement signals. func testEndorsement(ht *lntest.HarnessTest, aliceEndorse bool) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) carol := ht.NewNode( "carol", []string{"--protocol.no-experimental-endorsement"}, ) diff --git a/itest/lnd_forward_interceptor_test.go b/itest/lnd_forward_interceptor_test.go index a58dc34154..b677627e72 100644 --- a/itest/lnd_forward_interceptor_test.go +++ b/itest/lnd_forward_interceptor_test.go @@ -765,7 +765,9 @@ type interceptorTestScenario struct { func newInterceptorTestScenario( ht *lntest.HarnessTest) *interceptorTestScenario { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("bob", nil) + carol := ht.NewNode("carol", nil) dave := ht.NewNode("dave", nil) diff --git a/itest/lnd_funding_test.go b/itest/lnd_funding_test.go index 5f2c60a1b3..3cffd01f70 100644 --- a/itest/lnd_funding_test.go +++ b/itest/lnd_funding_test.go @@ -282,8 +282,7 @@ func testUnconfirmedChannelFunding(ht *lntest.HarnessTest) { // We'll start off by creating a node for Carol. carol := ht.NewNode("Carol", nil) - - alice := ht.Alice + alice := ht.NewNode("Alice", nil) // We'll send her some unconfirmed funds. ht.FundCoinsUnconfirmed(2*chanAmt, carol) @@ -402,7 +401,7 @@ func testUnconfirmedChannelFunding(ht *lntest.HarnessTest) { // testChannelFundingInputTypes tests that any type of supported input type can // be used to fund channels. func testChannelFundingInputTypes(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) // We'll start off by creating a node for Carol. carol := ht.NewNode("Carol", nil) @@ -841,7 +840,7 @@ func testChannelFundingPersistence(ht *lntest.HarnessTest) { } carol := ht.NewNode("Carol", carolArgs) - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) ht.ConnectNodes(alice, carol) // Create a new channel that requires 5 confs before it's considered @@ -957,8 +956,8 @@ func testBatchChanFunding(ht *lntest.HarnessTest) { } eve := ht.NewNode("eve", scidAliasArgs) - alice, bob := ht.Alice, ht.Bob - ht.RestartNodeWithExtraArgs(alice, scidAliasArgs) + alice := ht.NewNodeWithCoins("Alice", scidAliasArgs) + bob := ht.NewNodeWithCoins("Bob", nil) // Before we start the test, we'll ensure Alice is connected to Carol // and Dave, so she can open channels to both of them (and Bob). diff --git a/itest/lnd_hold_invoice_force_test.go b/itest/lnd_hold_invoice_force_test.go index d9b8517107..5f0a54670b 100644 --- a/itest/lnd_hold_invoice_force_test.go +++ b/itest/lnd_hold_invoice_force_test.go @@ -17,10 +17,11 @@ import ( // would otherwise trigger force closes when they expire. func testHoldInvoiceForceClose(ht *lntest.HarnessTest) { // Open a channel between alice and bob. - alice, bob := ht.Alice, ht.Bob - chanPoint := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{Amt: 300000}, + chanPoints, nodes := ht.CreateSimpleNetwork( + [][]string{nil, nil}, lntest.OpenChannelParams{Amt: 300000}, ) + alice, bob := nodes[0], nodes[1] + chanPoint := chanPoints[0] // Create a non-dust hold invoice for bob. var ( diff --git a/itest/lnd_hold_persistence_test.go b/itest/lnd_hold_persistence_test.go index 8bb84b2a30..97c6eb29ca 100644 --- a/itest/lnd_hold_persistence_test.go +++ b/itest/lnd_hold_persistence_test.go @@ -28,7 +28,9 @@ func testHoldInvoicePersistence(ht *lntest.HarnessTest) { carol := ht.NewNode("Carol", nil) // Connect Alice to Carol. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) + ht.EnsureConnected(alice, bob) ht.ConnectNodes(alice, carol) // Open a channel between Alice and Carol which is private so that we diff --git a/itest/lnd_htlc_test.go b/itest/lnd_htlc_test.go index fc04fe8d0f..001a4dc65a 100644 --- a/itest/lnd_htlc_test.go +++ b/itest/lnd_htlc_test.go @@ -14,7 +14,7 @@ import ( func testLookupHtlcResolution(ht *lntest.HarnessTest) { const chanAmt = btcutil.Amount(1000000) - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) carol := ht.NewNode("Carol", []string{ "--store-final-htlc-resolutions", }) diff --git a/itest/lnd_invoice_acceptor_test.go b/itest/lnd_invoice_acceptor_test.go index 60f6615ce2..0c42a33e3d 100644 --- a/itest/lnd_invoice_acceptor_test.go +++ b/itest/lnd_invoice_acceptor_test.go @@ -251,7 +251,8 @@ type acceptorTestScenario struct { // // Among them, Alice and Bob are standby nodes and Carol is a new node. func newAcceptorTestScenario(ht *lntest.HarnessTest) *acceptorTestScenario { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("bob", nil) carol := ht.NewNode("carol", nil) ht.EnsureConnected(alice, bob) diff --git a/itest/lnd_macaroons_test.go b/itest/lnd_macaroons_test.go index 3adfafffe9..b896d455ac 100644 --- a/itest/lnd_macaroons_test.go +++ b/itest/lnd_macaroons_test.go @@ -29,7 +29,7 @@ func testMacaroonAuthentication(ht *lntest.HarnessTest) { newAddrReq = &lnrpc.NewAddressRequest{ Type: AddrTypeWitnessPubkeyHash, } - testNode = ht.Alice + testNode = ht.NewNode("Alice", nil) testClient = testNode.RPC.LN ) @@ -295,7 +295,7 @@ func testMacaroonAuthentication(ht *lntest.HarnessTest) { // in the request must be set correctly, and the baked macaroon has the intended // permissions. func testBakeMacaroon(ht *lntest.HarnessTest) { - var testNode = ht.Alice + var testNode = ht.NewNode("Alice", nil) testCases := []struct { name string @@ -521,7 +521,7 @@ func testBakeMacaroon(ht *lntest.HarnessTest) { func testDeleteMacaroonID(ht *lntest.HarnessTest) { var ( ctxb = ht.Context() - testNode = ht.Alice + testNode = ht.NewNode("Alice", nil) ) ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) defer cancel() diff --git a/itest/lnd_max_htlcs_test.go b/itest/lnd_max_htlcs_test.go index ea023190f5..cc4f8adb58 100644 --- a/itest/lnd_max_htlcs_test.go +++ b/itest/lnd_max_htlcs_test.go @@ -19,25 +19,21 @@ func testMaxHtlcPathfind(ht *lntest.HarnessTest) { // Bob to add a maximum of 5 htlcs to her commitment. maxHtlcs := 5 - alice, bob := ht.Alice, ht.Bob - - // Restart nodes with the new flag so they understand the new payment + // Create nodes with the new flag so they understand the new payment // status. - ht.RestartNodeWithExtraArgs(alice, []string{ - "--routerrpc.usestatusinitiated", - }) - ht.RestartNodeWithExtraArgs(bob, []string{ - "--routerrpc.usestatusinitiated", - }) - - ht.EnsureConnected(alice, bob) - chanPoint := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{ + cfg := []string{"--routerrpc.usestatusinitiated"} + cfgs := [][]string{cfg, cfg} + + // Create a channel Alice->Bob. + chanPoints, nodes := ht.CreateSimpleNetwork( + cfgs, lntest.OpenChannelParams{ Amt: 1000000, PushAmt: 800000, RemoteMaxHtlcs: uint16(maxHtlcs), }, ) + chanPoint := chanPoints[0] + alice, bob := nodes[0], nodes[1] // Alice and bob should have one channel open with each other now. ht.AssertNodeNumChannels(alice, 1) diff --git a/itest/lnd_misc_test.go b/itest/lnd_misc_test.go index 21873109ff..70fcbe971b 100644 --- a/itest/lnd_misc_test.go +++ b/itest/lnd_misc_test.go @@ -39,9 +39,8 @@ func testDisconnectingTargetPeer(ht *lntest.HarnessTest) { "--maxbackoff=1m", } - alice, bob := ht.Alice, ht.Bob - ht.RestartNodeWithExtraArgs(alice, args) - ht.RestartNodeWithExtraArgs(bob, args) + alice := ht.NewNodeWithCoins("Alice", args) + bob := ht.NewNodeWithCoins("Bob", args) // Start by connecting Alice and Bob with no channels. ht.EnsureConnected(alice, bob) @@ -239,17 +238,11 @@ func testListChannels(ht *lntest.HarnessTest) { const aliceRemoteMaxHtlcs = 50 const bobRemoteMaxHtlcs = 100 - // Get the standby nodes and open a channel between them. - alice, bob := ht.Alice, ht.Bob - args := []string{fmt.Sprintf( "--default-remote-max-htlcs=%v", bobRemoteMaxHtlcs, )} - ht.RestartNodeWithExtraArgs(bob, args) - - // Connect Alice to Bob. - ht.EnsureConnected(alice, bob) + cfgs := [][]string{nil, args} // Open a channel with 100k satoshis between Alice and Bob with Alice // being the sole funder of the channel. The minial HTLC amount is set @@ -264,8 +257,10 @@ func testListChannels(ht *lntest.HarnessTest) { MinHtlc: customizedMinHtlc, RemoteMaxHtlcs: aliceRemoteMaxHtlcs, } - chanPoint := ht.OpenChannel(alice, bob, p) - defer ht.CloseChannel(alice, chanPoint) + + chanPoints, nodes := ht.CreateSimpleNetwork(cfgs, p) + alice, bob := nodes[0], nodes[1] + chanPoint := chanPoints[0] // Alice should have one channel opened with Bob. ht.AssertNodeNumChannels(alice, 1) @@ -369,7 +364,7 @@ func testMaxPendingChannels(ht *lntest.HarnessTest) { } carol := ht.NewNode("Carol", args) - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) ht.ConnectNodes(alice, carol) carolBalance := btcutil.Amount(maxPendingChannels) * amount @@ -439,7 +434,9 @@ func testMaxPendingChannels(ht *lntest.HarnessTest) { func testGarbageCollectLinkNodes(ht *lntest.HarnessTest) { const chanAmt = 1000000 - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) + ht.EnsureConnected(alice, bob) // Open a channel between Alice and Bob which will later be // cooperatively closed. @@ -553,7 +550,8 @@ func testRejectHTLC(ht *lntest.HarnessTest) { // Alice ------> Carol ------> Bob // const chanAmt = btcutil.Amount(1000000) - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) // Create Carol with reject htlc flag. carol := ht.NewNode("Carol", []string{"--rejecthtlc"}) @@ -649,15 +647,16 @@ func testRejectHTLC(ht *lntest.HarnessTest) { func testNodeSignVerify(ht *lntest.HarnessTest) { chanAmt := funding.MaxBtcFundingAmount pushAmt := btcutil.Amount(100000) - alice, bob := ht.Alice, ht.Bob + p := lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + } // Create a channel between alice and bob. - aliceBobCh := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{ - Amt: chanAmt, - PushAmt: pushAmt, - }, - ) + cfgs := [][]string{nil, nil} + chanPoints, nodes := ht.CreateSimpleNetwork(cfgs, p) + alice, bob := nodes[0], nodes[1] + aliceBobCh := chanPoints[0] // alice signs "alice msg" and sends her signature to bob. aliceMsg := []byte("alice msg") @@ -694,14 +693,17 @@ func testNodeSignVerify(ht *lntest.HarnessTest) { // and not in one of the pending closure states. It also verifies that the // abandoned channel is reported as closed with close type 'abandoned'. func testAbandonChannel(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob - // First establish a channel between Alice and Bob. channelParam := lntest.OpenChannelParams{ Amt: funding.MaxBtcFundingAmount, PushAmt: btcutil.Amount(100000), } - chanPoint := ht.OpenChannel(alice, bob, channelParam) + + // Create a channel between alice and bob. + cfgs := [][]string{nil, nil} + chanPoints, nodes := ht.CreateSimpleNetwork(cfgs, channelParam) + alice, bob := nodes[0], nodes[1] + chanPoint := chanPoints[0] // Now that the channel is open, we'll obtain its channel ID real quick // so we can use it to query the graph below. @@ -763,7 +765,7 @@ func testAbandonChannel(ht *lntest.HarnessTest) { // testSendAllCoins tests that we're able to properly sweep all coins from the // wallet into a single target address at the specified fee rate. func testSendAllCoins(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) // First, we'll make a new node, Ainz who'll we'll use to test wallet // sweeping. @@ -1162,7 +1164,8 @@ func assertChannelConstraintsEqual(ht *lntest.HarnessTest, // on a message with a provided address. func testSignVerifyMessageWithAddr(ht *lntest.HarnessTest) { // Using different nodes to sign the message and verify the signature. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNode("Alice,", nil) + bob := ht.NewNode("Bob,", nil) // Test an lnd wallet created P2WKH address. respAddr := alice.RPC.NewAddress(&lnrpc.NewAddressRequest{ @@ -1279,7 +1282,7 @@ func testSignVerifyMessageWithAddr(ht *lntest.HarnessTest) { // up with native SQL enabled, as we don't currently support migration of KV // invoices to the new SQL schema. func testNativeSQLNoMigration(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) // Make sure we run the test with SQLite or Postgres. if alice.Cfg.DBBackend != node.BackendSqlite && diff --git a/itest/lnd_mpp_test.go b/itest/lnd_mpp_test.go index 800708569d..99eb1eb599 100644 --- a/itest/lnd_mpp_test.go +++ b/itest/lnd_mpp_test.go @@ -180,8 +180,8 @@ type mppTestScenario struct { // \ / // \__ Dave ____/ func newMppTestScenario(ht *lntest.HarnessTest) *mppTestScenario { - alice, bob := ht.Alice, ht.Bob - ht.RestartNodeWithExtraArgs(bob, []string{ + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", []string{ "--maxpendingchannels=2", "--accept-amp", }) diff --git a/itest/lnd_multi-hop-error-propagation_test.go b/itest/lnd_multi-hop-error-propagation_test.go index 853dd4a978..1f0f651880 100644 --- a/itest/lnd_multi-hop-error-propagation_test.go +++ b/itest/lnd_multi-hop-error-propagation_test.go @@ -15,7 +15,9 @@ func testHtlcErrorPropagation(ht *lntest.HarnessTest) { // multi-hop payment. const chanAmt = funding.MaxBtcFundingAmount - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) + ht.EnsureConnected(alice, bob) // Since we'd like to test some multi-hop failure scenarios, we'll // introduce another node into our test network: Carol. diff --git a/itest/lnd_multi-hop-payments_test.go b/itest/lnd_multi-hop-payments_test.go index add520e10d..aa5ef7516a 100644 --- a/itest/lnd_multi-hop-payments_test.go +++ b/itest/lnd_multi-hop-payments_test.go @@ -18,7 +18,8 @@ func testMultiHopPayments(ht *lntest.HarnessTest) { // channel with Alice, and Carol with Dave. After this setup, the // network topology should now look like: // Carol -> Dave -> Alice -> Bob - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) daveArgs := []string{"--protocol.legacy.onion"} dave := ht.NewNode("Dave", daveArgs) @@ -37,6 +38,7 @@ func testMultiHopPayments(ht *lntest.HarnessTest) { ht.AssertHtlcEventType(daveEvents, routerrpc.HtlcEvent_UNKNOWN) // Connect the nodes. + ht.ConnectNodes(alice, bob) ht.ConnectNodes(dave, alice) ht.ConnectNodes(carol, dave) diff --git a/itest/lnd_network_test.go b/itest/lnd_network_test.go index fd17d04657..ff305b59f4 100644 --- a/itest/lnd_network_test.go +++ b/itest/lnd_network_test.go @@ -126,7 +126,7 @@ func testReconnectAfterIPChange(ht *lntest.HarnessTest) { } // Connect Alice to Dave and Charlie. - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) ht.ConnectNodes(alice, dave) ht.ConnectNodes(alice, charlie) @@ -218,7 +218,7 @@ func testReconnectAfterIPChange(ht *lntest.HarnessTest) { // testAddPeerConfig tests that the "--addpeer" config flag successfully adds // a new peer. func testAddPeerConfig(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) info := alice.RPC.GetInfo() alicePeerAddress := info.Uris[0] diff --git a/itest/lnd_neutrino_test.go b/itest/lnd_neutrino_test.go index 39531bb84c..22f19d848e 100644 --- a/itest/lnd_neutrino_test.go +++ b/itest/lnd_neutrino_test.go @@ -13,7 +13,7 @@ func testNeutrino(ht *lntest.HarnessTest) { ht.Skipf("skipping test for non neutrino backends") } - alice := ht.Alice + alice := ht.NewNode("Alice", nil) // Check if the neutrino sub server is running. statusRes := alice.RPC.Status(nil) diff --git a/itest/lnd_onchain_test.go b/itest/lnd_onchain_test.go index 704676d56b..8b14092558 100644 --- a/itest/lnd_onchain_test.go +++ b/itest/lnd_onchain_test.go @@ -33,7 +33,7 @@ func testChainKit(ht *lntest.HarnessTest) { // testChainKitGetBlock ensures that given a block hash, the RPC endpoint // returns the correct target block. func testChainKitGetBlock(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) // Get best block hash. bestBlockRes := alice.RPC.GetBestBlock(nil) @@ -63,7 +63,7 @@ func testChainKitGetBlock(ht *lntest.HarnessTest) { // testChainKitGetBlockHeader ensures that given a block hash, the RPC endpoint // returns the correct target block header. func testChainKitGetBlockHeader(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) // Get best block hash. bestBlockRes := alice.RPC.GetBestBlock(nil) @@ -108,7 +108,7 @@ func testChainKitGetBlockHeader(ht *lntest.HarnessTest) { // testChainKitGetBlockHash ensures that given a block height, the RPC endpoint // returns the correct target block hash. func testChainKitGetBlockHash(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) // Get best block hash. bestBlockRes := alice.RPC.GetBestBlock(nil) @@ -134,8 +134,7 @@ func testChainKitSendOutputsAnchorReserve(ht *lntest.HarnessTest) { // NOTE: we cannot reuse the standby node here as the test requires the // node to start with no UTXOs. charlie := ht.NewNode("Charlie", args) - bob := ht.Bob - ht.RestartNodeWithExtraArgs(bob, args) + bob := ht.NewNode("Bob", args) // We'll start the test by sending Charlie some coins. fundingAmount := btcutil.Amount(100_000) @@ -222,12 +221,8 @@ func testAnchorReservedValue(ht *lntest.HarnessTest) { // Start two nodes supporting anchor channels. args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) - // NOTE: we cannot reuse the standby node here as the test requires the - // node to start with no UTXOs. alice := ht.NewNode("Alice", args) - bob := ht.Bob - ht.RestartNodeWithExtraArgs(bob, args) - + bob := ht.NewNode("Bob", args) ht.ConnectNodes(alice, bob) // Send just enough coins for Alice to open a channel without a change diff --git a/itest/lnd_open_channel_test.go b/itest/lnd_open_channel_test.go index b47a766d53..20f456ea9b 100644 --- a/itest/lnd_open_channel_test.go +++ b/itest/lnd_open_channel_test.go @@ -34,7 +34,9 @@ func testOpenChannelAfterReorg(ht *lntest.HarnessTest) { tempMiner := ht.SpawnTempMiner() miner := ht.Miner() - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) + ht.EnsureConnected(alice, bob) // Create a new channel that requires 1 confs before it's considered // open, then broadcast the funding transaction @@ -242,9 +244,10 @@ func testOpenChannelUpdateFeePolicy(ht *lntest.HarnessTest) { // In this basic test, we'll need a third node, Carol, so we can forward // a payment through the channel we'll open with the different fee // policies. + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) carol := ht.NewNode("Carol", nil) - alice, bob := ht.Alice, ht.Bob nodes := []*node.HarnessNode{alice, bob, carol} runTestCase := func(ht *lntest.HarnessTest, @@ -301,7 +304,7 @@ func testOpenChannelUpdateFeePolicy(ht *lntest.HarnessTest) { // Send Carol enough coins to be able to open a channel // to Alice. - ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) + st.FundCoins(btcutil.SatoshiPerBitcoin, carol) runTestCase( st, feeScenario, @@ -315,7 +318,9 @@ func testOpenChannelUpdateFeePolicy(ht *lntest.HarnessTest) { // closing, and ensures that if a node is subscribed to channel updates they // will be received correctly for both cooperative and force closed channels. func testBasicChannelCreationAndUpdates(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) + ht.EnsureConnected(alice, bob) runBasicChannelCreationAndUpdates(ht, alice, bob) } @@ -519,8 +524,8 @@ func testUpdateOnPendingOpenChannels(ht *lntest.HarnessTest) { // processing the fundee's `channel_ready`, the HTLC will be cached and // eventually settled. func testUpdateOnFunderPendingOpenChannels(ht *lntest.HarnessTest) { - // Grab the channel participants. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) // Restart Alice with the config so she won't process Bob's // channel_ready msg immediately. @@ -603,8 +608,8 @@ func testUpdateOnFunderPendingOpenChannels(ht *lntest.HarnessTest) { // processing the funder's `channel_ready`, the HTLC will be cached and // eventually settled. func testUpdateOnFundeePendingOpenChannels(ht *lntest.HarnessTest) { - // Grab the channel participants. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) // Restart Bob with the config so he won't process Alice's // channel_ready msg immediately. @@ -746,7 +751,10 @@ func verifyCloseUpdate(chanUpdate *lnrpc.ChannelEventUpdate, // before the funding transaction is confirmed, that the FundingExpiryBlocks // field of a PendingChannels decreases. func testFundingExpiryBlocksOnPending(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) + ht.EnsureConnected(alice, bob) + param := lntest.OpenChannelParams{Amt: 100000} update := ht.OpenChannelAssertPending(alice, bob, param) @@ -844,7 +852,6 @@ func testSimpleTaprootChannelActivation(ht *lntest.HarnessTest) { // up as locked balance in the WalletBalance response. func testOpenChannelLockedBalance(ht *lntest.HarnessTest) { var ( - bob = ht.Bob req *lnrpc.ChannelAcceptRequest err error ) @@ -852,6 +859,7 @@ func testOpenChannelLockedBalance(ht *lntest.HarnessTest) { // Create a new node so we can assert exactly how much fund has been // locked later. alice := ht.NewNode("alice", nil) + bob := ht.NewNode("bob", nil) ht.FundCoins(btcutil.SatoshiPerBitcoin, alice) // Connect the nodes. diff --git a/itest/lnd_payment_test.go b/itest/lnd_payment_test.go index 4df148d95e..6c6fc1b178 100644 --- a/itest/lnd_payment_test.go +++ b/itest/lnd_payment_test.go @@ -346,7 +346,8 @@ func runTestPaymentHTLCTimeout(ht *lntest.HarnessTest, restartAlice bool) { // to return floor fee rate(1 sat/vb). func testSendDirectPayment(ht *lntest.HarnessTest) { // Grab Alice and Bob's nodes for convenience. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) // Create a list of commitment types we want to test. commitmentTypes := []lnrpc.CommitmentType{ @@ -466,7 +467,9 @@ func testSendDirectPayment(ht *lntest.HarnessTest) { } func testListPayments(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) + ht.EnsureConnected(alice, bob) // Check that there are no payments before test. ht.AssertNumPayments(alice, 0) @@ -658,7 +661,10 @@ func testPaymentFollowingChannelOpen(ht *lntest.HarnessTest) { channelCapacity := paymentAmt * 1000 // We first establish a channel between Alice and Bob. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) + ht.EnsureConnected(alice, bob) + p := lntest.OpenChannelParams{ Amt: channelCapacity, } @@ -934,7 +940,9 @@ func testBidirectionalAsyncPayments(ht *lntest.HarnessTest) { func testInvoiceSubscriptions(ht *lntest.HarnessTest) { const chanAmt = btcutil.Amount(500000) - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) + ht.EnsureConnected(alice, bob) // Create a new invoice subscription client for Bob, the notification // should be dispatched shortly below. diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go index deecbdbf22..f3687d74b5 100644 --- a/itest/lnd_psbt_test.go +++ b/itest/lnd_psbt_test.go @@ -146,7 +146,7 @@ func runPsbtChanFunding(ht *lntest.HarnessTest, carol, dave *node.HarnessNode, // Before we start the test, we'll ensure both sides are connected so // the funding flow can be properly executed. - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) ht.EnsureConnected(carol, dave) ht.EnsureConnected(carol, alice) @@ -344,7 +344,7 @@ func runPsbtChanFundingExternal(ht *lntest.HarnessTest, carol, // Before we start the test, we'll ensure both sides are connected so // the funding flow can be properly executed. - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) ht.EnsureConnected(carol, dave) ht.EnsureConnected(carol, alice) @@ -517,8 +517,7 @@ func runPsbtChanFundingSingleStep(ht *lntest.HarnessTest, carol, const chanSize = funding.MaxBtcFundingAmount - alice := ht.Alice - ht.FundCoins(btcutil.SatoshiPerBitcoin, alice) + alice := ht.NewNodeWithCoins("Alice", nil) // Get new address for anchor reserve. req := &lnrpc.NewAddressRequest{ @@ -697,7 +696,8 @@ func testSignPsbt(ht *lntest.HarnessTest) { for _, tc := range psbtTestRunners { succeed := ht.Run(tc.name, func(t *testing.T) { st := ht.Subtest(t) - tc.runner(st, st.Alice) + alice := st.NewNodeWithCoins("Alice", nil) + tc.runner(st, alice) }) // Abort the test if failed. @@ -1088,7 +1088,8 @@ func runFundAndSignPsbt(ht *lntest.HarnessTest, alice *node.HarnessNode) { // a PSBT that already specifies an input but where the user still wants the // wallet to perform coin selection. func testFundPsbt(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) // We test a pay-join between Alice and Bob. Bob wants to send Alice // 5 million Satoshis in a non-obvious way. So Bob selects a UTXO that's @@ -1598,8 +1599,8 @@ func sendAllCoinsToAddrType(ht *lntest.HarnessTest, // the channel opening. The psbt funding flow is used to simulate this behavior // because we can easily let the remote peer run into the timeout. func testPsbtChanFundingFailFlow(ht *lntest.HarnessTest) { - alice := ht.Alice - bob := ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) const chanSize = funding.MaxBtcFundingAmount diff --git a/itest/lnd_quiescence_test.go b/itest/lnd_quiescence_test.go index 3ce508e568..defb44d1b1 100644 --- a/itest/lnd_quiescence_test.go +++ b/itest/lnd_quiescence_test.go @@ -16,7 +16,8 @@ import ( // NOTE FOR REVIEW: this could be improved by blasting the channel with HTLC // traffic on both sides to increase the surface area of the change under test. func testQuiescence(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) chanPoint := ht.OpenChannel(bob, alice, lntest.OpenChannelParams{ Amt: btcutil.Amount(1000000), diff --git a/itest/lnd_res_handoff_test.go b/itest/lnd_res_handoff_test.go index dbf286293b..7238bf6b76 100644 --- a/itest/lnd_res_handoff_test.go +++ b/itest/lnd_res_handoff_test.go @@ -17,7 +17,8 @@ func testResHandoff(ht *lntest.HarnessTest) { paymentAmt = 50000 ) - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) // First we'll create a channel between Alice and Bob. ht.EnsureConnected(alice, bob) diff --git a/itest/lnd_rest_api_test.go b/itest/lnd_rest_api_test.go index 42a4783c21..e559230d9a 100644 --- a/itest/lnd_rest_api_test.go +++ b/itest/lnd_rest_api_test.go @@ -212,13 +212,13 @@ func testRestAPI(ht *lntest.HarnessTest) { // Make sure Alice allows all CORS origins. Bob will keep the default. // We also make sure the ping/pong messages are sent very often, so we // can test them without waiting half a minute. - alice, bob := ht.Alice, ht.Bob - alice.Cfg.ExtraArgs = append( - alice.Cfg.ExtraArgs, "--restcors=\"*\"", + bob := ht.NewNode("Bob", nil) + args := []string{ + "--restcors=\"*\"", fmt.Sprintf("--ws-ping-interval=%s", pingInterval), fmt.Sprintf("--ws-pong-wait=%s", pongWait), - ) - ht.RestartNode(alice) + } + alice := ht.NewNodeWithCoins("Alice", args) for _, tc := range testCases { tc := tc @@ -237,7 +237,7 @@ func testRestAPI(ht *lntest.HarnessTest) { } func wsTestCaseSubscription(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) // Find out the current best block so we can subscribe to the next one. hash, height := ht.GetBestBlock() @@ -328,7 +328,7 @@ func wsTestCaseSubscriptionMacaroon(ht *lntest.HarnessTest) { // This time we send the macaroon in the special header // Sec-Websocket-Protocol which is the only header field available to // browsers when opening a WebSocket. - alice := ht.Alice + alice := ht.NewNode("Alice", nil) mac, err := alice.ReadMacaroon( alice.Cfg.AdminMacPath, defaultTimeout, ) @@ -413,7 +413,7 @@ func wsTestCaseBiDirectionalSubscription(ht *lntest.HarnessTest) { // This time we send the macaroon in the special header // Sec-Websocket-Protocol which is the only header field available to // browsers when opening a WebSocket. - alice := ht.Alice + alice := ht.NewNode("Alice", nil) mac, err := alice.ReadMacaroon( alice.Cfg.AdminMacPath, defaultTimeout, ) @@ -522,7 +522,7 @@ func wsTestCaseBiDirectionalSubscription(ht *lntest.HarnessTest) { // Before we start opening channels, make sure the two nodes are // connected. - bob := ht.Bob + bob := ht.NewNodeWithCoins("Bob", nil) ht.EnsureConnected(alice, bob) // Open 3 channels to make sure multiple requests and responses can be @@ -554,7 +554,7 @@ func wsTestPingPongTimeout(ht *lntest.HarnessTest) { // This time we send the macaroon in the special header // Sec-Websocket-Protocol which is the only header field available to // browsers when opening a WebSocket. - alice := ht.Alice + alice := ht.NewNode("Alice", nil) mac, err := alice.ReadMacaroon( alice.Cfg.AdminMacPath, defaultTimeout, ) diff --git a/itest/lnd_route_blinding_test.go b/itest/lnd_route_blinding_test.go index f09d5dc35d..64ff8d12de 100644 --- a/itest/lnd_route_blinding_test.go +++ b/itest/lnd_route_blinding_test.go @@ -26,11 +26,9 @@ import ( // expected. It also includes the edge case of a single-hop blinded route, // which indicates that the introduction node is the recipient. func testQueryBlindedRoutes(ht *lntest.HarnessTest) { - var ( - // Convenience aliases. - alice = ht.Alice - bob = ht.Bob - ) + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) + ht.EnsureConnected(alice, bob) // Setup a two hop channel network: Alice -- Bob -- Carol. // We set our proportional fee for these channels to zero, so that @@ -318,6 +316,8 @@ func testQueryBlindedRoutes(ht *lntest.HarnessTest) { type blindedForwardTest struct { ht *lntest.HarnessTest + alice *node.HarnessNode + bob *node.HarnessNode carol *node.HarnessNode dave *node.HarnessNode channels []*lnrpc.ChannelPoint @@ -349,11 +349,24 @@ func newBlindedForwardTest(ht *lntest.HarnessTest) (context.Context, func (b *blindedForwardTest) setupNetwork(ctx context.Context, withInterceptor bool) { + const chanAmt = btcutil.Amount(100_000) + carolArgs := []string{"--bitcoin.timelockdelta=18"} if withInterceptor { carolArgs = append(carolArgs, "--requireinterceptor") } - b.carol = b.ht.NewNode("Carol", carolArgs) + + daveArgs := []string{"--bitcoin.timelockdelta=18"} + cfgs := [][]string{nil, nil, carolArgs, daveArgs} + param := lntest.OpenChannelParams{ + Amt: chanAmt, + } + + // Creates a network with the following topology and liquidity: + // Alice (100k)----- Bob (100k) ----- Carol (100k) ----- Dave + chanPoints, nodes := b.ht.CreateSimpleNetwork(cfgs, param) + b.channels = chanPoints + b.alice, b.bob, b.carol, b.dave = nodes[0], nodes[1], nodes[2], nodes[3] if withInterceptor { var err error @@ -362,10 +375,6 @@ func (b *blindedForwardTest) setupNetwork(ctx context.Context, ) require.NoError(b.ht, err, "interceptor") } - - b.dave = b.ht.NewNode("Dave", []string{"--bitcoin.timelockdelta=18"}) - - b.channels = setupFourHopNetwork(b.ht, b.carol, b.dave) } // buildBlindedPath returns a blinded route from Bob -> Carol -> Dave, with Bob @@ -395,7 +404,7 @@ func (b *blindedForwardTest) buildBlindedPath() *lnrpc.BlindedPaymentPath { require.Len(b.ht, payReq.BlindedPaths, 1) path := payReq.BlindedPaths[0].BlindedPath require.Len(b.ht, path.BlindedHops, 3) - require.EqualValues(b.ht, path.IntroductionNode, b.ht.Bob.PubKey[:]) + require.EqualValues(b.ht, path.IntroductionNode, b.bob.PubKey[:]) return payReq.BlindedPaths[0] } @@ -403,8 +412,8 @@ func (b *blindedForwardTest) buildBlindedPath() *lnrpc.BlindedPaymentPath { // cleanup tears down all channels created by the test and cancels the top // level context used in the test. func (b *blindedForwardTest) cleanup() { - b.ht.CloseChannel(b.ht.Alice, b.channels[0]) - b.ht.CloseChannel(b.ht.Bob, b.channels[1]) + b.ht.CloseChannel(b.alice, b.channels[0]) + b.ht.CloseChannel(b.bob, b.channels[1]) b.ht.CloseChannel(b.carol, b.channels[2]) b.cancel() @@ -431,7 +440,7 @@ func (b *blindedForwardTest) createRouteToBlinded(paymentAmt int64, }, } - resp := b.ht.Alice.RPC.QueryRoutes(req) + resp := b.alice.RPC.QueryRoutes(req) require.Greater(b.ht, len(resp.Routes), 0, "no routes") require.Len(b.ht, resp.Routes[0].Hops, 3, "unexpected route length") @@ -452,7 +461,7 @@ func (b *blindedForwardTest) sendBlindedPayment(ctx context.Context, ctx, cancel := context.WithTimeout(ctx, time.Hour) go func() { - _, err := b.ht.Alice.RPC.Router.SendToRouteV2(ctx, sendReq) + _, err := b.alice.RPC.Router.SendToRouteV2(ctx, sendReq) // We may get a context canceled error when the test is // finished. @@ -481,7 +490,7 @@ func (b *blindedForwardTest) sendToRoute(route *lnrpc.Route, // Let Alice send to the blinded payment path and assert that it // succeeds/fails. - htlcAttempt := b.ht.Alice.RPC.SendToRouteV2(sendReq) + htlcAttempt := b.alice.RPC.SendToRouteV2(sendReq) if assertSuccess { require.Nil(b.ht, htlcAttempt.Failure) require.Equal(b.ht, htlcAttempt.Status, @@ -498,7 +507,7 @@ func (b *blindedForwardTest) sendToRoute(route *lnrpc.Route, require.NoError(b.ht, err) pmt := b.ht.AssertPaymentStatus( - b.ht.Alice, preimage, lnrpc.Payment_FAILED, + b.alice, preimage, lnrpc.Payment_FAILED, ) require.Len(b.ht, pmt.Htlcs, 1) @@ -520,7 +529,7 @@ func (b *blindedForwardTest) drainCarolLiquidity(incoming bool) { receivingNode := b.dave if incoming { - sendingNode = b.ht.Bob + sendingNode = b.bob receivingNode = b.carol } @@ -556,7 +565,8 @@ func (b *blindedForwardTest) drainCarolLiquidity(incoming bool) { func setupFourHopNetwork(ht *lntest.HarnessTest, carol, dave *node.HarnessNode) []*lnrpc.ChannelPoint { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) const chanAmt = btcutil.Amount(100000) var networkChans []*lnrpc.ChannelPoint @@ -611,8 +621,6 @@ func setupFourHopNetwork(ht *lntest.HarnessTest, // path and forward payments in a blinded route and finally, receiving the // payment. func testBlindedRouteInvoices(ht *lntest.HarnessTest) { - alice := ht.Alice - ctx, testCase := newBlindedForwardTest(ht) defer testCase.cleanup() @@ -620,6 +628,8 @@ func testBlindedRouteInvoices(ht *lntest.HarnessTest) { // blinded path that uses Bob as an introduction node. testCase.setupNetwork(ctx, false) + alice := testCase.alice + // Let Dave add a blinded invoice. // Add restrictions so that he only ever creates a single blinded path // from Bob to himself. @@ -737,14 +747,14 @@ func testRelayingBlindedError(ht *lntest.HarnessTest) { // over Alice -- Bob -- Carol -- Dave, where Bob is the introduction node and // has insufficient outgoing liquidity to forward on to carol. func testIntroductionNodeError(ht *lntest.HarnessTest) { - bob := ht.Bob - ctx, testCase := newBlindedForwardTest(ht) defer testCase.cleanup() testCase.setupNetwork(ctx, false) blindedPaymentPath := testCase.buildBlindedPath() route := testCase.createRouteToBlinded(10_000_000, blindedPaymentPath) + bob := testCase.bob + // Before we send our payment, drain all of Carol's incoming liquidity // so that she can't receive the forward from Bob, causing a failure // at the introduction node. @@ -770,8 +780,6 @@ func testIntroductionNodeError(ht *lntest.HarnessTest) { // testDisableIntroductionNode tests disabling of blinded forwards for the // introduction node. func testDisableIntroductionNode(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob - // First construct a blinded route while Bob is still advertising the // route blinding feature bit to ensure that Bob is included in the // blinded path that Dave selects. @@ -781,6 +789,8 @@ func testDisableIntroductionNode(ht *lntest.HarnessTest) { blindedPaymentPath := testCase.buildBlindedPath() route := testCase.createRouteToBlinded(10_000_000, blindedPaymentPath) + alice, bob := testCase.alice, testCase.bob + // Now, disable route blinding for Bob, then re-connect to Alice. ht.RestartNodeWithExtraArgs(bob, []string{ "--protocol.no-route-blinding", @@ -796,8 +806,6 @@ func testDisableIntroductionNode(ht *lntest.HarnessTest) { // to resolve blinded HTLCs on chain between restarts, as we've got all the // infrastructure in place already for error testing. func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob - // Setup a test case, note that we don't use its built in clean up // because we're going to close a channel, so we'll close out the // rest manually. @@ -811,6 +819,8 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { 50_000_000, blindedPaymentPath, ) + alice, bob := testCase.alice, testCase.bob + // Once our interceptor is set up, we can send the blinded payment. cancelPmt := testCase.sendBlindedPayment(ctx, blindedRoute) defer cancelPmt() @@ -917,8 +927,8 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { func testMPPToSingleBlindedPath(ht *lntest.HarnessTest) { // Create a five-node context consisting of Alice, Bob and three new // nodes. - alice, bob := ht.Alice, ht.Bob - + alice := ht.NewNode("Alice", nil) + bob := ht.NewNode("Bob", nil) dave := ht.NewNode("dave", nil) carol := ht.NewNode("carol", nil) eve := ht.NewNode("eve", nil) @@ -932,10 +942,12 @@ func testMPPToSingleBlindedPath(ht *lntest.HarnessTest) { // Send coins to the nodes and mine 1 blocks to confirm them. for i := 0; i < 2; i++ { + ht.FundCoinsUnconfirmed(btcutil.SatoshiPerBitcoin, alice) + ht.FundCoinsUnconfirmed(btcutil.SatoshiPerBitcoin, bob) ht.FundCoinsUnconfirmed(btcutil.SatoshiPerBitcoin, carol) ht.FundCoinsUnconfirmed(btcutil.SatoshiPerBitcoin, dave) ht.FundCoinsUnconfirmed(btcutil.SatoshiPerBitcoin, eve) - ht.MineBlocksAndAssertNumTxes(1, 3) + ht.MineBlocksAndAssertNumTxes(1, 5) } const paymentAmt = btcutil.Amount(300000) @@ -1107,11 +1119,11 @@ func testMPPToSingleBlindedPath(ht *lntest.HarnessTest) { // between him and the introduction node. So we expect that Carol is chosen as // the intro node and that one dummy hops is appended. func testBlindedRouteDummyHops(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) // Disable route blinding for Bob so that he is never chosen as the // introduction node. - ht.RestartNodeWithExtraArgs(bob, []string{ + bob := ht.NewNodeWithCoins("Bob", []string{ "--protocol.no-route-blinding", }) @@ -1278,7 +1290,8 @@ func testBlindedRouteDummyHops(ht *lntest.HarnessTest) { // \ / // --- Carol --- func testMPPToMultipleBlindedPaths(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) // Create a four-node context consisting of Alice, Bob and three new // nodes. @@ -1440,8 +1453,6 @@ func testMPPToMultipleBlindedPaths(ht *lntest.HarnessTest) { // UpdateAddHTLC which we need to ensure gets included in the message on // restart. func testBlindedPaymentHTLCReForward(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob - // Setup a test case. ctx, testCase := newBlindedForwardTest(ht) defer testCase.cleanup() @@ -1449,6 +1460,8 @@ func testBlindedPaymentHTLCReForward(ht *lntest.HarnessTest) { // Set up network with carol interceptor. testCase.setupNetwork(ctx, true) + alice, bob := testCase.alice, testCase.bob + // Let dave create invoice. blindedPaymentPath := testCase.buildBlindedPath() route := testCase.createRouteToBlinded(10_000_000, blindedPaymentPath) @@ -1465,7 +1478,7 @@ func testBlindedPaymentHTLCReForward(ht *lntest.HarnessTest) { go func() { defer close(done) - htlcAttempt, err := testCase.ht.Alice.RPC.Router.SendToRouteV2( + htlcAttempt, err := testCase.alice.RPC.Router.SendToRouteV2( ctx, sendReq, ) require.NoError(testCase.ht, err) diff --git a/itest/lnd_routing_test.go b/itest/lnd_routing_test.go index 04500a47cd..e05bf441b2 100644 --- a/itest/lnd_routing_test.go +++ b/itest/lnd_routing_test.go @@ -317,9 +317,8 @@ func runMultiHopSendToRoute(ht *lntest.HarnessTest, useGraphCache bool) { opts = append(opts, "--db.no-graph-cache") } - alice, bob := ht.Alice, ht.Bob - ht.RestartNodeWithExtraArgs(alice, opts) - + alice := ht.NewNodeWithCoins("Alice", opts) + bob := ht.NewNodeWithCoins("Bob", opts) ht.EnsureConnected(alice, bob) const chanAmt = btcutil.Amount(100000) @@ -417,7 +416,10 @@ func testSendToRouteErrorPropagation(ht *lntest.HarnessTest) { // Open a channel with 100k satoshis between Alice and Bob with Alice // being the sole funder of the channel. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) + ht.EnsureConnected(alice, bob) + chanPointAlice := ht.OpenChannel( alice, bob, lntest.OpenChannelParams{Amt: chanAmt}, ) @@ -496,7 +498,10 @@ func testPrivateChannels(ht *lntest.HarnessTest) { // where the 100k channel between Carol and Alice is private. // Open a channel with 200k satoshis between Alice and Bob. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) + ht.EnsureConnected(alice, bob) + chanPointAlice := ht.OpenChannel( alice, bob, lntest.OpenChannelParams{Amt: chanAmt * 2}, ) @@ -618,7 +623,10 @@ func testInvoiceRoutingHints(ht *lntest.HarnessTest) { // throughout this test. We'll include a push amount since we currently // require channels to have enough remote balance to cover the // invoice's payment. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) + ht.EnsureConnected(alice, bob) + chanPointBob := ht.OpenChannel( alice, bob, lntest.OpenChannelParams{ Amt: chanAmt, @@ -750,7 +758,7 @@ func testInvoiceRoutingHints(ht *lntest.HarnessTest) { // testScidAliasRoutingHints tests that dynamically created aliases via the RPC // are properly used when routing. func testScidAliasRoutingHints(ht *lntest.HarnessTest) { - bob := ht.Bob + bob := ht.NewNodeWithCoins("Bob", nil) const chanAmt = btcutil.Amount(800000) @@ -948,7 +956,10 @@ func testMultiHopOverPrivateChannels(ht *lntest.HarnessTest) { // First, we'll open a private channel between Alice and Bob with Alice // being the funder. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) + ht.EnsureConnected(alice, bob) + chanPointAlice := ht.OpenChannel( alice, bob, lntest.OpenChannelParams{ Amt: chanAmt, @@ -958,7 +969,7 @@ func testMultiHopOverPrivateChannels(ht *lntest.HarnessTest) { // Next, we'll create Carol's node and open a public channel between // her and Bob with Bob being the funder. - carol := ht.NewNode("Carol", nil) + carol := ht.NewNodeWithCoins("Carol", nil) ht.ConnectNodes(bob, carol) chanPointBob := ht.OpenChannel( bob, carol, lntest.OpenChannelParams{ @@ -973,7 +984,6 @@ func testMultiHopOverPrivateChannels(ht *lntest.HarnessTest) { // him and Carol with Carol being the funder. dave := ht.NewNode("Dave", nil) ht.ConnectNodes(carol, dave) - ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) chanPointCarol := ht.OpenChannel( carol, dave, lntest.OpenChannelParams{ @@ -1050,7 +1060,9 @@ func testQueryRoutes(ht *lntest.HarnessTest) { const chanAmt = btcutil.Amount(100000) // Grab Alice and Bob from the standby nodes. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) + ht.EnsureConnected(alice, bob) // Create Carol and connect her to Bob. We also send her some coins for // channel opening. @@ -1353,7 +1365,10 @@ func testRouteFeeCutoff(ht *lntest.HarnessTest) { const chanAmt = btcutil.Amount(100000) // Open a channel between Alice and Bob. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("Bob", nil) + ht.EnsureConnected(alice, bob) + chanPointAliceBob := ht.OpenChannel( alice, bob, lntest.OpenChannelParams{Amt: chanAmt}, ) diff --git a/itest/lnd_signer_test.go b/itest/lnd_signer_test.go index 2858e771c5..ada7534089 100644 --- a/itest/lnd_signer_test.go +++ b/itest/lnd_signer_test.go @@ -25,7 +25,7 @@ import ( // the node's pubkey and a customized public key to check the validity of the // result. func testDeriveSharedKey(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) runDeriveSharedKey(ht, alice) } @@ -199,7 +199,7 @@ func runDeriveSharedKey(ht *lntest.HarnessTest, alice *node.HarnessNode) { // testSignOutputRaw makes sure that the SignOutputRaw RPC can be used with all // custom ways of specifying the signing key in the key descriptor/locator. func testSignOutputRaw(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) runSignOutputRaw(ht, alice) } @@ -381,7 +381,7 @@ func assertSignOutputRaw(ht *lntest.HarnessTest, // all custom flags by verifying with VerifyMessage. Tests both ECDSA and // Schnorr signatures. func testSignVerifyMessage(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) runSignVerifyMessage(ht, alice) } diff --git a/itest/lnd_single_hop_invoice_test.go b/itest/lnd_single_hop_invoice_test.go index 8051f7bb86..4adc37b72e 100644 --- a/itest/lnd_single_hop_invoice_test.go +++ b/itest/lnd_single_hop_invoice_test.go @@ -18,10 +18,11 @@ func testSingleHopInvoice(ht *lntest.HarnessTest) { // Open a channel with 100k satoshis between Alice and Bob with Alice // being the sole funder of the channel. chanAmt := btcutil.Amount(100000) - alice, bob := ht.Alice, ht.Bob - cp := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{Amt: chanAmt}, + chanPoints, nodes := ht.CreateSimpleNetwork( + [][]string{nil, nil}, lntest.OpenChannelParams{Amt: chanAmt}, ) + cp := chanPoints[0] + alice, bob := nodes[0], nodes[1] // assertAmountPaid is a helper closure that asserts the amount paid by // Alice and received by Bob are expected. diff --git a/itest/lnd_sweep_test.go b/itest/lnd_sweep_test.go index d86b382dd9..764ca93082 100644 --- a/itest/lnd_sweep_test.go +++ b/itest/lnd_sweep_test.go @@ -1558,7 +1558,7 @@ func testSweepCommitOutputAndAnchor(ht *lntest.HarnessTest) { // CPFP, then RBF. Along the way, we check the `BumpFee` can properly update // the fee function used by supplying new params. func testBumpFee(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) runBumpFee(ht, alice) } diff --git a/itest/lnd_switch_test.go b/itest/lnd_switch_test.go index f1ac628cab..ca68802fe0 100644 --- a/itest/lnd_switch_test.go +++ b/itest/lnd_switch_test.go @@ -383,7 +383,9 @@ func setupScenarioFourNodes(ht *lntest.HarnessTest) *scenarioFourNodes { } // Grab the standby nodes. - alice, bob := ht.Alice, ht.Bob + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNodeWithCoins("bob", nil) + ht.ConnectNodes(alice, bob) // As preliminary setup, we'll create two new nodes: Carol and Dave, // such that we now have a 4 node, 3 channel topology. Dave will make diff --git a/itest/lnd_taproot_test.go b/itest/lnd_taproot_test.go index d2dd35b528..2b68105fdb 100644 --- a/itest/lnd_taproot_test.go +++ b/itest/lnd_taproot_test.go @@ -49,7 +49,7 @@ var ( // testTaproot ensures that the daemon can send to and spend from taproot (p2tr) // outputs. func testTaproot(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) testTaprootSendCoinsKeySpendBip86(ht, alice) testTaprootComputeInputScriptKeySpendBip86(ht, alice) diff --git a/itest/lnd_trackpayments_test.go b/itest/lnd_trackpayments_test.go index b942cd4c72..0dd3467155 100644 --- a/itest/lnd_trackpayments_test.go +++ b/itest/lnd_trackpayments_test.go @@ -14,21 +14,19 @@ import ( // testTrackPayments tests whether a client that calls the TrackPayments api // receives payment updates. func testTrackPayments(ht *lntest.HarnessTest) { - alice, bob := ht.Alice, ht.Bob - - // Restart Alice with the new flag so she understands the new payment + // Create Alice with the new flag so she understands the new payment // status. - ht.RestartNodeWithExtraArgs(alice, []string{ - "--routerrpc.usestatusinitiated", - }) + cfgAlice := []string{"--routerrpc.usestatusinitiated"} + cfgs := [][]string{cfgAlice, nil} - // Open a channel between alice and bob. - ht.EnsureConnected(alice, bob) - channel := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{ + // Create a channel Alice->Bob. + chanPoints, nodes := ht.CreateSimpleNetwork( + cfgs, lntest.OpenChannelParams{ Amt: btcutil.Amount(300000), }, ) + channel := chanPoints[0] + alice, bob := nodes[0], nodes[1] // Call the TrackPayments api to listen for payment updates. req := &routerrpc.TrackPaymentsRequest{ @@ -104,12 +102,13 @@ func testTrackPayments(ht *lntest.HarnessTest) { // is not set, the new Payment_INITIATED is replaced with Payment_IN_FLIGHT. func testTrackPaymentsCompatible(ht *lntest.HarnessTest) { // Open a channel between alice and bob. - alice, bob := ht.Alice, ht.Bob - channel := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{ + chanPoints, nodes := ht.CreateSimpleNetwork( + [][]string{nil, nil}, lntest.OpenChannelParams{ Amt: btcutil.Amount(300000), }, ) + channel := chanPoints[0] + alice, bob := nodes[0], nodes[1] // Call the TrackPayments api to listen for payment updates. req := &routerrpc.TrackPaymentsRequest{ diff --git a/itest/lnd_wallet_import_test.go b/itest/lnd_wallet_import_test.go index f4acc6365b..eab0f2c04f 100644 --- a/itest/lnd_wallet_import_test.go +++ b/itest/lnd_wallet_import_test.go @@ -582,7 +582,7 @@ func runWalletImportAccountScenario(ht *lntest.HarnessTest, // Send coins to Carol's address and confirm them, making sure the // balance updates accordingly. - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) req := &lnrpc.SendCoinsRequest{ Addr: externalAddr, Amount: utxoAmt, @@ -694,7 +694,7 @@ func testWalletImportPubKeyScenario(ht *lntest.HarnessTest, addrType walletrpc.AddressType) { const utxoAmt int64 = btcutil.SatoshiPerBitcoin - alice := ht.Alice + alice := ht.NewNodeWithCoins("Alice", nil) // We'll start our test by having two nodes, Carol and Dave. // diff --git a/itest/lnd_watchtower_test.go b/itest/lnd_watchtower_test.go index 272d19d19d..1f5ad6ea31 100644 --- a/itest/lnd_watchtower_test.go +++ b/itest/lnd_watchtower_test.go @@ -39,7 +39,7 @@ var watchtowerTestCases = []*lntest.TestCase{ // testTowerClientTowerAndSessionManagement tests the various control commands // that a user has over the client's set of active towers and sessions. func testTowerClientTowerAndSessionManagement(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) const ( chanAmt = funding.MaxBtcFundingAmount @@ -240,7 +240,7 @@ func testTowerClientTowerAndSessionManagement(ht *lntest.HarnessTest) { // testTowerClientSessionDeletion tests that sessions are correctly deleted // when they are deemed closable. func testTowerClientSessionDeletion(ht *lntest.HarnessTest) { - alice := ht.Alice + alice := ht.NewNode("Alice", nil) const ( chanAmt = funding.MaxBtcFundingAmount @@ -395,7 +395,7 @@ func testRevokedCloseRetributionAltruistWatchtowerCase(ht *lntest.HarnessTest, // protection logic automatically. daveArgs := lntest.NodeArgsForCommitType(commitType) daveArgs = append(daveArgs, "--nolisten", "--wtclient.active") - dave := ht.NewNode("Dave", daveArgs) + dave := ht.NewNodeWithCoins("Dave", daveArgs) addTowerReq := &wtclientrpc.AddTowerRequest{ Pubkey: willyInfoPk, @@ -407,10 +407,6 @@ func testRevokedCloseRetributionAltruistWatchtowerCase(ht *lntest.HarnessTest, // announcement, so we open a channel with Carol, ht.ConnectNodes(dave, carol) - // Before we make a channel, we'll load up Dave with some coins sent - // directly from the miner. - ht.FundCoins(btcutil.SatoshiPerBitcoin, dave) - // Send one more UTXOs if this is a neutrino backend. if ht.IsNeutrinoBackend() { ht.FundCoins(btcutil.SatoshiPerBitcoin, dave) diff --git a/itest/lnd_wipe_fwdpkgs_test.go b/itest/lnd_wipe_fwdpkgs_test.go index b6211d7f8e..bd567f7a00 100644 --- a/itest/lnd_wipe_fwdpkgs_test.go +++ b/itest/lnd_wipe_fwdpkgs_test.go @@ -27,25 +27,12 @@ func testWipeForwardingPackages(ht *lntest.HarnessTest) { numInvoices = 3 ) - // Grab Alice and Bob from HarnessTest. - alice, bob := ht.Alice, ht.Bob - - // Create a new node Carol, which will create invoices that require - // Alice to pay. - carol := ht.NewNode("Carol", nil) - - // Connect Bob to Carol. - ht.ConnectNodes(bob, carol) - - // Open a channel between Alice and Bob. - chanPointAB := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{Amt: chanAmt}, - ) - - // Open a channel between Bob and Carol. - chanPointBC := ht.OpenChannel( - bob, carol, lntest.OpenChannelParams{Amt: chanAmt}, + chanPoints, nodes := ht.CreateSimpleNetwork( + [][]string{nil, nil, nil}, + lntest.OpenChannelParams{Amt: chanAmt}, ) + chanPointAB, chanPointBC := chanPoints[0], chanPoints[1] + alice, bob, carol := nodes[0], nodes[1], nodes[2] // Before we continue, make sure Alice has seen the channel between Bob // and Carol. diff --git a/itest/lnd_zero_conf_test.go b/itest/lnd_zero_conf_test.go index 6a658ab381..523a41c373 100644 --- a/itest/lnd_zero_conf_test.go +++ b/itest/lnd_zero_conf_test.go @@ -753,7 +753,7 @@ func testPrivateUpdateAlias(ht *lntest.HarnessTest, // testOptionScidUpgrade tests that toggling the option-scid-alias feature bit // correctly upgrades existing channels. func testOptionScidUpgrade(ht *lntest.HarnessTest) { - bob := ht.Bob + bob := ht.NewNodeWithCoins("Bob", nil) // Start carol with anchors only. carolArgs := []string{ diff --git a/lntest/harness.go b/lntest/harness.go index 606b64351b..ad9525c223 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -603,6 +603,42 @@ func (h *HarnessTest) NewNode(name string, return node } +// NewNodeWithCoins creates a new node and asserts its creation. The node is +// guaranteed to have finished its initialization and all its subservers are +// started. In addition, 5 UTXO of 1 BTC each are sent to the node. +func (h *HarnessTest) NewNodeWithCoins(name string, + extraArgs []string) *node.HarnessNode { + + node, err := h.manager.newNode(h.T, name, extraArgs, nil, false) + require.NoErrorf(h, err, "unable to create new node for %s", name) + + // Start the node. + err = node.Start(h.runCtx) + require.NoError(h, err, "failed to start node %s", node.Name()) + + // Load up the wallets of the node with 5 outputs of 1 BTC each. + const ( + numOutputs = 5 + fundAmount = 1 * btcutil.SatoshiPerBitcoin + totalAmount = fundAmount * numOutputs + ) + + for i := 0; i < numOutputs; i++ { + h.createAndSendOutput( + node, fundAmount, + lnrpc.AddressType_WITNESS_PUBKEY_HASH, + ) + } + + // Mine a block to confirm the transactions. + h.MineBlocksAndAssertNumTxes(1, numOutputs) + + // Now block until the wallet have fully synced up. + h.WaitForBalanceConfirmed(node, totalAmount) + + return node +} + // Shutdown shuts down the given node and asserts that no errors occur. func (h *HarnessTest) Shutdown(node *node.HarnessNode) { // The process may not be in a state to always shutdown immediately, so From 11c9dd5ff247bdaba21c0438cacfd057126176df Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 20 Nov 2024 14:48:35 +0800 Subject: [PATCH 06/64] itest: remove unused method `setupFourHopNetwork` --- itest/lnd_route_blinding_test.go | 59 -------------------------------- 1 file changed, 59 deletions(-) diff --git a/itest/lnd_route_blinding_test.go b/itest/lnd_route_blinding_test.go index 64ff8d12de..55b6894a17 100644 --- a/itest/lnd_route_blinding_test.go +++ b/itest/lnd_route_blinding_test.go @@ -557,65 +557,6 @@ func (b *blindedForwardTest) drainCarolLiquidity(incoming bool) { b.ht.AssertPaymentStatusFromStream(pmtClient, lnrpc.Payment_SUCCEEDED) } -// setupFourHopNetwork creates a network with the following topology and -// liquidity: -// Alice (100k)----- Bob (100k) ----- Carol (100k) ----- Dave -// -// The funding outpoint for AB / BC / CD are returned in-order. -func setupFourHopNetwork(ht *lntest.HarnessTest, - carol, dave *node.HarnessNode) []*lnrpc.ChannelPoint { - - alice := ht.NewNodeWithCoins("Alice", nil) - bob := ht.NewNodeWithCoins("Bob", nil) - - const chanAmt = btcutil.Amount(100000) - var networkChans []*lnrpc.ChannelPoint - - // Open a channel with 100k satoshis between Alice and Bob with Alice - // being the sole funder of the channel. - chanPointAlice := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{ - Amt: chanAmt, - }, - ) - networkChans = append(networkChans, chanPointAlice) - - // Create a channel between bob and carol. - ht.EnsureConnected(bob, carol) - chanPointBob := ht.OpenChannel( - bob, carol, lntest.OpenChannelParams{ - Amt: chanAmt, - }, - ) - networkChans = append(networkChans, chanPointBob) - - // Fund carol and connect her and dave so that she can create a channel - // between them. - ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) - ht.EnsureConnected(carol, dave) - - chanPointCarol := ht.OpenChannel( - carol, dave, lntest.OpenChannelParams{ - Amt: chanAmt, - }, - ) - networkChans = append(networkChans, chanPointCarol) - - // Wait for all nodes to have seen all channels. - nodes := []*node.HarnessNode{alice, bob, carol, dave} - for _, chanPoint := range networkChans { - for _, node := range nodes { - ht.AssertChannelInGraph(node, chanPoint) - } - } - - return []*lnrpc.ChannelPoint{ - chanPointAlice, - chanPointBob, - chanPointCarol, - } -} - // testBlindedRouteInvoices tests lnd's ability to create a blinded payment path // which it then inserts into an invoice, sending to an invoice with a blinded // path and forward payments in a blinded route and finally, receiving the From 00772ae28170d0311e8aef5b012d6d0abccfe3fa Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 20 Nov 2024 14:51:37 +0800 Subject: [PATCH 07/64] itest+lntest: remove standby nodes This commit removes the standby nodes Alice and Bob. --- itest/lnd_test.go | 22 +--- lntest/harness.go | 177 ++------------------------------- lntest/harness_node_manager.go | 13 +-- 3 files changed, 14 insertions(+), 198 deletions(-) diff --git a/itest/lnd_test.go b/itest/lnd_test.go index f2a345fa11..ebc751ab28 100644 --- a/itest/lnd_test.go +++ b/itest/lnd_test.go @@ -8,7 +8,6 @@ import ( "os" "path/filepath" "runtime" - "strings" "testing" "time" @@ -110,10 +109,6 @@ func TestLightningNetworkDaemon(t *testing.T) { ) defer harnessTest.Stop() - // Setup standby nodes, Alice and Bob, which will be alive and shared - // among all the test cases. - harnessTest.SetupStandbyNodes() - // Get the current block height. height := harnessTest.CurrentHeight() @@ -130,22 +125,7 @@ func TestLightningNetworkDaemon(t *testing.T) { // avoid overwriting the external harness test that is // tied to the parent test. ht := harnessTest.Subtest(t1) - - // TODO(yy): split log files. - cleanTestCaseName := strings.ReplaceAll( - testCase.Name, " ", "_", - ) - ht.SetTestName(cleanTestCaseName) - - logLine := fmt.Sprintf( - "STARTING ============ %v ============\n", - testCase.Name, - ) - - ht.Alice.AddToLogf(logLine) - ht.Bob.AddToLogf(logLine) - - ht.EnsureConnected(ht.Alice, ht.Bob) + ht.SetTestName(testCase.Name) ht.RunTestCase(testCase) }) diff --git a/lntest/harness.go b/lntest/harness.go index ad9525c223..281d5ff0bc 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -4,6 +4,7 @@ import ( "context" "encoding/hex" "fmt" + "strings" "testing" "time" @@ -67,24 +68,12 @@ type TestCase struct { TestFunc func(t *HarnessTest) } -// standbyNodes are a list of nodes which are created during the initialization -// of the test and used across all test cases. -type standbyNodes struct { - // Alice and Bob are the initial seeder nodes that are automatically - // created to be the initial participants of the test network. - Alice *node.HarnessNode - Bob *node.HarnessNode -} - // HarnessTest builds on top of a testing.T with enhanced error detection. It // is responsible for managing the interactions among different nodes, and // providing easy-to-use assertions. type HarnessTest struct { *testing.T - // Embed the standbyNodes so we can easily access them via `ht.Alice`. - standbyNodes - // miner is a reference to a running full node that can be used to // create new blocks on the network. miner *miner.HarnessMiner @@ -271,97 +260,6 @@ func (h *HarnessTest) createAndSendOutput(target *node.HarnessNode, h.miner.SendOutput(output, defaultMinerFeeRate) } -// SetupRemoteSigningStandbyNodes starts the initial seeder nodes within the -// test harness in a remote signing configuration. The initial node's wallets -// will be funded wallets with 100x1 BTC outputs each. -func (h *HarnessTest) SetupRemoteSigningStandbyNodes() { - h.Log("Setting up standby nodes Alice and Bob with remote " + - "signing configurations...") - defer h.Log("Finished the setup, now running tests...") - - password := []byte("itestpassword") - - // Setup remote signing nodes for Alice and Bob. - signerAlice := h.NewNode("SignerAlice", nil) - signerBob := h.NewNode("SignerBob", nil) - - // Setup watch-only nodes for Alice and Bob, each configured with their - // own remote signing instance. - h.Alice = h.setupWatchOnlyNode("Alice", signerAlice, password) - h.Bob = h.setupWatchOnlyNode("Bob", signerBob, password) - - // Fund each node with 100 BTC (using 100 separate transactions). - const fundAmount = 1 * btcutil.SatoshiPerBitcoin - const numOutputs = 100 - const totalAmount = fundAmount * numOutputs - for _, node := range []*node.HarnessNode{h.Alice, h.Bob} { - h.manager.standbyNodes[node.Cfg.NodeID] = node - for i := 0; i < numOutputs; i++ { - h.createAndSendOutput( - node, fundAmount, - lnrpc.AddressType_WITNESS_PUBKEY_HASH, - ) - } - } - - // We generate several blocks in order to give the outputs created - // above a good number of confirmations. - const totalTxes = 200 - h.MineBlocksAndAssertNumTxes(numBlocksSendOutput, totalTxes) - - // Now we want to wait for the nodes to catch up. - h.WaitForBlockchainSync(h.Alice) - h.WaitForBlockchainSync(h.Bob) - - // Now block until both wallets have fully synced up. - h.WaitForBalanceConfirmed(h.Alice, totalAmount) - h.WaitForBalanceConfirmed(h.Bob, totalAmount) -} - -// SetUp starts the initial seeder nodes within the test harness. The initial -// node's wallets will be funded wallets with 10x10 BTC outputs each. -func (h *HarnessTest) SetupStandbyNodes() { - h.Log("Setting up standby nodes Alice and Bob...") - defer h.Log("Finished the setup, now running tests...") - - lndArgs := []string{ - "--default-remote-max-htlcs=483", - "--channel-max-fee-exposure=5000000", - } - - // Start the initial seeder nodes within the test network. - h.Alice = h.NewNode("Alice", lndArgs) - h.Bob = h.NewNode("Bob", lndArgs) - - // Load up the wallets of the seeder nodes with 100 outputs of 1 BTC - // each. - const fundAmount = 1 * btcutil.SatoshiPerBitcoin - const numOutputs = 100 - const totalAmount = fundAmount * numOutputs - for _, node := range []*node.HarnessNode{h.Alice, h.Bob} { - h.manager.standbyNodes[node.Cfg.NodeID] = node - for i := 0; i < numOutputs; i++ { - h.createAndSendOutput( - node, fundAmount, - lnrpc.AddressType_WITNESS_PUBKEY_HASH, - ) - } - } - - // We generate several blocks in order to give the outputs created - // above a good number of confirmations. - const totalTxes = 200 - h.MineBlocksAndAssertNumTxes(numBlocksSendOutput, totalTxes) - - // Now we want to wait for the nodes to catch up. - h.WaitForBlockchainSync(h.Alice) - h.WaitForBlockchainSync(h.Bob) - - // Now block until both wallets have fully synced up. - h.WaitForBalanceConfirmed(h.Alice, totalAmount) - h.WaitForBalanceConfirmed(h.Bob, totalAmount) -} - // Stop stops the test harness. func (h *HarnessTest) Stop() { // Do nothing if it's not started. @@ -399,24 +297,6 @@ func (h *HarnessTest) RunTestCase(testCase *TestCase) { testCase.TestFunc(h) } -// resetStandbyNodes resets all standby nodes by attaching the new testing.T -// and restarting them with the original config. -func (h *HarnessTest) resetStandbyNodes(t *testing.T) { - t.Helper() - - for _, hn := range h.manager.standbyNodes { - // Inherit the testing.T. - h.T = t - - // Reset the config so the node will be using the default - // config for the coming test. This will also inherit the - // test's running context. - h.RestartNodeWithExtraArgs(hn, hn.Cfg.OriginalExtraArgs) - - hn.AddToLogf("Finished test case %v", h.manager.currentTestCase) - } -} - // Subtest creates a child HarnessTest, which inherits the harness net and // stand by nodes created by the parent test. It will return a cleanup function // which resets all the standby nodes' configs back to its original state and @@ -428,7 +308,6 @@ func (h *HarnessTest) Subtest(t *testing.T) *HarnessTest { T: t, manager: h.manager, miner: h.miner, - standbyNodes: h.standbyNodes, feeService: h.feeService, lndErrorChan: make(chan error, lndErrorChanSize), } @@ -439,9 +318,6 @@ func (h *HarnessTest) Subtest(t *testing.T) *HarnessTest { // Inherit the subtest for the miner. st.miner.T = st.T - // Reset the standby nodes. - st.resetStandbyNodes(t) - // Reset fee estimator. st.feeService.Reset() @@ -471,14 +347,8 @@ func (h *HarnessTest) Subtest(t *testing.T) *HarnessTest { return } - // When we finish the test, reset the nodes' configs and take a - // snapshot of each of the nodes' internal states. - for _, node := range st.manager.standbyNodes { - st.cleanupStandbyNode(node) - } - // If found running nodes, shut them down. - st.shutdownNonStandbyNodes() + st.shutdownAllNodes() // We require the mempool to be cleaned from the test. require.Empty(st, st.miner.GetRawMempool(), "mempool not "+ @@ -498,26 +368,9 @@ func (h *HarnessTest) Subtest(t *testing.T) *HarnessTest { return st } -// shutdownNonStandbyNodes will shutdown any non-standby nodes. -func (h *HarnessTest) shutdownNonStandbyNodes() { - h.shutdownNodes(true) -} - // shutdownAllNodes will shutdown all running nodes. func (h *HarnessTest) shutdownAllNodes() { - h.shutdownNodes(false) -} - -// shutdownNodes will shutdown any non-standby nodes. If skipStandby is false, -// all the standby nodes will be shutdown too. -func (h *HarnessTest) shutdownNodes(skipStandby bool) { - for nid, node := range h.manager.activeNodes { - // If it's a standby node, skip. - _, ok := h.manager.standbyNodes[nid] - if ok && skipStandby { - continue - } - + for _, node := range h.manager.activeNodes { // The process may not be in a state to always shutdown // immediately, so we'll retry up to a hard limit to ensure we // eventually shutdown. @@ -566,26 +419,14 @@ func (h *HarnessTest) cleanupStandbyNode(hn *node.HarnessNode) { func (h *HarnessTest) removeConnectionns(hn *node.HarnessNode) { resp := hn.RPC.ListPeers() for _, peer := range resp.Peers { - // Skip disconnecting Alice and Bob. - switch peer.PubKey { - case h.Alice.PubKeyStr: - continue - case h.Bob.PubKeyStr: - continue - } - hn.RPC.DisconnectPeer(peer.PubKey) } } // SetTestName set the test case name. func (h *HarnessTest) SetTestName(name string) { - h.manager.currentTestCase = name - - // Overwrite the old log filename so we can create new log files. - for _, node := range h.manager.standbyNodes { - node.Cfg.LogFilenamePrefix = name - } + cleanTestCaseName := strings.ReplaceAll(name, " ", "_") + h.manager.currentTestCase = cleanTestCaseName } // NewNode creates a new node and asserts its creation. The node is guaranteed @@ -1507,7 +1348,7 @@ func (h *HarnessTest) fundCoins(amt btcutil.Amount, target *node.HarnessNode, } // FundCoins attempts to send amt satoshis from the internal mining node to the -// targeted lightning node using a P2WKH address. 2 blocks are mined after in +// targeted lightning node using a P2WKH address. 1 blocks are mined after in // order to confirm the transaction. func (h *HarnessTest) FundCoins(amt btcutil.Amount, hn *node.HarnessNode) { h.fundCoins(amt, hn, lnrpc.AddressType_WITNESS_PUBKEY_HASH, true) @@ -1783,9 +1624,9 @@ func (h *HarnessTest) RestartNodeAndRestoreDB(hn *node.HarnessNode) { // closures as the caller doesn't need to mine all the blocks to make sure the // mempool is empty. func (h *HarnessTest) CleanShutDown() { - // First, shutdown all non-standby nodes to prevent new transactions - // being created and fed into the mempool. - h.shutdownNonStandbyNodes() + // First, shutdown all nodes to prevent new transactions being created + // and fed into the mempool. + h.shutdownAllNodes() // Now mine blocks till the mempool is empty. h.cleanMempool() diff --git a/lntest/harness_node_manager.go b/lntest/harness_node_manager.go index 6ad4b90318..2040acec7f 100644 --- a/lntest/harness_node_manager.go +++ b/lntest/harness_node_manager.go @@ -40,10 +40,6 @@ type nodeManager struct { // {pubkey: *HarnessNode}. activeNodes map[uint32]*node.HarnessNode - // standbyNodes is a map of all the standby nodes, format: - // {pubkey: *HarnessNode}. - standbyNodes map[uint32]*node.HarnessNode - // nodeCounter is a monotonically increasing counter that's used as the // node's unique ID. nodeCounter atomic.Uint32 @@ -57,11 +53,10 @@ func newNodeManager(lndBinary string, dbBackend node.DatabaseBackend, nativeSQL bool) *nodeManager { return &nodeManager{ - lndBinary: lndBinary, - dbBackend: dbBackend, - nativeSQL: nativeSQL, - activeNodes: make(map[uint32]*node.HarnessNode), - standbyNodes: make(map[uint32]*node.HarnessNode), + lndBinary: lndBinary, + dbBackend: dbBackend, + nativeSQL: nativeSQL, + activeNodes: make(map[uint32]*node.HarnessNode), } } From 72f3f41d4124f5f6cff174d638095614ff5286be Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 29 Oct 2024 16:48:23 +0800 Subject: [PATCH 08/64] itest: remove unnecessary channel close and node shutdown Since we don't have standby nodes anymore, we don't need to close the channels when the test finishes. Previously we would do so to make sure the standby nodes have a clean state for the next test case, which is no longer relevant. --- itest/lnd_channel_balance_test.go | 7 -- itest/lnd_channel_funding_fund_max_test.go | 6 +- ...lnd_channel_funding_utxo_selection_test.go | 3 - itest/lnd_channel_graph_test.go | 18 +---- itest/lnd_channel_policy_test.go | 11 ---- itest/lnd_custom_features.go | 5 +- itest/lnd_experimental_endorsement.go | 7 +- itest/lnd_forward_interceptor_test.go | 28 +------- itest/lnd_funding_test.go | 61 +++-------------- itest/lnd_hold_invoice_force_test.go | 3 - itest/lnd_hold_persistence_test.go | 6 +- itest/lnd_htlc_test.go | 1 - itest/lnd_invoice_acceptor_test.go | 6 +- itest/lnd_max_channel_size_test.go | 4 +- itest/lnd_max_htlcs_test.go | 5 +- itest/lnd_misc_test.go | 36 ++-------- itest/lnd_multi-hop-error-propagation_test.go | 8 --- itest/lnd_multi-hop-payments_test.go | 5 -- itest/lnd_network_test.go | 7 +- itest/lnd_onchain_test.go | 6 +- itest/lnd_open_channel_test.go | 50 ++------------ itest/lnd_payment_test.go | 56 +--------------- itest/lnd_psbt_test.go | 20 ------ itest/lnd_quiescence_test.go | 1 - itest/lnd_res_handoff_test.go | 2 - itest/lnd_rest_api_test.go | 3 +- itest/lnd_route_blinding_test.go | 9 --- itest/lnd_routing_test.go | 65 ++----------------- itest/lnd_single_hop_invoice_test.go | 2 - itest/lnd_switch_test.go | 20 +----- itest/lnd_trackpayments_test.go | 27 +------- itest/lnd_wumbo_channels_test.go | 3 +- itest/lnd_zero_conf_test.go | 3 - 33 files changed, 47 insertions(+), 447 deletions(-) diff --git a/itest/lnd_channel_balance_test.go b/itest/lnd_channel_balance_test.go index 82382e9110..f723b0492d 100644 --- a/itest/lnd_channel_balance_test.go +++ b/itest/lnd_channel_balance_test.go @@ -63,10 +63,6 @@ func testChannelBalance(ht *lntest.HarnessTest) { // Ensure Bob currently has no available balance within the channel. checkChannelBalance(bob, 0, amount-lntest.CalcStaticFee(cType, 0)) - - // Finally close the channel between Alice and Bob, asserting that the - // channel has been properly closed on-chain. - ht.CloseChannel(alice, chanPoint) } // testChannelUnsettledBalance will test that the UnsettledBalance field @@ -208,7 +204,4 @@ func testChannelUnsettledBalance(ht *lntest.HarnessTest) { // balance that equals to the amount of invoices * payAmt. The local // balance remains zero. checkChannelBalance(carol, 0, aliceLocal, numInvoices*payAmt, 0) - - // Force and assert the channel closure. - ht.ForceCloseChannel(alice, chanPointAlice) } diff --git a/itest/lnd_channel_funding_fund_max_test.go b/itest/lnd_channel_funding_fund_max_test.go index 43aec3c982..c93ab5fdc7 100644 --- a/itest/lnd_channel_funding_fund_max_test.go +++ b/itest/lnd_channel_funding_fund_max_test.go @@ -57,10 +57,7 @@ func testChannelFundMax(ht *lntest.HarnessTest) { // tests. args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) alice := ht.NewNode("Alice", args) - defer ht.Shutdown(alice) - bob := ht.NewNode("Bob", args) - defer ht.Shutdown(bob) // Ensure both sides are connected so the funding flow can be properly // executed. @@ -229,13 +226,12 @@ func runFundMaxTestCase(ht *lntest.HarnessTest, alice, bob *node.HarnessNode, // Otherwise, if we expect to open a channel use the helper function. chanPoint := ht.OpenChannel(alice, bob, chanParams) + cType := ht.GetChannelCommitType(alice, chanPoint) // Close the channel between Alice and Bob, asserting // that the channel has been properly closed on-chain. defer ht.CloseChannel(alice, chanPoint) - cType := ht.GetChannelCommitType(alice, chanPoint) - // Alice's balance should be her amount subtracted by the commitment // transaction fee. checkChannelBalance( diff --git a/itest/lnd_channel_funding_utxo_selection_test.go b/itest/lnd_channel_funding_utxo_selection_test.go index 2b6d0cd301..f840b8ac99 100644 --- a/itest/lnd_channel_funding_utxo_selection_test.go +++ b/itest/lnd_channel_funding_utxo_selection_test.go @@ -64,10 +64,7 @@ func testChannelUtxoSelection(ht *lntest.HarnessTest) { // tests. args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) alice := ht.NewNode("Alice", args) - defer ht.Shutdown(alice) - bob := ht.NewNode("Bob", args) - defer ht.Shutdown(bob) // Ensure both sides are connected so the funding flow can be properly // executed. diff --git a/itest/lnd_channel_graph_test.go b/itest/lnd_channel_graph_test.go index e6b3c77370..96fec8e90b 100644 --- a/itest/lnd_channel_graph_test.go +++ b/itest/lnd_channel_graph_test.go @@ -234,7 +234,7 @@ func testUnannouncedChannels(ht *lntest.HarnessTest) { // One block is enough to make the channel ready for use, since the // nodes have defaultNumConfs=1 set. - fundingChanPoint := ht.WaitForChannelOpenEvent(chanOpenUpdate) + ht.WaitForChannelOpenEvent(chanOpenUpdate) // Alice should have 1 edge in her graph. ht.AssertNumActiveEdges(alice, 1, true) @@ -248,9 +248,6 @@ func testUnannouncedChannels(ht *lntest.HarnessTest) { // Give the network a chance to learn that auth proof is confirmed. ht.AssertNumActiveEdges(alice, 1, false) - - // Close the channel used during the test. - ht.CloseChannel(alice, fundingChanPoint) } func testGraphTopologyNotifications(ht *lntest.HarnessTest) { @@ -367,9 +364,6 @@ func testGraphTopologyNtfns(ht *lntest.HarnessTest, pinned bool) { // Bob's new node announcement, and the channel between Bob and Carol. ht.AssertNumChannelUpdates(alice, chanPoint, 2) ht.AssertNumNodeAnns(alice, bob.PubKeyStr, 1) - - // Close the channel between Bob and Carol. - ht.CloseChannel(bob, chanPoint) } // testNodeAnnouncement ensures that when a node is started with one or more @@ -402,7 +396,7 @@ func testNodeAnnouncement(ht *lntest.HarnessTest) { // We'll then go ahead and open a channel between Bob and Dave. This // ensures that Alice receives the node announcement from Bob as part of // the announcement broadcast. - chanPoint := ht.OpenChannel( + ht.OpenChannel( bob, dave, lntest.OpenChannelParams{Amt: 1000000}, ) @@ -424,9 +418,6 @@ func testNodeAnnouncement(ht *lntest.HarnessTest) { allUpdates := ht.AssertNumNodeAnns(alice, dave.PubKeyStr, 1) nodeUpdate := allUpdates[len(allUpdates)-1] assertAddrs(nodeUpdate.Addresses, advertisedAddrs...) - - // Close the channel between Bob and Dave. - ht.CloseChannel(bob, chanPoint) } // testUpdateNodeAnnouncement ensures that the RPC endpoint validates @@ -531,7 +522,7 @@ func testUpdateNodeAnnouncement(ht *lntest.HarnessTest) { // Go ahead and open a channel between Bob and Dave. This // ensures that Alice receives the node announcement from Bob as part of // the announcement broadcast. - chanPoint := ht.OpenChannel( + ht.OpenChannel( bob, dave, lntest.OpenChannelParams{ Amt: 1000000, }, @@ -661,9 +652,6 @@ func testUpdateNodeAnnouncement(ht *lntest.HarnessTest) { FeatureUpdates: updateFeatureActions, } dave.RPC.UpdateNodeAnnouncementErr(nodeAnnReq) - - // Close the channel between Bob and Dave. - ht.CloseChannel(bob, chanPoint) } // assertSyncType asserts that the peer has an expected syncType. diff --git a/itest/lnd_channel_policy_test.go b/itest/lnd_channel_policy_test.go index 3031296c1c..259740e529 100644 --- a/itest/lnd_channel_policy_test.go +++ b/itest/lnd_channel_policy_test.go @@ -420,11 +420,6 @@ func testUpdateChannelPolicy(ht *lntest.HarnessTest) { ht.AssertChannelPolicy( carol, alice.PubKeyStr, expectedPolicy, chanPoint3, ) - - // Close all channels. - ht.CloseChannel(alice, chanPoint) - ht.CloseChannel(bob, chanPoint2) - ht.CloseChannel(alice, chanPoint3) } // testSendUpdateDisableChannel ensures that a channel update with the disable @@ -773,10 +768,6 @@ func testUpdateChannelPolicyForPrivateChannel(ht *lntest.HarnessTest) { // Alice should have sent 20k satoshis + fee to Bob. ht.AssertAmountPaid("Alice(local) => Bob(remote)", alice, chanPointAliceBob, amtExpected, 0) - - // Finally, close the channels. - ht.CloseChannel(alice, chanPointAliceBob) - ht.CloseChannel(bob, chanPointBobCarol) } // testUpdateChannelPolicyFeeRateAccuracy tests that updating the channel policy @@ -845,8 +836,6 @@ func testUpdateChannelPolicyFeeRateAccuracy(ht *lntest.HarnessTest) { // Make sure that both Alice and Bob sees the same policy after update. assertNodesPolicyUpdate(ht, nodes, alice, expectedPolicy, chanPoint) - - ht.CloseChannel(alice, chanPoint) } // assertNodesPolicyUpdate checks that a given policy update has been received diff --git a/itest/lnd_custom_features.go b/itest/lnd_custom_features.go index cba6ee4aaf..701a86e79b 100644 --- a/itest/lnd_custom_features.go +++ b/itest/lnd_custom_features.go @@ -29,11 +29,10 @@ func testCustomFeatures(ht *lntest.HarnessTest) { } cfgs := [][]string{extraArgs, nil} - chanPoints, nodes := ht.CreateSimpleNetwork( + _, nodes := ht.CreateSimpleNetwork( cfgs, lntest.OpenChannelParams{Amt: 1000000}, ) alice, bob := nodes[0], nodes[1] - chanPoint := chanPoints[0] // Check that Alice's custom feature bit was sent to Bob in her init // message. @@ -79,8 +78,6 @@ func testCustomFeatures(ht *lntest.HarnessTest) { }, } alice.RPC.UpdateNodeAnnouncementErr(nodeAnnReq) - - ht.CloseChannel(alice, chanPoint) } // assertFeatureNotInSet checks that the features provided aren't contained in diff --git a/itest/lnd_experimental_endorsement.go b/itest/lnd_experimental_endorsement.go index d537715ed6..5a1f8fffca 100644 --- a/itest/lnd_experimental_endorsement.go +++ b/itest/lnd_experimental_endorsement.go @@ -49,7 +49,7 @@ func testEndorsement(ht *lntest.HarnessTest, aliceEndorse bool) { {Local: dave, Remote: eve, Param: p}, } resp := ht.OpenMultiChannelsAsync(reqs) - cpAB, cpBC, cpCD, cpDE := resp[0], resp[1], resp[2], resp[3] + _, cpBC, cpCD, cpDE := resp[0], resp[1], resp[2], resp[3] // Make sure Alice is aware of Bob=>Carol=>Dave=>Eve channels. ht.AssertChannelInGraph(alice, cpBC) @@ -95,11 +95,6 @@ func testEndorsement(ht *lntest.HarnessTest, aliceEndorse bool) { var preimage lntypes.Preimage copy(preimage[:], invoice.RPreimage) ht.AssertPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED) - - ht.CloseChannel(alice, cpAB) - ht.CloseChannel(bob, cpBC) - ht.CloseChannel(carol, cpCD) - ht.CloseChannel(dave, cpDE) } func validateEndorsedAndResume(ht *lntest.HarnessTest, diff --git a/itest/lnd_forward_interceptor_test.go b/itest/lnd_forward_interceptor_test.go index b677627e72..70227be246 100644 --- a/itest/lnd_forward_interceptor_test.go +++ b/itest/lnd_forward_interceptor_test.go @@ -177,10 +177,6 @@ func testForwardInterceptorDedupHtlc(ht *lntest.HarnessTest) { case <-time.After(defaultTimeout): require.Fail(ht, "timeout waiting for interceptor error") } - - // Finally, close channels. - ht.CloseChannel(alice, cpAB) - ht.CloseChannel(bob, cpBC) } // testForwardInterceptorBasic tests the forward interceptor RPC layer. @@ -345,10 +341,6 @@ func testForwardInterceptorBasic(ht *lntest.HarnessTest) { case <-time.After(defaultTimeout): require.Fail(ht, "timeout waiting for interceptor error") } - - // Finally, close channels. - ht.CloseChannel(alice, cpAB) - ht.CloseChannel(bob, cpBC) } // testForwardInterceptorModifiedHtlc tests that the interceptor can modify the @@ -367,7 +359,7 @@ func testForwardInterceptorModifiedHtlc(ht *lntest.HarnessTest) { {Local: bob, Remote: carol, Param: p}, } resp := ht.OpenMultiChannelsAsync(reqs) - cpAB, cpBC := resp[0], resp[1] + cpBC := resp[1] // Make sure Alice is aware of channel Bob=>Carol. ht.AssertChannelInGraph(alice, cpBC) @@ -451,10 +443,6 @@ func testForwardInterceptorModifiedHtlc(ht *lntest.HarnessTest) { var preimage lntypes.Preimage copy(preimage[:], invoice.RPreimage) ht.AssertPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED) - - // Finally, close channels. - ht.CloseChannel(alice, cpAB) - ht.CloseChannel(bob, cpBC) } // testForwardInterceptorWireRecords tests that the interceptor can read any @@ -475,7 +463,7 @@ func testForwardInterceptorWireRecords(ht *lntest.HarnessTest) { {Local: carol, Remote: dave, Param: p}, } resp := ht.OpenMultiChannelsAsync(reqs) - cpAB, cpBC, cpCD := resp[0], resp[1], resp[2] + cpBC := resp[1] // Make sure Alice is aware of channel Bob=>Carol. ht.AssertChannelInGraph(alice, cpBC) @@ -579,11 +567,6 @@ func testForwardInterceptorWireRecords(ht *lntest.HarnessTest) { return nil }, ) - - // Finally, close channels. - ht.CloseChannel(alice, cpAB) - ht.CloseChannel(bob, cpBC) - ht.CloseChannel(carol, cpCD) } // testForwardInterceptorRestart tests that the interceptor can read any wire @@ -605,7 +588,7 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) { {Local: carol, Remote: dave, Param: p}, } resp := ht.OpenMultiChannelsAsync(reqs) - cpAB, cpBC, cpCD := resp[0], resp[1], resp[2] + cpBC, cpCD := resp[1], resp[2] // Make sure Alice is aware of channels Bob=>Carol and Carol=>Dave. ht.AssertChannelInGraph(alice, cpBC) @@ -742,11 +725,6 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) { return nil }, ) - - // Finally, close channels. - ht.CloseChannel(alice, cpAB) - ht.CloseChannel(bob, cpBC) - ht.CloseChannel(carol, cpCD) } // interceptorTestScenario is a helper struct to hold the test context and diff --git a/itest/lnd_funding_test.go b/itest/lnd_funding_test.go index 3cffd01f70..6fdd1d91c8 100644 --- a/itest/lnd_funding_test.go +++ b/itest/lnd_funding_test.go @@ -86,7 +86,7 @@ func testBasicChannelFunding(ht *lntest.HarnessTest) { return } - carolChan, daveChan, closeChan := basicChannelFundingTest( + carolChan, daveChan := basicChannelFundingTest( ht, carol, dave, nil, privateChan, &carolCommitType, ) @@ -152,10 +152,6 @@ func testBasicChannelFunding(ht *lntest.HarnessTest) { "commit type %v, instead got "+ "%v", expType, chansCommitType) } - - // As we've concluded this sub-test case we'll now close out - // the channel for both sides. - closeChan() } test: @@ -190,7 +186,7 @@ test: func basicChannelFundingTest(ht *lntest.HarnessTest, alice, bob *node.HarnessNode, fundingShim *lnrpc.FundingShim, privateChan bool, commitType *lnrpc.CommitmentType) (*lnrpc.Channel, - *lnrpc.Channel, func()) { + *lnrpc.Channel) { chanAmt := funding.MaxBtcFundingAmount pushAmt := btcutil.Amount(100000) @@ -262,14 +258,7 @@ func basicChannelFundingTest(ht *lntest.HarnessTest, aliceChannel := ht.GetChannelByChanPoint(alice, chanPoint) bobChannel := ht.GetChannelByChanPoint(bob, chanPoint) - closeChan := func() { - // Finally, immediately close the channel. This function will - // also block until the channel is closed and will additionally - // assert the relevant channel closing post conditions. - ht.CloseChannel(alice, chanPoint) - } - - return aliceChannel, bobChannel, closeChan + return aliceChannel, bobChannel } // testUnconfirmedChannelFunding tests that our unconfirmed change outputs can @@ -377,25 +366,12 @@ func testUnconfirmedChannelFunding(ht *lntest.HarnessTest) { // spend and the funding tx. ht.MineBlocksAndAssertNumTxes(6, 2) - chanPoint := ht.WaitForChannelOpenEvent(chanOpenUpdate) + ht.WaitForChannelOpenEvent(chanOpenUpdate) // With the channel open, we'll check the balances on each side of the // channel as a sanity check to ensure things worked out as intended. checkChannelBalance(carol, carolLocalBalance, pushAmt, 0, 0) checkChannelBalance(alice, pushAmt, carolLocalBalance, 0, 0) - - // TODO(yy): remove the sleep once the following bug is fixed. - // - // We may get the error `unable to gracefully close channel while peer - // is offline (try force closing it instead): channel link not found`. - // This happens because the channel link hasn't been added yet but we - // now proceed to closing the channel. We may need to revisit how the - // channel open event is created and make sure the event is only sent - // after all relevant states have been updated. - time.Sleep(2 * time.Second) - - // Now that we're done with the test, the channel can be closed. - ht.CloseChannel(carol, chanPoint) } // testChannelFundingInputTypes tests that any type of supported input type can @@ -602,7 +578,7 @@ func runExternalFundingScriptEnforced(ht *lntest.HarnessTest) { // At this point, we'll now carry out the normal basic channel funding // test as everything should now proceed as normal (a regular channel // funding flow). - carolChan, daveChan, _ := basicChannelFundingTest( + carolChan, daveChan := basicChannelFundingTest( ht, carol, dave, fundingShim2, false, nil, ) @@ -718,7 +694,7 @@ func runExternalFundingTaproot(ht *lntest.HarnessTest) { // At this point, we'll now carry out the normal basic channel funding // test as everything should now proceed as normal (a regular channel // funding flow). - carolChan, daveChan, _ := basicChannelFundingTest( + carolChan, daveChan := basicChannelFundingTest( ht, carol, dave, fundingShim2, true, &commitmentType, ) @@ -931,11 +907,6 @@ func testChannelFundingPersistence(ht *lntest.HarnessTest) { shortChanID := lnwire.NewShortChanIDFromInt(chanAlice.ChanId) label = labels.MakeLabel(labels.LabelTypeChannelOpen, &shortChanID) require.Equal(ht, label, tx.Label, "open channel label not updated") - - // Finally, immediately close the channel. This function will also - // block until the channel is closed and will additionally assert the - // relevant channel closing post conditions. - ht.CloseChannel(alice, chanPoint) } // testBatchChanFunding makes sure multiple channels can be opened in one batch @@ -1128,15 +1099,6 @@ func testBatchChanFunding(ht *lntest.HarnessTest) { chainreg.DefaultBitcoinBaseFeeMSat, chainreg.DefaultBitcoinFeeRate, ) - - // To conclude, we'll close the newly created channel between Carol and - // Dave. This function will also block until the channel is closed and - // will additionally assert the relevant channel closing post - // conditions. - ht.CloseChannel(alice, chanPoint1) - ht.CloseChannel(alice, chanPoint2) - ht.CloseChannel(alice, chanPoint3) - ht.CloseChannel(alice, chanPoint4) } // ensurePolicy ensures that the peer sees alice's channel fee settings. @@ -1210,13 +1172,12 @@ func testChannelFundingWithUnstableUtxos(ht *lntest.HarnessTest) { // Open a channel to dave with an unconfirmed utxo. Although this utxo // is unconfirmed it can be used to open a channel because it did not // originated from the sweeper subsystem. - update := ht.OpenChannelAssertPending(carol, dave, + ht.OpenChannelAssertPending(carol, dave, lntest.OpenChannelParams{ Amt: chanSize, SpendUnconfirmed: true, CommitmentType: cType, }) - chanPoint1 := lntest.ChanPointFromPendingUpdate(update) // Verify that both nodes know about the channel. ht.AssertNumPendingOpenChannels(carol, 1) @@ -1228,7 +1189,7 @@ func testChannelFundingWithUnstableUtxos(ht *lntest.HarnessTest) { // so unconfirmed utxos originated from prior channel opening are safe // to use because channel opening should not be RBFed, at least not for // now. - update = ht.OpenChannelAssertPending(carol, dave, + update := ht.OpenChannelAssertPending(carol, dave, lntest.OpenChannelParams{ Amt: chanSize, SpendUnconfirmed: true, @@ -1347,20 +1308,16 @@ func testChannelFundingWithUnstableUtxos(ht *lntest.HarnessTest) { // Now after the sweep utxo is confirmed it is stable and can be used // for channel openings again. - update = ht.OpenChannelAssertPending(carol, dave, + ht.OpenChannelAssertPending(carol, dave, lntest.OpenChannelParams{ Amt: chanSize, SpendUnconfirmed: true, CommitmentType: cType, }) - chanPoint4 := lntest.ChanPointFromPendingUpdate(update) // Verify that both nodes know about the channel. ht.AssertNumPendingOpenChannels(carol, 1) ht.AssertNumPendingOpenChannels(dave, 1) ht.MineBlocksAndAssertNumTxes(1, 1) - - ht.CloseChannel(carol, chanPoint1) - ht.CloseChannel(carol, chanPoint4) } diff --git a/itest/lnd_hold_invoice_force_test.go b/itest/lnd_hold_invoice_force_test.go index 5f0a54670b..19e44a8375 100644 --- a/itest/lnd_hold_invoice_force_test.go +++ b/itest/lnd_hold_invoice_force_test.go @@ -140,7 +140,4 @@ func testHoldInvoiceForceClose(ht *lntest.HarnessTest) { // outgoing HTLCs in her channel as the only HTLC has already been // canceled. ht.AssertNumPendingForceClose(alice, 0) - - // Clean up the channel. - ht.CloseChannel(alice, chanPoint) } diff --git a/itest/lnd_hold_persistence_test.go b/itest/lnd_hold_persistence_test.go index 97c6eb29ca..4335f26c75 100644 --- a/itest/lnd_hold_persistence_test.go +++ b/itest/lnd_hold_persistence_test.go @@ -35,7 +35,7 @@ func testHoldInvoicePersistence(ht *lntest.HarnessTest) { // Open a channel between Alice and Carol which is private so that we // cover the addition of hop hints for hold invoices. - chanPointAlice := ht.OpenChannel( + ht.OpenChannel( alice, carol, lntest.OpenChannelParams{ Amt: chanAmt, Private: true, @@ -222,8 +222,4 @@ func testHoldInvoicePersistence(ht *lntest.HarnessTest) { "wrong failure reason") } } - - // Finally, close all channels. - ht.CloseChannel(alice, chanPointBob) - ht.CloseChannel(alice, chanPointAlice) } diff --git a/itest/lnd_htlc_test.go b/itest/lnd_htlc_test.go index 001a4dc65a..e5825993f9 100644 --- a/itest/lnd_htlc_test.go +++ b/itest/lnd_htlc_test.go @@ -24,7 +24,6 @@ func testLookupHtlcResolution(ht *lntest.HarnessTest) { cp := ht.OpenChannel( alice, carol, lntest.OpenChannelParams{Amt: chanAmt}, ) - defer ht.CloseChannel(alice, cp) // Channel should be ready for payments. const payAmt = 100 diff --git a/itest/lnd_invoice_acceptor_test.go b/itest/lnd_invoice_acceptor_test.go index 0c42a33e3d..e94d815514 100644 --- a/itest/lnd_invoice_acceptor_test.go +++ b/itest/lnd_invoice_acceptor_test.go @@ -32,7 +32,7 @@ func testInvoiceHtlcModifierBasic(ht *lntest.HarnessTest) { {Local: bob, Remote: carol, Param: p}, } resp := ht.OpenMultiChannelsAsync(reqs) - cpAB, cpBC := resp[0], resp[1] + cpBC := resp[1] // Make sure Alice is aware of channel Bob=>Carol. ht.AssertChannelInGraph(alice, cpBC) @@ -208,10 +208,6 @@ func testInvoiceHtlcModifierBasic(ht *lntest.HarnessTest) { } cancelModifier() - - // Finally, close channels. - ht.CloseChannel(alice, cpAB) - ht.CloseChannel(bob, cpBC) } // acceptorTestCase is a helper struct to hold test case data. diff --git a/itest/lnd_max_channel_size_test.go b/itest/lnd_max_channel_size_test.go index 9959c75895..4e19f86538 100644 --- a/itest/lnd_max_channel_size_test.go +++ b/itest/lnd_max_channel_size_test.go @@ -56,9 +56,7 @@ func testMaxChannelSize(ht *lntest.HarnessTest) { // Creating a wumbo channel between these two nodes should succeed. ht.EnsureConnected(wumboNode, wumboNode3) - chanPoint := ht.OpenChannel( + ht.OpenChannel( wumboNode, wumboNode3, lntest.OpenChannelParams{Amt: chanAmt}, ) - - ht.CloseChannel(wumboNode, chanPoint) } diff --git a/itest/lnd_max_htlcs_test.go b/itest/lnd_max_htlcs_test.go index cc4f8adb58..aad489f752 100644 --- a/itest/lnd_max_htlcs_test.go +++ b/itest/lnd_max_htlcs_test.go @@ -25,14 +25,13 @@ func testMaxHtlcPathfind(ht *lntest.HarnessTest) { cfgs := [][]string{cfg, cfg} // Create a channel Alice->Bob. - chanPoints, nodes := ht.CreateSimpleNetwork( + _, nodes := ht.CreateSimpleNetwork( cfgs, lntest.OpenChannelParams{ Amt: 1000000, PushAmt: 800000, RemoteMaxHtlcs: uint16(maxHtlcs), }, ) - chanPoint := chanPoints[0] alice, bob := nodes[0], nodes[1] // Alice and bob should have one channel open with each other now. @@ -78,8 +77,6 @@ func testMaxHtlcPathfind(ht *lntest.HarnessTest) { ht.AssertNumActiveHtlcs(alice, 0) ht.AssertNumActiveHtlcs(bob, 0) - - ht.CloseChannel(alice, chanPoint) } type holdSubscription struct { diff --git a/itest/lnd_misc_test.go b/itest/lnd_misc_test.go index 70fcbe971b..f983b39e91 100644 --- a/itest/lnd_misc_test.go +++ b/itest/lnd_misc_test.go @@ -156,7 +156,6 @@ func testSphinxReplayPersistence(ht *lntest.HarnessTest) { Amt: chanAmt, }, ) - defer ht.CloseChannel(fred, chanPointFC) // Now that the channel is open, create an invoice for Dave which // expects a payment of 1000 satoshis from Carol paid via a particular @@ -225,9 +224,6 @@ func testSphinxReplayPersistence(ht *lntest.HarnessTest) { // unaltered. ht.AssertAmountPaid("carol => dave", carol, chanPoint, 0, 0) ht.AssertAmountPaid("dave <= carol", dave, chanPoint, 0, 0) - - // Cleanup by mining the force close and sweep transaction. - ht.ForceCloseChannel(carol, chanPoint) } // testListChannels checks that the response from ListChannels is correct. It @@ -420,12 +416,6 @@ func testMaxPendingChannels(ht *lntest.HarnessTest) { chanPoints[i] = fundingChanPoint } - - // Next, close the channel between Alice and Carol, asserting that the - // channel has been properly closed on-chain. - for _, chanPoint := range chanPoints { - ht.CloseChannel(alice, chanPoint) - } } // testGarbageCollectLinkNodes tests that we properly garbage collect link @@ -464,7 +454,7 @@ func testGarbageCollectLinkNodes(ht *lntest.HarnessTest) { dave := ht.NewNode("Dave", nil) ht.ConnectNodes(alice, dave) - persistentChanPoint := ht.OpenChannel( + ht.OpenChannel( alice, dave, lntest.OpenChannelParams{ Amt: chanAmt, }, @@ -537,9 +527,6 @@ func testGarbageCollectLinkNodes(ht *lntest.HarnessTest) { "did not expect to find bob in the channel graph, but did") require.NotContains(ht, channelGraph.Nodes, carol.PubKeyStr, "did not expect to find carol in the channel graph, but did") - - // Now that the test is done, we can also close the persistent link. - ht.CloseChannel(alice, persistentChanPoint) } // testRejectHTLC tests that a node can be created with the flag --rejecthtlc. @@ -566,14 +553,14 @@ func testRejectHTLC(ht *lntest.HarnessTest) { ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) // Open a channel between Alice and Carol. - chanPointAlice := ht.OpenChannel( + ht.OpenChannel( alice, carol, lntest.OpenChannelParams{ Amt: chanAmt, }, ) // Open a channel between Carol and Bob. - chanPointCarol := ht.OpenChannel( + ht.OpenChannel( carol, bob, lntest.OpenChannelParams{ Amt: chanAmt, }, @@ -636,10 +623,6 @@ func testRejectHTLC(ht *lntest.HarnessTest) { ) ht.AssertLastHTLCError(alice, lnrpc.Failure_CHANNEL_DISABLED) - - // Close all channels. - ht.CloseChannel(alice, chanPointAlice) - ht.CloseChannel(carol, chanPointCarol) } // testNodeSignVerify checks that only connected nodes are allowed to perform @@ -654,9 +637,8 @@ func testNodeSignVerify(ht *lntest.HarnessTest) { // Create a channel between alice and bob. cfgs := [][]string{nil, nil} - chanPoints, nodes := ht.CreateSimpleNetwork(cfgs, p) + _, nodes := ht.CreateSimpleNetwork(cfgs, p) alice, bob := nodes[0], nodes[1] - aliceBobCh := chanPoints[0] // alice signs "alice msg" and sends her signature to bob. aliceMsg := []byte("alice msg") @@ -684,9 +666,6 @@ func testNodeSignVerify(ht *lntest.HarnessTest) { require.False(ht, verifyResp.Valid, "carol's signature didn't validate") require.Equal(ht, verifyResp.Pubkey, carol.PubKeyStr, "carol's signature doesn't contain alice's pubkey.") - - // Close the channel between alice and bob. - ht.CloseChannel(alice, aliceBobCh) } // testAbandonChannel abandons a channel and asserts that it is no longer open @@ -702,7 +681,7 @@ func testAbandonChannel(ht *lntest.HarnessTest) { // Create a channel between alice and bob. cfgs := [][]string{nil, nil} chanPoints, nodes := ht.CreateSimpleNetwork(cfgs, channelParam) - alice, bob := nodes[0], nodes[1] + alice := nodes[0] chanPoint := chanPoints[0] // Now that the channel is open, we'll obtain its channel ID real quick @@ -755,11 +734,6 @@ func testAbandonChannel(ht *lntest.HarnessTest) { // Calling AbandonChannel again, should result in no new errors, as the // channel has already been removed. alice.RPC.AbandonChannel(abandonChannelRequest) - - // Now that we're done with the test, the channel can be closed. This - // is necessary to avoid unexpected outcomes of other tests that use - // Bob's lnd instance. - ht.ForceCloseChannel(bob, chanPoint) } // testSendAllCoins tests that we're able to properly sweep all coins from the diff --git a/itest/lnd_multi-hop-error-propagation_test.go b/itest/lnd_multi-hop-error-propagation_test.go index 1f0f651880..0f537ad5c7 100644 --- a/itest/lnd_multi-hop-error-propagation_test.go +++ b/itest/lnd_multi-hop-error-propagation_test.go @@ -365,12 +365,4 @@ func testHtlcErrorPropagation(ht *lntest.HarnessTest) { ht.AssertHtlcEventTypes( bobEvents, routerrpc.HtlcEvent_UNKNOWN, lntest.HtlcEventFinal, ) - - // Finally, immediately close the channel. This function will also - // block until the channel is closed and will additionally assert the - // relevant channel closing post conditions. - ht.CloseChannel(alice, chanPointAlice) - - // Force close Bob's final channel. - ht.ForceCloseChannel(bob, chanPointBob) } diff --git a/itest/lnd_multi-hop-payments_test.go b/itest/lnd_multi-hop-payments_test.go index aa5ef7516a..9c55d7845a 100644 --- a/itest/lnd_multi-hop-payments_test.go +++ b/itest/lnd_multi-hop-payments_test.go @@ -235,11 +235,6 @@ func testMultiHopPayments(ht *lntest.HarnessTest) { ht.AssertHtlcEvents( bobEvents, 0, 0, numPayments, 0, routerrpc.HtlcEvent_RECEIVE, ) - - // Finally, close all channels. - ht.CloseChannel(alice, chanPointAlice) - ht.CloseChannel(dave, chanPointDave) - ht.CloseChannel(carol, chanPointCarol) } // updateChannelPolicy updates the channel policy of node to the given fees and diff --git a/itest/lnd_network_test.go b/itest/lnd_network_test.go index ff305b59f4..44a0dcffa5 100644 --- a/itest/lnd_network_test.go +++ b/itest/lnd_network_test.go @@ -133,9 +133,7 @@ func testReconnectAfterIPChange(ht *lntest.HarnessTest) { // We'll then go ahead and open a channel between Alice and Dave. This // ensures that Charlie receives the node announcement from Alice as // part of the announcement broadcast. - chanPoint := ht.OpenChannel( - alice, dave, lntest.OpenChannelParams{Amt: 1000000}, - ) + ht.OpenChannel(alice, dave, lntest.OpenChannelParams{Amt: 1000000}) // waitForNodeAnnouncement is a closure used to wait on the given graph // subscription for a node announcement from a node with the given @@ -210,9 +208,6 @@ func testReconnectAfterIPChange(ht *lntest.HarnessTest) { // address to one not listed in Dave's original advertised list of // addresses. ht.AssertConnected(dave, charlie) - - // Finally, close the channel. - ht.CloseChannel(alice, chanPoint) } // testAddPeerConfig tests that the "--addpeer" config flag successfully adds diff --git a/itest/lnd_onchain_test.go b/itest/lnd_onchain_test.go index 8b14092558..3a32a8c6a5 100644 --- a/itest/lnd_onchain_test.go +++ b/itest/lnd_onchain_test.go @@ -153,7 +153,7 @@ func testChainKitSendOutputsAnchorReserve(ht *lntest.HarnessTest) { // Charlie opens an anchor channel and keeps twice the amount of the // anchor reserve in her wallet. chanAmt := fundingAmount - 2*btcutil.Amount(reserve.RequiredReserve) - outpoint := ht.OpenChannel(charlie, bob, lntest.OpenChannelParams{ + ht.OpenChannel(charlie, bob, lntest.OpenChannelParams{ Amt: chanAmt, CommitmentType: lnrpc.CommitmentType_ANCHORS, SatPerVByte: 1, @@ -207,11 +207,7 @@ func testChainKitSendOutputsAnchorReserve(ht *lntest.HarnessTest) { // This second transaction should be published correctly. charlie.RPC.SendOutputs(req) - ht.MineBlocksAndAssertNumTxes(1, 1) - - // Clean up our test setup. - ht.CloseChannel(charlie, outpoint) } // testAnchorReservedValue tests that we won't allow sending transactions when diff --git a/itest/lnd_open_channel_test.go b/itest/lnd_open_channel_test.go index 20f456ea9b..9fb41a2dea 100644 --- a/itest/lnd_open_channel_test.go +++ b/itest/lnd_open_channel_test.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" "testing" - "time" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -119,8 +118,6 @@ func testOpenChannelAfterReorg(ht *lntest.HarnessTest) { // Cleanup by mining the funding tx again, then closing the channel. block = ht.MineBlocksAndAssertNumTxes(1, 1)[0] ht.AssertTxInBlock(block, *fundingTxID) - - ht.CloseChannel(alice, chanPoint) } // testOpenChannelFeePolicy checks if different channel fee scenarios are @@ -256,15 +253,13 @@ func testOpenChannelUpdateFeePolicy(ht *lntest.HarnessTest) { // Create a channel Alice->Bob. chanPoint := ht.OpenChannel(alice, bob, chanParams) - defer ht.CloseChannel(alice, chanPoint) // Create a channel Carol->Alice. - chanPoint2 := ht.OpenChannel( + ht.OpenChannel( carol, alice, lntest.OpenChannelParams{ Amt: 500000, }, ) - defer ht.CloseChannel(carol, chanPoint2) // Alice and Bob should see each other's ChannelUpdates, // advertising the preferred routing policies. @@ -542,13 +537,7 @@ func testUpdateOnFunderPendingOpenChannels(ht *lntest.HarnessTest) { Amt: funding.MaxBtcFundingAmount, PushAmt: funding.MaxBtcFundingAmount / 2, } - pendingChan := ht.OpenChannelAssertPending(alice, bob, params) - chanPoint := &lnrpc.ChannelPoint{ - FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{ - FundingTxidBytes: pendingChan.Txid, - }, - OutputIndex: pendingChan.OutputIndex, - } + ht.OpenChannelAssertPending(alice, bob, params) // Alice and Bob should both consider the channel pending open. ht.AssertNumPendingOpenChannels(alice, 1) @@ -598,9 +587,6 @@ func testUpdateOnFunderPendingOpenChannels(ht *lntest.HarnessTest) { // Once Alice sees the channel as active, she will process the cached // premature `update_add_htlc` and settles the payment. ht.AssertPaymentStatusFromStream(bobStream, lnrpc.Payment_SUCCEEDED) - - // Close the channel. - ht.CloseChannel(alice, chanPoint) } // testUpdateOnFundeePendingOpenChannels checks that when the funder sends an @@ -625,13 +611,7 @@ func testUpdateOnFundeePendingOpenChannels(ht *lntest.HarnessTest) { params := lntest.OpenChannelParams{ Amt: funding.MaxBtcFundingAmount, } - pendingChan := ht.OpenChannelAssertPending(alice, bob, params) - chanPoint := &lnrpc.ChannelPoint{ - FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{ - FundingTxidBytes: pendingChan.Txid, - }, - OutputIndex: pendingChan.OutputIndex, - } + ht.OpenChannelAssertPending(alice, bob, params) // Alice and Bob should both consider the channel pending open. ht.AssertNumPendingOpenChannels(alice, 1) @@ -681,9 +661,6 @@ func testUpdateOnFundeePendingOpenChannels(ht *lntest.HarnessTest) { // Once Bob sees the channel as active, he will process the cached // premature `update_add_htlc` and settles the payment. ht.AssertPaymentStatusFromStream(aliceStream, lnrpc.Payment_SUCCEEDED) - - // Close the channel. - ht.CloseChannel(alice, chanPoint) } // verifyCloseUpdate is used to verify that a closed channel update is of the @@ -756,7 +733,7 @@ func testFundingExpiryBlocksOnPending(ht *lntest.HarnessTest) { ht.EnsureConnected(alice, bob) param := lntest.OpenChannelParams{Amt: 100000} - update := ht.OpenChannelAssertPending(alice, bob, param) + ht.OpenChannelAssertPending(alice, bob, param) // At this point, the channel's funding transaction will have been // broadcast, but not confirmed. Alice and Bob's nodes should reflect @@ -777,20 +754,6 @@ func testFundingExpiryBlocksOnPending(ht *lntest.HarnessTest) { // Mine 1 block to confirm the funding transaction, and then close the // channel. ht.MineBlocksAndAssertNumTxes(1, 1) - chanPoint := lntest.ChanPointFromPendingUpdate(update) - - // TODO(yy): remove the sleep once the following bug is fixed. - // - // We may get the error `unable to gracefully close channel - // while peer is offline (try force closing it instead): - // channel link not found`. This happens because the channel - // link hasn't been added yet but we now proceed to closing the - // channel. We may need to revisit how the channel open event - // is created and make sure the event is only sent after all - // relevant states have been updated. - time.Sleep(2 * time.Second) - - ht.CloseChannel(alice, chanPoint) } // testSimpleTaprootChannelActivation ensures that a simple taproot channel is @@ -803,9 +766,7 @@ func testSimpleTaprootChannelActivation(ht *lntest.HarnessTest) { // Make the new set of participants. alice := ht.NewNode("alice", simpleTaprootChanArgs) - defer ht.Shutdown(alice) bob := ht.NewNode("bob", simpleTaprootChanArgs) - defer ht.Shutdown(bob) ht.FundCoins(btcutil.SatoshiPerBitcoin, alice) @@ -842,9 +803,6 @@ func testSimpleTaprootChannelActivation(ht *lntest.HarnessTest) { // Verify that Alice sees an active channel to Bob. ht.AssertChannelActive(alice, chanPoint) - - // Our test is done and Alice closes her channel to Bob. - ht.CloseChannel(alice, chanPoint) } // testOpenChannelLockedBalance tests that when a funding reservation is diff --git a/itest/lnd_payment_test.go b/itest/lnd_payment_test.go index 6c6fc1b178..d36be796aa 100644 --- a/itest/lnd_payment_test.go +++ b/itest/lnd_payment_test.go @@ -477,9 +477,7 @@ func testListPayments(ht *lntest.HarnessTest) { // Open a channel with 100k satoshis between Alice and Bob with Alice // being the sole funder of the channel. chanAmt := btcutil.Amount(100000) - chanPoint := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{Amt: chanAmt}, - ) + ht.OpenChannel(alice, bob, lntest.OpenChannelParams{Amt: chanAmt}) // Now that the channel is open, create an invoice for Bob which // expects a payment of 1000 satoshis from Alice paid via a particular @@ -638,17 +636,6 @@ func testListPayments(ht *lntest.HarnessTest) { // Check that there are no payments after test. ht.AssertNumPayments(alice, 0) - - // TODO(yy): remove the sleep once the following bug is fixed. - // When the invoice is reported settled, the commitment dance is not - // yet finished, which can cause an error when closing the channel, - // saying there's active HTLCs. We need to investigate this issue and - // reverse the order to, first finish the commitment dance, then report - // the invoice as settled. - time.Sleep(2 * time.Second) - - // Close the channel. - ht.CloseChannel(alice, chanPoint) } // testPaymentFollowingChannelOpen tests that the channel transition from @@ -698,19 +685,6 @@ func testPaymentFollowingChannelOpen(ht *lntest.HarnessTest) { // Send payment to Bob so that a channel update to disk will be // executed. ht.CompletePaymentRequests(alice, []string{bobPayReqs[0]}) - - // TODO(yy): remove the sleep once the following bug is fixed. - // When the invoice is reported settled, the commitment dance is not - // yet finished, which can cause an error when closing the channel, - // saying there's active HTLCs. We need to investigate this issue and - // reverse the order to, first finish the commitment dance, then report - // the invoice as settled. - time.Sleep(2 * time.Second) - - // Finally, immediately close the channel. This function will also - // block until the channel is closed and will additionally assert the - // relevant channel closing post conditions. - ht.CloseChannel(alice, chanPoint) } // testAsyncPayments tests the performance of the async payments. @@ -818,11 +792,6 @@ func runAsyncPayments(ht *lntest.HarnessTest, alice, bob *node.HarnessNode, ht.Log("\tBenchmark info: Elapsed time: ", timeTaken) ht.Log("\tBenchmark info: TPS: ", float64(numInvoices)/timeTaken.Seconds()) - - // Finally, immediately close the channel. This function will also - // block until the channel is closed and will additionally assert the - // relevant channel closing post conditions. - ht.CloseChannel(alice, chanPoint) } // testBidirectionalAsyncPayments tests that nodes are able to send the @@ -930,11 +899,6 @@ func testBidirectionalAsyncPayments(ht *lntest.HarnessTest) { // Next query for Bob's and Alice's channel states, in order to confirm // that all payment have been successfully transmitted. assertChannelState(ht, bob, chanPoint, bobAmt, aliceAmt) - - // Finally, immediately close the channel. This function will also - // block until the channel is closed and will additionally assert the - // relevant channel closing post conditions. - ht.CloseChannel(alice, chanPoint) } func testInvoiceSubscriptions(ht *lntest.HarnessTest) { @@ -951,9 +915,7 @@ func testInvoiceSubscriptions(ht *lntest.HarnessTest) { // Open a channel with 500k satoshis between Alice and Bob with Alice // being the sole funder of the channel. - chanPoint := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{Amt: chanAmt}, - ) + ht.OpenChannel(alice, bob, lntest.OpenChannelParams{Amt: chanAmt}) // Next create a new invoice for Bob requesting 1k satoshis. const paymentAmt = 1000 @@ -1055,16 +1017,6 @@ func testInvoiceSubscriptions(ht *lntest.HarnessTest) { // At this point, all the invoices should be fully settled. require.Empty(ht, settledInvoices, "not all invoices settled") - - // TODO(yy): remove the sleep once the following bug is fixed. - // When the invoice is reported settled, the commitment dance is not - // yet finished, which can cause an error when closing the channel, - // saying there's active HTLCs. We need to investigate this issue and - // reverse the order to, first finish the commitment dance, then report - // the invoice as settled. - time.Sleep(2 * time.Second) - - ht.CloseChannel(alice, chanPoint) } // assertChannelState asserts the channel state by checking the values in @@ -1151,10 +1103,6 @@ func testPaymentFailureReasonCanceled(ht *lntest.HarnessTest) { ht, ts, cpAB, routerrpc.ResolveHoldForwardAction_FAIL, lnrpc.Payment_FAILED, interceptor, ) - - // Finally, close channels. - ht.CloseChannel(alice, cpAB) - ht.CloseChannel(bob, cpBC) } func sendPaymentInterceptAndCancel(ht *lntest.HarnessTest, diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go index f3687d74b5..1bba998be1 100644 --- a/itest/lnd_psbt_test.go +++ b/itest/lnd_psbt_test.go @@ -324,13 +324,6 @@ func runPsbtChanFunding(ht *lntest.HarnessTest, carol, dave *node.HarnessNode, } resp := dave.RPC.AddInvoice(invoice) ht.CompletePaymentRequests(carol, []string{resp.PaymentRequest}) - - // To conclude, we'll close the newly created channel between Carol and - // Dave. This function will also block until the channel is closed and - // will additionally assert the relevant channel closing post - // conditions. - ht.CloseChannel(carol, chanPoint) - ht.CloseChannel(carol, chanPoint2) } // runPsbtChanFundingExternal makes sure a channel can be opened between carol @@ -499,13 +492,6 @@ func runPsbtChanFundingExternal(ht *lntest.HarnessTest, carol, } resp := dave.RPC.AddInvoice(invoice) ht.CompletePaymentRequests(carol, []string{resp.PaymentRequest}) - - // To conclude, we'll close the newly created channel between Carol and - // Dave. This function will also block until the channels are closed and - // will additionally assert the relevant channel closing post - // conditions. - ht.CloseChannel(carol, chanPoint) - ht.CloseChannel(carol, chanPoint2) } // runPsbtChanFundingSingleStep checks whether PSBT funding works also when @@ -649,12 +635,6 @@ func runPsbtChanFundingSingleStep(ht *lntest.HarnessTest, carol, } resp := dave.RPC.AddInvoice(invoice) ht.CompletePaymentRequests(carol, []string{resp.PaymentRequest}) - - // To conclude, we'll close the newly created channel between Carol and - // Dave. This function will also block until the channel is closed and - // will additionally assert the relevant channel closing post - // conditions. - ht.CloseChannel(carol, chanPoint) } // testSignPsbt tests that the SignPsbt RPC works correctly. diff --git a/itest/lnd_quiescence_test.go b/itest/lnd_quiescence_test.go index defb44d1b1..c698b41e47 100644 --- a/itest/lnd_quiescence_test.go +++ b/itest/lnd_quiescence_test.go @@ -22,7 +22,6 @@ func testQuiescence(ht *lntest.HarnessTest) { chanPoint := ht.OpenChannel(bob, alice, lntest.OpenChannelParams{ Amt: btcutil.Amount(1000000), }) - defer ht.CloseChannel(bob, chanPoint) res := alice.RPC.Quiesce(&devrpc.QuiescenceRequest{ ChanId: chanPoint, diff --git a/itest/lnd_res_handoff_test.go b/itest/lnd_res_handoff_test.go index 7238bf6b76..d7bf499905 100644 --- a/itest/lnd_res_handoff_test.go +++ b/itest/lnd_res_handoff_test.go @@ -94,6 +94,4 @@ func testResHandoff(ht *lntest.HarnessTest) { // Assert that Alice's payment failed. ht.AssertFirstHTLCError(alice, lnrpc.Failure_PERMANENT_CHANNEL_FAILURE) - - ht.CloseChannel(alice, chanPointAlice) } diff --git a/itest/lnd_rest_api_test.go b/itest/lnd_rest_api_test.go index e559230d9a..7c4a3d988e 100644 --- a/itest/lnd_rest_api_test.go +++ b/itest/lnd_rest_api_test.go @@ -529,10 +529,9 @@ func wsTestCaseBiDirectionalSubscription(ht *lntest.HarnessTest) { // sent over the web socket. const numChannels = 3 for i := 0; i < numChannels; i++ { - chanPoint := ht.OpenChannel( + ht.OpenChannel( bob, alice, lntest.OpenChannelParams{Amt: 500000}, ) - defer ht.CloseChannel(bob, chanPoint) select { case <-msgChan: diff --git a/itest/lnd_route_blinding_test.go b/itest/lnd_route_blinding_test.go index 55b6894a17..b7604e6a8d 100644 --- a/itest/lnd_route_blinding_test.go +++ b/itest/lnd_route_blinding_test.go @@ -309,9 +309,6 @@ func testQueryBlindedRoutes(ht *lntest.HarnessTest) { require.Len(ht, resp.Routes, 1) require.Len(ht, resp.Routes[0].Hops, 2) require.Equal(ht, resp.Routes[0].TotalTimeLock, sendToIntroTimelock) - - ht.CloseChannel(alice, chanPointAliceBob) - ht.CloseChannel(bob, chanPointBobCarol) } type blindedForwardTest struct { @@ -412,10 +409,6 @@ func (b *blindedForwardTest) buildBlindedPath() *lnrpc.BlindedPaymentPath { // cleanup tears down all channels created by the test and cancels the top // level context used in the test. func (b *blindedForwardTest) cleanup() { - b.ht.CloseChannel(b.alice, b.channels[0]) - b.ht.CloseChannel(b.bob, b.channels[1]) - b.ht.CloseChannel(b.carol, b.channels[2]) - b.cancel() } @@ -846,8 +839,6 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { // Manually close out the rest of our channels and cancel (don't use // built in cleanup which will try close the already-force-closed // channel). - ht.CloseChannel(alice, testCase.channels[0]) - ht.CloseChannel(testCase.carol, testCase.channels[2]) testCase.cancel() } diff --git a/itest/lnd_routing_test.go b/itest/lnd_routing_test.go index e05bf441b2..63c5d54189 100644 --- a/itest/lnd_routing_test.go +++ b/itest/lnd_routing_test.go @@ -101,7 +101,6 @@ func testSingleHopSendToRouteCase(ht *lntest.HarnessTest, chanPointCarol := ht.OpenChannel( carol, dave, lntest.OpenChannelParams{Amt: chanAmt}, ) - defer ht.CloseChannel(carol, chanPointCarol) // Create invoices for Dave, which expect a payment from Carol. payReqs, rHashes, _ := ht.CreatePayReqs( @@ -328,7 +327,6 @@ func runMultiHopSendToRoute(ht *lntest.HarnessTest, useGraphCache bool) { chanPointAlice := ht.OpenChannel( alice, bob, lntest.OpenChannelParams{Amt: chanAmt}, ) - defer ht.CloseChannel(alice, chanPointAlice) // Create Carol and establish a channel from Bob. Bob is the sole // funder of the channel with 100k satoshis. The network topology @@ -340,7 +338,6 @@ func runMultiHopSendToRoute(ht *lntest.HarnessTest, useGraphCache bool) { chanPointBob := ht.OpenChannel( bob, carol, lntest.OpenChannelParams{Amt: chanAmt}, ) - defer ht.CloseChannel(carol, chanPointBob) // Make sure Alice knows the channel between Bob and Carol. ht.AssertChannelInGraph(alice, chanPointBob) @@ -420,9 +417,7 @@ func testSendToRouteErrorPropagation(ht *lntest.HarnessTest) { bob := ht.NewNode("Bob", nil) ht.EnsureConnected(alice, bob) - chanPointAlice := ht.OpenChannel( - alice, bob, lntest.OpenChannelParams{Amt: chanAmt}, - ) + ht.OpenChannel(alice, bob, lntest.OpenChannelParams{Amt: chanAmt}) // Create a new nodes (Carol and Charlie), load her with some funds, // then establish a connection between Carol and Charlie with a channel @@ -476,8 +471,6 @@ func testSendToRouteErrorPropagation(ht *lntest.HarnessTest) { require.NoError(ht, err, "payment stream has been closed but fake "+ "route has consumed") require.Contains(ht, event.PaymentError, "UnknownNextPeer") - - ht.CloseChannel(alice, chanPointAlice) } // testPrivateChannels tests that a private channel can be used for @@ -602,12 +595,6 @@ func testPrivateChannels(ht *lntest.HarnessTest) { ht.AssertNumActiveEdges(carol, 4, true) ht.AssertNumActiveEdges(carol, 3, false) ht.AssertNumActiveEdges(dave, 3, true) - - // Close all channels. - ht.CloseChannel(alice, chanPointAlice) - ht.CloseChannel(dave, chanPointDave) - ht.CloseChannel(carol, chanPointCarol) - ht.CloseChannel(carol, chanPointPrivate) } // testInvoiceRoutingHints tests that the routing hints for an invoice are @@ -641,7 +628,7 @@ func testInvoiceRoutingHints(ht *lntest.HarnessTest) { carol := ht.NewNode("Carol", nil) ht.ConnectNodes(alice, carol) - chanPointCarol := ht.OpenChannel( + ht.OpenChannel( alice, carol, lntest.OpenChannelParams{ Amt: chanAmt, PushAmt: chanAmt / 2, @@ -654,7 +641,7 @@ func testInvoiceRoutingHints(ht *lntest.HarnessTest) { // advertised, otherwise we'd end up leaking information about nodes // that wish to stay unadvertised. ht.ConnectNodes(bob, carol) - chanPointBobCarol := ht.OpenChannel( + ht.OpenChannel( bob, carol, lntest.OpenChannelParams{ Amt: chanAmt, PushAmt: chanAmt / 2, @@ -668,7 +655,7 @@ func testInvoiceRoutingHints(ht *lntest.HarnessTest) { dave := ht.NewNode("Dave", nil) ht.ConnectNodes(alice, dave) - chanPointDave := ht.OpenChannel( + ht.OpenChannel( alice, dave, lntest.OpenChannelParams{ Amt: chanAmt, Private: true, @@ -681,7 +668,7 @@ func testInvoiceRoutingHints(ht *lntest.HarnessTest) { // inactive channels. eve := ht.NewNode("Eve", nil) ht.ConnectNodes(alice, eve) - chanPointEve := ht.OpenChannel( + ht.OpenChannel( alice, eve, lntest.OpenChannelParams{ Amt: chanAmt, PushAmt: chanAmt / 2, @@ -742,17 +729,6 @@ func testInvoiceRoutingHints(ht *lntest.HarnessTest) { Private: true, } checkInvoiceHints(invoice) - - // Now that we've confirmed the routing hints were added correctly, we - // can close all the channels and shut down all the nodes created. - ht.CloseChannel(alice, chanPointBob) - ht.CloseChannel(alice, chanPointCarol) - ht.CloseChannel(bob, chanPointBobCarol) - ht.CloseChannel(alice, chanPointDave) - - // The channel between Alice and Eve should be force closed since Eve - // is offline. - ht.ForceCloseChannel(alice, chanPointEve) } // testScidAliasRoutingHints tests that dynamically created aliases via the RPC @@ -877,7 +853,7 @@ func testScidAliasRoutingHints(ht *lntest.HarnessTest) { // Connect the existing Bob node with Carol via a public channel. ht.ConnectNodes(bob, carol) - chanPointBC := ht.OpenChannel(bob, carol, lntest.OpenChannelParams{ + ht.OpenChannel(bob, carol, lntest.OpenChannelParams{ Amt: chanAmt, PushAmt: chanAmt / 2, }) @@ -940,9 +916,6 @@ func testScidAliasRoutingHints(ht *lntest.HarnessTest) { FeeLimitSat: math.MaxInt64, }) ht.AssertPaymentStatusFromStream(stream2, lnrpc.Payment_FAILED) - - ht.CloseChannel(carol, chanPointCD) - ht.CloseChannel(bob, chanPointBC) } // testMultiHopOverPrivateChannels tests that private channels can be used as @@ -1042,12 +1015,6 @@ func testMultiHopOverPrivateChannels(ht *lntest.HarnessTest) { // Alice should have sent 20k satoshis + fee for two hops to Bob. ht.AssertAmountPaid("Alice(local) [private=>] Bob(remote)", alice, chanPointAlice, paymentAmt+baseFee*2, 0) - - // At this point, the payment was successful. We can now close all the - // channels and shutdown the nodes created throughout this test. - ht.CloseChannel(alice, chanPointAlice) - ht.CloseChannel(bob, chanPointBob) - ht.CloseChannel(carol, chanPointCarol) } // testQueryRoutes checks the response of queryroutes. @@ -1085,7 +1052,6 @@ func testQueryRoutes(ht *lntest.HarnessTest) { resp := ht.OpenMultiChannelsAsync(reqs) // Extract channel points from the response. - chanPointAlice := resp[0] chanPointBob := resp[1] chanPointCarol := resp[2] @@ -1196,12 +1162,6 @@ func testQueryRoutes(ht *lntest.HarnessTest) { // control import function updates appropriately. testMissionControlCfg(ht.T, alice) testMissionControlImport(ht, alice, bob.PubKey[:], carol.PubKey[:]) - - // We clean up the test case by closing channels that were created for - // the duration of the tests. - ht.CloseChannel(alice, chanPointAlice) - ht.CloseChannel(bob, chanPointBob) - ht.CloseChannel(carol, chanPointCarol) } // testMissionControlCfg tests getting and setting of a node's mission control @@ -1528,13 +1488,6 @@ func testRouteFeeCutoff(ht *lntest.HarnessTest) { }, } testFeeCutoff(feeLimitFixed) - - // Once we're done, close the channels and shut down the nodes created - // throughout this test. - ht.CloseChannel(alice, chanPointAliceBob) - ht.CloseChannel(alice, chanPointAliceCarol) - ht.CloseChannel(bob, chanPointBobDave) - ht.CloseChannel(carol, chanPointCarolDave) } // testFeeLimitAfterQueryRoutes tests that a payment's fee limit is consistent @@ -1547,7 +1500,7 @@ func testFeeLimitAfterQueryRoutes(ht *lntest.HarnessTest) { cfgs, lntest.OpenChannelParams{Amt: chanAmt}, ) alice, bob, carol := nodes[0], nodes[1], nodes[2] - chanPointAliceBob, chanPointBobCarol := chanPoints[0], chanPoints[1] + chanPointAliceBob := chanPoints[0] // We set an inbound fee discount on Bob's channel to Alice to // effectively set the outbound fees charged to Carol to zero. @@ -1606,10 +1559,6 @@ func testFeeLimitAfterQueryRoutes(ht *lntest.HarnessTest) { // We assert that a route compatible with the fee limit is available. ht.SendPaymentAssertSettled(alice, sendReq) - - // Once we're done, close the channels. - ht.CloseChannel(alice, chanPointAliceBob) - ht.CloseChannel(bob, chanPointBobCarol) } // computeFee calculates the payment fee as specified in BOLT07. diff --git a/itest/lnd_single_hop_invoice_test.go b/itest/lnd_single_hop_invoice_test.go index 4adc37b72e..954f8666ef 100644 --- a/itest/lnd_single_hop_invoice_test.go +++ b/itest/lnd_single_hop_invoice_test.go @@ -137,6 +137,4 @@ func testSingleHopInvoice(ht *lntest.HarnessTest) { require.EqualValues(ht, 1, hopHint.FeeBaseMsat, "wrong FeeBaseMsat") require.EqualValues(ht, 20, hopHint.CltvExpiryDelta, "wrong CltvExpiryDelta") - - ht.CloseChannel(alice, cp) } diff --git a/itest/lnd_switch_test.go b/itest/lnd_switch_test.go index ca68802fe0..59e8ce9cec 100644 --- a/itest/lnd_switch_test.go +++ b/itest/lnd_switch_test.go @@ -29,7 +29,6 @@ func testSwitchCircuitPersistence(ht *lntest.HarnessTest) { // Setup our test scenario. We should now have four nodes running with // three channels. s := setupScenarioFourNodes(ht) - defer s.cleanUp() // Restart the intermediaries and the sender. ht.RestartNode(s.dave) @@ -99,7 +98,6 @@ func testSwitchOfflineDelivery(ht *lntest.HarnessTest) { // Setup our test scenario. We should now have four nodes running with // three channels. s := setupScenarioFourNodes(ht) - defer s.cleanUp() // First, disconnect Dave and Alice so that their link is broken. ht.DisconnectNodes(s.dave, s.alice) @@ -175,7 +173,6 @@ func testSwitchOfflineDeliveryPersistence(ht *lntest.HarnessTest) { // Setup our test scenario. We should now have four nodes running with // three channels. s := setupScenarioFourNodes(ht) - defer s.cleanUp() // Disconnect the two intermediaries, Alice and Dave, by shutting down // Alice. @@ -264,7 +261,6 @@ func testSwitchOfflineDeliveryOutgoingOffline(ht *lntest.HarnessTest) { // three channels. Note that we won't call the cleanUp function here as // we will manually stop the node Carol and her channel. s := setupScenarioFourNodes(ht) - defer s.cleanUp() // Disconnect the two intermediaries, Alice and Dave, so that when carol // restarts, the response will be held by Dave. @@ -355,8 +351,6 @@ type scenarioFourNodes struct { chanPointAliceBob *lnrpc.ChannelPoint chanPointCarolDave *lnrpc.ChannelPoint chanPointDaveAlice *lnrpc.ChannelPoint - - cleanUp func() } // setupScenarioFourNodes creates a topology for switch tests. It will create @@ -433,21 +427,9 @@ func setupScenarioFourNodes(ht *lntest.HarnessTest) *scenarioFourNodes { // above. ht.CompletePaymentRequestsNoWait(bob, payReqs, chanPointAliceBob) - // Create a cleanUp to wipe the states. - cleanUp := func() { - if ht.Failed() { - ht.Skip("Skipped cleanup for failed test") - return - } - - ht.CloseChannel(alice, chanPointAliceBob) - ht.CloseChannel(dave, chanPointDaveAlice) - ht.CloseChannel(carol, chanPointCarolDave) - } - s := &scenarioFourNodes{ alice, bob, carol, dave, chanPointAliceBob, - chanPointCarolDave, chanPointDaveAlice, cleanUp, + chanPointCarolDave, chanPointDaveAlice, } // Wait until all nodes in the network have 5 outstanding htlcs. diff --git a/itest/lnd_trackpayments_test.go b/itest/lnd_trackpayments_test.go index 0dd3467155..29fb2c0b3a 100644 --- a/itest/lnd_trackpayments_test.go +++ b/itest/lnd_trackpayments_test.go @@ -2,7 +2,6 @@ package itest import ( "encoding/hex" - "time" "github.com/btcsuite/btcd/btcutil" "github.com/lightningnetwork/lnd/lnrpc" @@ -20,12 +19,11 @@ func testTrackPayments(ht *lntest.HarnessTest) { cfgs := [][]string{cfgAlice, nil} // Create a channel Alice->Bob. - chanPoints, nodes := ht.CreateSimpleNetwork( + _, nodes := ht.CreateSimpleNetwork( cfgs, lntest.OpenChannelParams{ Amt: btcutil.Amount(300000), }, ) - channel := chanPoints[0] alice, bob := nodes[0], nodes[1] // Call the TrackPayments api to listen for payment updates. @@ -86,28 +84,17 @@ func testTrackPayments(ht *lntest.HarnessTest) { require.Equal(ht, amountMsat, update3.ValueMsat) require.Equal(ht, hex.EncodeToString(invoice.RPreimage), update3.PaymentPreimage) - - // TODO(yy): remove the sleep once the following bug is fixed. - // When the invoice is reported settled, the commitment dance is not - // yet finished, which can cause an error when closing the channel, - // saying there's active HTLCs. We need to investigate this issue and - // reverse the order to, first finish the commitment dance, then report - // the invoice as settled. - time.Sleep(2 * time.Second) - - ht.CloseChannel(alice, channel) } // testTrackPaymentsCompatible checks that when `routerrpc.usestatusinitiated` // is not set, the new Payment_INITIATED is replaced with Payment_IN_FLIGHT. func testTrackPaymentsCompatible(ht *lntest.HarnessTest) { // Open a channel between alice and bob. - chanPoints, nodes := ht.CreateSimpleNetwork( + _, nodes := ht.CreateSimpleNetwork( [][]string{nil, nil}, lntest.OpenChannelParams{ Amt: btcutil.Amount(300000), }, ) - channel := chanPoints[0] alice, bob := nodes[0], nodes[1] // Call the TrackPayments api to listen for payment updates. @@ -162,14 +149,4 @@ func testTrackPaymentsCompatible(ht *lntest.HarnessTest) { payment3, err := paymentClient.Recv() require.NoError(ht, err, "unable to get payment update") require.Equal(ht, lnrpc.Payment_SUCCEEDED, payment3.Status) - - // TODO(yy): remove the sleep once the following bug is fixed. - // When the invoice is reported settled, the commitment dance is not - // yet finished, which can cause an error when closing the channel, - // saying there's active HTLCs. We need to investigate this issue and - // reverse the order to, first finish the commitment dance, then report - // the invoice as settled. - time.Sleep(2 * time.Second) - - ht.CloseChannel(alice, channel) } diff --git a/itest/lnd_wumbo_channels_test.go b/itest/lnd_wumbo_channels_test.go index 18d170acc3..8bf18106e7 100644 --- a/itest/lnd_wumbo_channels_test.go +++ b/itest/lnd_wumbo_channels_test.go @@ -45,8 +45,7 @@ func testWumboChannels(ht *lntest.HarnessTest) { // Creating a wumbo channel between these two nodes should succeed. ht.EnsureConnected(wumboNode, wumboNode2) - chanPoint := ht.OpenChannel( + ht.OpenChannel( wumboNode, wumboNode2, lntest.OpenChannelParams{Amt: chanAmt}, ) - ht.CloseChannel(wumboNode, chanPoint) } diff --git a/itest/lnd_zero_conf_test.go b/itest/lnd_zero_conf_test.go index 523a41c373..8ec19945ca 100644 --- a/itest/lnd_zero_conf_test.go +++ b/itest/lnd_zero_conf_test.go @@ -854,9 +854,6 @@ func testOptionScidUpgrade(ht *lntest.HarnessTest) { daveInvoice2 := dave.RPC.AddInvoice(daveParams) ht.CompletePaymentRequests(bob, []string{daveInvoice2.PaymentRequest}) - - // Close standby node's channels. - ht.CloseChannel(bob, fundingPoint2) } // acceptChannel is used to accept a single channel that comes across. This From f64b2ce8f219bc698546df042a06b479225504af Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 2 Nov 2024 18:36:45 +0800 Subject: [PATCH 09/64] lntest: make sure node is properly shut down Soemtimes the node may be hanging for a while without being noticed, causing failures in its following tests, thus making the debugging extrememly difficult. We now assert the node has been shut down from the logs to assert the shutdown process behaves as expected. --- lntest/node/harness_node.go | 61 +++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/lntest/node/harness_node.go b/lntest/node/harness_node.go index 9ef1f212c0..d1353c25cf 100644 --- a/lntest/node/harness_node.go +++ b/lntest/node/harness_node.go @@ -983,6 +983,67 @@ func finalizeLogfile(hn *HarnessNode) { getFinalizedLogFilePrefix(hn), ) renameFile(hn.filename, newFileName) + + // Assert the node has shut down from the log file. + err := assertNodeShutdown(newFileName) + if err != nil { + err := fmt.Errorf("[%s]: assert shutdown failed in log[%s]: %w", + hn.Name(), newFileName, err) + panic(err) + } +} + +// assertNodeShutdown asserts that the node has shut down properly by checking +// the last lines of the log file for the shutdown message "Shutdown complete". +func assertNodeShutdown(filename string) error { + file, err := os.Open(filename) + if err != nil { + return err + } + defer file.Close() + + // Read more than one line to make sure we get the last line. + // const linesSize = 200 + // + // NOTE: Reading 200 bytes of lines should be more than enough to find + // the `Shutdown complete` message. However, this is only true if the + // message is printed the last, which means `lnd` will properly wait + // for all its subsystems to shut down before exiting. Unfortunately + // there is at least one bug in the shutdown process where we don't + // wait for the chain backend to fully quit first, which can be easily + // reproduced by turning on `RPCC=trace` and use a linesSize of 200. + // + // TODO(yy): fix the shutdown process and remove this workaround by + // refactoring the lnd to use only one rpcclient, which requires quite + // some work on the btcwallet front. + const linesSize = 1000 + + buf := make([]byte, linesSize) + stat, statErr := file.Stat() + if statErr != nil { + return err + } + + start := stat.Size() - linesSize + _, err = file.ReadAt(buf, start) + if err != nil { + return err + } + + // Exit early if the shutdown line is found. + if bytes.Contains(buf, []byte("Shutdown complete")) { + return nil + } + + // For etcd tests, we need to check for the line where the node is + // blocked at wallet unlock since we are testing how such a behavior is + // handled by etcd. + if bytes.Contains(buf, []byte("wallet and unlock")) { + return nil + } + + return fmt.Errorf("node did not shut down properly: found log "+ + "lines: %s", buf) } // finalizeEtcdLog saves the etcd log files when test ends. From 010a4f15718737f4daf1c7c5a2364d778e741829 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 20 Nov 2024 14:52:28 +0800 Subject: [PATCH 10/64] lntest: add human-readble names and check num of nodes --- lntest/harness.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lntest/harness.go b/lntest/harness.go index 281d5ff0bc..36a66ed0e4 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -2165,6 +2165,13 @@ func acceptChannel(t *testing.T, zeroConf bool, stream rpc.AcceptorClient) { require.NoError(t, err) } +// nodeNames defines a slice of human-reable names for the nodes created in the +// `createNodes` method. 8 nodes are defined here as by default we can only +// create this many nodes in one test. +var nodeNames = []string{ + "Alice", "Bob", "Carol", "Dave", "Eve", "Frank", "Grace", "Heidi", +} + // createNodes creates the number of nodes specified by the number of configs. // Each node is created using the specified config, the neighbors are // connected. @@ -2172,12 +2179,15 @@ func (h *HarnessTest) createNodes(nodeCfgs [][]string) []*node.HarnessNode { // Get the number of nodes. numNodes := len(nodeCfgs) + // Make sure we are creating a reasonable number of nodes. + require.LessOrEqual(h, numNodes, len(nodeNames), "too many nodes") + // Make a slice of nodes. nodes := make([]*node.HarnessNode, numNodes) // Create new nodes. for i, nodeCfg := range nodeCfgs { - nodeName := fmt.Sprintf("Node%q", string(rune('A'+i))) + nodeName := nodeNames[i] n := h.NewNode(nodeName, nodeCfg) nodes[i] = n } From e7310ff1b677c3a201bdd6c3c45f88d8548a0b59 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 29 Oct 2024 16:00:04 +0800 Subject: [PATCH 11/64] itest: fix `testOpenChannelUpdateFeePolicy` This commit fixes a misuse of `ht.Subtest`, where the nodes should always be created inside the subtest. --- itest/lnd_open_channel_test.go | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/itest/lnd_open_channel_test.go b/itest/lnd_open_channel_test.go index 9fb41a2dea..13a581921c 100644 --- a/itest/lnd_open_channel_test.go +++ b/itest/lnd_open_channel_test.go @@ -238,19 +238,22 @@ func testOpenChannelUpdateFeePolicy(ht *lntest.HarnessTest) { MaxHtlcMsat: defaultMaxHtlc, } - // In this basic test, we'll need a third node, Carol, so we can forward - // a payment through the channel we'll open with the different fee - // policies. - alice := ht.NewNodeWithCoins("Alice", nil) - bob := ht.NewNode("Bob", nil) - carol := ht.NewNode("Carol", nil) - - nodes := []*node.HarnessNode{alice, bob, carol} - runTestCase := func(ht *lntest.HarnessTest, chanParams lntest.OpenChannelParams, alicePolicy, bobPolicy *lnrpc.RoutingPolicy) { + // In this basic test, we'll need a third node, Carol, so we + // can forward a payment through the channel we'll open with + // the different fee policies. + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) + carol := ht.NewNodeWithCoins("Carol", nil) + + ht.EnsureConnected(alice, bob) + ht.EnsureConnected(alice, carol) + + nodes := []*node.HarnessNode{alice, bob, carol} + // Create a channel Alice->Bob. chanPoint := ht.OpenChannel(alice, bob, chanParams) @@ -287,19 +290,6 @@ func testOpenChannelUpdateFeePolicy(ht *lntest.HarnessTest) { for i, feeScenario := range feeScenarios { ht.Run(fmt.Sprintf("%d", i), func(t *testing.T) { st := ht.Subtest(t) - st.EnsureConnected(alice, bob) - - st.RestartNode(carol) - - // Because we're using ht.Subtest(), we need to restart - // any node we have to refresh its runtime context. - // Otherwise, we'll get a "context canceled" error on - // RPC calls. - st.EnsureConnected(alice, carol) - - // Send Carol enough coins to be able to open a channel - // to Alice. - st.FundCoins(btcutil.SatoshiPerBitcoin, carol) runTestCase( st, feeScenario, From 2a9b7ec5362447814060e81ab2fa2ccc5944aad7 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 20 Nov 2024 14:48:16 +0800 Subject: [PATCH 12/64] itest: fix flake in `testSendDirectPayment` This bug was hidden because we used standby nodes before, which always have more-than-necessary wallet utxos. --- itest/lnd_payment_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/itest/lnd_payment_test.go b/itest/lnd_payment_test.go index d36be796aa..74adc4ffad 100644 --- a/itest/lnd_payment_test.go +++ b/itest/lnd_payment_test.go @@ -449,6 +449,12 @@ func testSendDirectPayment(ht *lntest.HarnessTest) { // Make sure they are connected. st.EnsureConnected(alice, bob) + // There's a bug that causes the funding to be failed + // due to the `ListCoins` cannot find the utxos. + // + // TODO(yy): remove this line to fix the ListCoins bug. + st.FundCoins(btcutil.SatoshiPerBitcoin, alice) + // Open a channel with 100k satoshis between Alice and // Bob with Alice being the sole funder of the channel. params := lntest.OpenChannelParams{ From 3a454923983833f60772b0ffb5cd41cd6c05bf89 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 29 Oct 2024 16:05:06 +0800 Subject: [PATCH 13/64] itest: fix spawning temp miner --- itest/lnd_open_channel_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/itest/lnd_open_channel_test.go b/itest/lnd_open_channel_test.go index 13a581921c..66930a6c24 100644 --- a/itest/lnd_open_channel_test.go +++ b/itest/lnd_open_channel_test.go @@ -29,14 +29,17 @@ func testOpenChannelAfterReorg(ht *lntest.HarnessTest) { ht.Skipf("skipping reorg test for neutrino backend") } - // Create a temp miner. - tempMiner := ht.SpawnTempMiner() - miner := ht.Miner() alice := ht.NewNodeWithCoins("Alice", nil) bob := ht.NewNode("Bob", nil) ht.EnsureConnected(alice, bob) + // Create a temp miner after the creation of Alice. + // + // NOTE: this is needed since NewNodeWithCoins will mine a block and + // the temp miner needs to sync up. + tempMiner := ht.SpawnTempMiner() + // Create a new channel that requires 1 confs before it's considered // open, then broadcast the funding transaction params := lntest.OpenChannelParams{ From 762e59d78c42fcd9ade78873b14f1781b32c2933 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 31 Oct 2024 03:24:34 +0800 Subject: [PATCH 14/64] itest: fix flake for neutrino backend --- itest/lnd_channel_force_close_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/itest/lnd_channel_force_close_test.go b/itest/lnd_channel_force_close_test.go index 7c047fbcdb..9711e83a9b 100644 --- a/itest/lnd_channel_force_close_test.go +++ b/itest/lnd_channel_force_close_test.go @@ -340,6 +340,22 @@ func runChannelForceClosureTest(ht *lntest.HarnessTest, "sweep transaction not spending from commit") } + // For neutrino backend, due to it has no mempool, we need to check the + // sweep tx has already been saved to db before restarting. This is due + // to the possible race, + // - the fee bumper returns a TxPublished event, which is received by + // the sweeper and the sweep tx is saved to db. + // - the sweeper receives a shutdown signal before it receives the + // above event. + // + // TODO(yy): fix the above race. + if ht.IsNeutrinoBackend() { + // 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) + } + // Restart Alice to ensure that she resumes watching the finalized // commitment sweep txid. ht.RestartNode(alice) From 9f764c25f9827bf36e6084ac225b6c3929340d90 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 31 Oct 2024 05:57:22 +0800 Subject: [PATCH 15/64] itest: flatten PSBT funding test cases So it's easier to get the logs and debug. --- itest/list_on_test.go | 5 +- itest/lnd_psbt_test.go | 203 +++++++++++++++----------------- itest/lnd_remote_signer_test.go | 2 +- 3 files changed, 96 insertions(+), 114 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 67915dee8f..ebb691f996 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -283,10 +283,6 @@ var allTestCases = []*lntest.TestCase{ Name: "open channel reorg test", TestFunc: testOpenChannelAfterReorg, }, - { - Name: "psbt channel funding", - TestFunc: testPsbtChanFunding, - }, { Name: "sign psbt", TestFunc: testSignPsbt, @@ -694,4 +690,5 @@ func init() { // Register subtests. allTestCases = append(allTestCases, multiHopForceCloseTestCases...) allTestCases = append(allTestCases, watchtowerTestCases...) + allTestCases = append(allTestCases, psbtFundingTestCases...) } diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go index 1bba998be1..3d0872c3c8 100644 --- a/itest/lnd_psbt_test.go +++ b/itest/lnd_psbt_test.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/hex" "testing" - "time" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/ecdsa" @@ -27,119 +26,85 @@ import ( "github.com/stretchr/testify/require" ) -// testPsbtChanFunding makes sure a channel can be opened between carol and dave -// by using a Partially Signed Bitcoin Transaction that funds the channel -// multisig funding output. -func testPsbtChanFunding(ht *lntest.HarnessTest) { - const ( - burnAddr = "bcrt1qxsnqpdc842lu8c0xlllgvejt6rhy49u6fmpgyz" - ) - - testCases := []struct { - name string - commitmentType lnrpc.CommitmentType - private bool - }{ - { - name: "anchors", - commitmentType: lnrpc.CommitmentType_ANCHORS, - private: false, +// psbtFundingTestCases contains the test cases for funding via PSBT. +var psbtFundingTestCases = []*lntest.TestCase{ + { + Name: "psbt funding anchor", + TestFunc: func(ht *lntest.HarnessTest) { + runPsbtChanFunding( + ht, false, lnrpc.CommitmentType_ANCHORS, + ) }, - { - name: "simple taproot", - commitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT, - - // Set this to true once simple taproot channels can be - // announced to the network. - private: true, + }, + { + Name: "psbt external funding anchor", + TestFunc: func(ht *lntest.HarnessTest) { + runPsbtChanFundingExternal( + ht, false, lnrpc.CommitmentType_ANCHORS, + ) }, - } + }, + { + Name: "psbt single step funding anchor", + TestFunc: func(ht *lntest.HarnessTest) { + runPsbtChanFundingSingleStep( + ht, false, lnrpc.CommitmentType_ANCHORS, + ) + }, + }, + { + Name: "psbt funding simple taproot", + TestFunc: func(ht *lntest.HarnessTest) { + runPsbtChanFunding( + ht, true, lnrpc.CommitmentType_SIMPLE_TAPROOT, + ) + }, + }, + { + Name: "psbt external funding simple taproot", + TestFunc: func(ht *lntest.HarnessTest) { + runPsbtChanFundingExternal( + ht, true, lnrpc.CommitmentType_SIMPLE_TAPROOT, + ) + }, + }, + { + Name: "psbt single step funding simple taproot", + TestFunc: func(ht *lntest.HarnessTest) { + runPsbtChanFundingSingleStep( + ht, true, lnrpc.CommitmentType_SIMPLE_TAPROOT, + ) + }, + }, +} - for _, tc := range testCases { - tc := tc - - success := ht.T.Run(tc.name, func(tt *testing.T) { - st := ht.Subtest(tt) - - args := lntest.NodeArgsForCommitType(tc.commitmentType) - - // First, we'll create two new nodes that we'll use to - // open channels between for this test. Dave gets some - // coins that will be used to fund the PSBT, just to - // make sure that Carol has an empty wallet. - carol := st.NewNode("carol", args) - dave := st.NewNode("dave", args) - - // We just send enough funds to satisfy the anchor - // channel reserve for 5 channels (50k sats). - st.FundCoins(50_000, carol) - st.FundCoins(50_000, dave) - - st.RunTestCase(&lntest.TestCase{ - Name: tc.name, - TestFunc: func(sst *lntest.HarnessTest) { - runPsbtChanFunding( - sst, carol, dave, tc.private, - tc.commitmentType, - ) - }, - }) +// runPsbtChanFunding makes sure a channel can be opened between carol and dave +// by using a Partially Signed Bitcoin Transaction that funds the channel +// multisig funding output. +func runPsbtChanFunding(ht *lntest.HarnessTest, private bool, + commitType lnrpc.CommitmentType) { - // Empty out the wallets so there aren't any lingering - // coins. - sendAllCoinsConfirm(st, carol, burnAddr) - sendAllCoinsConfirm(st, dave, burnAddr) - - // Now we test the second scenario. Again, we just send - // enough funds to satisfy the anchor channel reserve - // for 5 channels (50k sats). - st.FundCoins(50_000, carol) - st.FundCoins(50_000, dave) - - st.RunTestCase(&lntest.TestCase{ - Name: tc.name, - TestFunc: func(sst *lntest.HarnessTest) { - runPsbtChanFundingExternal( - sst, carol, dave, tc.private, - tc.commitmentType, - ) - }, - }) + args := lntest.NodeArgsForCommitType(commitType) - // Empty out the wallets a last time, so there aren't - // any lingering coins. - sendAllCoinsConfirm(st, carol, burnAddr) - sendAllCoinsConfirm(st, dave, burnAddr) - - // The last test case tests the anchor channel reserve - // itself, so we need empty wallets. - st.RunTestCase(&lntest.TestCase{ - Name: tc.name, - TestFunc: func(sst *lntest.HarnessTest) { - runPsbtChanFundingSingleStep( - sst, carol, dave, tc.private, - tc.commitmentType, - ) - }, - }) - }) - if !success { - // Log failure time to help relate the lnd logs to the - // failure. - ht.Logf("Failure time: %v", time.Now().Format( - "2006-01-02 15:04:05.000", - )) + // First, we'll create two new nodes that we'll use to open channels + // between for this test. Dave gets some coins that will be used to + // fund the PSBT, just to make sure that Carol has an empty wallet. + carol := ht.NewNode("carol", args) + dave := ht.NewNode("dave", args) - break - } - } + // We just send enough funds to satisfy the anchor channel reserve for + // 5 channels (50k sats). + ht.FundCoins(50_000, carol) + ht.FundCoins(50_000, dave) + + runPsbtChanFundingWithNodes(ht, carol, dave, private, commitType) } -// runPsbtChanFunding makes sure a channel can be opened between carol and dave -// by using a Partially Signed Bitcoin Transaction that funds the channel +// runPsbtChanFundingWithNodes run a test case to make sure a channel can be +// opened between carol and dave by using a PSBT that funds the channel // multisig funding output. -func runPsbtChanFunding(ht *lntest.HarnessTest, carol, dave *node.HarnessNode, - private bool, commitType lnrpc.CommitmentType) { +func runPsbtChanFundingWithNodes(ht *lntest.HarnessTest, carol, + dave *node.HarnessNode, private bool, commitType lnrpc.CommitmentType) { const chanSize = funding.MaxBtcFundingAmount ht.FundCoins(btcutil.SatoshiPerBitcoin, dave) @@ -330,8 +295,21 @@ func runPsbtChanFunding(ht *lntest.HarnessTest, carol, dave *node.HarnessNode, // and dave by using a Partially Signed Bitcoin Transaction that funds the // channel multisig funding output and is fully funded by an external third // party. -func runPsbtChanFundingExternal(ht *lntest.HarnessTest, carol, - dave *node.HarnessNode, private bool, commitType lnrpc.CommitmentType) { +func runPsbtChanFundingExternal(ht *lntest.HarnessTest, private bool, + commitType lnrpc.CommitmentType) { + + args := lntest.NodeArgsForCommitType(commitType) + + // First, we'll create two new nodes that we'll use to open channels + // between for this test. Dave gets some coins that will be used to + // fund the PSBT, just to make sure that Carol has an empty wallet. + carol := ht.NewNode("carol", args) + dave := ht.NewNode("dave", args) + + // We just send enough funds to satisfy the anchor channel reserve for + // 5 channels (50k sats). + ht.FundCoins(50_000, carol) + ht.FundCoins(50_000, dave) const chanSize = funding.MaxBtcFundingAmount @@ -498,8 +476,15 @@ func runPsbtChanFundingExternal(ht *lntest.HarnessTest, carol, // the wallet of both nodes are empty and one of them uses PSBT and an external // wallet to fund the channel while creating reserve output in the same // transaction. -func runPsbtChanFundingSingleStep(ht *lntest.HarnessTest, carol, - dave *node.HarnessNode, private bool, commitType lnrpc.CommitmentType) { +func runPsbtChanFundingSingleStep(ht *lntest.HarnessTest, private bool, + commitType lnrpc.CommitmentType) { + + args := lntest.NodeArgsForCommitType(commitType) + + // First, we'll create two new nodes that we'll use to open channels + // between for this test. + carol := ht.NewNode("carol", args) + dave := ht.NewNode("dave", args) const chanSize = funding.MaxBtcFundingAmount diff --git a/itest/lnd_remote_signer_test.go b/itest/lnd_remote_signer_test.go index e18e5cb039..bd92ba37c8 100644 --- a/itest/lnd_remote_signer_test.go +++ b/itest/lnd_remote_signer_test.go @@ -123,7 +123,7 @@ func testRemoteSigner(ht *lntest.HarnessTest) { name: "psbt", randomSeed: true, fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { - runPsbtChanFunding( + runPsbtChanFundingWithNodes( tt, carol, wo, false, lnrpc.CommitmentType_LEGACY, ) From 782edde213f6f64226af10c621bcb7a8da8cb7a9 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 31 Oct 2024 06:11:06 +0800 Subject: [PATCH 16/64] itest: fix and document flake in sweeping tests We previously didn't see this issue because we always have nodes being over-funded. --- itest/lnd_sweep_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/itest/lnd_sweep_test.go b/itest/lnd_sweep_test.go index 764ca93082..5995d16945 100644 --- a/itest/lnd_sweep_test.go +++ b/itest/lnd_sweep_test.go @@ -113,6 +113,14 @@ func testSweepCPFPAnchorOutgoingTimeout(ht *lntest.HarnessTest) { ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) } + // Bob should have enough wallet UTXOs here to sweep the HTLC in the + // end of this test. However, due to a known issue, Bob's wallet may + // report there's no UTXO available. For details, + // - https://github.com/lightningnetwork/lnd/issues/8786 + // + // TODO(yy): remove this step once the issue is resolved. + ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) + // Subscribe the invoice. streamCarol := carol.RPC.SubscribeSingleInvoice(payHash[:]) @@ -432,6 +440,14 @@ func testSweepCPFPAnchorIncomingTimeout(ht *lntest.HarnessTest) { ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) } + // Bob should have enough wallet UTXOs here to sweep the HTLC in the + // end of this test. However, due to a known issue, Bob's wallet may + // report there's no UTXO available. For details, + // - https://github.com/lightningnetwork/lnd/issues/8786 + // + // TODO(yy): remove this step once the issue is resolved. + ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) + // Subscribe the invoice. streamCarol := carol.RPC.SubscribeSingleInvoice(payHash[:]) @@ -766,6 +782,14 @@ func testSweepHTLCs(ht *lntest.HarnessTest) { ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) + // Bob should have enough wallet UTXOs here to sweep the HTLC in the + // end of this test. However, due to a known issue, Bob's wallet may + // report there's no UTXO available. For details, + // - https://github.com/lightningnetwork/lnd/issues/8786 + // + // TODO(yy): remove this step once the issue is resolved. + ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) + // For neutrino backend, we need two more UTXOs for Bob to create his // sweeping txns. if ht.IsNeutrinoBackend() { From c07162603d41fef39bf46ecb1254dac75e90fe13 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 31 Oct 2024 07:29:28 +0800 Subject: [PATCH 17/64] itest: remove loop in `wsTestCaseBiDirectionalSubscription` So we know which open channel operation failed. --- itest/lnd_rest_api_test.go | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/itest/lnd_rest_api_test.go b/itest/lnd_rest_api_test.go index 7c4a3d988e..70e1032082 100644 --- a/itest/lnd_rest_api_test.go +++ b/itest/lnd_rest_api_test.go @@ -440,7 +440,6 @@ func wsTestCaseBiDirectionalSubscription(ht *lntest.HarnessTest) { msgChan := make(chan *lnrpc.ChannelAcceptResponse, 1) errChan := make(chan error) done := make(chan struct{}) - timeout := time.After(defaultTimeout) // We want to read messages over and over again. We just accept any // channels that are opened. @@ -506,6 +505,7 @@ func wsTestCaseBiDirectionalSubscription(ht *lntest.HarnessTest) { } return } + ht.Logf("Finish writing message %s", resMsg) // Also send the message on our message channel to make // sure we count it as successful. @@ -525,23 +525,27 @@ func wsTestCaseBiDirectionalSubscription(ht *lntest.HarnessTest) { bob := ht.NewNodeWithCoins("Bob", nil) ht.EnsureConnected(alice, bob) - // Open 3 channels to make sure multiple requests and responses can be - // sent over the web socket. - const numChannels = 3 - for i := 0; i < numChannels; i++ { - ht.OpenChannel( - bob, alice, lntest.OpenChannelParams{Amt: 500000}, - ) - + assertMsgReceived := func() { select { case <-msgChan: case err := <-errChan: ht.Fatalf("Received error from WS: %v", err) - case <-timeout: + case <-time.After(defaultTimeout): ht.Fatalf("Timeout before message was received") } } + + // Open 3 channels to make sure multiple requests and responses can be + // sent over the web socket. + ht.OpenChannel(bob, alice, lntest.OpenChannelParams{Amt: 500000}) + assertMsgReceived() + + ht.OpenChannel(bob, alice, lntest.OpenChannelParams{Amt: 500000}) + assertMsgReceived() + + ht.OpenChannel(bob, alice, lntest.OpenChannelParams{Amt: 500000}) + assertMsgReceived() } func wsTestPingPongTimeout(ht *lntest.HarnessTest) { From 66b35018b85a9ed0427bd13960b2e13f26a74638 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 2 Nov 2024 12:13:32 +0800 Subject: [PATCH 18/64] itest: fix flake in `testRevokedCloseRetributionZeroValueRemoteOutput` We need to mine an empty block as the tx may already have entered the mempool. This should be fixed once we start using the sweeper to handle the justice tx. --- itest/lnd_revocation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itest/lnd_revocation_test.go b/itest/lnd_revocation_test.go index 8e2638fe98..5074a3f02d 100644 --- a/itest/lnd_revocation_test.go +++ b/itest/lnd_revocation_test.go @@ -612,7 +612,7 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest, // transactions will be in the mempool at this point, we pass 0 // as the last argument, indicating we don't care what's in the // mempool. - ht.MineBlocks(1) + ht.MineEmptyBlocks(1) err = wait.NoError(func() error { txid, err := findJusticeTx() if err != nil { From 8b8f0c4eb426c0a04111ed17b1b5d987bfd22409 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sun, 3 Nov 2024 08:21:24 +0800 Subject: [PATCH 19/64] itest: fix flake in `testSwitchOfflineDelivery` The reconnection will happen automatically when the nodes have a channel, so we just ensure the connection instead of reconnecting directly. --- itest/lnd_switch_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itest/lnd_switch_test.go b/itest/lnd_switch_test.go index 59e8ce9cec..10be216130 100644 --- a/itest/lnd_switch_test.go +++ b/itest/lnd_switch_test.go @@ -103,7 +103,7 @@ func testSwitchOfflineDelivery(ht *lntest.HarnessTest) { ht.DisconnectNodes(s.dave, s.alice) // Then, reconnect them to ensure Dave doesn't just fail back the htlc. - ht.ConnectNodes(s.dave, s.alice) + ht.EnsureConnected(s.dave, s.alice) // Wait to ensure that the payment remain are not failed back after // reconnecting. All node should report the number payments initiated From 4eea2078fb7b89afd525900f3718d89c631cb77a Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sun, 3 Nov 2024 13:19:19 +0800 Subject: [PATCH 20/64] itest+routing: fix flake in `runFeeEstimationTestCase` The test used 10s as the timeout value, which can easily cause a timeout in a slow build so we increase it to 60s. --- itest/lnd_estimate_route_fee_test.go | 3 ++- routing/payment_lifecycle.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/itest/lnd_estimate_route_fee_test.go b/itest/lnd_estimate_route_fee_test.go index 0286976851..80d19fc043 100644 --- a/itest/lnd_estimate_route_fee_test.go +++ b/itest/lnd_estimate_route_fee_test.go @@ -9,6 +9,7 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest/node" + "github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/routing" "github.com/stretchr/testify/require" ) @@ -376,7 +377,7 @@ func runFeeEstimationTestCase(ht *lntest.HarnessTest, ) feeReq = &routerrpc.RouteFeeRequest{ PaymentRequest: payReqs[0], - Timeout: 10, + Timeout: uint32(wait.PaymentTimeout.Seconds()), } } else { feeReq = &routerrpc.RouteFeeRequest{ diff --git a/routing/payment_lifecycle.go b/routing/payment_lifecycle.go index 34de74461e..180d38a631 100644 --- a/routing/payment_lifecycle.go +++ b/routing/payment_lifecycle.go @@ -348,7 +348,7 @@ func (p *paymentLifecycle) checkContext(ctx context.Context) error { if errors.Is(ctx.Err(), context.DeadlineExceeded) { reason = channeldb.FailureReasonTimeout log.Warnf("Payment attempt not completed before "+ - "timeout, id=%s", p.identifier.String()) + "context timeout, id=%s", p.identifier.String()) } else { reason = channeldb.FailureReasonCanceled log.Warnf("Payment attempt context canceled, id=%s", From fee6b70519f200e7603bf1e26f70d292ea6c1b85 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sun, 3 Nov 2024 13:34:16 +0800 Subject: [PATCH 21/64] itest: use `ht.CreateSimpleNetwork` whenever applicable So we won't forget to assert the topology after opening a chain of channels. --- itest/lnd_experimental_endorsement.go | 34 ++---- itest/lnd_forward_interceptor_test.go | 157 +++++++++----------------- itest/lnd_payment_test.go | 32 ++---- itest/lnd_quiescence_test.go | 13 ++- 4 files changed, 83 insertions(+), 153 deletions(-) diff --git a/itest/lnd_experimental_endorsement.go b/itest/lnd_experimental_endorsement.go index 5a1f8fffca..43e29c2bea 100644 --- a/itest/lnd_experimental_endorsement.go +++ b/itest/lnd_experimental_endorsement.go @@ -7,6 +7,7 @@ import ( "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lntest" + "github.com/lightningnetwork/lnd/lntest/node" "github.com/lightningnetwork/lnd/lntest/rpc" "github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntypes" @@ -24,37 +25,18 @@ func testExperimentalEndorsement(ht *lntest.HarnessTest) { // testEndorsement sets up a 5 hop network and tests propagation of // experimental endorsement signals. func testEndorsement(ht *lntest.HarnessTest, aliceEndorse bool) { - alice := ht.NewNodeWithCoins("Alice", nil) - bob := ht.NewNodeWithCoins("Bob", nil) - carol := ht.NewNode( - "carol", []string{"--protocol.no-experimental-endorsement"}, + cfg := node.CfgAnchor + carolCfg := append( + []string{"--protocol.no-experimental-endorsement"}, cfg..., ) - dave := ht.NewNode("dave", nil) - eve := ht.NewNode("eve", nil) + cfgs := [][]string{cfg, cfg, carolCfg, cfg, cfg} - ht.EnsureConnected(alice, bob) - ht.EnsureConnected(bob, carol) - ht.EnsureConnected(carol, dave) - ht.EnsureConnected(dave, eve) - - ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) - ht.FundCoins(btcutil.SatoshiPerBitcoin, dave) - // Open and wait for channels. const chanAmt = btcutil.Amount(300000) p := lntest.OpenChannelParams{Amt: chanAmt} - reqs := []*lntest.OpenChannelRequest{ - {Local: alice, Remote: bob, Param: p}, - {Local: bob, Remote: carol, Param: p}, - {Local: carol, Remote: dave, Param: p}, - {Local: dave, Remote: eve, Param: p}, - } - resp := ht.OpenMultiChannelsAsync(reqs) - _, cpBC, cpCD, cpDE := resp[0], resp[1], resp[2], resp[3] - // Make sure Alice is aware of Bob=>Carol=>Dave=>Eve channels. - ht.AssertChannelInGraph(alice, cpBC) - ht.AssertChannelInGraph(alice, cpCD) - ht.AssertChannelInGraph(alice, cpDE) + _, nodes := ht.CreateSimpleNetwork(cfgs, p) + alice, bob, carol, dave, eve := nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4] bobIntercept, cancelBob := bob.RPC.HtlcInterceptor() defer cancelBob() diff --git a/itest/lnd_forward_interceptor_test.go b/itest/lnd_forward_interceptor_test.go index 70227be246..93012c98f3 100644 --- a/itest/lnd_forward_interceptor_test.go +++ b/itest/lnd_forward_interceptor_test.go @@ -42,23 +42,24 @@ type interceptorTestCase struct { // testForwardInterceptorDedupHtlc tests that upon reconnection, duplicate // HTLCs aren't re-notified using the HTLC interceptor API. func testForwardInterceptorDedupHtlc(ht *lntest.HarnessTest) { - // Initialize the test context with 3 connected nodes. - ts := newInterceptorTestScenario(ht) + const chanAmt = btcutil.Amount(300000) + p := lntest.OpenChannelParams{Amt: chanAmt} - alice, bob, carol := ts.alice, ts.bob, ts.carol + // Initialize the test context with 3 connected nodes. + cfgs := [][]string{nil, nil, nil} // Open and wait for channels. - const chanAmt = btcutil.Amount(300000) - p := lntest.OpenChannelParams{Amt: chanAmt} - reqs := []*lntest.OpenChannelRequest{ - {Local: alice, Remote: bob, Param: p}, - {Local: bob, Remote: carol, Param: p}, - } - resp := ht.OpenMultiChannelsAsync(reqs) - cpAB, cpBC := resp[0], resp[1] + chanPoints, nodes := ht.CreateSimpleNetwork(cfgs, p) + alice, bob, carol := nodes[0], nodes[1], nodes[2] + cpAB := chanPoints[0] - // Make sure Alice is aware of channel Bob=>Carol. - ht.AssertChannelInGraph(alice, cpBC) + // Init the scenario. + ts := &interceptorTestScenario{ + ht: ht, + alice: alice, + bob: bob, + carol: carol, + } // Connect the interceptor. interceptor, cancelInterceptor := bob.RPC.HtlcInterceptor() @@ -190,22 +191,24 @@ func testForwardInterceptorDedupHtlc(ht *lntest.HarnessTest) { // 4. When Interceptor disconnects it resumes all held htlcs, which result in // valid payment (invoice is settled). func testForwardInterceptorBasic(ht *lntest.HarnessTest) { - ts := newInterceptorTestScenario(ht) + const chanAmt = btcutil.Amount(300000) + p := lntest.OpenChannelParams{Amt: chanAmt} - alice, bob, carol := ts.alice, ts.bob, ts.carol + // Initialize the test context with 3 connected nodes. + cfgs := [][]string{nil, nil, nil} // Open and wait for channels. - const chanAmt = btcutil.Amount(300000) - p := lntest.OpenChannelParams{Amt: chanAmt} - reqs := []*lntest.OpenChannelRequest{ - {Local: alice, Remote: bob, Param: p}, - {Local: bob, Remote: carol, Param: p}, - } - resp := ht.OpenMultiChannelsAsync(reqs) - cpAB, cpBC := resp[0], resp[1] + chanPoints, nodes := ht.CreateSimpleNetwork(cfgs, p) + alice, bob, carol := nodes[0], nodes[1], nodes[2] + cpAB := chanPoints[0] - // Make sure Alice is aware of channel Bob=>Carol. - ht.AssertChannelInGraph(alice, cpBC) + // Init the scenario. + ts := &interceptorTestScenario{ + ht: ht, + alice: alice, + bob: bob, + carol: carol, + } // Connect the interceptor. interceptor, cancelInterceptor := bob.RPC.HtlcInterceptor() @@ -346,23 +349,23 @@ func testForwardInterceptorBasic(ht *lntest.HarnessTest) { // testForwardInterceptorModifiedHtlc tests that the interceptor can modify the // amount and custom records of an intercepted HTLC and resume it. func testForwardInterceptorModifiedHtlc(ht *lntest.HarnessTest) { - // Initialize the test context with 3 connected nodes. - ts := newInterceptorTestScenario(ht) + const chanAmt = btcutil.Amount(300000) + p := lntest.OpenChannelParams{Amt: chanAmt} - alice, bob, carol := ts.alice, ts.bob, ts.carol + // Initialize the test context with 3 connected nodes. + cfgs := [][]string{nil, nil, nil} // Open and wait for channels. - const chanAmt = btcutil.Amount(300000) - p := lntest.OpenChannelParams{Amt: chanAmt} - reqs := []*lntest.OpenChannelRequest{ - {Local: alice, Remote: bob, Param: p}, - {Local: bob, Remote: carol, Param: p}, - } - resp := ht.OpenMultiChannelsAsync(reqs) - cpBC := resp[1] + _, nodes := ht.CreateSimpleNetwork(cfgs, p) + alice, bob, carol := nodes[0], nodes[1], nodes[2] - // Make sure Alice is aware of channel Bob=>Carol. - ht.AssertChannelInGraph(alice, cpBC) + // Init the scenario. + ts := &interceptorTestScenario{ + ht: ht, + alice: alice, + bob: bob, + carol: carol, + } // Connect an interceptor to Bob's node. bobInterceptor, cancelBobInterceptor := bob.RPC.HtlcInterceptor() @@ -449,24 +452,15 @@ func testForwardInterceptorModifiedHtlc(ht *lntest.HarnessTest) { // wire custom records provided by the sender of a payment as part of the // update_add_htlc message. func testForwardInterceptorWireRecords(ht *lntest.HarnessTest) { - // Initialize the test context with 3 connected nodes. - ts := newInterceptorTestScenario(ht) - - alice, bob, carol, dave := ts.alice, ts.bob, ts.carol, ts.dave - - // Open and wait for channels. const chanAmt = btcutil.Amount(300000) p := lntest.OpenChannelParams{Amt: chanAmt} - reqs := []*lntest.OpenChannelRequest{ - {Local: alice, Remote: bob, Param: p}, - {Local: bob, Remote: carol, Param: p}, - {Local: carol, Remote: dave, Param: p}, - } - resp := ht.OpenMultiChannelsAsync(reqs) - cpBC := resp[1] - // Make sure Alice is aware of channel Bob=>Carol. - ht.AssertChannelInGraph(alice, cpBC) + // Initialize the test context with 4 connected nodes. + cfgs := [][]string{nil, nil, nil, nil} + + // Open and wait for channels. + _, nodes := ht.CreateSimpleNetwork(cfgs, p) + alice, bob, carol, dave := nodes[0], nodes[1], nodes[2], nodes[3] // Connect an interceptor to Bob's node. bobInterceptor, cancelBobInterceptor := bob.RPC.HtlcInterceptor() @@ -574,25 +568,15 @@ func testForwardInterceptorWireRecords(ht *lntest.HarnessTest) { // update_add_htlc message and that those records are persisted correctly and // re-sent on node restart. func testForwardInterceptorRestart(ht *lntest.HarnessTest) { - // Initialize the test context with 3 connected nodes. - ts := newInterceptorTestScenario(ht) - - alice, bob, carol, dave := ts.alice, ts.bob, ts.carol, ts.dave - - // Open and wait for channels. const chanAmt = btcutil.Amount(300000) p := lntest.OpenChannelParams{Amt: chanAmt} - reqs := []*lntest.OpenChannelRequest{ - {Local: alice, Remote: bob, Param: p}, - {Local: bob, Remote: carol, Param: p}, - {Local: carol, Remote: dave, Param: p}, - } - resp := ht.OpenMultiChannelsAsync(reqs) - cpBC, cpCD := resp[1], resp[2] - // Make sure Alice is aware of channels Bob=>Carol and Carol=>Dave. - ht.AssertChannelInGraph(alice, cpBC) - ht.AssertChannelInGraph(alice, cpCD) + // Initialize the test context with 4 connected nodes. + cfgs := [][]string{nil, nil, nil, nil} + + // Open and wait for channels. + _, nodes := ht.CreateSimpleNetwork(cfgs, p) + alice, bob, carol, dave := nodes[0], nodes[1], nodes[2], nodes[3] // Connect an interceptor to Bob's node. bobInterceptor, cancelBobInterceptor := bob.RPC.HtlcInterceptor() @@ -730,39 +714,8 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) { // interceptorTestScenario is a helper struct to hold the test context and // provide the needed functionality. type interceptorTestScenario struct { - ht *lntest.HarnessTest - alice, bob, carol, dave *node.HarnessNode -} - -// newInterceptorTestScenario initializes a new test scenario with three nodes -// and connects them to have the following topology, -// -// Alice --> Bob --> Carol --> Dave -// -// Among them, Alice and Bob are standby nodes and Carol is a new node. -func newInterceptorTestScenario( - ht *lntest.HarnessTest) *interceptorTestScenario { - - alice := ht.NewNodeWithCoins("Alice", nil) - bob := ht.NewNodeWithCoins("bob", nil) - - carol := ht.NewNode("carol", nil) - dave := ht.NewNode("dave", nil) - - ht.EnsureConnected(alice, bob) - ht.EnsureConnected(bob, carol) - ht.EnsureConnected(carol, dave) - - // So that carol can open channels. - ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) - - return &interceptorTestScenario{ - ht: ht, - alice: alice, - bob: bob, - carol: carol, - dave: dave, - } + ht *lntest.HarnessTest + alice, bob, carol *node.HarnessNode } // prepareTestCases prepares 4 tests: diff --git a/itest/lnd_payment_test.go b/itest/lnd_payment_test.go index 74adc4ffad..8f9b2bc748 100644 --- a/itest/lnd_payment_test.go +++ b/itest/lnd_payment_test.go @@ -1070,23 +1070,16 @@ func assertChannelState(ht *lntest.HarnessTest, hn *node.HarnessNode, // 5.) Alice observes a failed OR succeeded payment with failure reason // FAILURE_REASON_CANCELED which suppresses further payment attempts. func testPaymentFailureReasonCanceled(ht *lntest.HarnessTest) { - // Initialize the test context with 3 connected nodes. - ts := newInterceptorTestScenario(ht) - - alice, bob, carol := ts.alice, ts.bob, ts.carol - - // Open and wait for channels. const chanAmt = btcutil.Amount(300000) p := lntest.OpenChannelParams{Amt: chanAmt} - reqs := []*lntest.OpenChannelRequest{ - {Local: alice, Remote: bob, Param: p}, - {Local: bob, Remote: carol, Param: p}, - } - resp := ht.OpenMultiChannelsAsync(reqs) - cpAB, cpBC := resp[0], resp[1] - // Make sure Alice is aware of channel Bob=>Carol. - ht.AssertChannelInGraph(alice, cpBC) + // Initialize the test context with 3 connected nodes. + cfgs := [][]string{nil, nil, nil} + + // Open and wait for channels. + chanPoints, nodes := ht.CreateSimpleNetwork(cfgs, p) + alice, bob, carol := nodes[0], nodes[1], nodes[2] + cpAB := chanPoints[0] // Connect the interceptor. interceptor, cancelInterceptor := bob.RPC.HtlcInterceptor() @@ -1096,7 +1089,8 @@ func testPaymentFailureReasonCanceled(ht *lntest.HarnessTest) { // htlc even though the payment context was canceled before invoice // settlement. sendPaymentInterceptAndCancel( - ht, ts, cpAB, routerrpc.ResolveHoldForwardAction_RESUME, + ht, alice, bob, carol, cpAB, + routerrpc.ResolveHoldForwardAction_RESUME, lnrpc.Payment_SUCCEEDED, interceptor, ) @@ -1106,20 +1100,18 @@ func testPaymentFailureReasonCanceled(ht *lntest.HarnessTest) { // Note that we'd have to reset Alice's mission control if we tested the // htlc fail case before the htlc resume case. sendPaymentInterceptAndCancel( - ht, ts, cpAB, routerrpc.ResolveHoldForwardAction_FAIL, + ht, alice, bob, carol, cpAB, + routerrpc.ResolveHoldForwardAction_FAIL, lnrpc.Payment_FAILED, interceptor, ) } func sendPaymentInterceptAndCancel(ht *lntest.HarnessTest, - ts *interceptorTestScenario, cpAB *lnrpc.ChannelPoint, + alice, bob, carol *node.HarnessNode, cpAB *lnrpc.ChannelPoint, interceptorAction routerrpc.ResolveHoldForwardAction, expectedPaymentStatus lnrpc.Payment_PaymentStatus, interceptor rpc.InterceptorClient) { - // Prepare the test cases. - alice, bob, carol := ts.alice, ts.bob, ts.carol - // Prepare the test cases. addResponse := carol.RPC.AddInvoice(&lnrpc.Invoice{ ValueMsat: 1000, diff --git a/itest/lnd_quiescence_test.go b/itest/lnd_quiescence_test.go index c698b41e47..d38ee6c781 100644 --- a/itest/lnd_quiescence_test.go +++ b/itest/lnd_quiescence_test.go @@ -6,6 +6,7 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/devrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lntest" + "github.com/lightningnetwork/lnd/lntest/node" "github.com/stretchr/testify/require" ) @@ -16,12 +17,14 @@ import ( // NOTE FOR REVIEW: this could be improved by blasting the channel with HTLC // traffic on both sides to increase the surface area of the change under test. func testQuiescence(ht *lntest.HarnessTest) { - alice := ht.NewNodeWithCoins("Alice", nil) - bob := ht.NewNode("Bob", nil) + cfg := node.CfgAnchor + chanPoints, nodes := ht.CreateSimpleNetwork( + [][]string{cfg, cfg}, lntest.OpenChannelParams{ + Amt: btcutil.Amount(1000000), + }) - chanPoint := ht.OpenChannel(bob, alice, lntest.OpenChannelParams{ - Amt: btcutil.Amount(1000000), - }) + alice, bob := nodes[0], nodes[1] + chanPoint := chanPoints[0] res := alice.RPC.Quiesce(&devrpc.QuiescenceRequest{ ChanId: chanPoint, From 8f3100c984fcdeb8798e94ecc9747473b6b16c99 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Mon, 4 Nov 2024 11:14:47 +0800 Subject: [PATCH 22/64] itest: put mpp tests in one file --- itest/lnd_mpp_test.go | 105 ++++++++++++++++++++ itest/lnd_send_multi_path_payment_test.go | 115 ---------------------- 2 files changed, 105 insertions(+), 115 deletions(-) delete mode 100644 itest/lnd_send_multi_path_payment_test.go diff --git a/itest/lnd_mpp_test.go b/itest/lnd_mpp_test.go index 99eb1eb599..0316e253ae 100644 --- a/itest/lnd_mpp_test.go +++ b/itest/lnd_mpp_test.go @@ -1,6 +1,7 @@ package itest import ( + "encoding/hex" "time" "github.com/btcsuite/btcd/btcutil" @@ -14,6 +15,110 @@ import ( "github.com/stretchr/testify/require" ) +// testSendMultiPathPayment tests that we are able to successfully route a +// payment using multiple shards across different paths. +func testSendMultiPathPayment(ht *lntest.HarnessTest) { + mts := newMppTestScenario(ht) + + const paymentAmt = btcutil.Amount(300000) + + // Set up a network with three different paths Alice <-> Bob. Channel + // capacities are set such that the payment can only succeed if (at + // least) three paths are used. + // + // _ Eve _ + // / \ + // Alice -- Carol ---- Bob + // \ / + // \__ Dave ____/ + // + req := &mppOpenChannelRequest{ + amtAliceCarol: 285000, + amtAliceDave: 155000, + amtCarolBob: 200000, + amtCarolEve: 155000, + amtDaveBob: 155000, + amtEveBob: 155000, + } + mts.openChannels(req) + chanPointAliceDave := mts.channelPoints[1] + + // Increase Dave's fee to make the test deterministic. Otherwise, it + // would be unpredictable whether pathfinding would go through Charlie + // or Dave for the first shard. + expectedPolicy := &lnrpc.RoutingPolicy{ + FeeBaseMsat: 500_000, + FeeRateMilliMsat: int64(0.001 * 1_000_000), + TimeLockDelta: 40, + MinHtlc: 1000, // default value + MaxHtlcMsat: 133_650_000, + } + mts.dave.UpdateGlobalPolicy(expectedPolicy) + + // Make sure Alice has heard it. + ht.AssertChannelPolicyUpdate( + mts.alice, mts.dave, expectedPolicy, chanPointAliceDave, false, + ) + + // Our first test will be Alice paying Bob using a SendPayment call. + // Let Bob create an invoice for Alice to pay. + payReqs, rHashes, invoices := ht.CreatePayReqs(mts.bob, paymentAmt, 1) + + rHash := rHashes[0] + payReq := payReqs[0] + + sendReq := &routerrpc.SendPaymentRequest{ + PaymentRequest: payReq, + MaxParts: 10, + TimeoutSeconds: 60, + FeeLimitMsat: noFeeLimitMsat, + } + payment := ht.SendPaymentAssertSettled(mts.alice, sendReq) + + // Make sure we got the preimage. + require.Equal(ht, hex.EncodeToString(invoices[0].RPreimage), + payment.PaymentPreimage, "preimage doesn't match") + + // Check that Alice split the payment in at least three shards. Because + // the hand-off of the htlc to the link is asynchronous (via a mailbox), + // there is some non-determinism in the process. Depending on whether + // the new pathfinding round is started before or after the htlc is + // locked into the channel, different sharding may occur. Therefore we + // can only check if the number of shards isn't below the theoretical + // minimum. + succeeded := 0 + for _, htlc := range payment.Htlcs { + if htlc.Status == lnrpc.HTLCAttempt_SUCCEEDED { + succeeded++ + } + } + + const minExpectedShards = 3 + require.GreaterOrEqual(ht, succeeded, minExpectedShards, + "expected shards not reached") + + // Make sure Bob show the invoice as settled for the full amount. + inv := mts.bob.RPC.LookupInvoice(rHash) + + require.EqualValues(ht, paymentAmt, inv.AmtPaidSat, + "incorrect payment amt") + + require.Equal(ht, lnrpc.Invoice_SETTLED, inv.State, + "Invoice not settled") + + settled := 0 + for _, htlc := range inv.Htlcs { + if htlc.State == lnrpc.InvoiceHTLCState_SETTLED { + settled++ + } + } + require.Equal(ht, succeeded, settled, + "num of HTLCs wrong") + + // Finally, close all channels. + mts.closeChannels() +} + // testSendToRouteMultiPath tests that we are able to successfully route a // payment using multiple shards across different paths, by using SendToRoute. func testSendToRouteMultiPath(ht *lntest.HarnessTest) { diff --git a/itest/lnd_send_multi_path_payment_test.go b/itest/lnd_send_multi_path_payment_test.go deleted file mode 100644 index 935997c8d2..0000000000 --- a/itest/lnd_send_multi_path_payment_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package itest - -import ( - "encoding/hex" - - "github.com/btcsuite/btcd/btcutil" - "github.com/lightningnetwork/lnd/lnrpc" - "github.com/lightningnetwork/lnd/lnrpc/routerrpc" - "github.com/lightningnetwork/lnd/lntest" - "github.com/stretchr/testify/require" -) - -// testSendMultiPathPayment tests that we are able to successfully route a -// payment using multiple shards across different paths. -func testSendMultiPathPayment(ht *lntest.HarnessTest) { - mts := newMppTestScenario(ht) - - const paymentAmt = btcutil.Amount(300000) - - // Set up a network with three different paths Alice <-> Bob. Channel - // capacities are set such that the payment can only succeed if (at - // least) three paths are used. - // - // _ Eve _ - // / \ - // Alice -- Carol ---- Bob - // \ / - // \__ Dave ____/ - // - req := &mppOpenChannelRequest{ - amtAliceCarol: 285000, - amtAliceDave: 155000, - amtCarolBob: 200000, - amtCarolEve: 155000, - amtDaveBob: 155000, - amtEveBob: 155000, - } - mts.openChannels(req) - chanPointAliceDave := mts.channelPoints[1] - - // Increase Dave's fee to make the test deterministic. Otherwise, it - // would be unpredictable whether pathfinding would go through Charlie - // or Dave for the first shard. - expectedPolicy := &lnrpc.RoutingPolicy{ - FeeBaseMsat: 500_000, - FeeRateMilliMsat: int64(0.001 * 1_000_000), - TimeLockDelta: 40, - MinHtlc: 1000, // default value - MaxHtlcMsat: 133_650_000, - } - mts.dave.UpdateGlobalPolicy(expectedPolicy) - - // Make sure Alice has heard it. - ht.AssertChannelPolicyUpdate( - mts.alice, mts.dave, expectedPolicy, chanPointAliceDave, false, - ) - - // Our first test will be Alice paying Bob using a SendPayment call. - // Let Bob create an invoice for Alice to pay. - payReqs, rHashes, invoices := ht.CreatePayReqs(mts.bob, paymentAmt, 1) - - rHash := rHashes[0] - payReq := payReqs[0] - - sendReq := &routerrpc.SendPaymentRequest{ - PaymentRequest: payReq, - MaxParts: 10, - TimeoutSeconds: 60, - FeeLimitMsat: noFeeLimitMsat, - } - payment := ht.SendPaymentAssertSettled(mts.alice, sendReq) - - // Make sure we got the preimage. - require.Equal(ht, hex.EncodeToString(invoices[0].RPreimage), - payment.PaymentPreimage, "preimage doesn't match") - - // Check that Alice split the payment in at least three shards. Because - // the hand-off of the htlc to the link is asynchronous (via a mailbox), - // there is some non-determinism in the process. Depending on whether - // the new pathfinding round is started before or after the htlc is - // locked into the channel, different sharding may occur. Therefore we - // can only check if the number of shards isn't below the theoretical - // minimum. - succeeded := 0 - for _, htlc := range payment.Htlcs { - if htlc.Status == lnrpc.HTLCAttempt_SUCCEEDED { - succeeded++ - } - } - - const minExpectedShards = 3 - require.GreaterOrEqual(ht, succeeded, minExpectedShards, - "expected shards not reached") - - // Make sure Bob show the invoice as settled for the full amount. - inv := mts.bob.RPC.LookupInvoice(rHash) - - require.EqualValues(ht, paymentAmt, inv.AmtPaidSat, - "incorrect payment amt") - - require.Equal(ht, lnrpc.Invoice_SETTLED, inv.State, - "Invoice not settled") - - settled := 0 - for _, htlc := range inv.Htlcs { - if htlc.State == lnrpc.InvoiceHTLCState_SETTLED { - settled++ - } - } - require.Equal(ht, succeeded, settled, - "num of HTLCs wrong") - - // Finally, close all channels. - mts.closeChannels() -} From 7ceb9a4af5bcf4b8ea9a2dd748a0d5283df74aff Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 8 Nov 2024 16:52:59 +0800 Subject: [PATCH 23/64] lntest+itest: remove `AssertNumActiveEdges` This is no longer needed since we don't have standby nodes, plus it's causing panic in windows build due to `edge.Policy` being nil. --- itest/lnd_channel_graph_test.go | 6 ++-- itest/lnd_mpp_test.go | 2 +- itest/lnd_open_channel_test.go | 4 +-- itest/lnd_route_blinding_test.go | 6 ++-- itest/lnd_routing_test.go | 12 +++---- lntest/harness_assertion.go | 54 -------------------------------- 6 files changed, 15 insertions(+), 69 deletions(-) diff --git a/itest/lnd_channel_graph_test.go b/itest/lnd_channel_graph_test.go index 96fec8e90b..35506e2e56 100644 --- a/itest/lnd_channel_graph_test.go +++ b/itest/lnd_channel_graph_test.go @@ -237,17 +237,17 @@ func testUnannouncedChannels(ht *lntest.HarnessTest) { ht.WaitForChannelOpenEvent(chanOpenUpdate) // Alice should have 1 edge in her graph. - ht.AssertNumActiveEdges(alice, 1, true) + ht.AssertNumEdges(alice, 1, true) // Channels should not be announced yet, hence Alice should have no // announced edges in her graph. - ht.AssertNumActiveEdges(alice, 0, false) + ht.AssertNumEdges(alice, 0, false) // Mine 4 more blocks, and check that the channel is now announced. ht.MineBlocks(4) // Give the network a chance to learn that auth proof is confirmed. - ht.AssertNumActiveEdges(alice, 1, false) + ht.AssertNumEdges(alice, 1, false) } func testGraphTopologyNotifications(ht *lntest.HarnessTest) { diff --git a/itest/lnd_mpp_test.go b/itest/lnd_mpp_test.go index 0316e253ae..7bc23da2a8 100644 --- a/itest/lnd_mpp_test.go +++ b/itest/lnd_mpp_test.go @@ -404,7 +404,7 @@ func (m *mppTestScenario) openChannels(r *mppOpenChannelRequest) { } // Each node should have exactly 6 edges. - m.ht.AssertNumActiveEdges(hn, len(m.channelPoints), false) + m.ht.AssertNumEdges(hn, len(m.channelPoints), false) } } diff --git a/itest/lnd_open_channel_test.go b/itest/lnd_open_channel_test.go index 66930a6c24..47311b25ea 100644 --- a/itest/lnd_open_channel_test.go +++ b/itest/lnd_open_channel_test.go @@ -88,7 +88,7 @@ func testOpenChannelAfterReorg(ht *lntest.HarnessTest) { ht.AssertChannelInGraph(bob, chanPoint) // Alice should now have 1 edge in her graph. - ht.AssertNumActiveEdges(alice, 1, true) + ht.AssertNumEdges(alice, 1, true) // Now we disconnect Alice's chain backend from the original miner, and // connect the two miners together. Since the temporary miner knows @@ -116,7 +116,7 @@ func testOpenChannelAfterReorg(ht *lntest.HarnessTest) { // Since the fundingtx was reorged out, Alice should now have no edges // in her graph. - ht.AssertNumActiveEdges(alice, 0, true) + ht.AssertNumEdges(alice, 0, true) // Cleanup by mining the funding tx again, then closing the channel. block = ht.MineBlocksAndAssertNumTxes(1, 1)[0] diff --git a/itest/lnd_route_blinding_test.go b/itest/lnd_route_blinding_test.go index b7604e6a8d..9079a1589a 100644 --- a/itest/lnd_route_blinding_test.go +++ b/itest/lnd_route_blinding_test.go @@ -940,7 +940,7 @@ func testMPPToSingleBlindedPath(ht *lntest.HarnessTest) { } // Each node should have exactly numPublic edges. - ht.AssertNumActiveEdges(hn, numPublic, false) + ht.AssertNumEdges(hn, numPublic, false) } // Make Dave create an invoice with a blinded path for Alice to pay. @@ -1111,7 +1111,7 @@ func testBlindedRouteDummyHops(ht *lntest.HarnessTest) { } // Each node should have exactly 5 edges. - ht.AssertNumActiveEdges(hn, len(channelPoints), false) + ht.AssertNumEdges(hn, len(channelPoints), false) } // Make Dave create an invoice with a blinded path for Alice to pay. @@ -1281,7 +1281,7 @@ func testMPPToMultipleBlindedPaths(ht *lntest.HarnessTest) { } // Each node should have exactly 5 edges. - ht.AssertNumActiveEdges(hn, len(channelPoints), false) + ht.AssertNumEdges(hn, len(channelPoints), false) } // Ok now make a payment that must be split to succeed. diff --git a/itest/lnd_routing_test.go b/itest/lnd_routing_test.go index 63c5d54189..950b24d24b 100644 --- a/itest/lnd_routing_test.go +++ b/itest/lnd_routing_test.go @@ -589,12 +589,12 @@ func testPrivateChannels(ht *lntest.HarnessTest) { // Carol and Alice should know about 4, while Bob and Dave should only // know about 3, since one channel is private. - ht.AssertNumActiveEdges(alice, 4, true) - ht.AssertNumActiveEdges(alice, 3, false) - ht.AssertNumActiveEdges(bob, 3, true) - ht.AssertNumActiveEdges(carol, 4, true) - ht.AssertNumActiveEdges(carol, 3, false) - ht.AssertNumActiveEdges(dave, 3, true) + ht.AssertNumEdges(alice, 4, true) + ht.AssertNumEdges(alice, 3, false) + ht.AssertNumEdges(bob, 3, true) + ht.AssertNumEdges(carol, 4, true) + ht.AssertNumEdges(carol, 3, false) + ht.AssertNumEdges(dave, 3, true) } // testInvoiceRoutingHints tests that the routing hints for an invoice are diff --git a/lntest/harness_assertion.go b/lntest/harness_assertion.go index b99f461d18..3e369ed78a 100644 --- a/lntest/harness_assertion.go +++ b/lntest/harness_assertion.go @@ -19,7 +19,6 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" - "github.com/lightningnetwork/lnd/fn/v2" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" @@ -241,59 +240,6 @@ func (h *HarnessTest) EnsureConnected(a, b *node.HarnessNode) { h.AssertPeerConnected(b, a) } -// AssertNumActiveEdges checks that an expected number of active edges can be -// found in the node specified. -func (h *HarnessTest) AssertNumActiveEdges(hn *node.HarnessNode, - expected int, includeUnannounced bool) []*lnrpc.ChannelEdge { - - var edges []*lnrpc.ChannelEdge - - old := hn.State.Edge.Public - if includeUnannounced { - old = hn.State.Edge.Total - } - - // filterDisabled is a helper closure that filters out disabled - // channels. - filterDisabled := func(edge *lnrpc.ChannelEdge) bool { - if edge.Node1Policy != nil && edge.Node1Policy.Disabled { - return false - } - if edge.Node2Policy != nil && edge.Node2Policy.Disabled { - return false - } - - return true - } - - err := wait.NoError(func() error { - req := &lnrpc.ChannelGraphRequest{ - IncludeUnannounced: includeUnannounced, - } - resp := hn.RPC.DescribeGraph(req) - activeEdges := fn.Filter(resp.Edges, filterDisabled) - total := len(activeEdges) - - if total-old == expected { - if expected != 0 { - // NOTE: assume edges come in ascending order - // that the old edges are at the front of the - // slice. - edges = activeEdges[old:] - } - - return nil - } - - return errNumNotMatched(hn.Name(), "num of channel edges", - expected, total-old, total, old) - }, DefaultTimeout) - - require.NoError(h, err, "timeout while checking for edges") - - return edges -} - // AssertNumEdges checks that an expected number of edges can be found in the // node specified. func (h *HarnessTest) AssertNumEdges(hn *node.HarnessNode, From 7c3564eeb64ce024fb0a97257d9248df53850908 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sun, 10 Nov 2024 23:27:25 +0800 Subject: [PATCH 24/64] itest: fix flake in runPsbtChanFundingWithNodes --- itest/lnd_psbt_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go index 3d0872c3c8..8208f3629b 100644 --- a/itest/lnd_psbt_test.go +++ b/itest/lnd_psbt_test.go @@ -272,6 +272,9 @@ func runPsbtChanFundingWithNodes(ht *lntest.HarnessTest, carol, txHash := finalTx.TxHash() block := ht.MineBlocksAndAssertNumTxes(6, 1)[0] ht.AssertTxInBlock(block, txHash) + + ht.AssertChannelActive(carol, chanPoint) + ht.AssertChannelActive(carol, chanPoint2) ht.AssertChannelInGraph(carol, chanPoint) ht.AssertChannelInGraph(carol, chanPoint2) From 23edca8d19de27141633273c5b286393f47f835b Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 16 Nov 2024 12:23:21 +0800 Subject: [PATCH 25/64] itest: fix flake in `testPrivateUpdateAlias` --- itest/lnd_zero_conf_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/itest/lnd_zero_conf_test.go b/itest/lnd_zero_conf_test.go index 8ec19945ca..c7f4c59a78 100644 --- a/itest/lnd_zero_conf_test.go +++ b/itest/lnd_zero_conf_test.go @@ -621,6 +621,9 @@ func testPrivateUpdateAlias(ht *lntest.HarnessTest, // // TODO(yy): further investigate this sleep. time.Sleep(time.Second * 5) + + // Make sure Eve has heard about this public channel. + ht.AssertChannelInGraph(eve, fundingPoint2) } // Dave creates an invoice that Eve will pay. From 4e85d86a2e98b38606a65887c7c9afea8b916c36 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 16 Nov 2024 13:36:59 +0800 Subject: [PATCH 26/64] itest: fix flake in `update_pending_open_channels` --- itest/list_on_test.go | 8 ++++++-- itest/lnd_open_channel_test.go | 29 ++++++----------------------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index ebb691f996..3a5a10a9fa 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -569,8 +569,12 @@ var allTestCases = []*lntest.TestCase{ TestFunc: testChannelUtxoSelection, }, { - Name: "update pending open channels", - TestFunc: testUpdateOnPendingOpenChannels, + Name: "update pending open channels on funder side", + TestFunc: testUpdateOnFunderPendingOpenChannels, + }, + { + Name: "update pending open channels on fundee side", + TestFunc: testUpdateOnFundeePendingOpenChannels, }, { Name: "blinded payment htlc re-forward", diff --git a/itest/lnd_open_channel_test.go b/itest/lnd_open_channel_test.go index 47311b25ea..3142e09eb2 100644 --- a/itest/lnd_open_channel_test.go +++ b/itest/lnd_open_channel_test.go @@ -486,27 +486,6 @@ func runBasicChannelCreationAndUpdates(ht *lntest.HarnessTest, ) } -// testUpdateOnPendingOpenChannels checks that `update_add_htlc` followed by -// `channel_ready` is properly handled. In specific, when a node is in a state -// that it's still processing a remote `channel_ready` message, meanwhile an -// `update_add_htlc` is received, this HTLC message is cached and settled once -// processing `channel_ready` is complete. -func testUpdateOnPendingOpenChannels(ht *lntest.HarnessTest) { - // Test funder's behavior. Funder sees the channel pending, but fundee - // sees it active and sends an HTLC. - ht.Run("pending on funder side", func(t *testing.T) { - st := ht.Subtest(t) - testUpdateOnFunderPendingOpenChannels(st) - }) - - // Test fundee's behavior. Fundee sees the channel pending, but funder - // sees it active and sends an HTLC. - ht.Run("pending on fundee side", func(t *testing.T) { - st := ht.Subtest(t) - testUpdateOnFundeePendingOpenChannels(st) - }) -} - // testUpdateOnFunderPendingOpenChannels checks that when the fundee sends an // `update_add_htlc` followed by `channel_ready` while the funder is still // processing the fundee's `channel_ready`, the HTLC will be cached and @@ -530,7 +509,8 @@ func testUpdateOnFunderPendingOpenChannels(ht *lntest.HarnessTest) { Amt: funding.MaxBtcFundingAmount, PushAmt: funding.MaxBtcFundingAmount / 2, } - ht.OpenChannelAssertPending(alice, bob, params) + pending := ht.OpenChannelAssertPending(alice, bob, params) + chanPoint := lntest.ChanPointFromPendingUpdate(pending) // Alice and Bob should both consider the channel pending open. ht.AssertNumPendingOpenChannels(alice, 1) @@ -548,6 +528,7 @@ func testUpdateOnFunderPendingOpenChannels(ht *lntest.HarnessTest) { // Bob will consider the channel open as there's no wait time to send // and receive Alice's channel_ready message. ht.AssertNumPendingOpenChannels(bob, 0) + ht.AssertChannelInGraph(bob, chanPoint) // Alice and Bob now have different view of the channel. For Bob, // since the channel_ready messages are processed, he will have a @@ -604,7 +585,8 @@ func testUpdateOnFundeePendingOpenChannels(ht *lntest.HarnessTest) { params := lntest.OpenChannelParams{ Amt: funding.MaxBtcFundingAmount, } - ht.OpenChannelAssertPending(alice, bob, params) + pending := ht.OpenChannelAssertPending(alice, bob, params) + chanPoint := lntest.ChanPointFromPendingUpdate(pending) // Alice and Bob should both consider the channel pending open. ht.AssertNumPendingOpenChannels(alice, 1) @@ -616,6 +598,7 @@ func testUpdateOnFundeePendingOpenChannels(ht *lntest.HarnessTest) { // Alice will consider the channel open as there's no wait time to send // and receive Bob's channel_ready message. ht.AssertNumPendingOpenChannels(alice, 0) + ht.AssertChannelInGraph(alice, chanPoint) // TODO(yy): we've prematurely marked the channel as open before // processing channel ready messages. We need to mark it as open after From f912f407c8fe190abe0613d486eabbd01417bf5f Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 20 Nov 2024 21:11:06 +0800 Subject: [PATCH 27/64] lntest: increase `rpcmaxwebsockets` for `btcd` This has been seen in the itest which can lead to the node startup failure, ``` 2024-11-20 18:55:15.727 [INF] RPCS: Max websocket clients exceeded [25] - disconnecting client 127.0.0.1:57224 ``` --- lntest/btcd.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lntest/btcd.go b/lntest/btcd.go index 6b607978eb..91b25411c9 100644 --- a/lntest/btcd.go +++ b/lntest/btcd.go @@ -94,6 +94,14 @@ func NewBackend(miner string, netParams *chaincfg.Params) ( "--nobanning", // Don't disconnect if a reply takes too long. "--nostalldetect", + + // The default max num of websockets is 25, but the closed + // connections are not cleaned up immediately so we double the + // size. + // + // TODO(yy): fix this in `btcd` to clean up the stale + // connections. + "--rpcmaxwebsockets=50", } chainBackend, err := rpctest.New( netParams, nil, args, node.GetBtcdBinary(), From fb59669ae8e9209d168d9aa0f9e9823a4d921182 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 21 Nov 2024 13:45:34 +0800 Subject: [PATCH 28/64] itest: document details about MPP-related tests This is needed so we can have one place to fix the flakes found in the MPP-related tests, which is fixed in the following commit. --- itest/lnd_amp_test.go | 47 +++------------ itest/lnd_mpp_test.go | 136 +++++++++++++++++++++++++++++++++--------- 2 files changed, 116 insertions(+), 67 deletions(-) diff --git a/itest/lnd_amp_test.go b/itest/lnd_amp_test.go index 4b4cfb5a29..cc54d1c9d7 100644 --- a/itest/lnd_amp_test.go +++ b/itest/lnd_amp_test.go @@ -47,8 +47,6 @@ func testSendPaymentAMPInvoiceCase(ht *lntest.HarnessTest, req := &lnrpc.InvoiceSubscription{} bobInvoiceSubscription := mts.bob.RPC.SubscribeInvoices(req) - const paymentAmt = btcutil.Amount(300000) - // Set up a network with three different paths Alice <-> Bob. Channel // capacities are set such that the payment can only succeed if (at // least) three paths are used. @@ -59,15 +57,8 @@ func testSendPaymentAMPInvoiceCase(ht *lntest.HarnessTest, // \ / // \__ Dave ____/ // - mppReq := &mppOpenChannelRequest{ - amtAliceCarol: 285000, - amtAliceDave: 155000, - amtCarolBob: 200000, - amtCarolEve: 155000, - amtDaveBob: 155000, - amtEveBob: 155000, - } - mts.openChannels(mppReq) + paymentAmt := mts.setupSendPaymentCase() + chanPointAliceDave := mts.channelPoints[1] chanPointDaveBob := mts.channelPoints[4] @@ -373,7 +364,6 @@ func testSendPaymentAMPInvoiceRepeat(ht *lntest.HarnessTest) { // destination using SendPaymentV2. func testSendPaymentAMP(ht *lntest.HarnessTest) { mts := newMppTestScenario(ht) - const paymentAmt = btcutil.Amount(300000) // Set up a network with three different paths Alice <-> Bob. Channel // capacities are set such that the payment can only succeed if (at @@ -385,15 +375,8 @@ func testSendPaymentAMP(ht *lntest.HarnessTest) { // \ / // \__ Dave ____/ // - mppReq := &mppOpenChannelRequest{ - amtAliceCarol: 285000, - amtAliceDave: 155000, - amtCarolBob: 200000, - amtCarolEve: 155000, - amtDaveBob: 155000, - amtEveBob: 155000, - } - mts.openChannels(mppReq) + paymentAmt := mts.setupSendPaymentCase() + chanPointAliceDave := mts.channelPoints[1] // Increase Dave's fee to make the test deterministic. Otherwise, it @@ -497,12 +480,6 @@ func testSendPaymentAMP(ht *lntest.HarnessTest) { func testSendToRouteAMP(ht *lntest.HarnessTest) { mts := newMppTestScenario(ht) - const ( - paymentAmt = btcutil.Amount(300000) - numShards = 3 - shardAmt = paymentAmt / numShards - chanAmt = shardAmt * 3 / 2 - ) // Subscribe to bob's invoices. req := &lnrpc.InvoiceSubscription{} @@ -515,20 +492,10 @@ func testSendToRouteAMP(ht *lntest.HarnessTest) { // \ / // \__ Dave ____/ // - mppReq := &mppOpenChannelRequest{ - // Since the channel Alice-> Carol will have to carry two - // shards, we make it larger. - amtAliceCarol: chanAmt + shardAmt, - amtAliceDave: chanAmt, - amtCarolBob: chanAmt, - amtCarolEve: chanAmt, - amtDaveBob: chanAmt, - amtEveBob: chanAmt, - } - mts.openChannels(mppReq) + paymentAmt, shardAmt := mts.setupSendToRouteCase() // We'll send shards along three routes from Alice. - sendRoutes := [numShards][]*node.HarnessNode{ + sendRoutes := [][]*node.HarnessNode{ {mts.carol, mts.bob}, {mts.dave, mts.bob}, {mts.carol, mts.eve, mts.bob}, @@ -662,7 +629,7 @@ func testSendToRouteAMP(ht *lntest.HarnessTest) { // Finally, assert that the proper set id is recorded for each htlc, and // that the preimage hash pair is valid. - require.Equal(ht, numShards, len(rpcInvoice.Htlcs)) + require.Equal(ht, 3, len(rpcInvoice.Htlcs)) for _, htlc := range rpcInvoice.Htlcs { require.NotNil(ht, htlc.Amp) require.Equal(ht, setID, htlc.Amp.SetId) diff --git a/itest/lnd_mpp_test.go b/itest/lnd_mpp_test.go index 7bc23da2a8..902f5fec92 100644 --- a/itest/lnd_mpp_test.go +++ b/itest/lnd_mpp_test.go @@ -20,8 +20,6 @@ import ( func testSendMultiPathPayment(ht *lntest.HarnessTest) { mts := newMppTestScenario(ht) - const paymentAmt = btcutil.Amount(300000) - // Set up a network with three different paths Alice <-> Bob. Channel // capacities are set such that the payment can only succeed if (at // least) three paths are used. @@ -32,15 +30,8 @@ func testSendMultiPathPayment(ht *lntest.HarnessTest) { // \ / // \__ Dave ____/ // - req := &mppOpenChannelRequest{ - amtAliceCarol: 285000, - amtAliceDave: 155000, - amtCarolBob: 200000, - amtCarolEve: 155000, - amtDaveBob: 155000, - amtEveBob: 155000, - } - mts.openChannels(req) + paymentAmt := mts.setupSendPaymentCase() + chanPointAliceDave := mts.channelPoints[1] // Increase Dave's fee to make the test deterministic. Otherwise, it @@ -127,11 +118,6 @@ func testSendToRouteMultiPath(ht *lntest.HarnessTest) { // To ensure the payment goes through separate paths, we'll set a // channel size that can only carry one shard at a time. We'll divide // the payment into 3 shards. - const ( - paymentAmt = btcutil.Amount(300000) - shardAmt = paymentAmt / 3 - chanAmt = shardAmt * 3 / 2 - ) // Set up a network with three different paths Alice <-> Bob. // _ Eve _ @@ -140,17 +126,7 @@ func testSendToRouteMultiPath(ht *lntest.HarnessTest) { // \ / // \__ Dave ____/ // - req := &mppOpenChannelRequest{ - // Since the channel Alice-> Carol will have to carry two - // shards, we make it larger. - amtAliceCarol: chanAmt + shardAmt, - amtAliceDave: chanAmt, - amtCarolBob: chanAmt, - amtCarolEve: chanAmt, - amtDaveBob: chanAmt, - amtEveBob: chanAmt, - } - mts.openChannels(req) + paymentAmt, shardAmt := mts.setupSendToRouteCase() // Make Bob create an invoice for Alice to pay. payReqs, rHashes, invoices := ht.CreatePayReqs(mts.bob, paymentAmt, 1) @@ -284,6 +260,9 @@ type mppTestScenario struct { // Alice -- Carol ---- Bob // \ / // \__ Dave ____/ +// +// The scenario is setup in a way that when sending a payment from Alice to +// Bob, (at least) three routes must be tried to succeed. func newMppTestScenario(ht *lntest.HarnessTest) *mppTestScenario { alice := ht.NewNodeWithCoins("Alice", nil) bob := ht.NewNodeWithCoins("Bob", []string{ @@ -351,6 +330,109 @@ type mppOpenChannelRequest struct { amtEveBob btcutil.Amount } +// setupSendPaymentCase opens channels between the nodes for testing the +// `SendPaymentV2` case, where a payment amount of 300,000 sats is used and it +// tests sending three attempts: the first has 150,000 sats, the rest two have +// 75,000 sats. It returns the payment amt. +func (c *mppTestScenario) setupSendPaymentCase() btcutil.Amount { + // To ensure the payment goes through separate paths, we'll set a + // channel size that can only carry one HTLC attempt at a time. We'll + // divide the payment into 3 attempts. + // + // Set the payment amount to be 300,000 sats. When a route cannot be + // found for a given payment amount, we will halven the amount and try + // the pathfinding again, which means we need to see the following + // three attempts to succeed: + // 1. 1st attempt: 150,000 sats. + // 2. 2nd attempt: 75,000 sats. + // 3. 3rd attempt: 75,000 sats. + paymentAmt := btcutil.Amount(300_000) + + // Prepare to open channels between the nodes. Given our expected + // topology, + // + // _ Eve _ + // / \ + // Alice -- Carol ---- Bob + // \ / + // \__ Dave ___/ + // + // There are three routes from Alice to Bob: + // 1. Alice -> Carol -> Bob + // 2. Alice -> Dave -> Bob + // 3. Alice -> Carol -> Eve -> Bob + // We now use hardcoded amounts so it's easier to reason about the + // test. + req := &mppOpenChannelRequest{ + amtAliceCarol: 285_000, + amtAliceDave: 155_000, + amtCarolBob: 200_000, + amtCarolEve: 155_000, + amtDaveBob: 155_000, + amtEveBob: 155_000, + } + + // Given the above setup, the only possible routes to send each of the + // attempts are: + // - 1st attempt(150,000 sats): Alice->Carol->Bob: 200,000 sats. + // - 2nd attempt(75,000 sats): Alice->Dave->Bob: 155,000 sats. + // - 3rd attempt(75,000 sats): Alice->Carol->Eve->Bob: 155,000 sats. + // + // Open the channels as described above. + c.openChannels(req) + + return paymentAmt +} + +// setupSendToRouteCase opens channels between the nodes for testing the +// `SendToRouteV2` case, where a payment amount of 300,000 sats is used and it +// tests sending three attempts each holding 100,000 sats. It returns the +// payment amount and attempt amount. +func (c *mppTestScenario) setupSendToRouteCase() (btcutil.Amount, + btcutil.Amount) { + + // To ensure the payment goes through separate paths, we'll set a + // channel size that can only carry one HTLC attempt at a time. We'll + // divide the payment into 3 attempts, each holding 100,000 sats. + paymentAmt := btcutil.Amount(300_000) + attemptAmt := btcutil.Amount(100_000) + + // Prepare to open channels between the nodes. Given our expected + // topology, + // + // _ Eve _ + // / \ + // Alice -- Carol ---- Bob + // \ / + // \__ Dave ___/ + // + // There are three routes from Alice to Bob: + // 1. Alice -> Carol -> Bob + // 2. Alice -> Dave -> Bob + // 3. Alice -> Carol -> Eve -> Bob + // We now use hardcoded amounts so it's easier to reason about the + // test. + req := &mppOpenChannelRequest{ + amtAliceCarol: 250_000, + amtAliceDave: 150_000, + amtCarolBob: 150_000, + amtCarolEve: 150_000, + amtDaveBob: 150_000, + amtEveBob: 150_000, + } + + // Given the above setup, the only possible routes to send each of the + // attempts are: + // - 1st attempt(100,000 sats): Alice->Carol->Bob: 150,000 sats. + // - 2nd attempt(100,000 sats): Alice->Dave->Bob: 150,000 sats. + // - 3rd attempt(100,000 sats): Alice->Carol->Eve->Bob: 150,000 sats. + // + // Open the channels as described above. + c.openChannels(req) + + return paymentAmt, attemptAmt +} + // openChannels is a helper to open channels that sets up a network topology // with three different paths Alice <-> Bob as following, // From cfb5713cda41289e1bb5e1d028f65c167461a86c Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 21 Nov 2024 14:09:57 +0800 Subject: [PATCH 29/64] itest+lntest: fix flake in MPP-related tests --- itest/lnd_mpp_test.go | 27 +++++++++++++++++++++++++++ lntest/harness_assertion.go | 7 ++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/itest/lnd_mpp_test.go b/itest/lnd_mpp_test.go index 902f5fec92..387e9539cb 100644 --- a/itest/lnd_mpp_test.go +++ b/itest/lnd_mpp_test.go @@ -378,6 +378,33 @@ func (c *mppTestScenario) setupSendPaymentCase() btcutil.Amount { // - 2nd attempt(75,000 sats): Alice->Dave->Bob: 155,000 sats. // - 3rd attempt(75,000 sats): Alice->Carol->Eve->Bob: 155,000 sats. // + // There is a case where the payment will fail due to the channel + // bandwidth not being updated in the graph, which has been seen many + // times: + // 1. the 1st attempt (150,000 sats) is sent via + // Alice->Carol->Eve->Bob, after which the capacity in Carol->Eve + // should decrease. + // 2. the 2nd attempt (75,000 sats) is sent via Alice->Carol->Eve->Bob, + // which shouldn't happen because the capacity in Carol->Eve is + // depleted. However, since the HTLCs are sent in parallel, the 2nd + // attempt can be sent before the capacity is updated in the graph. + // 3. if the 2nd attempt succeeds, the 1st attempt will fail and be + // split into two attempts, each holding 75,000 sats. At this point, + // we have three attempts to send, but only two routes are + // available, causing the payment to be failed. + // 4. In addition, with recent fee buffer addition, the attempts will + // fail even earlier without being further split. + // + // To avoid this case, we now increase the channel capacity of the + // route Carol->Eve->Bob and Carol->Bob such that even the above case + // happened, we can still send the HTLCs. + // + // TODO(yy): we should properly fix this in the router. Atm we only + // perform this hack to unblock the CI. + req.amtCarolBob = 285_000 + req.amtEveBob = 285_000 + req.amtCarolEve = 285_000 + // Open the channels as described above. c.openChannels(req) diff --git a/lntest/harness_assertion.go b/lntest/harness_assertion.go index 3e369ed78a..5cadc09fdf 100644 --- a/lntest/harness_assertion.go +++ b/lntest/harness_assertion.go @@ -1513,13 +1513,14 @@ func (h *HarnessTest) AssertNumHTLCsAndStage(hn *node.HarnessNode, lnutils.SpewLogClosure(target.PendingHtlcs)()) } - for i, htlc := range target.PendingHtlcs { + for _, htlc := range target.PendingHtlcs { if htlc.Stage == stage { continue } - return fmt.Errorf("HTLC %d got stage: %v, "+ - "want stage: %v", i, htlc.Stage, stage) + return fmt.Errorf("HTLC %s got stage: %v, "+ + "want stage: %v", htlc.Outpoint, htlc.Stage, + stage) } return nil From 39104c53d4407ba501e27b5d7984ff9d0352b036 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 22 Nov 2024 23:16:33 +0800 Subject: [PATCH 30/64] lntest: fix flakeness in `openChannelsForNodes` We now make sure the channel participants have heard their private channel when opening channels. --- lntest/harness.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lntest/harness.go b/lntest/harness.go index 36a66ed0e4..e3d5c0dc93 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -2262,12 +2262,27 @@ func (h *HarnessTest) openChannelsForNodes(nodes []*node.HarnessNode, } resp := h.OpenMultiChannelsAsync(reqs) - // Make sure the nodes know each other's channels if they are public. - if !p.Private { + // If the channels are private, make sure the channel participants know + // the relevant channels. + if p.Private { + for i, chanPoint := range resp { + // Get the channel participants - for n channels we + // would have n+1 nodes. + nodeA, nodeB := nodes[i], nodes[i+1] + h.AssertChannelInGraph(nodeA, chanPoint) + h.AssertChannelInGraph(nodeB, chanPoint) + } + } else { + // Make sure the all nodes know all the channels if they are + // public. for _, node := range nodes { for _, chanPoint := range resp { h.AssertChannelInGraph(node, chanPoint) } + + // Make sure every node has updated its cached graph + // about the edges as indicated in `DescribeGraph`. + h.AssertNumEdges(node, len(resp), false) } } From 7e80b775352530f177165ae8e0df9ac83590039c Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 4 Dec 2024 14:12:38 +0800 Subject: [PATCH 31/64] itest: document a rare flake found in `macOS` --- itest/lnd_multi-hop_force_close_test.go | 118 ++++++++++++++++++++---- itest/lnd_test.go | 5 + 2 files changed, 104 insertions(+), 19 deletions(-) diff --git a/itest/lnd_multi-hop_force_close_test.go b/itest/lnd_multi-hop_force_close_test.go index fc417c5d74..f35ad8f47c 100644 --- a/itest/lnd_multi-hop_force_close_test.go +++ b/itest/lnd_multi-hop_force_close_test.go @@ -359,13 +359,29 @@ func runLocalClaimOutgoingHTLC(ht *lntest.HarnessTest, // time-sensitive HTLCs - we expect both anchors to be offered, while // the sweeping of the remote anchor will be marked as failed due to // `testmempoolaccept` check. - // + numSweeps := 1 + // For neutrino backend, there's no way to know the sweeping of the // remote anchor is failed, so Bob still sees two pending sweeps. if ht.IsNeutrinoBackend() { - ht.AssertNumPendingSweeps(bob, 2) - } else { - ht.AssertNumPendingSweeps(bob, 1) + numSweeps = 2 + } + + // When running in macOS, we might see three anchor sweeps - one from + // the local, one from the remote, and one from the pending remote: + // - the local one will be swept. + // - the remote one will be marked as failed due to `testmempoolaccept` + // check. + // - the pending remote one will not be attempted due to it being + // uneconomical since it was not used for CPFP. + // The anchor from the pending remote may or may not appear, which is a + // bug found only in macOS - when updating the commitments, the channel + // state machine somehow thinks we still have a pending remote + // commitment, causing it to sweep the anchor from that version. + // + // TODO(yy): fix the above bug in the channel state machine. + if !isDarwin() { + ht.AssertNumPendingSweeps(bob, numSweeps) } // We expect to see tow txns in the mempool, @@ -714,13 +730,29 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest, // time-sensitive HTLCs - we expect both anchors to be offered, while // the sweeping of the remote anchor will be marked as failed due to // `testmempoolaccept` check. - // + numSweeps := 1 + // For neutrino backend, there's no way to know the sweeping of the // remote anchor is failed, so Carol still sees two pending sweeps. if ht.IsNeutrinoBackend() { - ht.AssertNumPendingSweeps(carol, 2) - } else { - ht.AssertNumPendingSweeps(carol, 1) + numSweeps = 2 + } + + // When running in macOS, we might see three anchor sweeps - one from + // the local, one from the remote, and one from the pending remote: + // - the local one will be swept. + // - the remote one will be marked as failed due to `testmempoolaccept` + // check. + // - the pending remote one will not be attempted due to it being + // uneconomical since it was not used for CPFP. + // The anchor from the pending remote may or may not appear, which is a + // bug found only in macOS - when updating the commitments, the channel + // state machine somehow thinks we still have a pending remote + // commitment, causing it to sweep the anchor from that version. + // + // TODO(yy): fix the above bug in the channel state machine. + if !isDarwin() { + ht.AssertNumPendingSweeps(carol, numSweeps) } // We expect to see tow txns in the mempool, @@ -2394,13 +2426,29 @@ func runLocalPreimageClaim(ht *lntest.HarnessTest, // Since Carol has time-sensitive HTLCs, she will use the anchor for // CPFP purpose. Assert the anchor output is offered to the sweeper. - // + numSweeps := 1 + // For neutrino backend, Carol still have the two anchors - one from // local commitment and the other from the remote. if ht.IsNeutrinoBackend() { - ht.AssertNumPendingSweeps(carol, 2) - } else { - ht.AssertNumPendingSweeps(carol, 1) + numSweeps = 2 + } + + // When running in macOS, we might see three anchor sweeps - one from + // the local, one from the remote, and one from the pending remote: + // - the local one will be swept. + // - the remote one will be marked as failed due to `testmempoolaccept` + // check. + // - the pending remote one will not be attempted due to it being + // uneconomical since it was not used for CPFP. + // The anchor from the pending remote may or may not appear, which is a + // bug found only in macOS - when updating the commitments, the channel + // state machine somehow thinks we still have a pending remote + // commitment, causing it to sweep the anchor from that version. + // + // TODO(yy): fix the above bug in the channel state machine. + if !isDarwin() { + ht.AssertNumPendingSweeps(carol, numSweeps) } // We should see two txns in the mempool, we now a block to confirm, @@ -2675,13 +2723,29 @@ func runLocalPreimageClaimLeased(ht *lntest.HarnessTest, // Since Carol has time-sensitive HTLCs, she will use the anchor for // CPFP purpose. Assert the anchor output is offered to the sweeper. + numSweeps := 1 // // For neutrino backend, there's no way to know the sweeping of the // remote anchor is failed, so Carol still sees two pending sweeps. if ht.IsNeutrinoBackend() { - ht.AssertNumPendingSweeps(carol, 2) - } else { - ht.AssertNumPendingSweeps(carol, 1) + numSweeps = 2 + } + + // When running in macOS, we might see three anchor sweeps - one from + // the local, one from the remote, and one from the pending remote: + // - the local one will be swept. + // - the remote one will be marked as failed due to `testmempoolaccept` + // check. + // - the pending remote one will not be attempted due to it being + // uneconomical since it was not used for CPFP. + // The anchor from the pending remote may or may not appear, which is a + // bug found only in macOS - when updating the commitments, the channel + // state machine somehow thinks we still have a pending remote + // commitment, causing it to sweep the anchor from that version. + // + // TODO(yy): fix the above bug in the channel state machine. + if !isDarwin() { + ht.AssertNumPendingSweeps(carol, numSweeps) } // We should see two txns in the mempool, we now a block to confirm, @@ -3118,13 +3182,29 @@ func runHtlcAggregation(ht *lntest.HarnessTest, ht.MineBlocks(int(numBlocks)) // Bob should have one anchor sweep request. - // + numSweeps := 1 + // For neutrino backend, there's no way to know the sweeping of the // remote anchor is failed, so Bob still sees two pending sweeps. if ht.IsNeutrinoBackend() { - ht.AssertNumPendingSweeps(bob, 2) - } else { - ht.AssertNumPendingSweeps(bob, 1) + numSweeps = 2 + } + + // When running in macOS, we might see three anchor sweeps - one from + // the local, one from the remote, and one from the pending remote: + // - the local one will be swept. + // - the remote one will be marked as failed due to `testmempoolaccept` + // check. + // - the pending remote one will not be attempted due to it being + // uneconomical since it was not used for CPFP. + // The anchor from the pending remote may or may not appear, which is a + // bug found only in macOS - when updating the commitments, the channel + // state machine somehow thinks we still have a pending remote + // commitment, causing it to sweep the anchor from that version. + // + // TODO(yy): fix the above bug in the channel state machine. + if !isDarwin() { + ht.AssertNumPendingSweeps(bob, numSweeps) } // Bob's force close tx and anchor sweeping tx should now be found in diff --git a/itest/lnd_test.go b/itest/lnd_test.go index ebc751ab28..63462199ae 100644 --- a/itest/lnd_test.go +++ b/itest/lnd_test.go @@ -233,6 +233,11 @@ func getLndBinary(t *testing.T) string { return binary } +// isDarwin returns true if the test is running on a macOS. +func isDarwin() bool { + return runtime.GOOS == "darwin" +} + func init() { // Before we start any node, we need to make sure that any btcd node // that is started through the RPC harness uses a unique port as well From 1950d899251a8a072fcd99a21bc28f0189d8321e Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 5 Dec 2024 04:11:39 +0800 Subject: [PATCH 32/64] itest: document a flake found in `SendToRoute` --- itest/lnd_mpp_test.go | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/itest/lnd_mpp_test.go b/itest/lnd_mpp_test.go index 387e9539cb..59681dac06 100644 --- a/itest/lnd_mpp_test.go +++ b/itest/lnd_mpp_test.go @@ -2,6 +2,7 @@ package itest import ( "encoding/hex" + "fmt" "time" "github.com/btcsuite/btcd/btcutil" @@ -10,6 +11,7 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest/node" + "github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/routing/route" "github.com/stretchr/testify/require" @@ -558,7 +560,35 @@ func (m *mppTestScenario) buildRoute(amt btcutil.Amount, FinalCltvDelta: chainreg.DefaultBitcoinTimeLockDelta, HopPubkeys: rpcHops, } - routeResp := sender.RPC.BuildRoute(req) - return routeResp.Route + // We should be able to call `sender.RPC.BuildRoute` directly, but + // sometimes we will get a RPC-level error saying we cannot find the + // node index: + // - no matching outgoing channel available for node index 1 + // This happens because the `getEdgeUnifiers` cannot find a policy for + // one of the hops, + // - [ERR] CRTR router.go:1689: Cannot find policy for node ... + // However, by the time we get here, we have already checked that all + // nodes have heard all channels, so this indicates a bug in our + // pathfinding, specifically in the edge unifier. + // + // TODO(yy): Remove the following wait and use the direct call, then + // investigate the bug in the edge unifier. + var route *lnrpc.Route + err := wait.NoError(func() error { + routeResp, err := sender.RPC.Router.BuildRoute( + m.ht.Context(), req, + ) + if err != nil { + return fmt.Errorf("unable to build route for %v "+ + "using hops=%v: %v", sender.Name(), hops, err) + } + + route = routeResp.Route + + return nil + }, defaultTimeout) + require.NoError(m.ht, err, "build route timeout") + + return route } From cca2364097fef399e389bbd7f4ff3eaaec62f734 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 8 Nov 2024 15:41:14 +0800 Subject: [PATCH 33/64] itest: optimize blocks mined in `testGarbageCollectLinkNodes` There's no need to mine 80ish blocks here. --- itest/lnd_misc_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/itest/lnd_misc_test.go b/itest/lnd_misc_test.go index f983b39e91..30dba0a878 100644 --- a/itest/lnd_misc_test.go +++ b/itest/lnd_misc_test.go @@ -10,7 +10,6 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcwallet/wallet" - "github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lncfg" @@ -506,12 +505,6 @@ func testGarbageCollectLinkNodes(ht *lntest.HarnessTest) { // close the channel instead. ht.ForceCloseChannel(alice, forceCloseChanPoint) - // We'll need to mine some blocks in order to mark the channel fully - // closed. - ht.MineBlocks( - chainreg.DefaultBitcoinTimeLockDelta - defaultCSV, - ) - // Before we test reconnection, we'll ensure that the channel has been // fully cleaned up for both Carol and Alice. ht.AssertNumPendingForceClose(alice, 0) From 5663edfc2f468a82f259e331d865240258247150 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 8 Nov 2024 18:56:18 +0800 Subject: [PATCH 34/64] itest: break remote signer into independent cases So the test can run faster. --- itest/list_on_test.go | 5 +- itest/lnd_remote_signer_test.go | 358 +++++++++++++++++++++----------- 2 files changed, 238 insertions(+), 125 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 3a5a10a9fa..da525a8630 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -508,10 +508,6 @@ var allTestCases = []*lntest.TestCase{ Name: "async payments benchmark", TestFunc: testAsyncPayments, }, - { - Name: "remote signer", - TestFunc: testRemoteSigner, - }, { Name: "taproot coop close", TestFunc: testTaprootCoopClose, @@ -695,4 +691,5 @@ func init() { allTestCases = append(allTestCases, multiHopForceCloseTestCases...) allTestCases = append(allTestCases, watchtowerTestCases...) allTestCases = append(allTestCases, psbtFundingTestCases...) + allTestCases = append(allTestCases, remoteSignerTestCases...) } diff --git a/itest/lnd_remote_signer_test.go b/itest/lnd_remote_signer_test.go index bd92ba37c8..6cbda365aa 100644 --- a/itest/lnd_remote_signer_test.go +++ b/itest/lnd_remote_signer_test.go @@ -16,6 +16,59 @@ import ( "github.com/stretchr/testify/require" ) +// remoteSignerTestCases defines a set of test cases to run against the remote +// signer. +var remoteSignerTestCases = []*lntest.TestCase{ + { + Name: "remote signer random seed", + TestFunc: testRemoteSignerRadomSeed, + }, + { + Name: "remote signer account import", + TestFunc: testRemoteSignerAccountImport, + }, + { + Name: "remote signer channel open", + TestFunc: testRemoteSignerChannelOpen, + }, + { + Name: "remote signer funding input types", + TestFunc: testRemoteSignerChannelFundingInputTypes, + }, + { + Name: "remote signer funding async payments", + TestFunc: testRemoteSignerAsyncPayments, + }, + { + Name: "remote signer funding async payments taproot", + TestFunc: testRemoteSignerAsyncPaymentsTaproot, + }, + { + Name: "remote signer shared key", + TestFunc: testRemoteSignerSharedKey, + }, + { + Name: "remote signer bump fee", + TestFunc: testRemoteSignerBumpFee, + }, + { + Name: "remote signer psbt", + TestFunc: testRemoteSignerPSBT, + }, + { + Name: "remote signer sign output raw", + TestFunc: testRemoteSignerSignOutputRaw, + }, + { + Name: "remote signer verify msg", + TestFunc: testRemoteSignerSignVerifyMsg, + }, + { + Name: "remote signer taproot", + TestFunc: testRemoteSignerTaproot, + }, +} + var ( rootKey = "tprv8ZgxMBicQKsPe6jS4vDm2n7s42Q6MpvghUQqMmSKG7bTZvGKtjrcU3" + "PGzMNG37yzxywrcdvgkwrr8eYXJmbwdvUNVT4Ucv7ris4jvA7BUmg" @@ -53,25 +106,115 @@ var ( }} ) -// testRemoteSigner tests that a watch-only wallet can use a remote signing -// wallet to perform any signing or ECDH operations. -func testRemoteSigner(ht *lntest.HarnessTest) { - type testCase struct { - name string - randomSeed bool - sendCoins bool - commitType lnrpc.CommitmentType - fn func(tt *lntest.HarnessTest, - wo, carol *node.HarnessNode) +// remoteSignerTestCase defines a test case for the remote signer test suite. +type remoteSignerTestCase struct { + name string + randomSeed bool + sendCoins bool + commitType lnrpc.CommitmentType + fn func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) +} + +// prepareRemoteSignerTest prepares a test case for the remote signer test +// suite by creating three nodes. +func prepareRemoteSignerTest(ht *lntest.HarnessTest, tc remoteSignerTestCase) ( + *node.HarnessNode, *node.HarnessNode, *node.HarnessNode) { + + // Signer is our signing node and has the wallet with the full master + // private key. We test that we can create the watch-only wallet from + // the exported accounts but also from a static key to make sure the + // derivation of the account public keys is correct in both cases. + password := []byte("itestpassword") + var ( + signerNodePubKey = nodePubKey + watchOnlyAccounts = deriveCustomScopeAccounts(ht.T) + signer *node.HarnessNode + err error + ) + if !tc.randomSeed { + signer = ht.RestoreNodeWithSeed( + "Signer", nil, password, nil, rootKey, 0, nil, + ) + } else { + signer = ht.NewNode("Signer", nil) + signerNodePubKey = signer.PubKeyStr + + rpcAccts := signer.RPC.ListAccounts( + &walletrpc.ListAccountsRequest{}, + ) + + watchOnlyAccounts, err = walletrpc.AccountsToWatchOnly( + rpcAccts.Accounts, + ) + require.NoError(ht, err) } - subTests := []testCase{{ + var commitArgs []string + if tc.commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + commitArgs = lntest.NodeArgsForCommitType( + tc.commitType, + ) + } + + // WatchOnly is the node that has a watch-only wallet and uses the + // Signer node for any operation that requires access to private keys. + watchOnly := ht.NewNodeRemoteSigner( + "WatchOnly", append([]string{ + "--remotesigner.enable", + fmt.Sprintf( + "--remotesigner.rpchost=localhost:%d", + signer.Cfg.RPCPort, + ), + fmt.Sprintf( + "--remotesigner.tlscertpath=%s", + signer.Cfg.TLSCertPath, + ), + fmt.Sprintf( + "--remotesigner.macaroonpath=%s", + signer.Cfg.AdminMacPath, + ), + }, commitArgs...), + password, &lnrpc.WatchOnly{ + MasterKeyBirthdayTimestamp: 0, + MasterKeyFingerprint: nil, + Accounts: watchOnlyAccounts, + }, + ) + + resp := watchOnly.RPC.GetInfo() + require.Equal(ht, signerNodePubKey, resp.IdentityPubkey) + + if tc.sendCoins { + ht.FundCoins(btcutil.SatoshiPerBitcoin, watchOnly) + ht.AssertWalletAccountBalance( + watchOnly, "default", + btcutil.SatoshiPerBitcoin, 0, + ) + } + + carol := ht.NewNode("carol", commitArgs) + ht.EnsureConnected(watchOnly, carol) + + return signer, watchOnly, carol +} + +// testRemoteSignerRadomSeed tests that a watch-only wallet can use a remote +// signing wallet to perform any signing or ECDH operations. +func testRemoteSignerRadomSeed(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "random seed", randomSeed: true, fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { // Nothing more to test here. }, - }, { + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + +func testRemoteSignerAccountImport(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "account import", fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { runWalletImportAccountScenario( @@ -79,25 +222,53 @@ func testRemoteSigner(ht *lntest.HarnessTest) { carol, wo, ) }, - }, { + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + +func testRemoteSignerChannelOpen(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "basic channel open close", sendCoins: true, fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { runBasicChannelCreationAndUpdates(tt, wo, carol) }, - }, { + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + +func testRemoteSignerChannelFundingInputTypes(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "channel funding input types", sendCoins: false, fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { runChannelFundingInputTypes(tt, carol, wo) }, - }, { + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + +func testRemoteSignerAsyncPayments(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "async payments", sendCoins: true, fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { runAsyncPayments(tt, wo, carol, nil) }, - }, { + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + +func testRemoteSignerAsyncPaymentsTaproot(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "async payments taproot", sendCoins: true, fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { @@ -108,18 +279,39 @@ func testRemoteSigner(ht *lntest.HarnessTest) { ) }, commitType: lnrpc.CommitmentType_SIMPLE_TAPROOT, - }, { + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + +func testRemoteSignerSharedKey(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "shared key", fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { runDeriveSharedKey(tt, wo) }, - }, { + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + +func testRemoteSignerBumpFee(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "bumpfee", sendCoins: true, fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { runBumpFee(tt, wo) }, - }, { + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + +func testRemoteSignerPSBT(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "psbt", randomSeed: true, fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { @@ -137,19 +329,40 @@ func testRemoteSigner(ht *lntest.HarnessTest) { // sure we can fund and then sign PSBTs from our wallet. runFundAndSignPsbt(ht, wo) }, - }, { + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + +func testRemoteSignerSignOutputRaw(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "sign output raw", sendCoins: true, fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { runSignOutputRaw(tt, wo) }, - }, { + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + +func testRemoteSignerSignVerifyMsg(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "sign verify msg", sendCoins: true, fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { runSignVerifyMessage(tt, wo) }, - }, { + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + +func testRemoteSignerTaproot(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ name: "taproot", sendCoins: true, randomSeed: true, @@ -175,107 +388,10 @@ func testRemoteSigner(ht *lntest.HarnessTest) { ) } }, - }} - - prepareTest := func(st *lntest.HarnessTest, - subTest testCase) (*node.HarnessNode, - *node.HarnessNode, *node.HarnessNode) { - - // Signer is our signing node and has the wallet with the full - // master private key. We test that we can create the watch-only - // wallet from the exported accounts but also from a static key - // to make sure the derivation of the account public keys is - // correct in both cases. - password := []byte("itestpassword") - var ( - signerNodePubKey = nodePubKey - watchOnlyAccounts = deriveCustomScopeAccounts(ht.T) - signer *node.HarnessNode - err error - ) - if !subTest.randomSeed { - signer = st.RestoreNodeWithSeed( - "Signer", nil, password, nil, rootKey, 0, nil, - ) - } else { - signer = st.NewNode("Signer", nil) - signerNodePubKey = signer.PubKeyStr - - rpcAccts := signer.RPC.ListAccounts( - &walletrpc.ListAccountsRequest{}, - ) - - watchOnlyAccounts, err = walletrpc.AccountsToWatchOnly( - rpcAccts.Accounts, - ) - require.NoError(st, err) - } - - var commitArgs []string - if subTest.commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { - commitArgs = lntest.NodeArgsForCommitType( - subTest.commitType, - ) - } - - // WatchOnly is the node that has a watch-only wallet and uses - // the Signer node for any operation that requires access to - // private keys. - watchOnly := st.NewNodeRemoteSigner( - "WatchOnly", append([]string{ - "--remotesigner.enable", - fmt.Sprintf( - "--remotesigner.rpchost=localhost:%d", - signer.Cfg.RPCPort, - ), - fmt.Sprintf( - "--remotesigner.tlscertpath=%s", - signer.Cfg.TLSCertPath, - ), - fmt.Sprintf( - "--remotesigner.macaroonpath=%s", - signer.Cfg.AdminMacPath, - ), - }, commitArgs...), - password, &lnrpc.WatchOnly{ - MasterKeyBirthdayTimestamp: 0, - MasterKeyFingerprint: nil, - Accounts: watchOnlyAccounts, - }, - ) - - resp := watchOnly.RPC.GetInfo() - require.Equal(st, signerNodePubKey, resp.IdentityPubkey) - - if subTest.sendCoins { - st.FundCoins(btcutil.SatoshiPerBitcoin, watchOnly) - ht.AssertWalletAccountBalance( - watchOnly, "default", - btcutil.SatoshiPerBitcoin, 0, - ) - } - - carol := st.NewNode("carol", commitArgs) - st.EnsureConnected(watchOnly, carol) - - return signer, watchOnly, carol } - for _, testCase := range subTests { - subTest := testCase - - success := ht.Run(subTest.name, func(tt *testing.T) { - // Skip the cleanup here as no standby node is used. - st := ht.Subtest(tt) - - _, watchOnly, carol := prepareTest(st, subTest) - subTest.fn(st, watchOnly, carol) - }) - - if !success { - return - } - } + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) } // deriveCustomScopeAccounts derives the first 255 default accounts of the custom lnd From b1cb819f0742cf2e59423462cca2f097070df5c0 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 8 Nov 2024 19:10:02 +0800 Subject: [PATCH 35/64] itest: break down channel restore commit types cases --- itest/list_on_test.go | 5 +- itest/lnd_channel_backup_test.go | 137 +++++++++++++++---------------- 2 files changed, 65 insertions(+), 77 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index da525a8630..0d618108f9 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -27,10 +27,6 @@ var allTestCases = []*lntest.TestCase{ Name: "channel backup restore unconfirmed", TestFunc: testChannelBackupRestoreUnconfirmed, }, - { - Name: "channel backup restore commit types", - TestFunc: testChannelBackupRestoreCommitTypes, - }, { Name: "channel backup restore force close", TestFunc: testChannelBackupRestoreForceClose, @@ -692,4 +688,5 @@ func init() { allTestCases = append(allTestCases, watchtowerTestCases...) allTestCases = append(allTestCases, psbtFundingTestCases...) allTestCases = append(allTestCases, remoteSignerTestCases...) + allTestCases = append(allTestCases, channelRestoreTestCases...) } diff --git a/itest/lnd_channel_backup_test.go b/itest/lnd_channel_backup_test.go index 7691fdd194..abbec76be5 100644 --- a/itest/lnd_channel_backup_test.go +++ b/itest/lnd_channel_backup_test.go @@ -23,6 +23,70 @@ import ( "github.com/stretchr/testify/require" ) +// channelRestoreTestCases contains the test cases for the channel restore +// scenario. +var channelRestoreTestCases = []*lntest.TestCase{ + { + // Restore the backup from the on-disk file, using the RPC + // interface, for anchor commitment channels. + Name: "channel backup restore anchor", + TestFunc: func(ht *lntest.HarnessTest) { + runChanRestoreScenarioCommitTypes( + ht, lnrpc.CommitmentType_ANCHORS, false, + ) + }, + }, + { + // Restore the backup from the on-disk file, using the RPC + // interface, for script-enforced leased channels. + Name: "channel backup restore leased", + TestFunc: func(ht *lntest.HarnessTest) { + runChanRestoreScenarioCommitTypes( + ht, leasedType, false, + ) + }, + }, + { + // Restore the backup from the on-disk file, using the RPC + // interface, for zero-conf anchor channels. + Name: "channel backup restore anchor zero conf", + TestFunc: func(ht *lntest.HarnessTest) { + runChanRestoreScenarioCommitTypes( + ht, lnrpc.CommitmentType_ANCHORS, true, + ) + }, + }, + { + // Restore the backup from the on-disk file, using the RPC + // interface for a zero-conf script-enforced leased channel. + Name: "channel backup restore leased zero conf", + TestFunc: func(ht *lntest.HarnessTest) { + runChanRestoreScenarioCommitTypes( + ht, leasedType, true, + ) + }, + }, + { + // Restore a channel back up of a taproot channel that was + // confirmed. + Name: "channel backup restore simple taproot", + TestFunc: func(ht *lntest.HarnessTest) { + runChanRestoreScenarioCommitTypes( + ht, lnrpc.CommitmentType_SIMPLE_TAPROOT, false, + ) + }, + }, + { + // Restore a channel back up of an unconfirmed taproot channel. + Name: "channel backup restore simple taproot zero conf", + TestFunc: func(ht *lntest.HarnessTest) { + runChanRestoreScenarioCommitTypes( + ht, lnrpc.CommitmentType_SIMPLE_TAPROOT, true, + ) + }, + }, +} + type ( // nodeRestorer is a function closure that allows each test case to // control exactly *how* the prior node is restored. This might be @@ -540,79 +604,6 @@ func runChanRestoreScenarioUnConfirmed(ht *lntest.HarnessTest, useFile bool) { crs.testScenario(ht, restoredNodeFunc) } -// testChannelBackupRestoreCommitTypes tests that we're able to recover from, -// and initiate the DLP protocol for different channel commitment types and -// zero-conf channel. -func testChannelBackupRestoreCommitTypes(ht *lntest.HarnessTest) { - var testCases = []struct { - name string - ct lnrpc.CommitmentType - zeroConf bool - }{ - // Restore the backup from the on-disk file, using the RPC - // interface, for anchor commitment channels. - { - name: "restore from backup file anchors", - ct: lnrpc.CommitmentType_ANCHORS, - }, - - // Restore the backup from the on-disk file, using the RPC - // interface, for script-enforced leased channels. - { - name: "restore from backup file script " + - "enforced lease", - ct: lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE, - }, - - // Restore the backup from the on-disk file, using the RPC - // interface, for zero-conf anchor channels. - { - name: "restore from backup file for zero-conf " + - "anchors channel", - ct: lnrpc.CommitmentType_ANCHORS, - zeroConf: true, - }, - - // Restore the backup from the on-disk file, using the RPC - // interface for a zero-conf script-enforced leased channel. - { - name: "restore from backup file zero-conf " + - "script-enforced leased channel", - ct: lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE, - zeroConf: true, - }, - - // Restore a channel back up of a taproot channel that was - // confirmed. - { - name: "restore from backup taproot", - ct: lnrpc.CommitmentType_SIMPLE_TAPROOT, - zeroConf: false, - }, - - // Restore a channel back up of an unconfirmed taproot channel. - { - name: "restore from backup taproot zero conf", - ct: lnrpc.CommitmentType_SIMPLE_TAPROOT, - zeroConf: true, - }, - } - - for _, testCase := range testCases { - tc := testCase - success := ht.Run(tc.name, func(t *testing.T) { - h := ht.Subtest(t) - - runChanRestoreScenarioCommitTypes( - h, tc.ct, tc.zeroConf, - ) - }) - if !success { - break - } - } -} - // runChanRestoreScenarioCommitTypes tests that the DLP is applied for // different channel commitment types and zero-conf channel. func runChanRestoreScenarioCommitTypes(ht *lntest.HarnessTest, From a76ff79adc6f107312a54ac1b4a2226eff41bfed Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 8 Nov 2024 20:39:44 +0800 Subject: [PATCH 36/64] itest: break down utxo selection funding tests --- itest/list_on_test.go | 5 +- ...lnd_channel_funding_utxo_selection_test.go | 405 +++++++++++++----- 2 files changed, 287 insertions(+), 123 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 0d618108f9..218471e027 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -556,10 +556,6 @@ var allTestCases = []*lntest.TestCase{ Name: "custom features", TestFunc: testCustomFeatures, }, - { - Name: "utxo selection funding", - TestFunc: testChannelUtxoSelection, - }, { Name: "update pending open channels on funder side", TestFunc: testUpdateOnFunderPendingOpenChannels, @@ -689,4 +685,5 @@ func init() { allTestCases = append(allTestCases, psbtFundingTestCases...) allTestCases = append(allTestCases, remoteSignerTestCases...) allTestCases = append(allTestCases, channelRestoreTestCases...) + allTestCases = append(allTestCases, fundUtxoSelectionTestCases...) } diff --git a/itest/lnd_channel_funding_utxo_selection_test.go b/itest/lnd_channel_funding_utxo_selection_test.go index f840b8ac99..7868b73338 100644 --- a/itest/lnd_channel_funding_utxo_selection_test.go +++ b/itest/lnd_channel_funding_utxo_selection_test.go @@ -15,6 +15,37 @@ import ( "github.com/stretchr/testify/require" ) +var fundUtxoSelectionTestCases = []*lntest.TestCase{ + { + Name: "utxo selection funding error", + TestFunc: testChannelUtxoSelectionError, + }, + { + Name: "utxo selection selected valid chan size", + TestFunc: testUtxoSelectionSelectedValidChanSize, + }, + { + Name: "utxo selection selected valid chan reserve", + TestFunc: testUtxoSelectionSelectedValidChanReserve, + }, + { + Name: "utxo selection selected reserve from selected", + TestFunc: testUtxoSelectionReserveFromSelected, + }, + { + Name: "utxo selection fundmax", + TestFunc: testUtxoSelectionFundmax, + }, + { + Name: "utxo selection fundmax reserve", + TestFunc: testUtxoSelectionFundmaxReserve, + }, + { + Name: "utxo selection reused utxo", + TestFunc: testUtxoSelectionReuseUTXO, + }, +} + type chanFundUtxoSelectionTestCase struct { // name is the name of the target test case. name string @@ -57,9 +88,10 @@ type chanFundUtxoSelectionTestCase struct { reuseUtxo bool } -// testChannelUtxoSelection checks various channel funding scenarios where the -// user instructed the wallet to use a selection funds available in the wallet. -func testChannelUtxoSelection(ht *lntest.HarnessTest) { +// testChannelUtxoSelectionError checks various channel funding error scenarios +// where the user instructed the wallet to use a selection funds available in +// the wallet. +func testChannelUtxoSelectionError(ht *lntest.HarnessTest) { // Create two new nodes that open a channel between each other for these // tests. args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) @@ -115,73 +147,6 @@ func testChannelUtxoSelection(ht *lntest.HarnessTest) { "create funding transaction, need 0.00210337 " + "BTC only have 0.00100000 BTC available", }, - // We are spending two selected coins partially out of three - // available in the wallet and expect a change output and the - // unselected coin as remaining wallet balance. - { - name: "selected, local amount > " + - "min chan size", - initialCoins: []btcutil.Amount{ - 200_000, 50_000, 100_000, - }, - selectedCoins: []btcutil.Amount{ - 200_000, 100_000, - }, - localAmt: btcutil.Amount(250_000), - expectedBalance: btcutil.Amount(250_000), - remainingWalletBalance: btcutil.Amount(350_000) - - btcutil.Amount(250_000) - fundingFee(2, true), - }, - // We are spending the entirety of two selected coins out of - // three available in the wallet and expect no change output and - // the unselected coin as remaining wallet balance. - { - name: "fundmax, local amount > min " + - "chan size", - initialCoins: []btcutil.Amount{ - 200_000, 100_000, 50_000, - }, - selectedCoins: []btcutil.Amount{ - 200_000, 50_000, - }, - expectedBalance: btcutil.Amount(200_000) + - btcutil.Amount(50_000) - fundingFee(2, false), - remainingWalletBalance: btcutil.Amount(100_000), - }, - // Select all coins in wallet and use the maximum available - // local amount to fund an anchor channel. - { - name: "selected, local amount leaves sufficient " + - "reserve", - initialCoins: []btcutil.Amount{ - 200_000, 100_000, - }, - selectedCoins: []btcutil.Amount{200_000, 100_000}, - commitmentType: lnrpc.CommitmentType_ANCHORS, - localAmt: btcutil.Amount(300_000) - - reserveAmount - fundingFee(2, true), - expectedBalance: btcutil.Amount(300_000) - - reserveAmount - fundingFee(2, true), - remainingWalletBalance: reserveAmount, - }, - // Select all coins in wallet towards local amount except for an - // anchor reserve portion. Because the UTXOs are sorted by size - // by default, the reserve amount is just left in the wallet. - { - name: "selected, reserve from selected", - initialCoins: []btcutil.Amount{ - 200_000, reserveAmount, 100_000, - }, - selectedCoins: []btcutil.Amount{ - 200_000, reserveAmount, 100_000, - }, - commitmentType: lnrpc.CommitmentType_ANCHORS, - localAmt: btcutil.Amount(300_000) - - fundingFee(2, true), - expectedBalance: btcutil.Amount(300_000) - - fundingFee(2, true), - remainingWalletBalance: reserveAmount, - }, // Select all coins in wallet and use more than the maximum // available local amount to fund an anchor channel. { @@ -200,43 +165,6 @@ func testChannelUtxoSelection(ht *lntest.HarnessTest) { "insufficient funds for fee bumping anchor " + "channel closings", }, - // We fund an anchor channel with a single coin and just keep - // enough funds in the wallet to cover for the anchor reserve. - { - name: "fundmax, sufficient reserve", - initialCoins: []btcutil.Amount{ - 200_000, reserveAmount, - }, - selectedCoins: []btcutil.Amount{200_000}, - commitmentType: lnrpc.CommitmentType_ANCHORS, - expectedBalance: btcutil.Amount(200_000) - - fundingFee(1, false), - remainingWalletBalance: reserveAmount, - }, - // We fund an anchor channel with a single coin and expect the - // reserve amount left in the wallet. - { - name: "fundmax, sufficient reserve from channel " + - "balance carve out", - initialCoins: []btcutil.Amount{ - 200_000, - }, - selectedCoins: []btcutil.Amount{200_000}, - commitmentType: lnrpc.CommitmentType_ANCHORS, - expectedBalance: btcutil.Amount(200_000) - - reserveAmount - fundingFee(1, true), - remainingWalletBalance: reserveAmount, - }, - // Confirm that already spent outputs can't be reused to fund - // another channel. - { - name: "output already spent", - initialCoins: []btcutil.Amount{ - 200_000, - }, - selectedCoins: []btcutil.Amount{200_000}, - reuseUtxo: true, - }, } for _, tc := range tcs { @@ -255,24 +183,258 @@ func testChannelUtxoSelection(ht *lntest.HarnessTest) { } } +// testChannelUtxoSelection checks various channel funding scenarios where the +// user instructed the wallet to use a selection funds available in the wallet. +func testUtxoSelectionSelectedValidChanSize(ht *lntest.HarnessTest) { + // Create two new nodes that open a channel between each other for these + // tests. + args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) + alice := ht.NewNode("Alice", args) + bob := ht.NewNode("Bob", args) + + // Ensure both sides are connected so the funding flow can be properly + // executed. + ht.EnsureConnected(alice, bob) + + // Calculate reserve amount for one channel. + reserveResp, _ := alice.RPC.WalletKit.RequiredReserve( + context.Background(), &walletrpc.RequiredReserveRequest{ + AdditionalPublicChannels: 1, + }, + ) + + reserveAmount := btcutil.Amount(reserveResp.RequiredReserve) + + // We are spending two selected coins partially out of three available + // in the wallet and expect a change output and the unselected coin as + // remaining wallet balance. + tc := &chanFundUtxoSelectionTestCase{ + name: "selected, local amount > min chan size", + initialCoins: []btcutil.Amount{ + 200_000, 50_000, 100_000, + }, + selectedCoins: []btcutil.Amount{ + 200_000, 100_000, + }, + localAmt: btcutil.Amount(250_000), + expectedBalance: btcutil.Amount(250_000), + remainingWalletBalance: btcutil.Amount(350_000) - + btcutil.Amount(250_000) - fundingFee(2, true), + } + + runUtxoSelectionTestCase(ht, alice, bob, tc, reserveAmount) +} + +// testChannelUtxoSelection checks various channel funding scenarios where the +// user instructed the wallet to use a selection funds available in the wallet. +func testUtxoSelectionSelectedValidChanReserve(ht *lntest.HarnessTest) { + // Create two new nodes that open a channel between each other for these + // tests. + args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) + alice := ht.NewNode("Alice", args) + bob := ht.NewNode("Bob", args) + + // Ensure both sides are connected so the funding flow can be properly + // executed. + ht.EnsureConnected(alice, bob) + + // Calculate reserve amount for one channel. + reserveResp, _ := alice.RPC.WalletKit.RequiredReserve( + context.Background(), &walletrpc.RequiredReserveRequest{ + AdditionalPublicChannels: 1, + }, + ) + + reserveAmount := btcutil.Amount(reserveResp.RequiredReserve) + + // Select all coins in wallet and use the maximum available + // local amount to fund an anchor channel. + tc := &chanFundUtxoSelectionTestCase{ + name: "selected, local amount leaves sufficient reserve", + initialCoins: []btcutil.Amount{ + 200_000, 100_000, + }, + selectedCoins: []btcutil.Amount{200_000, 100_000}, + commitmentType: lnrpc.CommitmentType_ANCHORS, + localAmt: btcutil.Amount(300_000) - + reserveAmount - fundingFee(2, true), + expectedBalance: btcutil.Amount(300_000) - + reserveAmount - fundingFee(2, true), + remainingWalletBalance: reserveAmount, + } + + runUtxoSelectionTestCase(ht, alice, bob, tc, reserveAmount) +} + +// testChannelUtxoSelection checks various channel funding scenarios where the +// user instructed the wallet to use a selection funds available in the wallet. +func testUtxoSelectionReserveFromSelected(ht *lntest.HarnessTest) { + // Create two new nodes that open a channel between each other for these + // tests. + args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) + alice := ht.NewNode("Alice", args) + bob := ht.NewNode("Bob", args) + + // Ensure both sides are connected so the funding flow can be properly + // executed. + ht.EnsureConnected(alice, bob) + + // Calculate reserve amount for one channel. + reserveResp, _ := alice.RPC.WalletKit.RequiredReserve( + context.Background(), &walletrpc.RequiredReserveRequest{ + AdditionalPublicChannels: 1, + }, + ) + + reserveAmount := btcutil.Amount(reserveResp.RequiredReserve) + + // Select all coins in wallet towards local amount except for an anchor + // reserve portion. Because the UTXOs are sorted by size by default, + // the reserve amount is just left in the wallet. + tc := &chanFundUtxoSelectionTestCase{ + name: "selected, reserve from selected", + initialCoins: []btcutil.Amount{ + 200_000, reserveAmount, 100_000, + }, + selectedCoins: []btcutil.Amount{ + 200_000, reserveAmount, 100_000, + }, + commitmentType: lnrpc.CommitmentType_ANCHORS, + localAmt: btcutil.Amount(300_000) - + fundingFee(2, true), + expectedBalance: btcutil.Amount(300_000) - + fundingFee(2, true), + remainingWalletBalance: reserveAmount, + } + + runUtxoSelectionTestCase(ht, alice, bob, tc, reserveAmount) +} + +// testChannelUtxoSelection checks various channel funding scenarios where the +// user instructed the wallet to use a selection funds available in the wallet. +func testUtxoSelectionFundmax(ht *lntest.HarnessTest) { + // Create two new nodes that open a channel between each other for these + // tests. + args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) + alice := ht.NewNode("Alice", args) + bob := ht.NewNode("Bob", args) + + // Ensure both sides are connected so the funding flow can be properly + // executed. + ht.EnsureConnected(alice, bob) + + // Calculate reserve amount for one channel. + reserveResp, _ := alice.RPC.WalletKit.RequiredReserve( + context.Background(), &walletrpc.RequiredReserveRequest{ + AdditionalPublicChannels: 1, + }, + ) + + reserveAmount := btcutil.Amount(reserveResp.RequiredReserve) + + // We fund an anchor channel with a single coin and just keep enough + // funds in the wallet to cover for the anchor reserve. + tc := &chanFundUtxoSelectionTestCase{ + name: "fundmax, sufficient reserve", + initialCoins: []btcutil.Amount{ + 200_000, reserveAmount, + }, + selectedCoins: []btcutil.Amount{200_000}, + commitmentType: lnrpc.CommitmentType_ANCHORS, + expectedBalance: btcutil.Amount(200_000) - + fundingFee(1, false), + remainingWalletBalance: reserveAmount, + } + + runUtxoSelectionTestCase(ht, alice, bob, tc, reserveAmount) +} + +// testChannelUtxoSelection checks various channel funding scenarios where the +// user instructed the wallet to use a selection funds available in the wallet. +func testUtxoSelectionFundmaxReserve(ht *lntest.HarnessTest) { + // Create two new nodes that open a channel between each other for these + // tests. + args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) + alice := ht.NewNode("Alice", args) + bob := ht.NewNode("Bob", args) + + // Ensure both sides are connected so the funding flow can be properly + // executed. + ht.EnsureConnected(alice, bob) + + // Calculate reserve amount for one channel. + reserveResp, _ := alice.RPC.WalletKit.RequiredReserve( + context.Background(), &walletrpc.RequiredReserveRequest{ + AdditionalPublicChannels: 1, + }, + ) + + reserveAmount := btcutil.Amount(reserveResp.RequiredReserve) + + // We fund an anchor channel with a single coin and expect the reserve + // amount left in the wallet. + tc := &chanFundUtxoSelectionTestCase{ + name: "fundmax, sufficient reserve from channel " + + "balance carve out", + initialCoins: []btcutil.Amount{ + 200_000, + }, + selectedCoins: []btcutil.Amount{200_000}, + commitmentType: lnrpc.CommitmentType_ANCHORS, + expectedBalance: btcutil.Amount(200_000) - + reserveAmount - fundingFee(1, true), + remainingWalletBalance: reserveAmount, + } + + runUtxoSelectionTestCase(ht, alice, bob, tc, reserveAmount) +} + +// testChannelUtxoSelection checks various channel funding scenarios where the +// user instructed the wallet to use a selection funds available in the wallet. +func testUtxoSelectionReuseUTXO(ht *lntest.HarnessTest) { + // Create two new nodes that open a channel between each other for these + // tests. + args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) + alice := ht.NewNode("Alice", args) + bob := ht.NewNode("Bob", args) + + // Ensure both sides are connected so the funding flow can be properly + // executed. + ht.EnsureConnected(alice, bob) + + // Calculate reserve amount for one channel. + reserveResp, _ := alice.RPC.WalletKit.RequiredReserve( + context.Background(), &walletrpc.RequiredReserveRequest{ + AdditionalPublicChannels: 1, + }, + ) + + reserveAmount := btcutil.Amount(reserveResp.RequiredReserve) + + // Confirm that already spent outputs can't be reused to fund another + // channel. + tc := &chanFundUtxoSelectionTestCase{ + name: "output already spent", + initialCoins: []btcutil.Amount{ + 200_000, + }, + selectedCoins: []btcutil.Amount{200_000}, + reuseUtxo: true, + } + + runUtxoSelectionTestCase(ht, alice, bob, tc, reserveAmount) +} + // runUtxoSelectionTestCase runs a single test case asserting that test // conditions are met. func runUtxoSelectionTestCase(ht *lntest.HarnessTest, alice, bob *node.HarnessNode, tc *chanFundUtxoSelectionTestCase, reserveAmount btcutil.Amount) { - // fund initial coins + // Fund initial coins. for _, initialCoin := range tc.initialCoins { ht.FundCoins(initialCoin, alice) } - defer func() { - // Fund additional coins to sweep in case the wallet contains - // dust. - ht.FundCoins(100_000, alice) - - // Remove all funds from Alice. - sweepNodeWalletAndAssert(ht, alice) - }() // Create an outpoint lookup for each unique amount. lookup := make(map[int64]*lnrpc.OutPoint) @@ -314,9 +476,14 @@ func runUtxoSelectionTestCase(ht *lntest.HarnessTest, alice, // successful, simply check for an error. if tc.chanOpenShouldFail { expectedErr := errors.New(tc.expectedErrStr) - ht.OpenChannelAssertErr( - alice, bob, chanParams, expectedErr, - ) + ht.OpenChannelAssertErr(alice, bob, chanParams, expectedErr) + + // Fund additional coins to sweep in case the wallet contains + // dust. + ht.FundCoins(100_000, alice) + + // Remove all funds from Alice. + sweepNodeWalletAndAssert(ht, alice) return } From 04a15039d79ee13fdd7060a6d73bd9c069070338 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 8 Nov 2024 22:30:57 +0800 Subject: [PATCH 37/64] itest: break all multihop test cases --- itest/lnd_multi-hop_force_close_test.go | 1486 +++++++++++------------ 1 file changed, 717 insertions(+), 769 deletions(-) diff --git a/itest/lnd_multi-hop_force_close_test.go b/itest/lnd_multi-hop_force_close_test.go index f35ad8f47c..dc18792ea4 100644 --- a/itest/lnd_multi-hop_force_close_test.go +++ b/itest/lnd_multi-hop_force_close_test.go @@ -1,8 +1,6 @@ package itest import ( - "testing" - "github.com/btcsuite/btcd/btcutil" "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc" @@ -34,130 +32,207 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "multihop local claim outgoing htlc anchor", TestFunc: testLocalClaimOutgoingHTLCAnchor, }, + { + Name: "multihop local claim outgoing htlc anchor zero conf", + TestFunc: testLocalClaimOutgoingHTLCAnchorZeroConf, + }, { Name: "multihop local claim outgoing htlc simple taproot", TestFunc: testLocalClaimOutgoingHTLCSimpleTaproot, }, + { + Name: "multihop local claim outgoing htlc simple taproot zero conf", + TestFunc: testLocalClaimOutgoingHTLCSimpleTaprootZeroConf, + }, { Name: "multihop local claim outgoing htlc leased", TestFunc: testLocalClaimOutgoingHTLCLeased, }, + { + Name: "multihop local claim outgoing htlc leased zero conf", + TestFunc: testLocalClaimOutgoingHTLCLeasedZeroConf, + }, { Name: "multihop receiver preimage claim anchor", TestFunc: testMultiHopReceiverPreimageClaimAnchor, }, + { + Name: "multihop receiver preimage claim anchor zero conf", + TestFunc: testMultiHopReceiverPreimageClaimAnchorZeroConf, + }, { Name: "multihop receiver preimage claim simple taproot", TestFunc: testMultiHopReceiverPreimageClaimSimpleTaproot, }, + { + Name: "multihop receiver preimage claim simple taproot zero conf", + TestFunc: testMultiHopReceiverPreimageClaimSimpleTaprootZeroConf, + }, { Name: "multihop receiver preimage claim leased", TestFunc: testMultiHopReceiverPreimageClaimLeased, }, + { + Name: "multihop receiver preimage claim leased zero conf", + TestFunc: testMultiHopReceiverPreimageClaimLeasedZeroConf, + }, { Name: "multihop local force close before timeout anchor", TestFunc: testLocalForceCloseBeforeTimeoutAnchor, }, + { + Name: "multihop local force close before timeout anchor zero conf", + TestFunc: testLocalForceCloseBeforeTimeoutAnchorZeroConf, + }, { Name: "multihop local force close before timeout simple taproot", TestFunc: testLocalForceCloseBeforeTimeoutSimpleTaproot, }, + { + Name: "multihop local force close before timeout simple taproot zero conf", + TestFunc: testLocalForceCloseBeforeTimeoutSimpleTaprootZeroConf, + }, { Name: "multihop local force close before timeout leased", TestFunc: testLocalForceCloseBeforeTimeoutLeased, }, + { + Name: "multihop local force close before timeout leased zero conf", + TestFunc: testLocalForceCloseBeforeTimeoutLeasedZeroConf, + }, { Name: "multihop remote force close before timeout anchor", TestFunc: testRemoteForceCloseBeforeTimeoutAnchor, }, + { + Name: "multihop remote force close before timeout anchor zero conf", + TestFunc: testRemoteForceCloseBeforeTimeoutAnchorZeroConf, + }, { Name: "multihop remote force close before timeout simple taproot", TestFunc: testRemoteForceCloseBeforeTimeoutSimpleTaproot, }, + { + Name: "multihop remote force close before timeout simple taproot zero conf", + TestFunc: testRemoteForceCloseBeforeTimeoutSimpleTaprootZeroConf, + }, { Name: "multihop remote force close before timeout leased", TestFunc: testRemoteForceCloseBeforeTimeoutLeased, }, + { + Name: "multihop remote force close before timeout leased zero conf", + TestFunc: testRemoteForceCloseBeforeTimeoutLeasedZeroConf, + }, { Name: "multihop local claim incoming htlc anchor", TestFunc: testLocalClaimIncomingHTLCAnchor, }, + { + Name: "multihop local claim incoming htlc anchor zero conf", + TestFunc: testLocalClaimIncomingHTLCAnchorZeroConf, + }, { Name: "multihop local claim incoming htlc simple taproot", TestFunc: testLocalClaimIncomingHTLCSimpleTaproot, }, + { + Name: "multihop local claim incoming htlc simple taproot zero conf", + TestFunc: testLocalClaimIncomingHTLCSimpleTaprootZeroConf, + }, { Name: "multihop local claim incoming htlc leased", TestFunc: testLocalClaimIncomingHTLCLeased, }, + { + Name: "multihop local claim incoming htlc leased zero conf", + TestFunc: testLocalClaimIncomingHTLCLeasedZeroConf, + }, { Name: "multihop local preimage claim anchor", TestFunc: testLocalPreimageClaimAnchor, }, + { + Name: "multihop local preimage claim anchor zero conf", + TestFunc: testLocalPreimageClaimAnchorZeroConf, + }, { Name: "multihop local preimage claim simple taproot", TestFunc: testLocalPreimageClaimSimpleTaproot, }, + { + Name: "multihop local preimage claim simple taproot zero conf", + TestFunc: testLocalPreimageClaimSimpleTaprootZeroConf, + }, { Name: "multihop local preimage claim leased", TestFunc: testLocalPreimageClaimLeased, }, + { + Name: "multihop local preimage claim leased zero conf", + TestFunc: testLocalPreimageClaimLeasedZeroConf, + }, { Name: "multihop htlc aggregation anchor", TestFunc: testHtlcAggregaitonAnchor, }, + { + Name: "multihop htlc aggregation anchor zero conf", + TestFunc: testHtlcAggregaitonAnchorZeroConf, + }, { Name: "multihop htlc aggregation simple taproot", TestFunc: testHtlcAggregaitonSimpleTaproot, }, + { + Name: "multihop htlc aggregation simple taproot zero conf", + TestFunc: testHtlcAggregaitonSimpleTaprootZeroConf, + }, { Name: "multihop htlc aggregation leased", TestFunc: testHtlcAggregaitonLeased, }, + { + Name: "multihop htlc aggregation leased zero conf", + TestFunc: testHtlcAggregaitonLeasedZeroConf, + }, } // testLocalClaimOutgoingHTLCAnchor tests `runLocalClaimOutgoingHTLC` with // anchor channel. func testLocalClaimOutgoingHTLCAnchor(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Create a three hop network: Alice -> Bob -> Carol, using anchor + // channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{Amt: chanAmt} - // Create a three hop network: Alice -> Bob -> Carol, using - // anchor channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{Amt: chanAmt} + cfg := node.CfgAnchor + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - cfg := node.CfgAnchor - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) +} - runLocalClaimOutgoingHTLC(st, cfgs, openChannelParams) - }) - if !success { - return +// testLocalClaimOutgoingHTLCAnchorZeroConf tests `runLocalClaimOutgoingHTLC` +// with zero conf anchor channel. +func testLocalClaimOutgoingHTLCAnchorZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: lnrpc.CommitmentType_ANCHORS, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: lnrpc.CommitmentType_ANCHORS, - } - - // Prepare Carol's node config to enable zero-conf and anchor. - cfg := node.CfgZeroConf - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + // Prepare Carol's node config to enable zero-conf and anchor. + cfg := node.CfgZeroConf + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - runLocalClaimOutgoingHTLC(st, cfgs, openChannelParams) - }) + runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) } // testLocalClaimOutgoingHTLCSimpleTaproot tests `runLocalClaimOutgoingHTLC` @@ -165,101 +240,87 @@ func testLocalClaimOutgoingHTLCAnchor(ht *lntest.HarnessTest) { func testLocalClaimOutgoingHTLCSimpleTaproot(ht *lntest.HarnessTest) { c := lnrpc.CommitmentType_SIMPLE_TAPROOT - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // simple taproot channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: c, - Private: true, - } + // Create a three hop network: Alice -> Bob -> Carol, using simple + // taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } - cfg := node.CfgSimpleTaproot - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - runLocalClaimOutgoingHTLC(st, cfgs, openChannelParams) - }) - if !success { - return - } + runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) +} - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) +// testLocalClaimOutgoingHTLCSimpleTaprootZeroConf tests +// `runLocalClaimOutgoingHTLC` with zero-conf simple taproot channel. +func testLocalClaimOutgoingHTLCSimpleTaprootZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf simple taproot channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: c, - Private: true, - } + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // simple taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgSimpleTaproot - cfg = append(cfg, node.CfgZeroConf...) - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - runLocalClaimOutgoingHTLC(st, cfgs, openChannelParams) - }) + runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) } // testLocalClaimOutgoingHTLCLeased tests `runLocalClaimOutgoingHTLC` with // script enforced lease channel. func testLocalClaimOutgoingHTLCLeased(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Create a three hop network: Alice -> Bob -> Carol, using leased + // channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: leasedType, + } - // Create a three hop network: Alice -> Bob -> Carol, using - // leased channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: leasedType, - } + cfg := node.CfgLeased + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - cfg := node.CfgLeased - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) +} - runLocalClaimOutgoingHTLC(st, cfgs, openChannelParams) - }) - if !success { - return +// testLocalClaimOutgoingHTLCLeasedZeroConf tests `runLocalClaimOutgoingHTLC` +// with zero-conf script enforced lease channel. +func testLocalClaimOutgoingHTLCLeasedZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: leasedType, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: leasedType, - } + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgLeased + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgLeased - cfg = append(cfg, node.CfgZeroConf...) - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} - - runLocalClaimOutgoingHTLC(st, cfgs, openChannelParams) - }) + runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) } // runLocalClaimOutgoingHTLC tests that in a multi-hop scenario, if the @@ -476,43 +537,36 @@ func runLocalClaimOutgoingHTLC(ht *lntest.HarnessTest, // testMultiHopReceiverPreimageClaimAnchor tests // `runMultiHopReceiverPreimageClaim` with anchor channels. func testMultiHopReceiverPreimageClaimAnchor(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Create a three hop network: Alice -> Bob -> Carol, using anchor + // channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{Amt: chanAmt} - // Create a three hop network: Alice -> Bob -> Carol, using - // anchor channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{Amt: chanAmt} + cfg := node.CfgAnchor + cfgs := [][]string{cfg, cfg, cfg} - cfg := node.CfgAnchor - cfgs := [][]string{cfg, cfg, cfg} + runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) +} - runMultiHopReceiverPreimageClaim(st, cfgs, openChannelParams) - }) - if !success { - return +// testMultiHopReceiverPreimageClaimAnchorZeroConf tests +// `runMultiHopReceiverPreimageClaim` with zero-conf anchor channels. +func testMultiHopReceiverPreimageClaimAnchorZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: lnrpc.CommitmentType_ANCHORS, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: lnrpc.CommitmentType_ANCHORS, - } - - // Prepare Carol's node config to enable zero-conf and anchor. - cfg := node.CfgZeroConf - cfgs := [][]string{cfg, cfg, cfg} + // Prepare Carol's node config to enable zero-conf and anchor. + cfg := node.CfgZeroConf + cfgs := [][]string{cfg, cfg, cfg} - runMultiHopReceiverPreimageClaim(st, cfgs, openChannelParams) - }) + runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) } // testMultiHopReceiverPreimageClaimSimpleTaproot tests @@ -520,97 +574,88 @@ func testMultiHopReceiverPreimageClaimAnchor(ht *lntest.HarnessTest) { func testMultiHopReceiverPreimageClaimSimpleTaproot(ht *lntest.HarnessTest) { c := lnrpc.CommitmentType_SIMPLE_TAPROOT - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Create a three hop network: Alice -> Bob -> Carol, using simple + // taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } - // Create a three hop network: Alice -> Bob -> Carol, using - // simple taproot channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: c, - Private: true, - } + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} - cfg := node.CfgSimpleTaproot - cfgs := [][]string{cfg, cfg, cfg} + runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) +} - runMultiHopReceiverPreimageClaim(st, cfgs, openChannelParams) - }) - if !success { - return - } +// testMultiHopReceiverPreimageClaimSimpleTaproot tests +// `runMultiHopReceiverPreimageClaim` with zero-conf simple taproot channels. +func testMultiHopReceiverPreimageClaimSimpleTaprootZeroConf( + ht *lntest.HarnessTest) { - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) + c := lnrpc.CommitmentType_SIMPLE_TAPROOT - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf simple taproot channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: c, - Private: true, - } + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // simple taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgSimpleTaproot - cfg = append(cfg, node.CfgZeroConf...) - cfgs := [][]string{cfg, cfg, cfg} + // Prepare Carol's node config to enable zero-conf and leased + // channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} - runMultiHopReceiverPreimageClaim(st, cfgs, openChannelParams) - }) + runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) } // testMultiHopReceiverPreimageClaimLeased tests // `runMultiHopReceiverPreimageClaim` with script enforce lease channels. func testMultiHopReceiverPreimageClaimLeased(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Create a three hop network: Alice -> Bob -> Carol, using leased + // channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: leasedType, + } - // Create a three hop network: Alice -> Bob -> Carol, using - // leased channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: leasedType, - } + cfg := node.CfgLeased + cfgs := [][]string{cfg, cfg, cfg} - cfg := node.CfgLeased - cfgs := [][]string{cfg, cfg, cfg} + runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) +} - runMultiHopReceiverPreimageClaim(st, cfgs, openChannelParams) - }) - if !success { - return +// testMultiHopReceiverPreimageClaimLeased tests +// `runMultiHopReceiverPreimageClaim` with zero-conf script enforce lease +// channels. +func testMultiHopReceiverPreimageClaimLeasedZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: leasedType, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - openChannelParams := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: leasedType, - } - - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgLeased - cfg = append(cfg, node.CfgZeroConf...) - cfgs := [][]string{cfg, cfg, cfg} + // Prepare Carol's node config to enable zero-conf and leased + // channel. + cfg := node.CfgLeased + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} - runMultiHopReceiverPreimageClaim(st, cfgs, openChannelParams) - }) + runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) } // runMultiHopReceiverClaim tests that in the multi-hop setting, if the @@ -878,45 +923,38 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest, // testLocalForceCloseBeforeTimeoutAnchor tests // `runLocalForceCloseBeforeHtlcTimeout` with anchor channel. func testLocalForceCloseBeforeTimeoutAnchor(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Create a three hop network: Alice -> Bob -> Carol, using anchor + // channels. + // + // Prepare params. + params := lntest.OpenChannelParams{Amt: chanAmt} - // Create a three hop network: Alice -> Bob -> Carol, using - // anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{Amt: chanAmt} + cfg := node.CfgAnchor + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - cfg := node.CfgAnchor - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} - runLocalForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) - if !success { - return +// testLocalForceCloseBeforeTimeoutAnchorZeroConf tests +// `runLocalForceCloseBeforeHtlcTimeout` with zero-conf anchor channel. +func testLocalForceCloseBeforeTimeoutAnchorZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: lnrpc.CommitmentType_ANCHORS, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: lnrpc.CommitmentType_ANCHORS, - } - - // Prepare Carol's node config to enable zero-conf and anchor. - cfg := node.CfgZeroConf - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + // Prepare Carol's node config to enable zero-conf and anchor. + cfg := node.CfgZeroConf + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - runLocalForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) + runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) } // testLocalForceCloseBeforeTimeoutSimpleTaproot tests @@ -924,101 +962,90 @@ func testLocalForceCloseBeforeTimeoutAnchor(ht *lntest.HarnessTest) { func testLocalForceCloseBeforeTimeoutSimpleTaproot(ht *lntest.HarnessTest) { c := lnrpc.CommitmentType_SIMPLE_TAPROOT - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Create a three hop network: Alice -> Bob -> Carol, using simple + // taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } - // Create a three hop network: Alice -> Bob -> Carol, using - // simple taproot channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: c, - Private: true, - } + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - cfg := node.CfgSimpleTaproot - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} - runLocalForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) - if !success { - return - } +// testLocalForceCloseBeforeTimeoutSimpleTaproot tests +// `runLocalForceCloseBeforeHtlcTimeout` with zero-conf simple taproot channel. +func testLocalForceCloseBeforeTimeoutSimpleTaprootZeroConf( + ht *lntest.HarnessTest) { - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) + c := lnrpc.CommitmentType_SIMPLE_TAPROOT - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf simple taproot channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: c, - Private: true, - } + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgSimpleTaproot - cfg = append(cfg, node.CfgZeroConf...) - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - runLocalForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) + runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) } // testLocalForceCloseBeforeTimeoutLeased tests // `runLocalForceCloseBeforeHtlcTimeout` with script enforced lease channel. func testLocalForceCloseBeforeTimeoutLeased(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Create a three hop network: Alice -> Bob -> Carol, using leased + // channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: leasedType, + } - // Create a three hop network: Alice -> Bob -> Carol, using - // leased channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: leasedType, - } + cfg := node.CfgLeased + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - cfg := node.CfgLeased - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} - runLocalForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) - if !success { - return +// testLocalForceCloseBeforeTimeoutLeased tests +// `runLocalForceCloseBeforeHtlcTimeout` with zero-conf script enforced lease +// channel. +func testLocalForceCloseBeforeTimeoutLeasedZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: leasedType, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: leasedType, - } - - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgLeased - cfg = append(cfg, node.CfgZeroConf...) - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgLeased + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - runLocalForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) + runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) } // runLocalForceCloseBeforeHtlcTimeout tests that in a multi-hop HTLC scenario, @@ -1210,45 +1237,65 @@ func runLocalForceCloseBeforeHtlcTimeout(ht *lntest.HarnessTest, // testRemoteForceCloseBeforeTimeoutAnchor tests // `runRemoteForceCloseBeforeHtlcTimeout` with anchor channel. func testRemoteForceCloseBeforeTimeoutAnchor(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Create a three hop network: Alice -> Bob -> Carol, using anchor + // channels. + // + // Prepare params. + params := lntest.OpenChannelParams{Amt: chanAmt} - // Create a three hop network: Alice -> Bob -> Carol, using - // anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{Amt: chanAmt} + cfg := node.CfgAnchor + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - cfg := node.CfgAnchor - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} - runRemoteForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) - if !success { - return +// testRemoteForceCloseBeforeTimeoutAnchor tests +// `runRemoteForceCloseBeforeHtlcTimeout` with zero-conf anchor channel. +func testRemoteForceCloseBeforeTimeoutAnchorZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: lnrpc.CommitmentType_ANCHORS, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Prepare Carol's node config to enable zero-conf and anchor. + cfg := node.CfgZeroConf + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: lnrpc.CommitmentType_ANCHORS, - } + runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} - // Prepare Carol's node config to enable zero-conf and anchor. - cfg := node.CfgZeroConf - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} +// testRemoteForceCloseBeforeTimeoutSimpleTaproot tests +// `runLocalForceCloseBeforeHtlcTimeout` with zero-conf simple taproot channel. +func testRemoteForceCloseBeforeTimeoutSimpleTaprootZeroConf( + ht *lntest.HarnessTest) { + + c := lnrpc.CommitmentType_SIMPLE_TAPROOT - runRemoteForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) } // testRemoteForceCloseBeforeTimeoutSimpleTaproot tests @@ -1256,101 +1303,64 @@ func testRemoteForceCloseBeforeTimeoutAnchor(ht *lntest.HarnessTest) { func testRemoteForceCloseBeforeTimeoutSimpleTaproot(ht *lntest.HarnessTest) { c := lnrpc.CommitmentType_SIMPLE_TAPROOT - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Create a three hop network: Alice -> Bob -> Carol, using simple + // taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } - // Create a three hop network: Alice -> Bob -> Carol, using - // simple taproot channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: c, - Private: true, - } + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - cfg := node.CfgSimpleTaproot - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} - runRemoteForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) - if !success { - return +// testRemoteForceCloseBeforeTimeoutLeasedZeroConf tests +// `runRemoteForceCloseBeforeHtlcTimeout` with zero-conf script enforced lease +// channel. +func testRemoteForceCloseBeforeTimeoutLeasedZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: leasedType, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Prepare Carol's node config to enable zero-conf and leased + // channel. + cfg := node.CfgLeased + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf simple taproot channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: c, - Private: true, - } - - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgSimpleTaproot - cfg = append(cfg, node.CfgZeroConf...) - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} - - runRemoteForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) + runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) } // testRemoteForceCloseBeforeTimeoutLeased tests // `runRemoteForceCloseBeforeHtlcTimeout` with script enforced lease channel. func testRemoteForceCloseBeforeTimeoutLeased(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // leased channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: leasedType, - } - - cfg := node.CfgLeased - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} - - runRemoteForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) - if !success { - return + // Create a three hop network: Alice -> Bob -> Carol, using leased + // channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: leasedType, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: leasedType, - } - - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgLeased - cfg = append(cfg, node.CfgZeroConf...) - cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) - cfgs := [][]string{cfg, cfg, cfgCarol} + cfg := node.CfgLeased + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} - runRemoteForceCloseBeforeHtlcTimeout(st, cfgs, params) - }) + runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) } // runRemoteForceCloseBeforeHtlcTimeout tests that if we extend a multi-hop @@ -1521,46 +1531,63 @@ func runRemoteForceCloseBeforeHtlcTimeout(ht *lntest.HarnessTest, ht.AssertInvoiceState(stream, lnrpc.Invoice_CANCELED) } +// testLocalClaimIncomingHTLCAnchorZeroConf tests `runLocalClaimIncomingHTLC` +// with zero-conf anchor channel. +func testLocalClaimIncomingHTLCAnchorZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: lnrpc.CommitmentType_ANCHORS, + } + + // Prepare Carol's node config to enable zero-conf and anchor. + cfg := node.CfgZeroConf + cfgs := [][]string{cfg, cfg, cfg} + + runLocalClaimIncomingHTLC(ht, cfgs, params) +} + // testLocalClaimIncomingHTLCAnchor tests `runLocalClaimIncomingHTLC` with // anchor channel. func testLocalClaimIncomingHTLCAnchor(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{Amt: chanAmt} + // Create a three hop network: Alice -> Bob -> Carol, using anchor + // channels. + // + // Prepare params. + params := lntest.OpenChannelParams{Amt: chanAmt} - cfg := node.CfgAnchor - cfgs := [][]string{cfg, cfg, cfg} + cfg := node.CfgAnchor + cfgs := [][]string{cfg, cfg, cfg} - runLocalClaimIncomingHTLC(st, cfgs, params) - }) - if !success { - return - } + runLocalClaimIncomingHTLC(ht, cfgs, params) +} - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) +// testLocalClaimIncomingHTLCSimpleTaprootZeroConf tests +// `runLocalClaimIncomingHTLC` with zero-conf simple taproot channel. +func testLocalClaimIncomingHTLCSimpleTaprootZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: lnrpc.CommitmentType_ANCHORS, - } + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } - // Prepare Carol's node config to enable zero-conf and anchor. - cfg := node.CfgZeroConf - cfgs := [][]string{cfg, cfg, cfg} + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} - runLocalClaimIncomingHTLC(st, cfgs, params) - }) + runLocalClaimIncomingHTLC(ht, cfgs, params) } // testLocalClaimIncomingHTLCSimpleTaproot tests `runLocalClaimIncomingHTLC` @@ -1568,50 +1595,20 @@ func testLocalClaimIncomingHTLCAnchor(ht *lntest.HarnessTest) { func testLocalClaimIncomingHTLCSimpleTaproot(ht *lntest.HarnessTest) { c := lnrpc.CommitmentType_SIMPLE_TAPROOT - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // simple taproot channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: c, - Private: true, - } - - cfg := node.CfgSimpleTaproot - cfgs := [][]string{cfg, cfg, cfg} - - runLocalClaimIncomingHTLC(st, cfgs, params) - }) - if !success { - return + // Create a three hop network: Alice -> Bob -> Carol, using simple + // taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf simple taproot channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: c, - Private: true, - } - - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgSimpleTaproot - cfg = append(cfg, node.CfgZeroConf...) - cfgs := [][]string{cfg, cfg, cfg} - - runLocalClaimIncomingHTLC(st, cfgs, params) - }) + runLocalClaimIncomingHTLC(ht, cfgs, params) } // runLocalClaimIncomingHTLC tests that in a multi-hop HTLC scenario, if we @@ -1885,51 +1882,44 @@ func runLocalClaimIncomingHTLC(ht *lntest.HarnessTest, ht.AssertPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED) } -// testLocalClaimIncomingHTLCLeased tests `runLocalClaimIncomingHTLCLeased` -// with script enforced lease channel. -func testLocalClaimIncomingHTLCLeased(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) +// testLocalClaimIncomingHTLCLeasedZeroConf tests +// `runLocalClaimIncomingHTLCLeased` with zero-conf script enforced lease +// channel. +func testLocalClaimIncomingHTLCLeasedZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: leasedType, + } - // Create a three hop network: Alice -> Bob -> Carol, using - // leased channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: leasedType, - } + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgLeased + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} - cfg := node.CfgLeased - cfgs := [][]string{cfg, cfg, cfg} + runLocalClaimIncomingHTLCLeased(ht, cfgs, params) +} - runLocalClaimIncomingHTLCLeased(st, cfgs, params) - }) - if !success { - return +// testLocalClaimIncomingHTLCLeased tests `runLocalClaimIncomingHTLCLeased` +// with script enforced lease channel. +func testLocalClaimIncomingHTLCLeased(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using leased + // channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: leasedType, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) + cfg := node.CfgLeased + cfgs := [][]string{cfg, cfg, cfg} - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: leasedType, - } - - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgLeased - cfg = append(cfg, node.CfgZeroConf...) - cfgs := [][]string{cfg, cfg, cfg} - - runLocalClaimIncomingHTLCLeased(st, cfgs, params) - }) + runLocalClaimIncomingHTLCLeased(ht, cfgs, params) } // runLocalClaimIncomingHTLCLeased tests that in a multi-hop HTLC scenario, if @@ -2196,46 +2186,63 @@ func runLocalClaimIncomingHTLCLeased(ht *lntest.HarnessTest, ht.AssertPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED) } +// testLocalPreimageClaimAnchorZeroConf tests `runLocalPreimageClaim` with +// zero-conf anchor channel. +func testLocalPreimageClaimAnchorZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: lnrpc.CommitmentType_ANCHORS, + } + + // Prepare Carol's node config to enable zero-conf and anchor. + cfg := node.CfgZeroConf + cfgs := [][]string{cfg, cfg, cfg} + + runLocalPreimageClaim(ht, cfgs, params) +} + // testLocalPreimageClaimAnchor tests `runLocalPreimageClaim` with anchor // channel. func testLocalPreimageClaimAnchor(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{Amt: chanAmt} + // Create a three hop network: Alice -> Bob -> Carol, using anchor + // channels. + // + // Prepare params. + params := lntest.OpenChannelParams{Amt: chanAmt} - cfg := node.CfgAnchor - cfgs := [][]string{cfg, cfg, cfg} + cfg := node.CfgAnchor + cfgs := [][]string{cfg, cfg, cfg} - runLocalPreimageClaim(st, cfgs, params) - }) - if !success { - return - } + runLocalPreimageClaim(ht, cfgs, params) +} - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) +// testLocalPreimageClaimSimpleTaprootZeroConf tests +// `runLocalClaimIncomingHTLC` with zero-conf simple taproot channel. +func testLocalPreimageClaimSimpleTaprootZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: lnrpc.CommitmentType_ANCHORS, - } + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } - // Prepare Carol's node config to enable zero-conf and anchor. - cfg := node.CfgZeroConf - cfgs := [][]string{cfg, cfg, cfg} + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} - runLocalPreimageClaim(st, cfgs, params) - }) + runLocalPreimageClaim(ht, cfgs, params) } // testLocalPreimageClaimSimpleTaproot tests `runLocalClaimIncomingHTLC` with @@ -2243,50 +2250,20 @@ func testLocalPreimageClaimAnchor(ht *lntest.HarnessTest) { func testLocalPreimageClaimSimpleTaproot(ht *lntest.HarnessTest) { c := lnrpc.CommitmentType_SIMPLE_TAPROOT - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // simple taproot channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: c, - Private: true, - } - - cfg := node.CfgSimpleTaproot - cfgs := [][]string{cfg, cfg, cfg} - - runLocalPreimageClaim(st, cfgs, params) - }) - if !success { - return + // Create a three hop network: Alice -> Bob -> Carol, using simple + // taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf simple taproot channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: c, - Private: true, - } - - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgSimpleTaproot - cfg = append(cfg, node.CfgZeroConf...) - cfgs := [][]string{cfg, cfg, cfg} + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} - runLocalPreimageClaim(st, cfgs, params) - }) + runLocalPreimageClaim(ht, cfgs, params) } // runLocalPreimageClaim tests that in the multi-hop HTLC scenario, if the @@ -2564,51 +2541,43 @@ func runLocalPreimageClaim(ht *lntest.HarnessTest, ht.AssertPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED) } -// testLocalPreimageClaimLeased tests `runLocalPreimageClaim` with script -// enforced lease channel. -func testLocalPreimageClaimLeased(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) +// testLocalPreimageClaimLeasedZeroConf tests `runLocalPreimageClaim` with +// zero-conf script enforced lease channel. +func testLocalPreimageClaimLeasedZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: leasedType, + } - // Create a three hop network: Alice -> Bob -> Carol, using - // leased channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: leasedType, - } + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgLeased + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} - cfg := node.CfgLeased - cfgs := [][]string{cfg, cfg, cfg} + runLocalPreimageClaimLeased(ht, cfgs, params) +} - runLocalPreimageClaimLeased(st, cfgs, params) - }) - if !success { - return +// testLocalPreimageClaimLeased tests `runLocalPreimageClaim` with script +// enforced lease channel. +func testLocalPreimageClaimLeased(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using leased + // channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: leasedType, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) + cfg := node.CfgLeased + cfgs := [][]string{cfg, cfg, cfg} - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: leasedType, - } - - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgLeased - cfg = append(cfg, node.CfgZeroConf...) - cfgs := [][]string{cfg, cfg, cfg} - - runLocalPreimageClaimLeased(st, cfgs, params) - }) + runLocalPreimageClaimLeased(ht, cfgs, params) } // runLocalPreimageClaimLeased tests that in the multi-hop HTLC scenario, if @@ -2862,45 +2831,62 @@ func runLocalPreimageClaimLeased(ht *lntest.HarnessTest, ht.AssertNumPendingForceClose(bob, 0) } +// testHtlcAggregaitonAnchor tests `runHtlcAggregation` with zero-conf anchor +// channel. +func testHtlcAggregaitonAnchorZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: lnrpc.CommitmentType_ANCHORS, + } + + // Prepare Carol's node config to enable zero-conf and anchor. + cfg := node.CfgZeroConf + cfgs := [][]string{cfg, cfg, cfg} + + runHtlcAggregation(ht, cfgs, params) +} + // testHtlcAggregaitonAnchor tests `runHtlcAggregation` with anchor channel. func testHtlcAggregaitonAnchor(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{Amt: chanAmt} + // Create a three hop network: Alice -> Bob -> Carol, using anchor + // channels. + // + // Prepare params. + params := lntest.OpenChannelParams{Amt: chanAmt} - cfg := node.CfgAnchor - cfgs := [][]string{cfg, cfg, cfg} + cfg := node.CfgAnchor + cfgs := [][]string{cfg, cfg, cfg} - runHtlcAggregation(st, cfgs, params) - }) - if !success { - return - } + runHtlcAggregation(ht, cfgs, params) +} - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) +// testHtlcAggregaitonSimpleTaprootZeroConf tests `runHtlcAggregation` with +// zero-conf simple taproot channel. +func testHtlcAggregaitonSimpleTaprootZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: lnrpc.CommitmentType_ANCHORS, - } + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } - // Prepare Carol's node config to enable zero-conf and anchor. - cfg := node.CfgZeroConf - cfgs := [][]string{cfg, cfg, cfg} + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} - runHtlcAggregation(st, cfgs, params) - }) + runHtlcAggregation(ht, cfgs, params) } // testHtlcAggregaitonSimpleTaproot tests `runHtlcAggregation` with simple @@ -2908,97 +2894,59 @@ func testHtlcAggregaitonAnchor(ht *lntest.HarnessTest) { func testHtlcAggregaitonSimpleTaproot(ht *lntest.HarnessTest) { c := lnrpc.CommitmentType_SIMPLE_TAPROOT - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) + // Create a three hop network: Alice -> Bob -> Carol, using simple + // taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } - // Create a three hop network: Alice -> Bob -> Carol, using - // simple taproot channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: c, - Private: true, - } + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} - cfg := node.CfgSimpleTaproot - cfgs := [][]string{cfg, cfg, cfg} + runHtlcAggregation(ht, cfgs, params) +} - runHtlcAggregation(st, cfgs, params) - }) - if !success { - return +// testHtlcAggregaitonLeasedZeroConf tests `runHtlcAggregation` with zero-conf +// script enforced lease channel. +func testHtlcAggregaitonLeasedZeroConf(ht *lntest.HarnessTest) { + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // anchor channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: leasedType, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf simple taproot channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: c, - Private: true, - } - - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgSimpleTaproot - cfg = append(cfg, node.CfgZeroConf...) - cfgs := [][]string{cfg, cfg, cfg} + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgLeased + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} - runHtlcAggregation(st, cfgs, params) - }) + runHtlcAggregation(ht, cfgs, params) } // testHtlcAggregaitonLeased tests `runHtlcAggregation` with script enforced // lease channel. func testHtlcAggregaitonLeased(ht *lntest.HarnessTest) { - success := ht.Run("no zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // leased channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - CommitmentType: leasedType, - } - - cfg := node.CfgLeased - cfgs := [][]string{cfg, cfg, cfg} - - runHtlcAggregation(st, cfgs, params) - }) - if !success { - return + // Create a three hop network: Alice -> Bob -> Carol, using leased + // channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: leasedType, } - ht.Run("zero conf", func(t *testing.T) { - st := ht.Subtest(t) - - // Create a three hop network: Alice -> Bob -> Carol, using - // zero-conf anchor channels. - // - // Prepare params. - params := lntest.OpenChannelParams{ - Amt: chanAmt, - ZeroConf: true, - CommitmentType: leasedType, - } - - // Prepare Carol's node config to enable zero-conf and leased - // channel. - cfg := node.CfgLeased - cfg = append(cfg, node.CfgZeroConf...) - cfgs := [][]string{cfg, cfg, cfg} + cfg := node.CfgLeased + cfgs := [][]string{cfg, cfg, cfg} - runHtlcAggregation(st, cfgs, params) - }) + runHtlcAggregation(ht, cfgs, params) } // runHtlcAggregation tests that in a multi-hop HTLC scenario, if we force From 21c5d36812625b7977a07ebc044887f0672dbcc1 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 9 Nov 2024 00:37:50 +0800 Subject: [PATCH 38/64] itest: break down scid alias channel update tests --- itest/list_on_test.go | 5 +- itest/lnd_zero_conf_test.go | 116 +++++++++++++++++++----------------- 2 files changed, 62 insertions(+), 59 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 218471e027..aaa21fe2fa 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -448,10 +448,6 @@ var allTestCases = []*lntest.TestCase{ Name: "option scid alias", TestFunc: testOptionScidAlias, }, - { - Name: "scid alias channel update", - TestFunc: testUpdateChannelPolicyScidAlias, - }, { Name: "scid alias upgrade", TestFunc: testOptionScidUpgrade, @@ -686,4 +682,5 @@ func init() { allTestCases = append(allTestCases, remoteSignerTestCases...) allTestCases = append(allTestCases, channelRestoreTestCases...) allTestCases = append(allTestCases, fundUtxoSelectionTestCases...) + allTestCases = append(allTestCases, zeroConfPolicyTestCases...) } diff --git a/itest/lnd_zero_conf_test.go b/itest/lnd_zero_conf_test.go index c7f4c59a78..5b87846be5 100644 --- a/itest/lnd_zero_conf_test.go +++ b/itest/lnd_zero_conf_test.go @@ -19,6 +19,67 @@ import ( "github.com/stretchr/testify/require" ) +// zeroConfPolicyTestCases checks that option-scid-alias, zero-conf +// channel-types, and option-scid-alias feature-bit-only channels have the +// expected graph and that payments work when updating the channel policy. +var zeroConfPolicyTestCases = []*lntest.TestCase{ + { + Name: "channel policy update private", + TestFunc: func(ht *lntest.HarnessTest) { + // zeroConf: false + // scidAlias: false + // private: true + testPrivateUpdateAlias( + ht, false, false, true, + ) + }, + }, + { + Name: "channel policy update private scid alias", + TestFunc: func(ht *lntest.HarnessTest) { + // zeroConf: false + // scidAlias: true + // private: true + testPrivateUpdateAlias( + ht, false, true, true, + ) + }, + }, + { + Name: "channel policy update private zero conf", + TestFunc: func(ht *lntest.HarnessTest) { + // zeroConf: true + // scidAlias: false + // private: true + testPrivateUpdateAlias( + ht, true, false, true, + ) + }, + }, + { + Name: "channel policy update public zero conf", + TestFunc: func(ht *lntest.HarnessTest) { + // zeroConf: true + // scidAlias: false + // private: false + testPrivateUpdateAlias( + ht, true, false, false, + ) + }, + }, + { + Name: "channel policy update public", + TestFunc: func(ht *lntest.HarnessTest) { + // zeroConf: false + // scidAlias: false + // private: false + testPrivateUpdateAlias( + ht, false, false, false, + ) + }, + }, +} + // testZeroConfChannelOpen tests that opening a zero-conf channel works and // sending payments also works. func testZeroConfChannelOpen(ht *lntest.HarnessTest) { @@ -395,61 +456,6 @@ func waitForZeroConfGraphChange(hn *node.HarnessNode, }, defaultTimeout) } -// testUpdateChannelPolicyScidAlias checks that option-scid-alias, zero-conf -// channel-types, and option-scid-alias feature-bit-only channels have the -// expected graph and that payments work when updating the channel policy. -func testUpdateChannelPolicyScidAlias(ht *lntest.HarnessTest) { - tests := []struct { - name string - - // The option-scid-alias channel type. - scidAliasType bool - - // The zero-conf channel type. - zeroConf bool - - private bool - }{ - { - name: "private scid-alias chantype update", - scidAliasType: true, - private: true, - }, - { - name: "private zero-conf update", - zeroConf: true, - private: true, - }, - { - name: "public zero-conf update", - zeroConf: true, - }, - { - name: "public no-chan-type update", - }, - { - name: "private no-chan-type update", - private: true, - }, - } - - for _, test := range tests { - test := test - - success := ht.Run(test.name, func(t *testing.T) { - st := ht.Subtest(t) - - testPrivateUpdateAlias( - st, test.zeroConf, test.scidAliasType, - test.private, - ) - }) - if !success { - return - } - } -} - func testPrivateUpdateAlias(ht *lntest.HarnessTest, zeroConf, scidAliasType, private bool) { From 3319d0d98309a2cb1cfcc47496a63b3ccec605f0 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 9 Nov 2024 00:55:54 +0800 Subject: [PATCH 39/64] itest: break down open channel fee policy --- itest/list_on_test.go | 5 +- itest/lnd_open_channel_test.go | 407 +++++++++++++++++++++------------ 2 files changed, 268 insertions(+), 144 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index aaa21fe2fa..0f6fa41ffc 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -512,10 +512,6 @@ var allTestCases = []*lntest.TestCase{ Name: "trackpayments compatible", TestFunc: testTrackPaymentsCompatible, }, - { - Name: "open channel fee policy", - TestFunc: testOpenChannelUpdateFeePolicy, - }, { Name: "custom message", TestFunc: testCustomMessage, @@ -683,4 +679,5 @@ func init() { allTestCases = append(allTestCases, channelRestoreTestCases...) allTestCases = append(allTestCases, fundUtxoSelectionTestCases...) allTestCases = append(allTestCases, zeroConfPolicyTestCases...) + allTestCases = append(allTestCases, channelFeePolicyTestCases...) } diff --git a/itest/lnd_open_channel_test.go b/itest/lnd_open_channel_test.go index 3142e09eb2..9d51fc5635 100644 --- a/itest/lnd_open_channel_test.go +++ b/itest/lnd_open_channel_test.go @@ -3,7 +3,6 @@ package itest import ( "fmt" "strings" - "testing" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -18,6 +17,31 @@ import ( "github.com/stretchr/testify/require" ) +// channelFeePolicyTestCases defines a set of tests to check the update channel +// policy fee behavior. +var channelFeePolicyTestCases = []*lntest.TestCase{ + { + Name: "channel fee policy default", + TestFunc: testChannelFeePolicyDefault, + }, + { + Name: "channel fee policy base fee", + TestFunc: testChannelFeePolicyBaseFee, + }, + { + Name: "channel fee policy fee rate", + TestFunc: testChannelFeePolicyFeeRate, + }, + { + Name: "channel fee policy base fee and fee rate", + TestFunc: testChannelFeePolicyBaseFeeAndFeeRate, + }, + { + Name: "channel fee policy low base fee and fee rate", + TestFunc: testChannelFeePolicyLowBaseFeeAndFeeRate, + }, +} + // testOpenChannelAfterReorg tests that in the case where we have an open // channel where the funding tx gets reorged out, the channel will no // longer be present in the node's routing table. @@ -123,32 +147,103 @@ func testOpenChannelAfterReorg(ht *lntest.HarnessTest) { ht.AssertTxInBlock(block, *fundingTxID) } -// testOpenChannelFeePolicy checks if different channel fee scenarios are -// correctly handled when the optional channel fee parameters baseFee and -// feeRate are provided. If the OpenChannelRequest is not provided with a value -// for baseFee/feeRate the expectation is that the default baseFee/feeRate is -// applied. -// -// 1. No params provided to OpenChannelRequest: -// ChannelUpdate --> defaultBaseFee, defaultFeeRate -// 2. Only baseFee provided to OpenChannelRequest: -// ChannelUpdate --> provided baseFee, defaultFeeRate -// 3. Only feeRate provided to OpenChannelRequest: -// ChannelUpdate --> defaultBaseFee, provided FeeRate -// 4. baseFee and feeRate provided to OpenChannelRequest: -// ChannelUpdate --> provided baseFee, provided feeRate -// 5. Both baseFee and feeRate are set to a value lower than the default: -// ChannelUpdate --> provided baseFee, provided feeRate -func testOpenChannelUpdateFeePolicy(ht *lntest.HarnessTest) { +// testChannelFeePolicyDefault check when no params provided to +// OpenChannelRequest: ChannelUpdate --> defaultBaseFee, defaultFeeRate. +func testChannelFeePolicyDefault(ht *lntest.HarnessTest) { + const ( + defaultBaseFee = 1000 + defaultFeeRate = 1 + defaultTimeLockDelta = chainreg.DefaultBitcoinTimeLockDelta + defaultMinHtlc = 1000 + ) + + defaultMaxHtlc := lntest.CalculateMaxHtlc(funding.MaxBtcFundingAmount) + + chanAmt := funding.MaxBtcFundingAmount + pushAmt := chanAmt / 2 + + feeScenario := lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + UseBaseFee: false, + UseFeeRate: false, + } + + expectedPolicy := lnrpc.RoutingPolicy{ + FeeBaseMsat: defaultBaseFee, + FeeRateMilliMsat: defaultFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, + } + + bobExpectedPolicy := lnrpc.RoutingPolicy{ + FeeBaseMsat: defaultBaseFee, + FeeRateMilliMsat: defaultFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, + } + + runChannelFeePolicyTest( + ht, feeScenario, &expectedPolicy, &bobExpectedPolicy, + ) +} + +// testChannelFeePolicyBaseFee checks only baseFee provided to +// OpenChannelRequest: ChannelUpdate --> provided baseFee, defaultFeeRate. +func testChannelFeePolicyBaseFee(ht *lntest.HarnessTest) { const ( defaultBaseFee = 1000 defaultFeeRate = 1 defaultTimeLockDelta = chainreg.DefaultBitcoinTimeLockDelta defaultMinHtlc = 1000 optionalBaseFee = 1337 + ) + + defaultMaxHtlc := lntest.CalculateMaxHtlc(funding.MaxBtcFundingAmount) + + chanAmt := funding.MaxBtcFundingAmount + pushAmt := chanAmt / 2 + + feeScenario := lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + BaseFee: optionalBaseFee, + UseBaseFee: true, + UseFeeRate: false, + } + + expectedPolicy := lnrpc.RoutingPolicy{ + FeeBaseMsat: optionalBaseFee, + FeeRateMilliMsat: defaultFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, + } + + bobExpectedPolicy := lnrpc.RoutingPolicy{ + FeeBaseMsat: defaultBaseFee, + FeeRateMilliMsat: defaultFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, + } + + runChannelFeePolicyTest( + ht, feeScenario, &expectedPolicy, &bobExpectedPolicy, + ) +} + +// testChannelFeePolicyFeeRate checks if only feeRate provided to +// OpenChannelRequest: ChannelUpdate --> defaultBaseFee, provided FeeRate. +func testChannelFeePolicyFeeRate(ht *lntest.HarnessTest) { + const ( + defaultBaseFee = 1000 + defaultFeeRate = 1 + defaultTimeLockDelta = chainreg.DefaultBitcoinTimeLockDelta + defaultMinHtlc = 1000 optionalFeeRate = 1337 - lowBaseFee = 0 - lowFeeRate = 900 ) defaultMaxHtlc := lntest.CalculateMaxHtlc(funding.MaxBtcFundingAmount) @@ -156,81 +251,20 @@ func testOpenChannelUpdateFeePolicy(ht *lntest.HarnessTest) { chanAmt := funding.MaxBtcFundingAmount pushAmt := chanAmt / 2 - feeScenarios := []lntest.OpenChannelParams{ - { - Amt: chanAmt, - PushAmt: pushAmt, - UseBaseFee: false, - UseFeeRate: false, - }, - { - Amt: chanAmt, - PushAmt: pushAmt, - BaseFee: optionalBaseFee, - UseBaseFee: true, - UseFeeRate: false, - }, - { - Amt: chanAmt, - PushAmt: pushAmt, - FeeRate: optionalFeeRate, - UseBaseFee: false, - UseFeeRate: true, - }, - { - Amt: chanAmt, - PushAmt: pushAmt, - BaseFee: optionalBaseFee, - FeeRate: optionalFeeRate, - UseBaseFee: true, - UseFeeRate: true, - }, - { - Amt: chanAmt, - PushAmt: pushAmt, - BaseFee: lowBaseFee, - FeeRate: lowFeeRate, - UseBaseFee: true, - UseFeeRate: true, - }, + feeScenario := lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + FeeRate: optionalFeeRate, + UseBaseFee: false, + UseFeeRate: true, } - expectedPolicies := []lnrpc.RoutingPolicy{ - { - FeeBaseMsat: defaultBaseFee, - FeeRateMilliMsat: defaultFeeRate, - TimeLockDelta: defaultTimeLockDelta, - MinHtlc: defaultMinHtlc, - MaxHtlcMsat: defaultMaxHtlc, - }, - { - FeeBaseMsat: optionalBaseFee, - FeeRateMilliMsat: defaultFeeRate, - TimeLockDelta: defaultTimeLockDelta, - MinHtlc: defaultMinHtlc, - MaxHtlcMsat: defaultMaxHtlc, - }, - { - FeeBaseMsat: defaultBaseFee, - FeeRateMilliMsat: optionalFeeRate, - TimeLockDelta: defaultTimeLockDelta, - MinHtlc: defaultMinHtlc, - MaxHtlcMsat: defaultMaxHtlc, - }, - { - FeeBaseMsat: optionalBaseFee, - FeeRateMilliMsat: optionalFeeRate, - TimeLockDelta: defaultTimeLockDelta, - MinHtlc: defaultMinHtlc, - MaxHtlcMsat: defaultMaxHtlc, - }, - { - FeeBaseMsat: lowBaseFee, - FeeRateMilliMsat: lowFeeRate, - TimeLockDelta: defaultTimeLockDelta, - MinHtlc: defaultMinHtlc, - MaxHtlcMsat: defaultMaxHtlc, - }, + expectedPolicy := lnrpc.RoutingPolicy{ + FeeBaseMsat: defaultBaseFee, + FeeRateMilliMsat: optionalFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, } bobExpectedPolicy := lnrpc.RoutingPolicy{ @@ -241,65 +275,158 @@ func testOpenChannelUpdateFeePolicy(ht *lntest.HarnessTest) { MaxHtlcMsat: defaultMaxHtlc, } - runTestCase := func(ht *lntest.HarnessTest, - chanParams lntest.OpenChannelParams, - alicePolicy, bobPolicy *lnrpc.RoutingPolicy) { + runChannelFeePolicyTest( + ht, feeScenario, &expectedPolicy, &bobExpectedPolicy, + ) +} - // In this basic test, we'll need a third node, Carol, so we - // can forward a payment through the channel we'll open with - // the different fee policies. - alice := ht.NewNodeWithCoins("Alice", nil) - bob := ht.NewNode("Bob", nil) - carol := ht.NewNodeWithCoins("Carol", nil) +// testChannelFeePolicyBaseFeeAndFeeRate checks if baseFee and feeRate provided +// to OpenChannelRequest: ChannelUpdate --> provided baseFee, provided feeRate. +func testChannelFeePolicyBaseFeeAndFeeRate(ht *lntest.HarnessTest) { + const ( + defaultBaseFee = 1000 + defaultFeeRate = 1 + defaultTimeLockDelta = chainreg.DefaultBitcoinTimeLockDelta + defaultMinHtlc = 1000 + optionalBaseFee = 1337 + optionalFeeRate = 1337 + ) - ht.EnsureConnected(alice, bob) - ht.EnsureConnected(alice, carol) + defaultMaxHtlc := lntest.CalculateMaxHtlc(funding.MaxBtcFundingAmount) - nodes := []*node.HarnessNode{alice, bob, carol} + chanAmt := funding.MaxBtcFundingAmount + pushAmt := chanAmt / 2 - // Create a channel Alice->Bob. - chanPoint := ht.OpenChannel(alice, bob, chanParams) + feeScenario := lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + BaseFee: optionalBaseFee, + FeeRate: optionalFeeRate, + UseBaseFee: true, + UseFeeRate: true, + } - // Create a channel Carol->Alice. - ht.OpenChannel( - carol, alice, lntest.OpenChannelParams{ - Amt: 500000, - }, - ) + expectedPolicy := lnrpc.RoutingPolicy{ + FeeBaseMsat: optionalBaseFee, + FeeRateMilliMsat: optionalFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, + } - // Alice and Bob should see each other's ChannelUpdates, - // advertising the preferred routing policies. - assertNodesPolicyUpdate( - ht, nodes, alice, alicePolicy, chanPoint, - ) - assertNodesPolicyUpdate(ht, nodes, bob, bobPolicy, chanPoint) + bobExpectedPolicy := lnrpc.RoutingPolicy{ + FeeBaseMsat: defaultBaseFee, + FeeRateMilliMsat: defaultFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, + } - // They should now know about the default policies. - for _, n := range nodes { - ht.AssertChannelPolicy( - n, alice.PubKeyStr, alicePolicy, chanPoint, - ) - ht.AssertChannelPolicy( - n, bob.PubKeyStr, bobPolicy, chanPoint, - ) - } + runChannelFeePolicyTest( + ht, feeScenario, &expectedPolicy, &bobExpectedPolicy, + ) +} + +// testChannelFeePolicyLowBaseFeeAndFeeRate checks if both baseFee and feeRate +// are set to a value lower than the default: ChannelUpdate --> provided +// baseFee, provided feeRate. +func testChannelFeePolicyLowBaseFeeAndFeeRate(ht *lntest.HarnessTest) { + const ( + defaultBaseFee = 1000 + defaultFeeRate = 1 + defaultTimeLockDelta = chainreg.DefaultBitcoinTimeLockDelta + defaultMinHtlc = 1000 + lowBaseFee = 0 + lowFeeRate = 900 + ) - // We should be able to forward a payment from Carol to Bob - // through the new channel we opened. - payReqs, _, _ := ht.CreatePayReqs(bob, paymentAmt, 1) - ht.CompletePaymentRequests(carol, payReqs) + defaultMaxHtlc := lntest.CalculateMaxHtlc(funding.MaxBtcFundingAmount) + + chanAmt := funding.MaxBtcFundingAmount + pushAmt := chanAmt / 2 + + feeScenario := lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + BaseFee: lowBaseFee, + FeeRate: lowFeeRate, + UseBaseFee: true, + UseFeeRate: true, } - for i, feeScenario := range feeScenarios { - ht.Run(fmt.Sprintf("%d", i), func(t *testing.T) { - st := ht.Subtest(t) + expectedPolicy := lnrpc.RoutingPolicy{ + FeeBaseMsat: lowBaseFee, + FeeRateMilliMsat: lowFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, + } - runTestCase( - st, feeScenario, - &expectedPolicies[i], &bobExpectedPolicy, - ) - }) + bobExpectedPolicy := lnrpc.RoutingPolicy{ + FeeBaseMsat: defaultBaseFee, + FeeRateMilliMsat: defaultFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, } + + runChannelFeePolicyTest( + ht, feeScenario, &expectedPolicy, &bobExpectedPolicy, + ) +} + +// runChannelFeePolicyTest checks if different channel fee scenarios are +// correctly handled when the optional channel fee parameters baseFee and +// feeRate are provided. If the OpenChannelRequest is not provided with a value +// for baseFee/feeRate the expectation is that the default baseFee/feeRate is +// applied. +func runChannelFeePolicyTest(ht *lntest.HarnessTest, + chanParams lntest.OpenChannelParams, + alicePolicy, bobPolicy *lnrpc.RoutingPolicy) { + + // In this basic test, we'll need a third node, Carol, so we can + // forward a payment through the channel we'll open with the different + // fee policies. + alice := ht.NewNodeWithCoins("Alice", nil) + bob := ht.NewNode("Bob", nil) + carol := ht.NewNodeWithCoins("Carol", nil) + + ht.EnsureConnected(alice, bob) + ht.EnsureConnected(alice, carol) + + nodes := []*node.HarnessNode{alice, bob, carol} + + // Create a channel Alice->Bob. + chanPoint := ht.OpenChannel(alice, bob, chanParams) + + // Create a channel Carol->Alice. + ht.OpenChannel( + carol, alice, lntest.OpenChannelParams{ + Amt: 500000, + }, + ) + + // Alice and Bob should see each other's ChannelUpdates, advertising + // the preferred routing policies. + assertNodesPolicyUpdate( + ht, nodes, alice, alicePolicy, chanPoint, + ) + assertNodesPolicyUpdate(ht, nodes, bob, bobPolicy, chanPoint) + + // They should now know about the default policies. + for _, n := range nodes { + ht.AssertChannelPolicy( + n, alice.PubKeyStr, alicePolicy, chanPoint, + ) + ht.AssertChannelPolicy( + n, bob.PubKeyStr, bobPolicy, chanPoint, + ) + } + + // We should be able to forward a payment from Carol to Bob + // through the new channel we opened. + payReqs, _, _ := ht.CreatePayReqs(bob, paymentAmt, 1) + ht.CompletePaymentRequests(carol, payReqs) } // testBasicChannelCreationAndUpdates tests multiple channel opening and From 7b1427a5657fb828d46e013d466025814e56670a Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 9 Nov 2024 00:59:15 +0800 Subject: [PATCH 40/64] itest: break down payment failed tests --- itest/list_on_test.go | 8 +++++++ itest/lnd_payment_test.go | 50 +++++++++++++++++++-------------------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 0f6fa41ffc..040fea1b69 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -648,6 +648,10 @@ var allTestCases = []*lntest.TestCase{ Name: "payment failed htlc local swept", TestFunc: testPaymentFailedHTLCLocalSwept, }, + { + Name: "payment failed htlc local swept resumed", + TestFunc: testPaymentFailedHTLCLocalSweptResumed, + }, { Name: "payment succeeded htlc remote swept", TestFunc: testPaymentSucceededHTLCRemoteSwept, @@ -656,6 +660,10 @@ var allTestCases = []*lntest.TestCase{ Name: "send to route failed htlc timeout", TestFunc: testSendToRouteFailHTLCTimeout, }, + { + Name: "send to route failed htlc timeout resumed", + TestFunc: testSendToRouteFailHTLCTimeoutResumed, + }, { Name: "debuglevel show", TestFunc: testDebuglevelShow, diff --git a/itest/lnd_payment_test.go b/itest/lnd_payment_test.go index 8f9b2bc748..72a2c16030 100644 --- a/itest/lnd_payment_test.go +++ b/itest/lnd_payment_test.go @@ -179,21 +179,19 @@ func testPaymentSucceededHTLCRemoteSwept(ht *lntest.HarnessTest) { // out and claimed onchain via the timeout path, the payment will be marked as // failed. This test creates a topology from Alice -> Bob, and let Alice send // payments to Bob. Bob then goes offline, such that Alice's outgoing HTLC will -// time out. Alice will also be restarted to make sure resumed payments are -// also marked as failed. +// time out. func testPaymentFailedHTLCLocalSwept(ht *lntest.HarnessTest) { - success := ht.Run("fail payment", func(t *testing.T) { - st := ht.Subtest(t) - runTestPaymentHTLCTimeout(st, false) - }) - if !success { - return - } + runTestPaymentHTLCTimeout(ht, false) +} - ht.Run("fail resumed payment", func(t *testing.T) { - st := ht.Subtest(t) - runTestPaymentHTLCTimeout(st, true) - }) +// testPaymentFailedHTLCLocalSweptResumed checks that when an outgoing HTLC is +// timed out and claimed onchain via the timeout path, the payment will be +// marked as failed. This test creates a topology from Alice -> Bob, and let +// Alice send payments to Bob. Bob then goes offline, such that Alice's +// outgoing HTLC will time out. Alice will be restarted to make sure resumed +// payments are also marked as failed. +func testPaymentFailedHTLCLocalSweptResumed(ht *lntest.HarnessTest) { + runTestPaymentHTLCTimeout(ht, true) } // runTestPaymentHTLCTimeout is the helper function that actually runs the @@ -1181,21 +1179,21 @@ func sendPaymentInterceptAndCancel(ht *lntest.HarnessTest, // out and claimed onchain via the timeout path, the payment will be marked as // failed. This test creates a topology from Alice -> Bob, and let Alice send // payments to Bob. Bob then goes offline, such that Alice's outgoing HTLC will -// time out. Alice will also be restarted to make sure resumed payments are -// also marked as failed. +// time out. func testSendToRouteFailHTLCTimeout(ht *lntest.HarnessTest) { - success := ht.Run("fail payment", func(t *testing.T) { - st := ht.Subtest(t) - runSendToRouteFailHTLCTimeout(st, false) - }) - if !success { - return - } + runSendToRouteFailHTLCTimeout(ht, false) +} - ht.Run("fail resumed payment", func(t *testing.T) { - st := ht.Subtest(t) - runTestPaymentHTLCTimeout(st, true) - }) +// testSendToRouteFailHTLCTimeout is similar to +// testPaymentFailedHTLCLocalSwept. The only difference is the `SendPayment` is +// replaced with `SendToRouteV2`. It checks that when an outgoing HTLC is timed +// out and claimed onchain via the timeout path, the payment will be marked as +// failed. This test creates a topology from Alice -> Bob, and let Alice send +// payments to Bob. Bob then goes offline, such that Alice's outgoing HTLC will +// time out. Alice will be restarted to make sure resumed payments are also +// marked as failed. +func testSendToRouteFailHTLCTimeoutResumed(ht *lntest.HarnessTest) { + runTestPaymentHTLCTimeout(ht, true) } // runSendToRouteFailHTLCTimeout is the helper function that actually runs the From 31aada65a42cb2cbffdf12d1f4e4fd0d6ac6524f Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 9 Nov 2024 01:12:49 +0800 Subject: [PATCH 41/64] itest: break down channel backup restore tests --- itest/list_on_test.go | 4 - itest/lnd_channel_backup_test.go | 351 +++++++++++++++---------------- 2 files changed, 168 insertions(+), 187 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 040fea1b69..6ded67143b 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -19,10 +19,6 @@ var allTestCases = []*lntest.TestCase{ Name: "external channel funding", TestFunc: testExternalFundingChanPoint, }, - { - Name: "channel backup restore basic", - TestFunc: testChannelBackupRestoreBasic, - }, { Name: "channel backup restore unconfirmed", TestFunc: testChannelBackupRestoreUnconfirmed, diff --git a/itest/lnd_channel_backup_test.go b/itest/lnd_channel_backup_test.go index abbec76be5..72861f9ce1 100644 --- a/itest/lnd_channel_backup_test.go +++ b/itest/lnd_channel_backup_test.go @@ -85,6 +85,26 @@ var channelRestoreTestCases = []*lntest.TestCase{ ) }, }, + { + Name: "channel backup restore from rpc", + TestFunc: testChannelBackupRestoreFromRPC, + }, + { + Name: "channel backup restore from file", + TestFunc: testChannelBackupRestoreFromFile, + }, + { + Name: "channel backup restore during creation", + TestFunc: testChannelBackupRestoreDuringCreation, + }, + { + Name: "channel backup restore during unlock", + TestFunc: testChannelBackupRestoreDuringUnlock, + }, + { + Name: "channel backup restore twice", + TestFunc: testChannelBackupRestoreTwice, + }, } type ( @@ -298,202 +318,167 @@ func (c *chanRestoreScenario) testScenario(ht *lntest.HarnessTest, ) } -// testChannelBackupRestore tests that we're able to recover from, and initiate -// the DLP protocol via: the RPC restore command, restoring on unlock, and -// restoring from initial wallet creation. We'll also alternate between -// restoring form the on disk file, and restoring from the exported RPC command -// as well. -func testChannelBackupRestoreBasic(ht *lntest.HarnessTest) { - var testCases = []struct { - name string - restoreMethod restoreMethodType - }{ - // Restore from backups obtained via the RPC interface. Dave - // was the initiator, of the non-advertised channel. - { - name: "restore from RPC backup", - restoreMethod: func(st *lntest.HarnessTest, - oldNode *node.HarnessNode, - backupFilePath string, - password []byte, - mnemonic []string) nodeRestorer { - - // For this restoration method, we'll grab the - // current multi-channel backup from the old - // node, and use it to restore a new node - // within the closure. - chanBackup := oldNode.RPC.ExportAllChanBackups() - - multi := chanBackup.MultiChanBackup. - MultiChanBackup - - // In our nodeRestorer function, we'll restore - // the node from seed, then manually recover - // the channel backup. - return chanRestoreViaRPC( - st, password, mnemonic, multi, - ) - }, - }, +// testChannelBackupRestoreFromRPC tests that we're able to recover from, and +// initiate the DLP protocol via the RPC restore command. +func testChannelBackupRestoreFromRPC(ht *lntest.HarnessTest) { + // Restore from backups obtained via the RPC interface. Dave was the + // initiator, of the non-advertised channel. + restoreMethod := func(st *lntest.HarnessTest, oldNode *node.HarnessNode, + backupFilePath string, password []byte, + mnemonic []string) nodeRestorer { - // Restore the backup from the on-disk file, using the RPC - // interface. - { - name: "restore from backup file", - restoreMethod: func(st *lntest.HarnessTest, - oldNode *node.HarnessNode, - backupFilePath string, - password []byte, - mnemonic []string) nodeRestorer { - - // Read the entire Multi backup stored within - // this node's channel.backup file. - multi, err := os.ReadFile(backupFilePath) - require.NoError(st, err) - - // Now that we have Dave's backup file, we'll - // create a new nodeRestorer that will restore - // using the on-disk channel.backup. - return chanRestoreViaRPC( - st, password, mnemonic, multi, - ) - }, - }, + // For this restoration method, we'll grab the current + // multi-channel backup from the old node, and use it to + // restore a new node within the closure. + chanBackup := oldNode.RPC.ExportAllChanBackups() - // Restore the backup as part of node initialization with the - // prior mnemonic and new backup seed. - { - name: "restore during creation", - restoreMethod: func(st *lntest.HarnessTest, - oldNode *node.HarnessNode, - backupFilePath string, - password []byte, - mnemonic []string) nodeRestorer { - - // First, fetch the current backup state as is, - // to obtain our latest Multi. - chanBackup := oldNode.RPC.ExportAllChanBackups() - backupSnapshot := &lnrpc.ChanBackupSnapshot{ - MultiChanBackup: chanBackup. - MultiChanBackup, - } + multi := chanBackup.MultiChanBackup. + MultiChanBackup - // Create a new nodeRestorer that will restore - // the node using the Multi backup we just - // obtained above. - return func() *node.HarnessNode { - return st.RestoreNodeWithSeed( - "dave", nil, password, mnemonic, - "", revocationWindow, - backupSnapshot, - ) - } - }, - }, + // In our nodeRestorer function, we'll restore the node from + // seed, then manually recover the channel backup. + return chanRestoreViaRPC( + st, password, mnemonic, multi, + ) + } - // Restore the backup once the node has already been - // re-created, using the Unlock call. - { - name: "restore during unlock", - restoreMethod: func(st *lntest.HarnessTest, - oldNode *node.HarnessNode, - backupFilePath string, - password []byte, - mnemonic []string) nodeRestorer { - - // First, fetch the current backup state as is, - // to obtain our latest Multi. - chanBackup := oldNode.RPC.ExportAllChanBackups() - backupSnapshot := &lnrpc.ChanBackupSnapshot{ - MultiChanBackup: chanBackup. - MultiChanBackup, - } + runChanRestoreScenarioBasic(ht, restoreMethod) +} - // Create a new nodeRestorer that will restore - // the node with its seed, but no channel - // backup, shutdown this initialized node, then - // restart it again using Unlock. - return func() *node.HarnessNode { - newNode := st.RestoreNodeWithSeed( - "dave", nil, password, mnemonic, - "", revocationWindow, nil, - ) - st.RestartNodeWithChanBackups( - newNode, backupSnapshot, - ) - - return newNode - } - }, - }, +// testChannelBackupRestoreFromFile tests that we're able to recover from, and +// initiate the DLP protocol via the backup file. +func testChannelBackupRestoreFromFile(ht *lntest.HarnessTest) { + // Restore the backup from the on-disk file, using the RPC interface. + restoreMethod := func(st *lntest.HarnessTest, oldNode *node.HarnessNode, + backupFilePath string, password []byte, + mnemonic []string) nodeRestorer { - // Restore the backup from the on-disk file a second time to - // make sure imports can be canceled and later resumed. - { - name: "restore from backup file twice", - restoreMethod: func(st *lntest.HarnessTest, - oldNode *node.HarnessNode, - backupFilePath string, - password []byte, - mnemonic []string) nodeRestorer { - - // Read the entire Multi backup stored within - // this node's channel.backup file. - multi, err := os.ReadFile(backupFilePath) - require.NoError(st, err) - - // Now that we have Dave's backup file, we'll - // create a new nodeRestorer that will restore - // using the on-disk channel.backup. - // - //nolint:ll - backup := &lnrpc.RestoreChanBackupRequest_MultiChanBackup{ - MultiChanBackup: multi, - } + // Read the entire Multi backup stored within this node's + // channel.backup file. + multi, err := os.ReadFile(backupFilePath) + require.NoError(st, err) + + // Now that we have Dave's backup file, we'll create a new + // nodeRestorer that will restore using the on-disk + // channel.backup. + return chanRestoreViaRPC( + st, password, mnemonic, multi, + ) + } - return func() *node.HarnessNode { - newNode := st.RestoreNodeWithSeed( - "dave", nil, password, mnemonic, - "", revocationWindow, nil, - ) + runChanRestoreScenarioBasic(ht, restoreMethod) +} - req := &lnrpc.RestoreChanBackupRequest{ - Backup: backup, - } - res := newNode.RPC.RestoreChanBackups( - req, - ) - require.EqualValues( - st, 1, res.NumRestored, - ) - - req = &lnrpc.RestoreChanBackupRequest{ - Backup: backup, - } - res = newNode.RPC.RestoreChanBackups( - req, - ) - require.EqualValues( - st, 0, res.NumRestored, - ) - - return newNode - } - }, - }, +// testChannelBackupRestoreFromFile tests that we're able to recover from, and +// initiate the DLP protocol via restoring from initial wallet creation. +func testChannelBackupRestoreDuringCreation(ht *lntest.HarnessTest) { + // Restore the backup as part of node initialization with the prior + // mnemonic and new backup seed. + restoreMethod := func(st *lntest.HarnessTest, oldNode *node.HarnessNode, + backupFilePath string, password []byte, + mnemonic []string) nodeRestorer { + + // First, fetch the current backup state as is, to obtain our + // latest Multi. + chanBackup := oldNode.RPC.ExportAllChanBackups() + backupSnapshot := &lnrpc.ChanBackupSnapshot{ + MultiChanBackup: chanBackup. + MultiChanBackup, + } + + // Create a new nodeRestorer that will restore the node using + // the Multi backup we just obtained above. + return func() *node.HarnessNode { + return st.RestoreNodeWithSeed( + "dave", nil, password, mnemonic, + "", revocationWindow, + backupSnapshot, + ) + } + } + + runChanRestoreScenarioBasic(ht, restoreMethod) +} + +// testChannelBackupRestoreFromFile tests that we're able to recover from, and +// initiate the DLP protocol via restoring on unlock. +func testChannelBackupRestoreDuringUnlock(ht *lntest.HarnessTest) { + // Restore the backup once the node has already been re-created, using + // the Unlock call. + restoreMethod := func(st *lntest.HarnessTest, oldNode *node.HarnessNode, + backupFilePath string, password []byte, + mnemonic []string) nodeRestorer { + + // First, fetch the current backup state as is, to obtain our + // latest Multi. + chanBackup := oldNode.RPC.ExportAllChanBackups() + backupSnapshot := &lnrpc.ChanBackupSnapshot{ + MultiChanBackup: chanBackup. + MultiChanBackup, + } + + // Create a new nodeRestorer that will restore the node with + // its seed, but no channel backup, shutdown this initialized + // node, then restart it again using Unlock. + return func() *node.HarnessNode { + newNode := st.RestoreNodeWithSeed( + "dave", nil, password, mnemonic, + "", revocationWindow, nil, + ) + st.RestartNodeWithChanBackups( + newNode, backupSnapshot, + ) + + return newNode + } } - for _, testCase := range testCases { - tc := testCase - success := ht.Run(tc.name, func(t *testing.T) { - h := ht.Subtest(t) + runChanRestoreScenarioBasic(ht, restoreMethod) +} + +// testChannelBackupRestoreTwice tests that we're able to recover from, and +// initiate the DLP protocol twice by alternating between restoring form the on +// disk file, and restoring from the exported RPC command. +func testChannelBackupRestoreTwice(ht *lntest.HarnessTest) { + // Restore the backup from the on-disk file a second time to make sure + // imports can be canceled and later resumed. + restoreMethod := func(st *lntest.HarnessTest, oldNode *node.HarnessNode, + backupFilePath string, password []byte, + mnemonic []string) nodeRestorer { + + // Read the entire Multi backup stored within this node's + // channel.backup file. + multi, err := os.ReadFile(backupFilePath) + require.NoError(st, err) + + // Now that we have Dave's backup file, we'll create a new + // nodeRestorer that will restore using the on-disk + // channel.backup. + backup := &lnrpc.RestoreChanBackupRequest_MultiChanBackup{ + MultiChanBackup: multi, + } + + return func() *node.HarnessNode { + newNode := st.RestoreNodeWithSeed( + "dave", nil, password, mnemonic, + "", revocationWindow, nil, + ) + + req := &lnrpc.RestoreChanBackupRequest{ + Backup: backup, + } + newNode.RPC.RestoreChanBackups(req) + + req = &lnrpc.RestoreChanBackupRequest{ + Backup: backup, + } + newNode.RPC.RestoreChanBackups(req) - runChanRestoreScenarioBasic(h, tc.restoreMethod) - }) - if !success { - break + return newNode } } + + runChanRestoreScenarioBasic(ht, restoreMethod) } // runChanRestoreScenarioBasic executes a given test case from end to end, From c58fa01a664998c7b7c1f98804ccc0cb3ed57439 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 9 Nov 2024 01:19:43 +0800 Subject: [PATCH 42/64] itest: break down wallet import account tests --- itest/list_on_test.go | 5 +- itest/lnd_wallet_import_test.go | 108 +++++++++++++++----------------- 2 files changed, 50 insertions(+), 63 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 6ded67143b..a70d67f4c9 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -484,10 +484,6 @@ var allTestCases = []*lntest.TestCase{ Name: "simple taproot channel activation", TestFunc: testSimpleTaprootChannelActivation, }, - { - Name: "wallet import account", - TestFunc: testWalletImportAccount, - }, { Name: "wallet import pubkey", TestFunc: testWalletImportPubKey, @@ -684,4 +680,5 @@ func init() { allTestCases = append(allTestCases, fundUtxoSelectionTestCases...) allTestCases = append(allTestCases, zeroConfPolicyTestCases...) allTestCases = append(allTestCases, channelFeePolicyTestCases...) + allTestCases = append(allTestCases, walletImportAccountTestCases...) } diff --git a/itest/lnd_wallet_import_test.go b/itest/lnd_wallet_import_test.go index eab0f2c04f..f861390337 100644 --- a/itest/lnd_wallet_import_test.go +++ b/itest/lnd_wallet_import_test.go @@ -23,6 +23,55 @@ import ( "github.com/stretchr/testify/require" ) +// walletImportAccountTestCases tests that an imported account can fund +// transactions and channels through PSBTs, by having one node (the one with +// the imported account) craft the transactions and another node act as the +// signer. +// +//nolint:ll +var walletImportAccountTestCases = []*lntest.TestCase{ + { + Name: "wallet import account standard BIP-0044", + TestFunc: func(ht *lntest.HarnessTest) { + testWalletImportAccountScenario( + ht, walletrpc.AddressType_WITNESS_PUBKEY_HASH, + ) + }, + }, + { + Name: "wallet import account standard BIP-0049", + TestFunc: func(ht *lntest.HarnessTest) { + testWalletImportAccountScenario( + ht, walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH, + ) + }, + }, + { + Name: "wallet import account lnd BIP-0049 variant", + TestFunc: func(ht *lntest.HarnessTest) { + testWalletImportAccountScenario( + ht, walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH, + ) + }, + }, + { + Name: "wallet import account standard BIP-0084", + TestFunc: func(ht *lntest.HarnessTest) { + testWalletImportAccountScenario( + ht, walletrpc.AddressType_WITNESS_PUBKEY_HASH, + ) + }, + }, + { + Name: "wallet import account standard BIP-0086", + TestFunc: func(ht *lntest.HarnessTest) { + testWalletImportAccountScenario( + ht, walletrpc.AddressType_TAPROOT_PUBKEY, + ) + }, + }, +} + const ( defaultAccount = lnwallet.DefaultAccountName defaultImportedAccount = waddrmgr.ImportedAddrAccountName @@ -452,65 +501,6 @@ func fundChanAndCloseFromImportedAccount(ht *lntest.HarnessTest, srcNode, } } -// testWalletImportAccount tests that an imported account can fund transactions -// and channels through PSBTs, by having one node (the one with the imported -// account) craft the transactions and another node act as the signer. -func testWalletImportAccount(ht *lntest.HarnessTest) { - testCases := []struct { - name string - addrType walletrpc.AddressType - }{ - { - name: "standard BIP-0044", - addrType: walletrpc.AddressType_WITNESS_PUBKEY_HASH, - }, - { - name: "standard BIP-0049", - addrType: walletrpc. - AddressType_NESTED_WITNESS_PUBKEY_HASH, - }, - { - name: "lnd BIP-0049 variant", - addrType: walletrpc. - AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH, - }, - { - name: "standard BIP-0084", - addrType: walletrpc.AddressType_WITNESS_PUBKEY_HASH, - }, - { - name: "standard BIP-0086", - addrType: walletrpc.AddressType_TAPROOT_PUBKEY, - }, - } - - for _, tc := range testCases { - tc := tc - success := ht.Run(tc.name, func(tt *testing.T) { - testFunc := func(ht *lntest.HarnessTest) { - testWalletImportAccountScenario( - ht, tc.addrType, - ) - } - - st := ht.Subtest(tt) - - st.RunTestCase(&lntest.TestCase{ - Name: tc.name, - TestFunc: testFunc, - }) - }) - if !success { - // Log failure time to help relate the lnd logs to the - // failure. - ht.Logf("Failure time: %v", time.Now().Format( - "2006-01-02 15:04:05.000", - )) - break - } - } -} - func testWalletImportAccountScenario(ht *lntest.HarnessTest, addrType walletrpc.AddressType) { From c029f0a84fa290ceaca3384a1f4acec4c43ba2f6 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 9 Nov 2024 14:56:57 +0800 Subject: [PATCH 43/64] itest: break down basic funding flow tests --- itest/list_on_test.go | 5 +- itest/lnd_funding_test.go | 332 +++++++++++++++++++++++--------------- 2 files changed, 201 insertions(+), 136 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index a70d67f4c9..73016dd92a 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -11,10 +11,6 @@ var allTestCases = []*lntest.TestCase{ Name: "update channel status", TestFunc: testUpdateChanStatus, }, - { - Name: "basic funding flow", - TestFunc: testBasicChannelFunding, - }, { Name: "external channel funding", TestFunc: testExternalFundingChanPoint, @@ -681,4 +677,5 @@ func init() { allTestCases = append(allTestCases, zeroConfPolicyTestCases...) allTestCases = append(allTestCases, channelFeePolicyTestCases...) allTestCases = append(allTestCases, walletImportAccountTestCases...) + allTestCases = append(allTestCases, basicFundingTestCases...) } diff --git a/itest/lnd_funding_test.go b/itest/lnd_funding_test.go index 6fdd1d91c8..a2ef2e269d 100644 --- a/itest/lnd_funding_test.go +++ b/itest/lnd_funding_test.go @@ -20,162 +20,230 @@ import ( "github.com/stretchr/testify/require" ) -// testBasicChannelFunding performs a test exercising expected behavior from a -// basic funding workflow. The test creates a new channel between Alice and -// Bob, then immediately closes the channel after asserting some expected post -// conditions. Finally, the chain itself is checked to ensure the closing -// transaction was mined. -func testBasicChannelFunding(ht *lntest.HarnessTest) { - // Run through the test with combinations of all the different - // commitment types. - allTypes := []lnrpc.CommitmentType{ - lnrpc.CommitmentType_STATIC_REMOTE_KEY, - lnrpc.CommitmentType_ANCHORS, - lnrpc.CommitmentType_SIMPLE_TAPROOT, - } +// basicFundingTestCases defines the test cases for the basic funding test. +var basicFundingTestCases = []*lntest.TestCase{ + { + Name: "basic funding flow static key remote", + TestFunc: testBasicChannelFundingStaticRemote, + }, + { + Name: "basic funding flow anchor", + TestFunc: testBasicChannelFundingAnchor, + }, + { + Name: "basic funding flow simple taproot", + TestFunc: testBasicChannelFundingSimpleTaproot, + }, +} + +// allFundingTypes defines the channel types to test for the basic funding +// test. +var allFundingTypes = []lnrpc.CommitmentType{ + lnrpc.CommitmentType_STATIC_REMOTE_KEY, + lnrpc.CommitmentType_ANCHORS, + lnrpc.CommitmentType_SIMPLE_TAPROOT, +} - // testFunding is a function closure that takes Carol and Dave's - // commitment types and test the funding flow. - testFunding := func(ht *lntest.HarnessTest, carolCommitType, - daveCommitType lnrpc.CommitmentType) { +// testBasicChannelFundingStaticRemote performs a test exercising expected +// behavior from a basic funding workflow. The test creates a new channel +// between Carol and Dave, with Carol using the static remote key commitment +// type, and Dave using allFundingTypes. +func testBasicChannelFundingStaticRemote(ht *lntest.HarnessTest) { + carolCommitType := lnrpc.CommitmentType_STATIC_REMOTE_KEY - // Based on the current tweak variable for Carol, we'll - // preferentially signal the legacy commitment format. We do - // the same for Dave shortly below. - carolArgs := lntest.NodeArgsForCommitType(carolCommitType) - carol := ht.NewNode("Carol", carolArgs) + // We'll test all possible combinations of the feature bit presence + // that both nodes can signal for this new channel type. We'll make a + // new Carol+Dave for each test instance as well. + for _, daveCommitType := range allFundingTypes { + cc := carolCommitType + dc := daveCommitType - // Each time, we'll send Carol a new set of coins in order to - // fund the channel. - ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) + testName := fmt.Sprintf( + "carol_commit=%v,dave_commit=%v", cc, dc, + ) - daveArgs := lntest.NodeArgsForCommitType(daveCommitType) - dave := ht.NewNode("Dave", daveArgs) + success := ht.Run(testName, func(t *testing.T) { + st := ht.Subtest(t) + runBasicFundingTest(st, cc, dc) + }) - // Before we start the test, we'll ensure both sides are - // connected to the funding flow can properly be executed. - ht.EnsureConnected(carol, dave) + if !success { + break + } + } +} - var privateChan bool +// testBasicChannelFundingAnchor performs a test exercising expected behavior +// from a basic funding workflow. The test creates a new channel between Carol +// and Dave, with Carol using the anchor commitment type, and Dave using +// allFundingTypes. +func testBasicChannelFundingAnchor(ht *lntest.HarnessTest) { + carolCommitType := lnrpc.CommitmentType_ANCHORS - // If this is to be a taproot channel type, then it needs to be - // private, otherwise it'll be rejected by Dave. - // - // TODO(roasbeef): lift after gossip 1.75 - if carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { - privateChan = true + // We'll test all possible combinations of the feature bit presence + // that both nodes can signal for this new channel type. We'll make a + // new Carol+Dave for each test instance as well. + for _, daveCommitType := range allFundingTypes { + cc := carolCommitType + dc := daveCommitType + + testName := fmt.Sprintf( + "carol_commit=%v,dave_commit=%v", cc, dc, + ) + + success := ht.Run(testName, func(t *testing.T) { + st := ht.Subtest(t) + runBasicFundingTest(st, cc, dc) + }) + + if !success { + break } + } +} + +// testBasicChannelFundingSimpleTaproot performs a test exercising expected +// behavior from a basic funding workflow. The test creates a new channel +// between Carol and Dave, with Carol using the simple taproot commitment type, +// and Dave using allFundingTypes. +func testBasicChannelFundingSimpleTaproot(ht *lntest.HarnessTest) { + carolCommitType := lnrpc.CommitmentType_SIMPLE_TAPROOT + + // We'll test all possible combinations of the feature bit presence + // that both nodes can signal for this new channel type. We'll make a + // new Carol+Dave for each test instance as well. + for _, daveCommitType := range allFundingTypes { + cc := carolCommitType + dc := daveCommitType + + testName := fmt.Sprintf( + "carol_commit=%v,dave_commit=%v", cc, dc, + ) + + success := ht.Run(testName, func(t *testing.T) { + st := ht.Subtest(t) + runBasicFundingTest(st, cc, dc) + }) - // If carol wants taproot, but dave wants something - // else, then we'll assert that the channel negotiation - // attempt fails. - if carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT && - daveCommitType != lnrpc.CommitmentType_SIMPLE_TAPROOT { - - expectedErr := fmt.Errorf("requested channel type " + - "not supported") - amt := funding.MaxBtcFundingAmount - ht.OpenChannelAssertErr( - carol, dave, lntest.OpenChannelParams{ - Private: privateChan, - Amt: amt, - CommitmentType: carolCommitType, - }, expectedErr, - ) - - return + if !success { + break } + } +} + +// runBasicFundingTest is a helper function that takes Carol and Dave's +// commitment types and test the funding flow. +func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, + daveCommitType lnrpc.CommitmentType) { + + // Based on the current tweak variable for Carol, we'll preferentially + // signal the legacy commitment format. We do the same for Dave + // shortly below. + carolArgs := lntest.NodeArgsForCommitType(carolCommitType) + carol := ht.NewNode("Carol", carolArgs) + + // Each time, we'll send Carol a new set of coins in order to fund the + // channel. + ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) - carolChan, daveChan := basicChannelFundingTest( - ht, carol, dave, nil, privateChan, &carolCommitType, + daveArgs := lntest.NodeArgsForCommitType(daveCommitType) + dave := ht.NewNode("Dave", daveArgs) + + // Before we start the test, we'll ensure both sides are connected to + // the funding flow can properly be executed. + ht.EnsureConnected(carol, dave) + + var privateChan bool + + // If this is to be a taproot channel type, then it needs to be + // private, otherwise it'll be rejected by Dave. + // + // TODO(roasbeef): lift after gossip 1.75 + if carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + privateChan = true + } + + // If carol wants taproot, but dave wants something else, then we'll + // assert that the channel negotiation attempt fails. + if carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT && + daveCommitType != lnrpc.CommitmentType_SIMPLE_TAPROOT { + + expectedErr := fmt.Errorf("requested channel type " + + "not supported") + amt := funding.MaxBtcFundingAmount + ht.OpenChannelAssertErr( + carol, dave, lntest.OpenChannelParams{ + Private: privateChan, + Amt: amt, + CommitmentType: carolCommitType, + }, expectedErr, ) - // Both nodes should report the same commitment - // type. - chansCommitType := carolChan.CommitmentType - require.Equal(ht, chansCommitType, daveChan.CommitmentType, - "commit types don't match") + return + } - // Now check that the commitment type reported by both nodes is - // what we expect. It will be the minimum of the two nodes' - // preference, in the order Legacy, Tweakless, Anchors. - expType := carolCommitType + carolChan, daveChan := basicChannelFundingTest( + ht, carol, dave, nil, privateChan, &carolCommitType, + ) - switch daveCommitType { - // Dave supports taproot, type will be what Carol supports. - case lnrpc.CommitmentType_SIMPLE_TAPROOT: + // Both nodes should report the same commitment type. + chansCommitType := carolChan.CommitmentType + require.Equal(ht, chansCommitType, daveChan.CommitmentType, + "commit types don't match") + + // Now check that the commitment type reported by both nodes is what we + // expect. It will be the minimum of the two nodes' preference, in the + // order Legacy, Tweakless, Anchors. + expType := carolCommitType + + switch daveCommitType { + // Dave supports taproot, type will be what Carol supports. + case lnrpc.CommitmentType_SIMPLE_TAPROOT: + + // Dave supports anchors, type will be what Carol supports. + case lnrpc.CommitmentType_ANCHORS: + // However if Alice wants taproot chans, then we downgrade to + // anchors as this is still using implicit negotiation. + if expType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + expType = lnrpc.CommitmentType_ANCHORS + } - // Dave supports anchors, type will be what Carol supports. + // Dave only supports tweakless, channel will be downgraded to this + // type if Carol supports anchors. + case lnrpc.CommitmentType_STATIC_REMOTE_KEY: + switch expType { case lnrpc.CommitmentType_ANCHORS: - // However if Alice wants taproot chans, then we - // downgrade to anchors as this is still using implicit - // negotiation. - if expType == lnrpc.CommitmentType_SIMPLE_TAPROOT { - expType = lnrpc.CommitmentType_ANCHORS - } - - // Dave only supports tweakless, channel will be downgraded to - // this type if Carol supports anchors. - case lnrpc.CommitmentType_STATIC_REMOTE_KEY: - switch expType { - case lnrpc.CommitmentType_ANCHORS: - expType = lnrpc.CommitmentType_STATIC_REMOTE_KEY - case lnrpc.CommitmentType_SIMPLE_TAPROOT: - expType = lnrpc.CommitmentType_STATIC_REMOTE_KEY - } - - // Dave only supports legacy type, channel will be downgraded - // to this type. - case lnrpc.CommitmentType_LEGACY: - expType = lnrpc.CommitmentType_LEGACY - - default: - ht.Fatalf("invalid commit type %v", daveCommitType) + expType = lnrpc.CommitmentType_STATIC_REMOTE_KEY + case lnrpc.CommitmentType_SIMPLE_TAPROOT: + expType = lnrpc.CommitmentType_STATIC_REMOTE_KEY } - // Check that the signalled type matches what we expect. - switch { - case expType == lnrpc.CommitmentType_ANCHORS && - chansCommitType == lnrpc.CommitmentType_ANCHORS: + // Dave only supports legacy type, channel will be downgraded to this + // type. + case lnrpc.CommitmentType_LEGACY: + expType = lnrpc.CommitmentType_LEGACY - case expType == lnrpc.CommitmentType_STATIC_REMOTE_KEY && - chansCommitType == lnrpc.CommitmentType_STATIC_REMOTE_KEY: //nolint:ll + default: + ht.Fatalf("invalid commit type %v", daveCommitType) + } - case expType == lnrpc.CommitmentType_LEGACY && - chansCommitType == lnrpc.CommitmentType_LEGACY: + // Check that the signalled type matches what we expect. + switch { + case expType == lnrpc.CommitmentType_ANCHORS && + chansCommitType == lnrpc.CommitmentType_ANCHORS: - case expType == lnrpc.CommitmentType_SIMPLE_TAPROOT && - chansCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT: + case expType == lnrpc.CommitmentType_STATIC_REMOTE_KEY && + chansCommitType == lnrpc.CommitmentType_STATIC_REMOTE_KEY: - default: - ht.Fatalf("expected nodes to signal "+ - "commit type %v, instead got "+ - "%v", expType, chansCommitType) - } - } + case expType == lnrpc.CommitmentType_LEGACY && + chansCommitType == lnrpc.CommitmentType_LEGACY: -test: - // We'll test all possible combinations of the feature bit presence - // that both nodes can signal for this new channel type. We'll make a - // new Carol+Dave for each test instance as well. - for _, carolCommitType := range allTypes { - for _, daveCommitType := range allTypes { - cc := carolCommitType - dc := daveCommitType - - testName := fmt.Sprintf( - "carol_commit=%v,dave_commit=%v", cc, dc, - ) - - success := ht.Run(testName, func(t *testing.T) { - st := ht.Subtest(t) - testFunding(st, cc, dc) - }) - - if !success { - break test - } - } + case expType == lnrpc.CommitmentType_SIMPLE_TAPROOT && + chansCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT: + + default: + ht.Fatalf("expected nodes to signal commit type %v, instead "+ + "got %v", expType, chansCommitType) } } From efae8ea56f5c36ff8dd90fd574b959416e2141c9 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 9 Nov 2024 15:14:53 +0800 Subject: [PATCH 44/64] itest: break down single hop send to route Also removed the duplicate test cases. --- itest/list_on_test.go | 5 +-- itest/lnd_routing_test.go | 70 +++++++++++++-------------------------- 2 files changed, 24 insertions(+), 51 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 73016dd92a..b0146f16bf 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -300,10 +300,6 @@ var allTestCases = []*lntest.TestCase{ Name: "revoked uncooperative close retribution remote hodl", TestFunc: testRevokedCloseRetributionRemoteHodl, }, - { - Name: "single-hop send to route", - TestFunc: testSingleHopSendToRoute, - }, { Name: "multi-hop send to route", TestFunc: testMultiHopSendToRoute, @@ -678,4 +674,5 @@ func init() { allTestCases = append(allTestCases, channelFeePolicyTestCases...) allTestCases = append(allTestCases, walletImportAccountTestCases...) allTestCases = append(allTestCases, basicFundingTestCases...) + allTestCases = append(allTestCases, sendToRouteTestCases...) } diff --git a/itest/lnd_routing_test.go b/itest/lnd_routing_test.go index 950b24d24b..c32e021d44 100644 --- a/itest/lnd_routing_test.go +++ b/itest/lnd_routing_test.go @@ -20,46 +20,33 @@ import ( "google.golang.org/protobuf/proto" ) -type singleHopSendToRouteCase struct { - name string - - // streaming tests streaming SendToRoute if true, otherwise tests - // synchronous SenToRoute. - streaming bool - - // routerrpc submits the request to the routerrpc subserver if true, - // otherwise submits to the main rpc server. - routerrpc bool -} - -var singleHopSendToRouteCases = []singleHopSendToRouteCase{ - { - name: "regular main sync", - }, - { - name: "regular main stream", - streaming: true, - }, - { - name: "regular routerrpc sync", - routerrpc: true, - }, +var sendToRouteTestCases = []*lntest.TestCase{ { - name: "mpp main sync", + Name: "single hop send to route sync", + TestFunc: func(ht *lntest.HarnessTest) { + // useStream: false, routerrpc: false. + testSingleHopSendToRouteCase(ht, false, false) + }, }, { - name: "mpp main stream", - streaming: true, + Name: "single hop send to route stream", + TestFunc: func(ht *lntest.HarnessTest) { + // useStream: true, routerrpc: false. + testSingleHopSendToRouteCase(ht, true, false) + }, }, { - name: "mpp routerrpc sync", - routerrpc: true, + Name: "single hop send to route v2", + TestFunc: func(ht *lntest.HarnessTest) { + // useStream: false, routerrpc: true. + testSingleHopSendToRouteCase(ht, false, true) + }, }, } -// testSingleHopSendToRoute tests that payments are properly processed through a -// provided route with a single hop. We'll create the following network -// topology: +// testSingleHopSendToRouteCase tests that payments are properly processed +// through a provided route with a single hop. We'll create the following +// network topology: // // Carol --100k--> Dave // @@ -67,19 +54,8 @@ var singleHopSendToRouteCases = []singleHopSendToRouteCase{ // by feeding the route back into the various SendToRoute RPC methods. Here we // test all three SendToRoute endpoints, forcing each to perform both a regular // payment and an MPP payment. -func testSingleHopSendToRoute(ht *lntest.HarnessTest) { - for _, test := range singleHopSendToRouteCases { - test := test - - ht.Run(test.name, func(t1 *testing.T) { - st := ht.Subtest(t1) - testSingleHopSendToRouteCase(st, test) - }) - } -} - func testSingleHopSendToRouteCase(ht *lntest.HarnessTest, - test singleHopSendToRouteCase) { + useStream, useRPC bool) { const chanAmt = btcutil.Amount(100000) const paymentAmtSat = 1000 @@ -199,11 +175,11 @@ func testSingleHopSendToRouteCase(ht *lntest.HarnessTest, // synchronously via the routerrpc's SendToRoute, or via the main RPC // server's SendToRoute streaming or sync calls. switch { - case !test.routerrpc && test.streaming: + case !useRPC && useStream: sendToRouteStream() - case !test.routerrpc && !test.streaming: + case !useRPC && !useStream: sendToRouteSync() - case test.routerrpc && !test.streaming: + case useRPC && !useStream: sendToRouteRouterRPC() default: require.Fail(ht, "routerrpc does not support "+ From 37b8210f37038d2c98f4cd500734e7125cb48837 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 9 Nov 2024 15:18:40 +0800 Subject: [PATCH 45/64] itest: break down taproot tests --- itest/list_on_test.go | 12 ++++++++++-- itest/lnd_taproot_test.go | 17 ++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index b0146f16bf..e8ae3fbe0e 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -469,8 +469,16 @@ var allTestCases = []*lntest.TestCase{ TestFunc: testBumpForceCloseFee, }, { - Name: "taproot", - TestFunc: testTaproot, + Name: "taproot spend", + TestFunc: testTaprootSpend, + }, + { + Name: "taproot musig2", + TestFunc: testTaprootMuSig2, + }, + { + Name: "taproot import scripts", + TestFunc: testTaprootImportScripts, }, { Name: "simple taproot channel activation", diff --git a/itest/lnd_taproot_test.go b/itest/lnd_taproot_test.go index 2b68105fdb..ddbfb6983a 100644 --- a/itest/lnd_taproot_test.go +++ b/itest/lnd_taproot_test.go @@ -46,9 +46,9 @@ var ( )) ) -// testTaproot ensures that the daemon can send to and spend from taproot (p2tr) -// outputs. -func testTaproot(ht *lntest.HarnessTest) { +// testTaprootSpend ensures that the daemon can send to and spend from taproot +// (p2tr) outputs. +func testTaprootSpend(ht *lntest.HarnessTest) { alice := ht.NewNode("Alice", nil) testTaprootSendCoinsKeySpendBip86(ht, alice) @@ -62,6 +62,12 @@ func testTaproot(ht *lntest.HarnessTest) { ht, alice, txscript.SigHashSingle, ) testTaprootSignOutputRawKeySpendRootHash(ht, alice) +} + +// testTaprootMuSig2 ensures that the daemon can send to and spend from taproot +// (p2tr) outputs using musig2. +func testTaprootMuSig2(ht *lntest.HarnessTest) { + alice := ht.NewNodeWithCoins("Alice", nil) muSig2Versions := []signrpc.MuSig2Version{ signrpc.MuSig2Version_MUSIG2_VERSION_V040, @@ -74,6 +80,11 @@ func testTaproot(ht *lntest.HarnessTest) { testTaprootMuSig2CombinedLeafKeySpend(ht, alice, version) testMuSig2CombineKey(ht, alice, version) } +} + +// testTaprootImportScripts ensures that the daemon can import taproot scripts. +func testTaprootImportScripts(ht *lntest.HarnessTest) { + alice := ht.NewNodeWithCoins("Alice", nil) testTaprootImportTapscriptFullTree(ht, alice) testTaprootImportTapscriptPartialReveal(ht, alice) From c7b83796025565ffd18a76e84e275acc3fbe89ed Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 9 Nov 2024 15:41:48 +0800 Subject: [PATCH 46/64] itest: break down channel fundmax tests --- itest/list_on_test.go | 12 ++- itest/lnd_channel_funding_fund_max_test.go | 120 +++++++++++++++++---- 2 files changed, 111 insertions(+), 21 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index e8ae3fbe0e..7562350fff 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -525,8 +525,16 @@ var allTestCases = []*lntest.TestCase{ TestFunc: testLookupHtlcResolution, }, { - Name: "channel fundmax", - TestFunc: testChannelFundMax, + Name: "channel fundmax error", + TestFunc: testChannelFundMaxError, + }, + { + Name: "channel fundmax wallet amount", + TestFunc: testChannelFundMaxWalletAmount, + }, + { + Name: "channel fundmax anchor reserve", + TestFunc: testChannelFundMaxAnchorReserve, }, { Name: "htlc timeout resolver extract preimage remote", diff --git a/itest/lnd_channel_funding_fund_max_test.go b/itest/lnd_channel_funding_fund_max_test.go index c93ab5fdc7..5a19ccdebd 100644 --- a/itest/lnd_channel_funding_fund_max_test.go +++ b/itest/lnd_channel_funding_fund_max_test.go @@ -50,9 +50,9 @@ type chanFundMaxTestCase struct { private bool } -// testChannelFundMax checks various channel funding scenarios where the user -// instructed the wallet to use all remaining funds. -func testChannelFundMax(ht *lntest.HarnessTest) { +// testChannelFundMaxError checks various error channel funding scenarios where +// the user instructed the wallet to use all remaining funds. +func testChannelFundMaxError(ht *lntest.HarnessTest) { // Create two new nodes that open a channel between each other for these // tests. args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) @@ -92,22 +92,6 @@ func testChannelFundMax(ht *lntest.HarnessTest) { expectedErrStr: "available funds(0.00017877 BTC) " + "below the minimum amount(0.00020000 BTC)", }, - { - name: "wallet amount > min chan " + - "size (37000sat)", - initialWalletBalance: 37_000, - // The transaction fee to open the channel must be - // subtracted from Alice's balance. - // (since wallet balance < max-chan-size) - expectedBalanceAlice: btcutil.Amount(37_000) - - fundingFee(1, false), - }, - { - name: "wallet amount > max chan size " + - "(20000000sat)", - initialWalletBalance: 20_000_000, - expectedBalanceAlice: lnd.MaxFundingAmount, - }, // Expects, that if the maximum funding amount for a channel is // pushed to the remote side, then the funding flow is failing // because the push amount has to be less than the local channel @@ -137,6 +121,63 @@ func testChannelFundMax(ht *lntest.HarnessTest) { expectedErrStr: "funder balance too small (-8050000) " + "with fee=9050 sat, minimum=708 sat required", }, + } + + for _, testCase := range testCases { + success := ht.Run( + testCase.name, func(tt *testing.T) { + runFundMaxTestCase( + ht, alice, bob, testCase, reserveAmount, + ) + }, + ) + + // Stop at the first failure. Mimic behavior of original test + // framework. + if !success { + break + } + } +} + +// testChannelFundMaxWalletAmount checks various channel funding scenarios +// where the user instructed the wallet to use all remaining funds and succeed. +func testChannelFundMaxWalletAmount(ht *lntest.HarnessTest) { + // Create two new nodes that open a channel between each other for these + // tests. + args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) + alice := ht.NewNode("Alice", args) + bob := ht.NewNode("Bob", args) + + // Ensure both sides are connected so the funding flow can be properly + // executed. + ht.EnsureConnected(alice, bob) + + // Calculate reserve amount for one channel. + reserveResp, _ := alice.RPC.WalletKit.RequiredReserve( + context.Background(), &walletrpc.RequiredReserveRequest{ + AdditionalPublicChannels: 1, + }, + ) + reserveAmount := btcutil.Amount(reserveResp.RequiredReserve) + + var testCases = []*chanFundMaxTestCase{ + { + name: "wallet amount > min chan " + + "size (37000sat)", + initialWalletBalance: 37_000, + // The transaction fee to open the channel must be + // subtracted from Alice's balance. + // (since wallet balance < max-chan-size) + expectedBalanceAlice: btcutil.Amount(37_000) - + fundingFee(1, false), + }, + { + name: "wallet amount > max chan size " + + "(20000000sat)", + initialWalletBalance: 20_000_000, + expectedBalanceAlice: lnd.MaxFundingAmount, + }, { name: "wallet amount > max chan size, " + "push amount 16766000", @@ -144,7 +185,48 @@ func testChannelFundMax(ht *lntest.HarnessTest) { pushAmt: 16_766_000, expectedBalanceAlice: lnd.MaxFundingAmount - 16_766_000, }, + } + for _, testCase := range testCases { + success := ht.Run( + testCase.name, func(tt *testing.T) { + runFundMaxTestCase( + ht, alice, bob, testCase, reserveAmount, + ) + }, + ) + + // Stop at the first failure. Mimic behavior of original test + // framework. + if !success { + break + } + } +} + +// testChannelFundMaxAnchorReserve checks various channel funding scenarios +// where the user instructed the wallet to use all remaining funds and its +// impact on anchor reserve. +func testChannelFundMaxAnchorReserve(ht *lntest.HarnessTest) { + // Create two new nodes that open a channel between each other for these + // tests. + args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) + alice := ht.NewNode("Alice", args) + bob := ht.NewNode("Bob", args) + + // Ensure both sides are connected so the funding flow can be properly + // executed. + ht.EnsureConnected(alice, bob) + + // Calculate reserve amount for one channel. + reserveResp, _ := alice.RPC.WalletKit.RequiredReserve( + context.Background(), &walletrpc.RequiredReserveRequest{ + AdditionalPublicChannels: 1, + }, + ) + reserveAmount := btcutil.Amount(reserveResp.RequiredReserve) + + var testCases = []*chanFundMaxTestCase{ { name: "anchor reserved value", initialWalletBalance: 100_000, From 6f2e7feb940847a67f705c71a51492b72327443a Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 5 Dec 2024 08:49:56 +0800 Subject: [PATCH 47/64] itest: breakdown `testSendDirectPayment` Also fixes a wrong usage of `ht.Subtest`. --- itest/list_on_test.go | 8 +- itest/lnd_payment_test.go | 207 ++++++++++++++++---------------------- 2 files changed, 91 insertions(+), 124 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 7562350fff..22bcd5866f 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -168,8 +168,12 @@ var allTestCases = []*lntest.TestCase{ TestFunc: testListPayments, }, { - Name: "send direct payment", - TestFunc: testSendDirectPayment, + Name: "send direct payment anchor", + TestFunc: testSendDirectPaymentAnchor, + }, + { + Name: "send direct payment simple taproot", + TestFunc: testSendDirectPaymentSimpleTaproot, }, { Name: "immediate payment after channel opened", diff --git a/itest/lnd_payment_test.go b/itest/lnd_payment_test.go index 72a2c16030..ecd0cb06bd 100644 --- a/itest/lnd_payment_test.go +++ b/itest/lnd_payment_test.go @@ -339,135 +339,98 @@ func runTestPaymentHTLCTimeout(ht *lntest.HarnessTest, restartAlice bool) { ht.AssertPaymentStatusFromStream(payStream, lnrpc.Payment_FAILED) } -// testSendDirectPayment creates a topology Alice->Bob and then tests that -// Alice can send a direct payment to Bob. This test modifies the fee estimator -// to return floor fee rate(1 sat/vb). -func testSendDirectPayment(ht *lntest.HarnessTest) { - // Grab Alice and Bob's nodes for convenience. - alice := ht.NewNodeWithCoins("Alice", nil) - bob := ht.NewNodeWithCoins("Bob", nil) +// runSendDirectPayment opens a channel between Alice and Bob using the +// specified params. It then sends a payment from Alice to Bob and asserts it +// being successful. +func runSendDirectPayment(ht *lntest.HarnessTest, cfgs [][]string, + params lntest.OpenChannelParams) { - // Create a list of commitment types we want to test. - commitmentTypes := []lnrpc.CommitmentType{ - lnrpc.CommitmentType_ANCHORS, - lnrpc.CommitmentType_SIMPLE_TAPROOT, - } + // Set the fee estimate to 1sat/vbyte. + ht.SetFeeEstimate(250) - // testSendPayment opens a channel between Alice and Bob using the - // specified params. It then sends a payment from Alice to Bob and - // asserts it being successful. - testSendPayment := func(ht *lntest.HarnessTest, - params lntest.OpenChannelParams) { - - // Check that there are no payments before test. - chanPoint := ht.OpenChannel(alice, bob, params) - - // Now that the channel is open, create an invoice for Bob - // which expects a payment of 1000 satoshis from Alice paid via - // a particular preimage. - const paymentAmt = 1000 - preimage := ht.Random32Bytes() - invoice := &lnrpc.Invoice{ - RPreimage: preimage, - Value: paymentAmt, - } - invoiceResp := bob.RPC.AddInvoice(invoice) - - // With the invoice for Bob added, send a payment towards Alice - // paying to the above generated invoice. - payReqs := []string{invoiceResp.PaymentRequest} - ht.CompletePaymentRequests(alice, payReqs) - - p := ht.AssertNumPayments(alice, 1)[0] - path := p.Htlcs[len(p.Htlcs)-1].Route.Hops - - // Ensure that the stored path shows a direct payment to Bob - // with no other nodes in-between. - require.Len(ht, path, 1, "wrong number of routes in path") - require.Equal(ht, bob.PubKeyStr, path[0].PubKey, "wrong pubkey") - - // The payment amount should also match our previous payment - // directly. - require.EqualValues(ht, paymentAmt, p.ValueSat, - "incorrect sat amount") - require.EqualValues(ht, paymentAmt*1000, p.ValueMsat, - "incorrect msat amount") - - // The payment hash (or r-hash) should have been stored - // correctly. - correctRHash := hex.EncodeToString(invoiceResp.RHash) - require.Equal(ht, correctRHash, p.PaymentHash, "incorrect hash") - - // As we made a single-hop direct payment, there should have - // been no fee applied. - require.Zero(ht, p.FeeSat, "fee should be 0") - require.Zero(ht, p.FeeMsat, "fee should be 0") - - // Now verify that the payment request returned by the rpc - // matches the invoice that we paid. - require.Equal(ht, invoiceResp.PaymentRequest, p.PaymentRequest, - "incorrect payreq") - - // Delete all payments from Alice. DB should have no payments. - alice.RPC.DeleteAllPayments() - ht.AssertNumPayments(alice, 0) - - // TODO(yy): remove the sleep once the following bug is fixed. - // When the invoice is reported settled, the commitment dance - // is not yet finished, which can cause an error when closing - // the channel, saying there's active HTLCs. We need to - // investigate this issue and reverse the order to, first - // finish the commitment dance, then report the invoice as - // settled. - time.Sleep(2 * time.Second) - - // Close the channel. - // - // NOTE: This implicitly tests that the channel link is active - // before closing this channel. The above payment will trigger - // a commitment dance in both of the nodes. If the node fails - // to update the commitment state, we will fail to close the - // channel as the link won't be active. - ht.CloseChannel(alice, chanPoint) + // Create a two-hop network: Alice -> Bob. + _, nodes := ht.CreateSimpleNetwork(cfgs, params) + alice, bob := nodes[0], nodes[1] + + // Now that the channel is open, create an invoice for Bob + // which expects a payment of 1000 satoshis from Alice paid via + // a particular preimage. + const paymentAmt = 1000 + preimage := ht.Random32Bytes() + invoice := &lnrpc.Invoice{ + RPreimage: preimage, + Value: paymentAmt, } + invoiceResp := bob.RPC.AddInvoice(invoice) - // Run the test cases. - for _, ct := range commitmentTypes { - ht.Run(ct.String(), func(t *testing.T) { - st := ht.Subtest(t) - - // Set the fee estimate to 1sat/vbyte. - st.SetFeeEstimate(250) - - // Restart the nodes with the specified commitment type. - args := lntest.NodeArgsForCommitType(ct) - st.RestartNodeWithExtraArgs(alice, args) - st.RestartNodeWithExtraArgs(bob, args) - - // Make sure they are connected. - st.EnsureConnected(alice, bob) - - // There's a bug that causes the funding to be failed - // due to the `ListCoins` cannot find the utxos. - // - // TODO(yy): remove this line to fix the ListCoins bug. - st.FundCoins(btcutil.SatoshiPerBitcoin, alice) - - // Open a channel with 100k satoshis between Alice and - // Bob with Alice being the sole funder of the channel. - params := lntest.OpenChannelParams{ - Amt: 100_000, - CommitmentType: ct, - } + // With the invoice for Bob added, send a payment towards Alice + // paying to the above generated invoice. + payReqs := []string{invoiceResp.PaymentRequest} + ht.CompletePaymentRequests(alice, payReqs) - // Open private channel for taproot channels. - if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT { - params.Private = true - } + p := ht.AssertNumPayments(alice, 1)[0] + path := p.Htlcs[len(p.Htlcs)-1].Route.Hops - testSendPayment(st, params) - }) + // Ensure that the stored path shows a direct payment to Bob + // with no other nodes in-between. + require.Len(ht, path, 1, "wrong number of routes in path") + require.Equal(ht, bob.PubKeyStr, path[0].PubKey, "wrong pubkey") + + // The payment amount should also match our previous payment + // directly. + require.EqualValues(ht, paymentAmt, p.ValueSat, + "incorrect sat amount") + require.EqualValues(ht, paymentAmt*1000, p.ValueMsat, + "incorrect msat amount") + + // The payment hash (or r-hash) should have been stored + // correctly. + correctRHash := hex.EncodeToString(invoiceResp.RHash) + require.Equal(ht, correctRHash, p.PaymentHash, "incorrect hash") + + // As we made a single-hop direct payment, there should have + // been no fee applied. + require.Zero(ht, p.FeeSat, "fee should be 0") + require.Zero(ht, p.FeeMsat, "fee should be 0") + + // Now verify that the payment request returned by the rpc + // matches the invoice that we paid. + require.Equal(ht, invoiceResp.PaymentRequest, p.PaymentRequest, + "incorrect payreq") +} + +// testSendDirectPaymentAnchor creates a topology Alice->Bob using anchor +// channel and then tests that Alice can send a direct payment to Bob. +func testSendDirectPaymentAnchor(ht *lntest.HarnessTest) { + // Create a two-hop network: Alice -> Bob using anchor channel. + // + // Prepare params. + params := lntest.OpenChannelParams{Amt: chanAmt} + cfg := node.CfgAnchor + cfgs := [][]string{cfg, cfg} + + runSendDirectPayment(ht, cfgs, params) +} + +// testSendDirectPaymentSimpleTaproot creates a topology Alice->Bob using +// simple taproot channel and then tests that Alice can send a direct payment +// to Bob. +func testSendDirectPaymentSimpleTaproot(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT + + // Create a two-hop network: Alice -> Bob using simple taproot channel. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, } + + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg} + + runSendDirectPayment(ht, cfgs, params) } func testListPayments(ht *lntest.HarnessTest) { From e79ad6e5aa0d8669c66c2e1dc9693c67a8c61636 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 9 Nov 2024 14:39:12 +0800 Subject: [PATCH 48/64] itest: further reduce block mined in tests --- itest/lnd_channel_backup_test.go | 1 - itest/lnd_estimate_route_fee_test.go | 36 ++++++++++--------------- itest/lnd_hold_invoice_force_test.go | 2 +- itest/lnd_route_blinding_test.go | 39 ++++++++++++---------------- itest/lnd_wipe_fwdpkgs_test.go | 3 --- 5 files changed, 30 insertions(+), 51 deletions(-) diff --git a/itest/lnd_channel_backup_test.go b/itest/lnd_channel_backup_test.go index 72861f9ce1..624e70a08d 100644 --- a/itest/lnd_channel_backup_test.go +++ b/itest/lnd_channel_backup_test.go @@ -1499,7 +1499,6 @@ func assertTimeLockSwept(ht *lntest.HarnessTest, carol, dave *node.HarnessNode, ht.AssertNumPendingSweeps(dave, 2) // Mine a block to trigger the sweeps. - ht.MineEmptyBlocks(1) daveSweep := ht.AssertNumTxsInMempool(1)[0] block := ht.MineBlocksAndAssertNumTxes(1, 1)[0] ht.AssertTxInBlock(block, daveSweep) diff --git a/itest/lnd_estimate_route_fee_test.go b/itest/lnd_estimate_route_fee_test.go index 80d19fc043..713cfe1ed8 100644 --- a/itest/lnd_estimate_route_fee_test.go +++ b/itest/lnd_estimate_route_fee_test.go @@ -94,21 +94,17 @@ func testEstimateRouteFee(ht *lntest.HarnessTest) { // added to the invoice always have enough liquidity, but here we check // that the prober uses the more expensive route. ht.EnsureConnected(mts.bob, paula) - channelPointBobPaula := ht.OpenChannel( - mts.bob, paula, lntest.OpenChannelParams{ - Private: true, - Amt: 90_000, - PushAmt: 69_000, - }, - ) + ht.OpenChannel(mts.bob, paula, lntest.OpenChannelParams{ + Private: true, + Amt: 90_000, + PushAmt: 69_000, + }) ht.EnsureConnected(mts.eve, paula) - channelPointEvePaula := ht.OpenChannel( - mts.eve, paula, lntest.OpenChannelParams{ - Private: true, - Amt: 1_000_000, - }, - ) + ht.OpenChannel(mts.eve, paula, lntest.OpenChannelParams{ + Private: true, + Amt: 1_000_000, + }) bobsPrivChannels := mts.bob.RPC.ListChannels(&lnrpc.ListChannelsRequest{ PrivateOnly: true, @@ -243,6 +239,8 @@ func testEstimateRouteFee(ht *lntest.HarnessTest) { locktime := initialBlockHeight + defaultTimelock + int64(routing.BlockPadding) + noChanNode := ht.NewNode("ImWithoutChannels", nil) + var testCases = []*estimateRouteFeeTestCase{ // Single hop payment is free. { @@ -304,10 +302,8 @@ func testEstimateRouteFee(ht *lntest.HarnessTest) { { name: "single hop hint, destination " + "without channels", - probing: true, - destination: ht.NewNode( - "ImWithoutChannels", nil, - ), + probing: true, + destination: noChanNode, routeHints: singleRouteHint, expectedRoutingFeesMsat: feeACBP, expectedCltvDelta: locktime + deltaACBP, @@ -357,12 +353,6 @@ func testEstimateRouteFee(ht *lntest.HarnessTest) { break } } - - mts.ht.CloseChannelAssertPending(mts.bob, channelPointBobPaula, false) - mts.ht.CloseChannelAssertPending(mts.eve, channelPointEvePaula, false) - ht.MineBlocksAndAssertNumTxes(1, 2) - - mts.closeChannels() } // runTestCase runs a single test case asserting that test conditions are met. diff --git a/itest/lnd_hold_invoice_force_test.go b/itest/lnd_hold_invoice_force_test.go index 19e44a8375..5fe8ea0daa 100644 --- a/itest/lnd_hold_invoice_force_test.go +++ b/itest/lnd_hold_invoice_force_test.go @@ -30,7 +30,7 @@ func testHoldInvoiceForceClose(ht *lntest.HarnessTest) { ) invoiceReq := &invoicesrpc.AddHoldInvoiceRequest{ Value: 30000, - CltvExpiry: 40, + CltvExpiry: finalCltvDelta, Hash: payHash[:], } bobInvoice := bob.RPC.AddHoldInvoice(invoiceReq) diff --git a/itest/lnd_route_blinding_test.go b/itest/lnd_route_blinding_test.go index 9079a1589a..4b6f98d18e 100644 --- a/itest/lnd_route_blinding_test.go +++ b/itest/lnd_route_blinding_test.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "encoding/hex" "errors" + "fmt" "time" "github.com/btcsuite/btcd/btcec/v2" @@ -19,6 +20,10 @@ import ( "github.com/stretchr/testify/require" ) +// toLocalCSV is the CSV delay for the node's to_local output. We use a small +// value to save us from mining blocks. +var toLocalCSV = 2 + // testQueryBlindedRoutes tests querying routes to blinded routes. To do this, // it sets up a nework of Alice - Bob - Carol and creates a mock blinded route // that uses Carol as the introduction node (plus dummy hops to cover multiple @@ -346,14 +351,18 @@ func newBlindedForwardTest(ht *lntest.HarnessTest) (context.Context, func (b *blindedForwardTest) setupNetwork(ctx context.Context, withInterceptor bool) { - const chanAmt = btcutil.Amount(100_000) - - carolArgs := []string{"--bitcoin.timelockdelta=18"} + carolArgs := []string{ + "--bitcoin.timelockdelta=18", + fmt.Sprintf("--bitcoin.defaultremotedelay=%v", toLocalCSV), + } if withInterceptor { carolArgs = append(carolArgs, "--requireinterceptor") } - daveArgs := []string{"--bitcoin.timelockdelta=18"} + daveArgs := []string{ + "--bitcoin.timelockdelta=18", + fmt.Sprintf("--bitcoin.defaultremotedelay=%v", toLocalCSV), + } cfgs := [][]string{nil, nil, carolArgs, daveArgs} param := lntest.OpenChannelParams{ Amt: chanAmt, @@ -780,11 +789,11 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { // SuspendCarol so that she can't interfere with the resolution of the // HTLC from now on. - restartCarol := ht.SuspendNode(testCase.carol) + ht.SuspendNode(testCase.carol) // Mine blocks so that Bob will claim his CSV delayed local commitment, // we've already mined 1 block so we need one less than our CSV. - ht.MineBlocks(node.DefaultCSV - 1) + ht.MineBlocks(toLocalCSV - 1) ht.AssertNumPendingSweeps(bob, 1) ht.MineBlocksAndAssertNumTxes(1, 1) @@ -797,6 +806,7 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { // value. info := bob.RPC.GetInfo() target := carolHTLC.IncomingExpiry - info.BlockHeight + ht.Log(carolHTLC.IncomingExpiry, info.BlockHeight, target) ht.MineBlocks(int(target)) // Wait for Bob's timeout transaction in the mempool, since we've @@ -819,23 +829,6 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) { lnrpc.Failure_INVALID_ONION_BLINDING, ) - // Clean up the rest of our force close: mine blocks so that Bob's CSV - // expires to trigger his sweep and then mine it. - ht.MineBlocks(node.DefaultCSV) - ht.AssertNumPendingSweeps(bob, 1) - ht.MineBlocksAndAssertNumTxes(1, 1) - - // Bring carol back up so that we can close out the rest of our - // channels cooperatively. She requires an interceptor to start up - // so we just re-register our interceptor. - require.NoError(ht, restartCarol()) - _, err = testCase.carol.RPC.Router.HtlcInterceptor(ctx) - require.NoError(ht, err, "interceptor") - - // Assert that Carol has started up and reconnected to dave so that - // we can close out channels cooperatively. - ht.EnsureConnected(testCase.carol, testCase.dave) - // Manually close out the rest of our channels and cancel (don't use // built in cleanup which will try close the already-force-closed // channel). diff --git a/itest/lnd_wipe_fwdpkgs_test.go b/itest/lnd_wipe_fwdpkgs_test.go index bd567f7a00..9aafd960a0 100644 --- a/itest/lnd_wipe_fwdpkgs_test.go +++ b/itest/lnd_wipe_fwdpkgs_test.go @@ -106,7 +106,4 @@ func testWipeForwardingPackages(ht *lntest.HarnessTest) { // Mine 1 block to get Alice's sweeping tx confirmed. ht.MineBlocksAndAssertNumTxes(1, 1) - - // Clean up the force closed channel. - ht.CleanupForceClose(bob) } From efe81f2d3c6ce61eefca9d7042f3fd314925c934 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 7 Nov 2024 23:19:19 +0800 Subject: [PATCH 49/64] itest: track and skip flaky tests for windows To make the CI indicative, we now starting tracking the flaky tests found when running on Windows. As a starting point, rather than ignore the windows CI entirely, we now identify there are cases where lnd can be buggy when running in windows. We should fix the tests in the future, otherwise the windows build should be deleted. --- itest/list_exclude_test.go | 108 +++++++++++++++++++++++++++++++++++++ itest/list_on_test.go | 15 ++++++ itest/lnd_test.go | 5 ++ 3 files changed, 128 insertions(+) create mode 100644 itest/list_exclude_test.go diff --git a/itest/list_exclude_test.go b/itest/list_exclude_test.go new file mode 100644 index 0000000000..86567cf352 --- /dev/null +++ b/itest/list_exclude_test.go @@ -0,0 +1,108 @@ +//go:build integration + +package itest + +import ( + "fmt" + + "github.com/lightningnetwork/lnd/fn/v2" + "github.com/lightningnetwork/lnd/lntest" +) + +// excludedTestsWindows is a list of tests that are flaky on Windows and should +// be excluded from the test suite atm. +// +// TODO(yy): fix these tests and remove them from this list. +var excludedTestsWindows = []string{ + "batch channel funding", + "zero conf channel open", + "open channel with unstable utxos", + "funding flow persistence", + "channel policy update public zero conf", + + "listsweeps", + "sweep htlcs", + "sweep cpfp anchor incoming timeout", + "payment succeeded htlc remote swept", + "3rd party anchor spend", + + "send payment amp", + "async payments benchmark", + "async bidirectional payments", + + "multihop htlc aggregation leased", + "multihop htlc aggregation leased zero conf", + "multihop htlc aggregation anchor", + "multihop htlc aggregation anchor zero conf", + "multihop htlc aggregation simple taproot", + "multihop htlc aggregation simple taproot zero conf", + + "channel force closure anchor", + "channel force closure simple taproot", + "channel backup restore force close", + "wipe forwarding packages", + + "coop close with htlcs", + "coop close with external delivery", + + "forward interceptor restart", + "forward interceptor dedup htlcs", + "invoice HTLC modifier basic", + "lookup htlc resolution", + + "remote signer taproot", + "remote signer account import", + "remote signer bump fee", + "remote signer funding input types", + "remote signer funding async payments taproot", + "remote signer funding async payments", + "remote signer random seed", + "remote signer verify msg", + "remote signer channel open", + "remote signer shared key", + "remote signer psbt", + "remote signer sign output raw", + + "on chain to blinded", + "query blinded route", + + "data loss protection", +} + +// filterWindowsFlakyTests filters out the flaky tests that are excluded from +// the test suite on Windows. +func filterWindowsFlakyTests() []*lntest.TestCase { + // filteredTestCases is a substest of allTestCases that excludes the + // above flaky tests. + filteredTestCases := make([]*lntest.TestCase, 0, len(allTestCases)) + + // Create a set for the excluded test cases for fast lookup. + excludedSet := fn.NewSet(excludedTestsWindows...) + + // Remove the tests from the excludedSet if it's found in the list of + // all test cases. This is done to ensure the excluded tests are not + // pointing to a test case that doesn't exist. + for _, tc := range allTestCases { + if excludedSet.Contains(tc.Name) { + excludedSet.Remove(tc.Name) + + continue + } + + filteredTestCases = append(filteredTestCases, tc) + } + + // Exit early if all the excluded tests are found in allTestCases. + if excludedSet.IsEmpty() { + return filteredTestCases + } + + // Otherwise, print out the tests that are not found in allTestCases. + errStr := "\nThe following tests are not found, please make sure the " + + "test names are correct in `excludedTestsWindows`.\n" + for _, name := range excludedSet.ToSlice() { + errStr += fmt.Sprintf("Test not found in test suite: %v", name) + } + + panic(errStr) +} diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 22bcd5866f..4b1ccafc12 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -695,4 +695,19 @@ func init() { allTestCases = append(allTestCases, walletImportAccountTestCases...) allTestCases = append(allTestCases, basicFundingTestCases...) allTestCases = append(allTestCases, sendToRouteTestCases...) + + // Prepare the test cases for windows to exclude some of the flaky + // ones. + // + // NOTE: We need to run this before the isWindowsOS check to make sure + // the excluded tests are found in allTestCases. Otherwise, if a + // non-existing test is included in excludedTestsWindows, we won't be + // able to find it until it's pushed to the CI, which creates a much + // longer feedback loop. + windowsTestCases := filterWindowsFlakyTests() + + // If this is Windows, we'll skip running some of the flaky tests. + if isWindowsOS() { + allTestCases = windowsTestCases + } } diff --git a/itest/lnd_test.go b/itest/lnd_test.go index 63462199ae..c1a43b4106 100644 --- a/itest/lnd_test.go +++ b/itest/lnd_test.go @@ -238,6 +238,11 @@ func isDarwin() bool { return runtime.GOOS == "darwin" } +// isWindowsOS returns true if the test is running on a Windows OS. +func isWindowsOS() bool { + return runtime.GOOS == "windows" +} + func init() { // Before we start any node, we need to make sure that any btcd node // that is started through the RPC harness uses a unique port as well From c97c31a70bee8ecddab2caf2a4a34a823f12044f Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 9 Nov 2024 22:39:34 +0800 Subject: [PATCH 50/64] lntest: increase node start timeout and payment benchmark timeout --- lntest/wait/timeouts_darwin.go | 16 +++++++++++++++- lntest/wait/timeouts_remote_db.go | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lntest/wait/timeouts_darwin.go b/lntest/wait/timeouts_darwin.go index f992d06b22..42b1d0dc6c 100644 --- a/lntest/wait/timeouts_darwin.go +++ b/lntest/wait/timeouts_darwin.go @@ -29,7 +29,21 @@ const ( // NodeStartTimeout is the timeout value when waiting for a node to // become fully started. - NodeStartTimeout = time.Minute * 2 + // + // TODO(yy): There is an optimization we can do to increase the time it + // takes to finish the initial wallet sync. Instead of finding the + // block birthday using binary search in btcwallet, we can instead + // search optimistically by looking at the chain tip minus X blocks to + // get the birthday block. This way in the test the node won't attempt + // to sync from the beginning of the chain, which is always the case + // due to how regtest blocks are mined. + // The other direction of optimization is to change the precision of + // the regtest block's median time. By consensus, we need to increase + // at least one second(?), this means in regtest when large amount of + // blocks are mined in a short time, the block time is actually in the + // future. We could instead allow the median time to increase by + // microseconds for itests. + NodeStartTimeout = time.Minute * 3 // SqliteBusyTimeout is the maximum time that a call to the sqlite db // will wait for the connection to become available. diff --git a/lntest/wait/timeouts_remote_db.go b/lntest/wait/timeouts_remote_db.go index 43cd6e022b..ae7043ff0e 100644 --- a/lntest/wait/timeouts_remote_db.go +++ b/lntest/wait/timeouts_remote_db.go @@ -29,7 +29,7 @@ const ( // AsyncBenchmarkTimeout is the timeout used when running the async // payments benchmark. - AsyncBenchmarkTimeout = time.Minute*2 + extraTimeout + AsyncBenchmarkTimeout = time.Minute*5 + extraTimeout // NodeStartTimeout is the timeout value when waiting for a node to // become fully started. From 77b2fa027194b31093587c82314095bbf65dcb8e Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 21 Nov 2024 22:31:13 +0800 Subject: [PATCH 51/64] lntest: make sure policies are populated in `AssertChannelInGraph` --- lntest/harness_assertion.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lntest/harness_assertion.go b/lntest/harness_assertion.go index 5cadc09fdf..fd4a0dfd73 100644 --- a/lntest/harness_assertion.go +++ b/lntest/harness_assertion.go @@ -1859,6 +1859,18 @@ func (h *HarnessTest) AssertChannelInGraph(hn *node.HarnessNode, op, err) } + // Make sure the policies are populated, otherwise this edge + // cannot be used for routing. + if resp.Node1Policy == nil { + return fmt.Errorf("channel %s has no policy1: %w", + op, err) + } + + if resp.Node2Policy == nil { + return fmt.Errorf("channel %s has no policy2: %w", + op, err) + } + edge = resp return nil From 691a6267be72b464d27bf973b9b30756690d307a Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sun, 10 Nov 2024 00:36:08 +0800 Subject: [PATCH 52/64] workflows: use `btcd` for macOS To increase the speed from 40m per run to roughly 20m per run. --- .github/workflows/main.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ad5748e5c3..bc672a435b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -407,14 +407,8 @@ jobs: go-version: '${{ env.GO_VERSION }}' key-prefix: integration-test - - name: install bitcoind - run: | - wget https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_VERSION}.0/bitcoin-${BITCOIN_VERSION}.0-arm64-apple-darwin.tar.gz - tar zxvf bitcoin-${BITCOIN_VERSION}.0-arm64-apple-darwin.tar.gz - mv bitcoin-${BITCOIN_VERSION}.0 /tmp/bitcoin - - name: run itest - run: PATH=$PATH:/tmp/bitcoin/bin make itest-parallel tranches=${{ env.TRANCHES }} backend=bitcoind shuffleseed=${{ github.run_id }} + run: make itest-parallel tranches=${{ env.TRANCHES }} shuffleseed=${{ github.run_id }} - name: Zip log files on failure if: ${{ failure() }} From 5236c05dc67ee901b7b3aca167460b977c63f295 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Mon, 25 Nov 2024 21:56:47 +0800 Subject: [PATCH 53/64] itest+lntest: add new method `FundNumCoins` Most of the time we only need to fund the node with given number of UTXOs without concerning the amount, so we add the more efficient funding method as it mines a single block in the end. --- itest/lnd_sweep_test.go | 12 ++++++------ lntest/harness.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/itest/lnd_sweep_test.go b/itest/lnd_sweep_test.go index 5995d16945..8ad00a4309 100644 --- a/itest/lnd_sweep_test.go +++ b/itest/lnd_sweep_test.go @@ -779,24 +779,24 @@ func testSweepHTLCs(ht *lntest.HarnessTest) { // Bob needs two more wallet utxos: // - when sweeping anchors, he needs one utxo for each sweep. // - when sweeping HTLCs, he needs one utxo for each sweep. - ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) - ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) + numUTXOs := 2 // Bob should have enough wallet UTXOs here to sweep the HTLC in the // end of this test. However, due to a known issue, Bob's wallet may // report there's no UTXO available. For details, // - https://github.com/lightningnetwork/lnd/issues/8786 // - // TODO(yy): remove this step once the issue is resolved. - ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) + // TODO(yy): remove this extra UTXO once the issue is resolved. + numUTXOs++ // For neutrino backend, we need two more UTXOs for Bob to create his // sweeping txns. if ht.IsNeutrinoBackend() { - ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) - ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) + numUTXOs += 2 } + ht.FundNumCoins(bob, numUTXOs) + // Subscribe the invoices. stream1 := carol.RPC.SubscribeSingleInvoice(payHashSettled[:]) stream2 := carol.RPC.SubscribeSingleInvoice(payHashHold[:]) diff --git a/lntest/harness.go b/lntest/harness.go index e3d5c0dc93..18f252fd12 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -1379,6 +1379,40 @@ func (h *HarnessTest) FundCoinsP2TR(amt btcutil.Amount, h.fundCoins(amt, target, lnrpc.AddressType_TAPROOT_PUBKEY, true) } +// FundNumCoins attempts to send the given number of UTXOs from the internal +// mining node to the targeted lightning node using a P2WKH address. Each UTXO +// has an amount of 1 BTC. 1 blocks are mined to confirm the tx. +func (h *HarnessTest) FundNumCoins(hn *node.HarnessNode, num int) { + // Get the initial balance first. + resp := hn.RPC.WalletBalance() + initialBalance := btcutil.Amount(resp.ConfirmedBalance) + + const fundAmount = 1 * btcutil.SatoshiPerBitcoin + + // Send out the outputs from the miner. + for i := 0; i < num; i++ { + h.createAndSendOutput( + hn, fundAmount, lnrpc.AddressType_WITNESS_PUBKEY_HASH, + ) + } + + // Wait for ListUnspent to show the correct number of unconfirmed + // UTXOs. + // + // Since neutrino doesn't support unconfirmed outputs, skip this check. + if !h.IsNeutrinoBackend() { + h.AssertNumUTXOsUnconfirmed(hn, num) + } + + // Mine a block to confirm the transactions. + h.MineBlocksAndAssertNumTxes(1, num) + + // Now block until the wallet have fully synced up. + totalAmount := btcutil.Amount(fundAmount * num) + expectedBalance := initialBalance + totalAmount + h.WaitForBalanceConfirmed(hn, expectedBalance) +} + // completePaymentRequestsAssertStatus sends payments from a node to complete // all payment requests. This function does not return until all payments // have reached the specified status. From becbdce64c95c4f5335ba2434f095a86c41b5288 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Mon, 25 Nov 2024 17:15:34 +0800 Subject: [PATCH 54/64] lntest: limit the num of blocks mined in each test --- lntest/harness.go | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/lntest/harness.go b/lntest/harness.go index 18f252fd12..54f183d39f 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -326,11 +326,8 @@ func (h *HarnessTest) Subtest(t *testing.T) *HarnessTest { startHeight := int32(h.CurrentHeight()) st.Cleanup(func() { - _, endHeight := h.GetBestBlock() - - st.Logf("finished test: %s, start height=%d, end height=%d, "+ - "mined blocks=%d", st.manager.currentTestCase, - startHeight, endHeight, endHeight-startHeight) + // Make sure the test is not consuming too many blocks. + st.checkAndLimitBlocksMined(startHeight) // Don't bother run the cleanups if the test is failed. if st.Failed() { @@ -368,6 +365,43 @@ func (h *HarnessTest) Subtest(t *testing.T) *HarnessTest { return st } +// checkAndLimitBlocksMined asserts that the blocks mined in a single test +// doesn't exceed 50, which implicitly discourage table-drive tests, which are +// hard to maintain and take a long time to run. +func (h *HarnessTest) checkAndLimitBlocksMined(startHeight int32) { + _, endHeight := h.GetBestBlock() + blocksMined := endHeight - startHeight + + h.Logf("finished test: %s, start height=%d, end height=%d, mined "+ + "blocks=%d", h.manager.currentTestCase, startHeight, endHeight, + blocksMined) + + // If the number of blocks is less than 40, we consider the test + // healthy. + if blocksMined < 40 { + return + } + + // Otherwise log a warning if it's mining more than 40 blocks. + desc := "!============================================!\n" + + desc += fmt.Sprintf("Too many blocks (%v) mined in one test! Tips:\n", + blocksMined) + + desc += "1. break test into smaller individual tests, especially if " + + "this is a table-drive test.\n" + + "2. use smaller CSV via `--bitcoin.defaultremotedelay=1.`\n" + + "3. use smaller CLTV via `--bitcoin.timelockdelta=18.`\n" + + "4. remove unnecessary CloseChannel when test ends.\n" + + "5. use `CreateSimpleNetwork` for efficient channel creation.\n" + h.Log(desc) + + // We enforce that the test should not mine more than 50 blocks, which + // is more than enough to test a multi hop force close scenario. + require.LessOrEqual(h, int(blocksMined), 50, "cannot mine more than "+ + "50 blocks in one test") +} + // shutdownAllNodes will shutdown all running nodes. func (h *HarnessTest) shutdownAllNodes() { for _, node := range h.manager.activeNodes { From 686a7dd31c70263fc4c488d5dc591aac4ce1dea7 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 26 Nov 2024 17:45:12 +0800 Subject: [PATCH 55/64] docs: update release notes --- docs/release-notes/release-notes-0.19.0.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index f9491658f8..4fc64028d3 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -221,6 +221,10 @@ The underlying functionality between those two options remain the same. estimator provided by bitcoind or btcd in regtest and simnet modes instead of static fee estimator if feeurl is not provided. +* The integration tests CI have been optimized to run faster and all flakes are + now documented and + [fixed](https://github.com/lightningnetwork/lnd/pull/9368). + ## Database * [Migrate the mission control From c536bc220f0b91c3488941ae4c37ff7d9e31bbba Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 4 Dec 2024 06:29:22 +0800 Subject: [PATCH 56/64] itest: add a prefix before appending a subtest case --- itest/list_exclude_test.go | 43 +++++----- itest/list_on_test.go | 63 +++++++++++--- itest/lnd_channel_backup_test.go | 22 ++--- ...lnd_channel_funding_utxo_selection_test.go | 14 ++-- itest/lnd_funding_test.go | 6 +- itest/lnd_multi-hop_force_close_test.go | 84 +++++++++---------- itest/lnd_open_channel_test.go | 10 +-- itest/lnd_remote_signer_test.go | 24 +++--- itest/lnd_routing_test.go | 6 +- itest/lnd_wallet_import_test.go | 16 +--- itest/lnd_watchtower_test.go | 6 +- 11 files changed, 165 insertions(+), 129 deletions(-) diff --git a/itest/list_exclude_test.go b/itest/list_exclude_test.go index 86567cf352..aba4e79b8d 100644 --- a/itest/list_exclude_test.go +++ b/itest/list_exclude_test.go @@ -18,7 +18,9 @@ var excludedTestsWindows = []string{ "zero conf channel open", "open channel with unstable utxos", "funding flow persistence", - "channel policy update public zero conf", + + // Gives "channel link not found" error. + "zero conf-channel policy update public zero conf", "listsweeps", "sweep htlcs", @@ -30,12 +32,12 @@ var excludedTestsWindows = []string{ "async payments benchmark", "async bidirectional payments", - "multihop htlc aggregation leased", - "multihop htlc aggregation leased zero conf", - "multihop htlc aggregation anchor", - "multihop htlc aggregation anchor zero conf", - "multihop htlc aggregation simple taproot", - "multihop htlc aggregation simple taproot zero conf", + "multihop-htlc aggregation leased", + "multihop-htlc aggregation leased zero conf", + "multihop-htlc aggregation anchor", + "multihop-htlc aggregation anchor zero conf", + "multihop-htlc aggregation simple taproot", + "multihop-htlc aggregation simple taproot zero conf", "channel force closure anchor", "channel force closure simple taproot", @@ -50,18 +52,18 @@ var excludedTestsWindows = []string{ "invoice HTLC modifier basic", "lookup htlc resolution", - "remote signer taproot", - "remote signer account import", - "remote signer bump fee", - "remote signer funding input types", - "remote signer funding async payments taproot", - "remote signer funding async payments", - "remote signer random seed", - "remote signer verify msg", - "remote signer channel open", - "remote signer shared key", - "remote signer psbt", - "remote signer sign output raw", + "remote signer-taproot", + "remote signer-account import", + "remote signer-bump fee", + "remote signer-funding input types", + "remote signer-funding async payments taproot", + "remote signer-funding async payments", + "remote signer-random seed", + "remote signer-verify msg", + "remote signer-channel open", + "remote signer-shared key", + "remote signer-psbt", + "remote signer-sign output raw", "on chain to blinded", "query blinded route", @@ -101,7 +103,8 @@ func filterWindowsFlakyTests() []*lntest.TestCase { errStr := "\nThe following tests are not found, please make sure the " + "test names are correct in `excludedTestsWindows`.\n" for _, name := range excludedSet.ToSlice() { - errStr += fmt.Sprintf("Test not found in test suite: %v", name) + errStr += fmt.Sprintf("Test not found in test suite: %v\n", + name) } panic(errStr) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 4b1ccafc12..be3244fe5e 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -3,6 +3,8 @@ package itest import ( + "fmt" + "github.com/lightningnetwork/lnd/lntest" ) @@ -682,19 +684,58 @@ var allTestCases = []*lntest.TestCase{ }, } +// appendPrefixed is used to add a prefix to each test name in the subtests +// before appending them to the main test cases. +func appendPrefixed(prefix string, testCases, + subtestCases []*lntest.TestCase) []*lntest.TestCase { + + for _, tc := range subtestCases { + name := fmt.Sprintf("%s-%s", prefix, tc.Name) + testCases = append(testCases, &lntest.TestCase{ + Name: name, + TestFunc: tc.TestFunc, + }) + } + + return testCases +} + func init() { // Register subtests. - allTestCases = append(allTestCases, multiHopForceCloseTestCases...) - allTestCases = append(allTestCases, watchtowerTestCases...) - allTestCases = append(allTestCases, psbtFundingTestCases...) - allTestCases = append(allTestCases, remoteSignerTestCases...) - allTestCases = append(allTestCases, channelRestoreTestCases...) - allTestCases = append(allTestCases, fundUtxoSelectionTestCases...) - allTestCases = append(allTestCases, zeroConfPolicyTestCases...) - allTestCases = append(allTestCases, channelFeePolicyTestCases...) - allTestCases = append(allTestCases, walletImportAccountTestCases...) - allTestCases = append(allTestCases, basicFundingTestCases...) - allTestCases = append(allTestCases, sendToRouteTestCases...) + allTestCases = appendPrefixed( + "multihop", allTestCases, multiHopForceCloseTestCases, + ) + allTestCases = appendPrefixed( + "watchtower", allTestCases, watchtowerTestCases, + ) + allTestCases = appendPrefixed( + "psbt", allTestCases, psbtFundingTestCases, + ) + allTestCases = appendPrefixed( + "remote signer", allTestCases, remoteSignerTestCases, + ) + allTestCases = appendPrefixed( + "channel backup", allTestCases, channelRestoreTestCases, + ) + allTestCases = appendPrefixed( + "utxo selection", allTestCases, fundUtxoSelectionTestCases, + ) + allTestCases = appendPrefixed( + "zero conf", allTestCases, zeroConfPolicyTestCases, + ) + allTestCases = appendPrefixed( + "channel fee policy", allTestCases, channelFeePolicyTestCases, + ) + allTestCases = appendPrefixed( + "wallet import account", allTestCases, + walletImportAccountTestCases, + ) + allTestCases = appendPrefixed( + "funding", allTestCases, basicFundingTestCases, + ) + allTestCases = appendPrefixed( + "send to route", allTestCases, sendToRouteTestCases, + ) // Prepare the test cases for windows to exclude some of the flaky // ones. diff --git a/itest/lnd_channel_backup_test.go b/itest/lnd_channel_backup_test.go index 624e70a08d..5baf3e1a12 100644 --- a/itest/lnd_channel_backup_test.go +++ b/itest/lnd_channel_backup_test.go @@ -29,7 +29,7 @@ var channelRestoreTestCases = []*lntest.TestCase{ { // Restore the backup from the on-disk file, using the RPC // interface, for anchor commitment channels. - Name: "channel backup restore anchor", + Name: "restore anchor", TestFunc: func(ht *lntest.HarnessTest) { runChanRestoreScenarioCommitTypes( ht, lnrpc.CommitmentType_ANCHORS, false, @@ -39,7 +39,7 @@ var channelRestoreTestCases = []*lntest.TestCase{ { // Restore the backup from the on-disk file, using the RPC // interface, for script-enforced leased channels. - Name: "channel backup restore leased", + Name: "restore leased", TestFunc: func(ht *lntest.HarnessTest) { runChanRestoreScenarioCommitTypes( ht, leasedType, false, @@ -49,7 +49,7 @@ var channelRestoreTestCases = []*lntest.TestCase{ { // Restore the backup from the on-disk file, using the RPC // interface, for zero-conf anchor channels. - Name: "channel backup restore anchor zero conf", + Name: "restore anchor zero conf", TestFunc: func(ht *lntest.HarnessTest) { runChanRestoreScenarioCommitTypes( ht, lnrpc.CommitmentType_ANCHORS, true, @@ -59,7 +59,7 @@ var channelRestoreTestCases = []*lntest.TestCase{ { // Restore the backup from the on-disk file, using the RPC // interface for a zero-conf script-enforced leased channel. - Name: "channel backup restore leased zero conf", + Name: "restore leased zero conf", TestFunc: func(ht *lntest.HarnessTest) { runChanRestoreScenarioCommitTypes( ht, leasedType, true, @@ -69,7 +69,7 @@ var channelRestoreTestCases = []*lntest.TestCase{ { // Restore a channel back up of a taproot channel that was // confirmed. - Name: "channel backup restore simple taproot", + Name: "restore simple taproot", TestFunc: func(ht *lntest.HarnessTest) { runChanRestoreScenarioCommitTypes( ht, lnrpc.CommitmentType_SIMPLE_TAPROOT, false, @@ -78,7 +78,7 @@ var channelRestoreTestCases = []*lntest.TestCase{ }, { // Restore a channel back up of an unconfirmed taproot channel. - Name: "channel backup restore simple taproot zero conf", + Name: "restore simple taproot zero conf", TestFunc: func(ht *lntest.HarnessTest) { runChanRestoreScenarioCommitTypes( ht, lnrpc.CommitmentType_SIMPLE_TAPROOT, true, @@ -86,23 +86,23 @@ var channelRestoreTestCases = []*lntest.TestCase{ }, }, { - Name: "channel backup restore from rpc", + Name: "restore from rpc", TestFunc: testChannelBackupRestoreFromRPC, }, { - Name: "channel backup restore from file", + Name: "restore from file", TestFunc: testChannelBackupRestoreFromFile, }, { - Name: "channel backup restore during creation", + Name: "restore during creation", TestFunc: testChannelBackupRestoreDuringCreation, }, { - Name: "channel backup restore during unlock", + Name: "restore during unlock", TestFunc: testChannelBackupRestoreDuringUnlock, }, { - Name: "channel backup restore twice", + Name: "restore twice", TestFunc: testChannelBackupRestoreTwice, }, } diff --git a/itest/lnd_channel_funding_utxo_selection_test.go b/itest/lnd_channel_funding_utxo_selection_test.go index 7868b73338..c5ee72e6a0 100644 --- a/itest/lnd_channel_funding_utxo_selection_test.go +++ b/itest/lnd_channel_funding_utxo_selection_test.go @@ -17,31 +17,31 @@ import ( var fundUtxoSelectionTestCases = []*lntest.TestCase{ { - Name: "utxo selection funding error", + Name: "funding error", TestFunc: testChannelUtxoSelectionError, }, { - Name: "utxo selection selected valid chan size", + Name: "selected valid chan size", TestFunc: testUtxoSelectionSelectedValidChanSize, }, { - Name: "utxo selection selected valid chan reserve", + Name: "selected valid chan reserve", TestFunc: testUtxoSelectionSelectedValidChanReserve, }, { - Name: "utxo selection selected reserve from selected", + Name: "selected reserve from selected", TestFunc: testUtxoSelectionReserveFromSelected, }, { - Name: "utxo selection fundmax", + Name: "fundmax", TestFunc: testUtxoSelectionFundmax, }, { - Name: "utxo selection fundmax reserve", + Name: "fundmax reserve", TestFunc: testUtxoSelectionFundmaxReserve, }, { - Name: "utxo selection reused utxo", + Name: "reused utxo", TestFunc: testUtxoSelectionReuseUTXO, }, } diff --git a/itest/lnd_funding_test.go b/itest/lnd_funding_test.go index a2ef2e269d..bde5bebc3b 100644 --- a/itest/lnd_funding_test.go +++ b/itest/lnd_funding_test.go @@ -23,15 +23,15 @@ import ( // basicFundingTestCases defines the test cases for the basic funding test. var basicFundingTestCases = []*lntest.TestCase{ { - Name: "basic funding flow static key remote", + Name: "basic flow static key remote", TestFunc: testBasicChannelFundingStaticRemote, }, { - Name: "basic funding flow anchor", + Name: "basic flow anchor", TestFunc: testBasicChannelFundingAnchor, }, { - Name: "basic funding flow simple taproot", + Name: "basic flow simple taproot", TestFunc: testBasicChannelFundingSimpleTaproot, }, } diff --git a/itest/lnd_multi-hop_force_close_test.go b/itest/lnd_multi-hop_force_close_test.go index dc18792ea4..fde18c67db 100644 --- a/itest/lnd_multi-hop_force_close_test.go +++ b/itest/lnd_multi-hop_force_close_test.go @@ -29,171 +29,171 @@ var leasedType = lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE //nolint:ll var multiHopForceCloseTestCases = []*lntest.TestCase{ { - Name: "multihop local claim outgoing htlc anchor", + Name: "local claim outgoing htlc anchor", TestFunc: testLocalClaimOutgoingHTLCAnchor, }, { - Name: "multihop local claim outgoing htlc anchor zero conf", + Name: "local claim outgoing htlc anchor zero conf", TestFunc: testLocalClaimOutgoingHTLCAnchorZeroConf, }, { - Name: "multihop local claim outgoing htlc simple taproot", + Name: "local claim outgoing htlc simple taproot", TestFunc: testLocalClaimOutgoingHTLCSimpleTaproot, }, { - Name: "multihop local claim outgoing htlc simple taproot zero conf", + Name: "local claim outgoing htlc simple taproot zero conf", TestFunc: testLocalClaimOutgoingHTLCSimpleTaprootZeroConf, }, { - Name: "multihop local claim outgoing htlc leased", + Name: "local claim outgoing htlc leased", TestFunc: testLocalClaimOutgoingHTLCLeased, }, { - Name: "multihop local claim outgoing htlc leased zero conf", + Name: "local claim outgoing htlc leased zero conf", TestFunc: testLocalClaimOutgoingHTLCLeasedZeroConf, }, { - Name: "multihop receiver preimage claim anchor", + Name: "receiver preimage claim anchor", TestFunc: testMultiHopReceiverPreimageClaimAnchor, }, { - Name: "multihop receiver preimage claim anchor zero conf", + Name: "receiver preimage claim anchor zero conf", TestFunc: testMultiHopReceiverPreimageClaimAnchorZeroConf, }, { - Name: "multihop receiver preimage claim simple taproot", + Name: "receiver preimage claim simple taproot", TestFunc: testMultiHopReceiverPreimageClaimSimpleTaproot, }, { - Name: "multihop receiver preimage claim simple taproot zero conf", + Name: "receiver preimage claim simple taproot zero conf", TestFunc: testMultiHopReceiverPreimageClaimSimpleTaprootZeroConf, }, { - Name: "multihop receiver preimage claim leased", + Name: "receiver preimage claim leased", TestFunc: testMultiHopReceiverPreimageClaimLeased, }, { - Name: "multihop receiver preimage claim leased zero conf", + Name: "receiver preimage claim leased zero conf", TestFunc: testMultiHopReceiverPreimageClaimLeasedZeroConf, }, { - Name: "multihop local force close before timeout anchor", + Name: "local force close before timeout anchor", TestFunc: testLocalForceCloseBeforeTimeoutAnchor, }, { - Name: "multihop local force close before timeout anchor zero conf", + Name: "local force close before timeout anchor zero conf", TestFunc: testLocalForceCloseBeforeTimeoutAnchorZeroConf, }, { - Name: "multihop local force close before timeout simple taproot", + Name: "local force close before timeout simple taproot", TestFunc: testLocalForceCloseBeforeTimeoutSimpleTaproot, }, { - Name: "multihop local force close before timeout simple taproot zero conf", + Name: "local force close before timeout simple taproot zero conf", TestFunc: testLocalForceCloseBeforeTimeoutSimpleTaprootZeroConf, }, { - Name: "multihop local force close before timeout leased", + Name: "local force close before timeout leased", TestFunc: testLocalForceCloseBeforeTimeoutLeased, }, { - Name: "multihop local force close before timeout leased zero conf", + Name: "local force close before timeout leased zero conf", TestFunc: testLocalForceCloseBeforeTimeoutLeasedZeroConf, }, { - Name: "multihop remote force close before timeout anchor", + Name: "remote force close before timeout anchor", TestFunc: testRemoteForceCloseBeforeTimeoutAnchor, }, { - Name: "multihop remote force close before timeout anchor zero conf", + Name: "remote force close before timeout anchor zero conf", TestFunc: testRemoteForceCloseBeforeTimeoutAnchorZeroConf, }, { - Name: "multihop remote force close before timeout simple taproot", + Name: "remote force close before timeout simple taproot", TestFunc: testRemoteForceCloseBeforeTimeoutSimpleTaproot, }, { - Name: "multihop remote force close before timeout simple taproot zero conf", + Name: "remote force close before timeout simple taproot zero conf", TestFunc: testRemoteForceCloseBeforeTimeoutSimpleTaprootZeroConf, }, { - Name: "multihop remote force close before timeout leased", + Name: "remote force close before timeout leased", TestFunc: testRemoteForceCloseBeforeTimeoutLeased, }, { - Name: "multihop remote force close before timeout leased zero conf", + Name: "remote force close before timeout leased zero conf", TestFunc: testRemoteForceCloseBeforeTimeoutLeasedZeroConf, }, { - Name: "multihop local claim incoming htlc anchor", + Name: "local claim incoming htlc anchor", TestFunc: testLocalClaimIncomingHTLCAnchor, }, { - Name: "multihop local claim incoming htlc anchor zero conf", + Name: "local claim incoming htlc anchor zero conf", TestFunc: testLocalClaimIncomingHTLCAnchorZeroConf, }, { - Name: "multihop local claim incoming htlc simple taproot", + Name: "local claim incoming htlc simple taproot", TestFunc: testLocalClaimIncomingHTLCSimpleTaproot, }, { - Name: "multihop local claim incoming htlc simple taproot zero conf", + Name: "local claim incoming htlc simple taproot zero conf", TestFunc: testLocalClaimIncomingHTLCSimpleTaprootZeroConf, }, { - Name: "multihop local claim incoming htlc leased", + Name: "local claim incoming htlc leased", TestFunc: testLocalClaimIncomingHTLCLeased, }, { - Name: "multihop local claim incoming htlc leased zero conf", + Name: "local claim incoming htlc leased zero conf", TestFunc: testLocalClaimIncomingHTLCLeasedZeroConf, }, { - Name: "multihop local preimage claim anchor", + Name: "local preimage claim anchor", TestFunc: testLocalPreimageClaimAnchor, }, { - Name: "multihop local preimage claim anchor zero conf", + Name: "local preimage claim anchor zero conf", TestFunc: testLocalPreimageClaimAnchorZeroConf, }, { - Name: "multihop local preimage claim simple taproot", + Name: "local preimage claim simple taproot", TestFunc: testLocalPreimageClaimSimpleTaproot, }, { - Name: "multihop local preimage claim simple taproot zero conf", + Name: "local preimage claim simple taproot zero conf", TestFunc: testLocalPreimageClaimSimpleTaprootZeroConf, }, { - Name: "multihop local preimage claim leased", + Name: "local preimage claim leased", TestFunc: testLocalPreimageClaimLeased, }, { - Name: "multihop local preimage claim leased zero conf", + Name: "local preimage claim leased zero conf", TestFunc: testLocalPreimageClaimLeasedZeroConf, }, { - Name: "multihop htlc aggregation anchor", + Name: "htlc aggregation anchor", TestFunc: testHtlcAggregaitonAnchor, }, { - Name: "multihop htlc aggregation anchor zero conf", + Name: "htlc aggregation anchor zero conf", TestFunc: testHtlcAggregaitonAnchorZeroConf, }, { - Name: "multihop htlc aggregation simple taproot", + Name: "htlc aggregation simple taproot", TestFunc: testHtlcAggregaitonSimpleTaproot, }, { - Name: "multihop htlc aggregation simple taproot zero conf", + Name: "htlc aggregation simple taproot zero conf", TestFunc: testHtlcAggregaitonSimpleTaprootZeroConf, }, { - Name: "multihop htlc aggregation leased", + Name: "htlc aggregation leased", TestFunc: testHtlcAggregaitonLeased, }, { - Name: "multihop htlc aggregation leased zero conf", + Name: "htlc aggregation leased zero conf", TestFunc: testHtlcAggregaitonLeasedZeroConf, }, } diff --git a/itest/lnd_open_channel_test.go b/itest/lnd_open_channel_test.go index 9d51fc5635..84bf8cc353 100644 --- a/itest/lnd_open_channel_test.go +++ b/itest/lnd_open_channel_test.go @@ -21,23 +21,23 @@ import ( // policy fee behavior. var channelFeePolicyTestCases = []*lntest.TestCase{ { - Name: "channel fee policy default", + Name: "default", TestFunc: testChannelFeePolicyDefault, }, { - Name: "channel fee policy base fee", + Name: "base fee", TestFunc: testChannelFeePolicyBaseFee, }, { - Name: "channel fee policy fee rate", + Name: "fee rate", TestFunc: testChannelFeePolicyFeeRate, }, { - Name: "channel fee policy base fee and fee rate", + Name: "base fee and fee rate", TestFunc: testChannelFeePolicyBaseFeeAndFeeRate, }, { - Name: "channel fee policy low base fee and fee rate", + Name: "low base fee and fee rate", TestFunc: testChannelFeePolicyLowBaseFeeAndFeeRate, }, } diff --git a/itest/lnd_remote_signer_test.go b/itest/lnd_remote_signer_test.go index 6cbda365aa..fd48df6432 100644 --- a/itest/lnd_remote_signer_test.go +++ b/itest/lnd_remote_signer_test.go @@ -20,51 +20,51 @@ import ( // signer. var remoteSignerTestCases = []*lntest.TestCase{ { - Name: "remote signer random seed", + Name: "random seed", TestFunc: testRemoteSignerRadomSeed, }, { - Name: "remote signer account import", + Name: "account import", TestFunc: testRemoteSignerAccountImport, }, { - Name: "remote signer channel open", + Name: "channel open", TestFunc: testRemoteSignerChannelOpen, }, { - Name: "remote signer funding input types", + Name: "funding input types", TestFunc: testRemoteSignerChannelFundingInputTypes, }, { - Name: "remote signer funding async payments", + Name: "funding async payments", TestFunc: testRemoteSignerAsyncPayments, }, { - Name: "remote signer funding async payments taproot", + Name: "funding async payments taproot", TestFunc: testRemoteSignerAsyncPaymentsTaproot, }, { - Name: "remote signer shared key", + Name: "shared key", TestFunc: testRemoteSignerSharedKey, }, { - Name: "remote signer bump fee", + Name: "bump fee", TestFunc: testRemoteSignerBumpFee, }, { - Name: "remote signer psbt", + Name: "psbt", TestFunc: testRemoteSignerPSBT, }, { - Name: "remote signer sign output raw", + Name: "sign output raw", TestFunc: testRemoteSignerSignOutputRaw, }, { - Name: "remote signer verify msg", + Name: "verify msg", TestFunc: testRemoteSignerSignVerifyMsg, }, { - Name: "remote signer taproot", + Name: "taproot", TestFunc: testRemoteSignerTaproot, }, } diff --git a/itest/lnd_routing_test.go b/itest/lnd_routing_test.go index c32e021d44..802f1831bf 100644 --- a/itest/lnd_routing_test.go +++ b/itest/lnd_routing_test.go @@ -22,21 +22,21 @@ import ( var sendToRouteTestCases = []*lntest.TestCase{ { - Name: "single hop send to route sync", + Name: "single hop with sync", TestFunc: func(ht *lntest.HarnessTest) { // useStream: false, routerrpc: false. testSingleHopSendToRouteCase(ht, false, false) }, }, { - Name: "single hop send to route stream", + Name: "single hop with stream", TestFunc: func(ht *lntest.HarnessTest) { // useStream: true, routerrpc: false. testSingleHopSendToRouteCase(ht, true, false) }, }, { - Name: "single hop send to route v2", + Name: "single hop with v2", TestFunc: func(ht *lntest.HarnessTest) { // useStream: false, routerrpc: true. testSingleHopSendToRouteCase(ht, false, true) diff --git a/itest/lnd_wallet_import_test.go b/itest/lnd_wallet_import_test.go index f861390337..4a08fb2e6c 100644 --- a/itest/lnd_wallet_import_test.go +++ b/itest/lnd_wallet_import_test.go @@ -31,15 +31,7 @@ import ( //nolint:ll var walletImportAccountTestCases = []*lntest.TestCase{ { - Name: "wallet import account standard BIP-0044", - TestFunc: func(ht *lntest.HarnessTest) { - testWalletImportAccountScenario( - ht, walletrpc.AddressType_WITNESS_PUBKEY_HASH, - ) - }, - }, - { - Name: "wallet import account standard BIP-0049", + Name: "standard BIP-0049", TestFunc: func(ht *lntest.HarnessTest) { testWalletImportAccountScenario( ht, walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH, @@ -47,7 +39,7 @@ var walletImportAccountTestCases = []*lntest.TestCase{ }, }, { - Name: "wallet import account lnd BIP-0049 variant", + Name: "lnd BIP-0049 variant", TestFunc: func(ht *lntest.HarnessTest) { testWalletImportAccountScenario( ht, walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH, @@ -55,7 +47,7 @@ var walletImportAccountTestCases = []*lntest.TestCase{ }, }, { - Name: "wallet import account standard BIP-0084", + Name: "standard BIP-0084", TestFunc: func(ht *lntest.HarnessTest) { testWalletImportAccountScenario( ht, walletrpc.AddressType_WITNESS_PUBKEY_HASH, @@ -63,7 +55,7 @@ var walletImportAccountTestCases = []*lntest.TestCase{ }, }, { - Name: "wallet import account standard BIP-0086", + Name: "standard BIP-0086", TestFunc: func(ht *lntest.HarnessTest) { testWalletImportAccountScenario( ht, walletrpc.AddressType_TAPROOT_PUBKEY, diff --git a/itest/lnd_watchtower_test.go b/itest/lnd_watchtower_test.go index 1f5ad6ea31..73857bab93 100644 --- a/itest/lnd_watchtower_test.go +++ b/itest/lnd_watchtower_test.go @@ -23,15 +23,15 @@ import ( // watchtower client and server. var watchtowerTestCases = []*lntest.TestCase{ { - Name: "watchtower revoked close retribution altruist", + Name: "revoked close retribution altruist", TestFunc: testRevokedCloseRetributionAltruistWatchtower, }, { - Name: "watchtower client session deletion", + Name: "client session deletion", TestFunc: testTowerClientSessionDeletion, }, { - Name: "watchtower client tower and session management", + Name: "client tower and session management", TestFunc: testTowerClientTowerAndSessionManagement, }, } From 33b07be8c37cd2b484b5258e7b594ed4b3c85cd2 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 4 Dec 2024 09:51:10 +0800 Subject: [PATCH 57/64] itest: even out num of tests per tranche Previous splitting logic simply put all the remainder in the last tranche, which could make the last tranche run significantly more test cases. We now change it so the remainder is evened out across tranches. --- itest/lnd_test.go | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/itest/lnd_test.go b/itest/lnd_test.go index c1a43b4106..07b8554f2f 100644 --- a/itest/lnd_test.go +++ b/itest/lnd_test.go @@ -174,6 +174,30 @@ func maybeShuffleTestCases() { }) } +// createIndices divides the number of test cases into pairs of indices that +// specify the start and end of a tranche. +func createIndices(numCases, numTranches uint) [][2]uint { + // Calculate base value and remainder. + base := numCases / numTranches + remainder := numCases % numTranches + + // Generate indices. + indices := make([][2]uint, numTranches) + start := uint(0) + + for i := uint(0); i < numTranches; i++ { + end := start + base + if i < remainder { + // Add one for the remainder. + end++ + } + indices[i] = [2]uint{start, end} + start = end + } + + return indices +} + // getTestCaseSplitTranche returns the sub slice of the test cases that should // be run as the current split tranche as well as the index and slice offset of // the tranche. @@ -200,12 +224,9 @@ func getTestCaseSplitTranche() ([]*lntest.TestCase, uint, uint) { maybeShuffleTestCases() numCases := uint(len(allTestCases)) - testsPerTranche := numCases / numTranches - trancheOffset := runTranche * testsPerTranche - trancheEnd := trancheOffset + testsPerTranche - if trancheEnd > numCases || runTranche == numTranches-1 { - trancheEnd = numCases - } + indices := createIndices(numCases, numTranches) + index := indices[runTranche] + trancheOffset, trancheEnd := index[0], index[1] return allTestCases[trancheOffset:trancheEnd], threadID, trancheOffset From d7f8fa6ab6d09f810a982fdaee5704f1cff1cb3f Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 4 Dec 2024 10:46:25 +0800 Subject: [PATCH 58/64] lntest: increase port timeout --- lntest/port/port.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lntest/port/port.go b/lntest/port/port.go index 28db1918dc..28cd92d69b 100644 --- a/lntest/port/port.go +++ b/lntest/port/port.go @@ -8,6 +8,8 @@ import ( "strconv" "sync" "time" + + "github.com/lightningnetwork/lnd/lntest/wait" ) const ( @@ -45,7 +47,7 @@ func NextAvailablePort() int { defer portFileMutex.Unlock() lockFile := filepath.Join(os.TempDir(), uniquePortFile+".lock") - timeout := time.After(time.Second) + timeout := time.After(wait.DefaultTimeout) var ( lockFileHandle *os.File From 73574d919d9c141f36b4d64fd19cf0d43cb3ad88 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 4 Dec 2024 13:44:32 +0800 Subject: [PATCH 59/64] lntest: add timeouts for windows For Windows the tests run much slower so we create customized timeouts for them. --- lntest/wait/timeouts.go | 4 ++-- lntest/wait/timeouts_windows.go | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 lntest/wait/timeouts_windows.go diff --git a/lntest/wait/timeouts.go b/lntest/wait/timeouts.go index f8239799b6..312c788c42 100644 --- a/lntest/wait/timeouts.go +++ b/lntest/wait/timeouts.go @@ -1,5 +1,5 @@ -//go:build !darwin && !kvdb_etcd && !kvdb_postgres -// +build !darwin,!kvdb_etcd,!kvdb_postgres +//go:build !darwin && !windows && !kvdb_etcd && !kvdb_postgres +// +build !darwin,!windows,!kvdb_etcd,!kvdb_postgres package wait diff --git a/lntest/wait/timeouts_windows.go b/lntest/wait/timeouts_windows.go new file mode 100644 index 0000000000..4fba516f1e --- /dev/null +++ b/lntest/wait/timeouts_windows.go @@ -0,0 +1,39 @@ +//go:build windows && !kvdb_etcd && !kvdb_postgres +// +build windows,!kvdb_etcd,!kvdb_postgres + +package wait + +import "time" + +const ( + // MinerMempoolTimeout is the max time we will wait for a transaction + // to propagate to the mining node's mempool. + MinerMempoolTimeout = time.Minute + + // ChannelOpenTimeout is the max time we will wait before a channel to + // be considered opened. + ChannelOpenTimeout = time.Second * 30 + + // ChannelCloseTimeout is the max time we will wait before a channel is + // considered closed. + ChannelCloseTimeout = time.Second * 30 + + // DefaultTimeout is a timeout that will be used for various wait + // scenarios where no custom timeout value is defined. + DefaultTimeout = time.Second * 60 + + // AsyncBenchmarkTimeout is the timeout used when running the async + // payments benchmark. + AsyncBenchmarkTimeout = time.Minute * 5 + + // NodeStartTimeout is the timeout value when waiting for a node to + // become fully started. + NodeStartTimeout = time.Minute * 3 + + // SqliteBusyTimeout is the maximum time that a call to the sqlite db + // will wait for the connection to become available. + SqliteBusyTimeout = time.Second * 10 + + // PaymentTimeout is the timeout used when sending payments. + PaymentTimeout = time.Second * 120 +) From 31b66962d83aeac12ffba3a69c4597bc236ee204 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 5 Dec 2024 10:25:23 +0800 Subject: [PATCH 60/64] lntest: properly handle shutdown error This commit removes the panic used in checking the shutdown log. Instead, the error is returned and asserted in `shutdownAllNodes` so it's easier to check which node failed in which test. We also catch all the errors returned from `StopDaemon` call to properly access the shutdown behavior. --- lntest/harness.go | 32 ++++++++-------- lntest/harness_node_manager.go | 5 ++- lntest/node/harness_node.go | 68 +++++++++++++++++----------------- 3 files changed, 56 insertions(+), 49 deletions(-) diff --git a/lntest/harness.go b/lntest/harness.go index 54f183d39f..f32f677737 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -332,7 +332,7 @@ func (h *HarnessTest) Subtest(t *testing.T) *HarnessTest { // Don't bother run the cleanups if the test is failed. if st.Failed() { st.Log("test failed, skipped cleanup") - st.shutdownAllNodes() + st.shutdownNodesNoAssert() return } @@ -402,16 +402,20 @@ func (h *HarnessTest) checkAndLimitBlocksMined(startHeight int32) { "50 blocks in one test") } +// shutdownNodesNoAssert will shutdown all running nodes without assertions. +// This is used when the test has already failed, we don't want to log more +// errors but focusing on the original error. +func (h *HarnessTest) shutdownNodesNoAssert() { + for _, node := range h.manager.activeNodes { + _ = h.manager.shutdownNode(node) + } +} + // shutdownAllNodes will shutdown all running nodes. func (h *HarnessTest) shutdownAllNodes() { + var err error for _, node := range h.manager.activeNodes { - // The process may not be in a state to always shutdown - // immediately, so we'll retry up to a hard limit to ensure we - // eventually shutdown. - err := wait.NoError(func() error { - return h.manager.shutdownNode(node) - }, DefaultTimeout) - + err = h.manager.shutdownNode(node) if err == nil { continue } @@ -421,6 +425,8 @@ func (h *HarnessTest) shutdownAllNodes() { // processes. h.Logf("unable to shutdown %s, got err: %v", node.Name(), err) } + + require.NoError(h, err, "failed to shutdown all nodes") } // cleanupStandbyNode is a function should be called with defer whenever a @@ -516,12 +522,7 @@ func (h *HarnessTest) NewNodeWithCoins(name string, // Shutdown shuts down the given node and asserts that no errors occur. func (h *HarnessTest) Shutdown(node *node.HarnessNode) { - // The process may not be in a state to always shutdown immediately, so - // we'll retry up to a hard limit to ensure we eventually shutdown. - err := wait.NoError(func() error { - return h.manager.shutdownNode(node) - }, DefaultTimeout) - + err := h.manager.shutdownNode(node) require.NoErrorf(h, err, "unable to shutdown %v in %v", node.Name(), h.manager.currentTestCase) } @@ -764,9 +765,10 @@ func (h *HarnessTest) NewNodeRemoteSigner(name string, extraArgs []string, // KillNode kills the node and waits for the node process to stop. func (h *HarnessTest) KillNode(hn *node.HarnessNode) { + delete(h.manager.activeNodes, hn.Cfg.NodeID) + h.Logf("Manually killing the node %s", hn.Name()) require.NoErrorf(h, hn.KillAndWait(), "%s: kill got error", hn.Name()) - delete(h.manager.activeNodes, hn.Cfg.NodeID) } // SetFeeEstimate sets a fee rate to be returned from fee estimator. diff --git a/lntest/harness_node_manager.go b/lntest/harness_node_manager.go index 2040acec7f..48afa6b358 100644 --- a/lntest/harness_node_manager.go +++ b/lntest/harness_node_manager.go @@ -112,11 +112,14 @@ func (nm *nodeManager) registerNode(node *node.HarnessNode) { // ShutdownNode stops an active lnd process and returns when the process has // exited and any temporary directories have been cleaned up. func (nm *nodeManager) shutdownNode(node *node.HarnessNode) error { + // Remove the node from the active nodes map even if the shutdown + // fails as the shutdown cannot be retried in that case. + delete(nm.activeNodes, node.Cfg.NodeID) + if err := node.Shutdown(); err != nil { return err } - delete(nm.activeNodes, node.Cfg.NodeID) return nil } diff --git a/lntest/node/harness_node.go b/lntest/node/harness_node.go index d1353c25cf..0ac74f8779 100644 --- a/lntest/node/harness_node.go +++ b/lntest/node/harness_node.go @@ -636,12 +636,11 @@ func (hn *HarnessNode) cleanup() error { // waitForProcessExit Launch a new goroutine which that bubbles up any // potential fatal process errors to the goroutine running the tests. func (hn *HarnessNode) WaitForProcessExit() error { - var err error + var errReturned error errChan := make(chan error, 1) go func() { - err = hn.cmd.Wait() - errChan <- err + errChan <- hn.cmd.Wait() }() select { @@ -656,24 +655,36 @@ func (hn *HarnessNode) WaitForProcessExit() error { return nil } + // The process may have already been killed in the test, in + // that case we will skip the error and continue processing + // the logs. + if strings.Contains(err.Error(), "signal: killed") { + break + } + // Otherwise, we print the error, break the select and save // logs. hn.printErrf("wait process exit got err: %v", err) - - break + errReturned = err case <-time.After(wait.DefaultTimeout): hn.printErrf("timeout waiting for process to exit") } // Make sure log file is closed and renamed if necessary. - finalizeLogfile(hn) + filename := finalizeLogfile(hn) - // Rename the etcd.log file if the node was running on embedded - // etcd. + // Assert the node has shut down from the log file. + err1 := assertNodeShutdown(filename) + if err1 != nil { + return fmt.Errorf("[%s]: assert shutdown failed in log[%s]: %w", + hn.Name(), filename, err1) + } + + // Rename the etcd.log file if the node was running on embedded etcd. finalizeEtcdLog(hn) - return err + return errReturned } // Stop attempts to stop the active lnd process. @@ -700,23 +711,21 @@ func (hn *HarnessNode) Stop() error { err := wait.NoError(func() error { _, err := hn.RPC.LN.StopDaemon(ctxt, &req) - - switch { - case err == nil: + if err == nil { return nil + } - // Try again if a recovery/rescan is in progress. - case strings.Contains( - err.Error(), "recovery in progress", - ): - return err - - default: + // If the connection is already closed, we can exit + // early as the node has already been shut down in the + // test, e.g., in etcd leader health check test. + if strings.Contains(err.Error(), "connection refused") { return nil } + + return err }, wait.DefaultTimeout) if err != nil { - return err + return fmt.Errorf("shutdown timeout: %w", err) } // Wait for goroutines to be finished. @@ -724,6 +733,7 @@ func (hn *HarnessNode) Stop() error { go func() { hn.Watcher.wg.Wait() close(done) + hn.Watcher = nil }() // If the goroutines fail to finish before timeout, we'll print @@ -966,31 +976,23 @@ func getFinalizedLogFilePrefix(hn *HarnessNode) string { // finalizeLogfile makes sure the log file cleanup function is initialized, // even if no log file is created. -func finalizeLogfile(hn *HarnessNode) { +func finalizeLogfile(hn *HarnessNode) string { // Exit early if there's no log file. if hn.logFile == nil { - return + return "" } hn.logFile.Close() // If logoutput flag is not set, return early. if !*logOutput { - return + return "" } - newFileName := fmt.Sprintf("%v.log", - getFinalizedLogFilePrefix(hn), - ) + newFileName := fmt.Sprintf("%v.log", getFinalizedLogFilePrefix(hn)) renameFile(hn.filename, newFileName) - // Assert the node has shut down from the log file. - err := assertNodeShutdown(newFileName) - if err != nil { - err := fmt.Errorf("[%s]: assert shutdown failed in log[%s]: %w", - hn.Name(), newFileName, err) - panic(err) - } + return newFileName } // assertNodeShutdown asserts that the node has shut down properly by checking From 1dec92616599323f682fe5e51f53fc1f5507264e Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 5 Dec 2024 17:29:54 +0800 Subject: [PATCH 61/64] workflows: increase num of tranches to 16 Keep the SQL, etcd, bitcoin rpcpolling builds and non-ubuntu builds at 8 since they are less stable. --- .github/workflows/main.yml | 104 +++++++++++++++++++++++++++++-------- 1 file changed, 83 insertions(+), 21 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bc672a435b..b180aa04d0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,7 +23,14 @@ defaults: env: BITCOIN_VERSION: "28" - TRANCHES: 8 + # TRANCHES defines the number of tranches used in the itests. + TRANCHES: 16 + + # SMALL_TRANCHES defines the number of tranches used in the less stable itest + # builds + # + # TODO(yy): remove this value and use TRANCHES. + SMALL_TRANCHES: 8 # If you change this please also update GO_VERSION in Makefile (then run # `make lint` to see where else it needs to be updated as well). @@ -262,10 +269,10 @@ jobs: ######################## - # run ubuntu integration tests + # run integration tests with TRANCHES ######################## - ubuntu-integration-test: - name: run ubuntu itests + basic-integration-test: + name: basic itests runs-on: ubuntu-latest if: '!contains(github.event.pull_request.labels.*.name, ''no-itest'')' strategy: @@ -279,18 +286,6 @@ jobs: args: backend=bitcoind cover=1 - name: bitcoind-notxindex args: backend="bitcoind notxindex" - - name: bitcoind-rpcpolling - args: backend="bitcoind rpcpolling" cover=1 - - name: bitcoind-etcd - args: backend=bitcoind dbbackend=etcd - - name: bitcoind-postgres - args: backend=bitcoind dbbackend=postgres - - name: bitcoind-sqlite - args: backend=bitcoind dbbackend=sqlite - - name: bitcoind-postgres-nativesql - args: backend=bitcoind dbbackend=postgres nativesql=true - - name: bitcoind-sqlite-nativesql - args: backend=bitcoind dbbackend=sqlite nativesql=true - name: neutrino args: backend=neutrino cover=1 steps: @@ -339,12 +334,79 @@ jobs: path: logs-itest-${{ matrix.name }}.zip retention-days: 5 + ######################## + # run integration tests with SMALL_TRANCHES + ######################## + integration-test: + name: itests + runs-on: ubuntu-latest + if: '!contains(github.event.pull_request.labels.*.name, ''no-itest'')' + strategy: + # Allow other tests in the matrix to continue if one fails. + fail-fast: false + matrix: + include: + - name: bitcoind-rpcpolling + args: backend="bitcoind rpcpolling" + - name: bitcoind-etcd + args: backend=bitcoind dbbackend=etcd + - name: bitcoind-sqlite + args: backend=bitcoind dbbackend=sqlite + - name: bitcoind-sqlite-nativesql + args: backend=bitcoind dbbackend=sqlite nativesql=true + - name: bitcoind-postgres + args: backend=bitcoind dbbackend=postgres + - name: bitcoind-postgres-nativesql + args: backend=bitcoind dbbackend=postgres nativesql=true + steps: + - name: git checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: fetch and rebase on ${{ github.base_ref }} + if: github.event_name == 'pull_request' + uses: ./.github/actions/rebase + + - name: setup go ${{ env.GO_VERSION }} + uses: ./.github/actions/setup-go + with: + go-version: '${{ env.GO_VERSION }}' + key-prefix: integration-test + + - name: install bitcoind + run: ./scripts/install_bitcoind.sh $BITCOIN_VERSION + + - name: run ${{ matrix.name }} + run: make itest-parallel tranches=${{ env.SMALL_TRANCHES }} ${{ matrix.args }} shuffleseed=${{ github.run_id }}${{ strategy.job-index }} + + - name: Send coverage + if: ${{ contains(matrix.args, 'cover=1') }} + uses: shogo82148/actions-goveralls@v1 + with: + path-to-profile: coverage.txt + flag-name: 'itest-${{ matrix.name }}' + parallel: true + + - name: Zip log files on failure + if: ${{ failure() }} + timeout-minutes: 5 # timeout after 5 minute + run: 7z a logs-itest-${{ matrix.name }}.zip itest/**/*.log + + - name: Upload log files on failure + uses: actions/upload-artifact@v3 + if: ${{ failure() }} + with: + name: logs-itest-${{ matrix.name }} + path: logs-itest-${{ matrix.name }}.zip + retention-days: 5 + ######################## # run windows integration test ######################## windows-integration-test: - name: run windows itest + name: windows itest runs-on: windows-latest if: '!contains(github.event.pull_request.labels.*.name, ''no-itest'')' steps: @@ -364,7 +426,7 @@ jobs: key-prefix: integration-test - name: run itest - run: make itest-parallel tranches=${{ env.TRANCHES }} windows=1 shuffleseed=${{ github.run_id }} + run: make itest-parallel tranches=${{ env.SMALL_TRANCHES }} windows=1 shuffleseed=${{ github.run_id }} - name: kill any remaining lnd processes if: ${{ failure() }} @@ -388,7 +450,7 @@ jobs: # run macOS integration test ######################## macos-integration-test: - name: run macOS itest + name: macOS itest runs-on: macos-14 if: '!contains(github.event.pull_request.labels.*.name, ''no-itest'')' steps: @@ -408,7 +470,7 @@ jobs: key-prefix: integration-test - name: run itest - run: make itest-parallel tranches=${{ env.TRANCHES }} shuffleseed=${{ github.run_id }} + run: make itest-parallel tranches=${{ env.SMALL_TRANCHES }} shuffleseed=${{ github.run_id }} - name: Zip log files on failure if: ${{ failure() }} @@ -467,7 +529,7 @@ jobs: # Notify about the completion of all coverage collecting jobs. finish: if: ${{ always() }} - needs: [unit-test, ubuntu-integration-test] + needs: [unit-test, basic-integration-test] runs-on: ubuntu-latest steps: - uses: ziggie1984/actions-goveralls@c440f43938a4032b627d2b03d61d4ae1a2ba2b5c From 7ab4081ffd1d39adfab29808ea4472231182c28a Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 7 Dec 2024 18:02:59 +0800 Subject: [PATCH 62/64] lntest: make sure chain backend is synced to miner We sometimes see `timeout waiting for UTXOs` error from bitcoind-related itests due to the chain backend not synced to the miner. We now assert it's synced before continue. --- lntest/harness.go | 15 +++++++++------ lntest/harness_assertion.go | 6 +++--- lntest/harness_miner.go | 6 +++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lntest/harness.go b/lntest/harness.go index f32f677737..fe0caa84d2 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -481,6 +481,14 @@ func (h *HarnessTest) NewNode(name string, err = node.Start(h.runCtx) require.NoError(h, err, "failed to start node %s", node.Name()) + // Get the miner's best block hash. + bestBlock, err := h.miner.Client.GetBestBlockHash() + require.NoError(h, err, "unable to get best block hash") + + // Wait until the node's chain backend is synced to the miner's best + // block. + h.WaitForBlockchainSyncTo(node, *bestBlock) + return node } @@ -490,12 +498,7 @@ func (h *HarnessTest) NewNode(name string, func (h *HarnessTest) NewNodeWithCoins(name string, extraArgs []string) *node.HarnessNode { - node, err := h.manager.newNode(h.T, name, extraArgs, nil, false) - require.NoErrorf(h, err, "unable to create new node for %s", name) - - // Start the node. - err = node.Start(h.runCtx) - require.NoError(h, err, "failed to start node %s", node.Name()) + node := h.NewNode(name, extraArgs) // Load up the wallets of the node with 5 outputs of 1 BTC each. const ( diff --git a/lntest/harness_assertion.go b/lntest/harness_assertion.go index fd4a0dfd73..d5835fe573 100644 --- a/lntest/harness_assertion.go +++ b/lntest/harness_assertion.go @@ -61,9 +61,9 @@ func (h *HarnessTest) WaitForBlockchainSync(hn *node.HarnessNode) { // WaitForBlockchainSyncTo waits until the node is synced to bestBlock. func (h *HarnessTest) WaitForBlockchainSyncTo(hn *node.HarnessNode, - bestBlock *wire.MsgBlock) { + bestBlock chainhash.Hash) { - bestBlockHash := bestBlock.BlockHash().String() + bestBlockHash := bestBlock.String() err := wait.NoError(func() error { resp := hn.RPC.GetInfo() if resp.SyncedToChain { @@ -1629,7 +1629,7 @@ func (h *HarnessTest) AssertActiveNodesSynced() { // AssertActiveNodesSyncedTo asserts all active nodes have synced to the // provided bestBlock. -func (h *HarnessTest) AssertActiveNodesSyncedTo(bestBlock *wire.MsgBlock) { +func (h *HarnessTest) AssertActiveNodesSyncedTo(bestBlock chainhash.Hash) { for _, node := range h.manager.activeNodes { h.WaitForBlockchainSyncTo(node, bestBlock) } diff --git a/lntest/harness_miner.go b/lntest/harness_miner.go index 17fd864ed7..cde9663c4f 100644 --- a/lntest/harness_miner.go +++ b/lntest/harness_miner.go @@ -41,7 +41,7 @@ func (h *HarnessTest) MineBlocks(num int) { // Check the block doesn't have any txns except the coinbase. if len(block.Transactions) <= 1 { // Make sure all the active nodes are synced. - h.AssertActiveNodesSyncedTo(block) + h.AssertActiveNodesSyncedTo(block.BlockHash()) // Mine the next block. continue @@ -116,7 +116,7 @@ func (h *HarnessTest) MineBlocksAndAssertNumTxes(num uint32, // Finally, make sure all the active nodes are synced. bestBlock := blocks[len(blocks)-1] - h.AssertActiveNodesSyncedTo(bestBlock) + h.AssertActiveNodesSyncedTo(bestBlock.BlockHash()) return blocks } @@ -157,7 +157,7 @@ func (h *HarnessTest) cleanMempool() { bestBlock = blocks[len(blocks)-1] // Make sure all the active nodes are synced. - h.AssertActiveNodesSyncedTo(bestBlock) + h.AssertActiveNodesSyncedTo(bestBlock.BlockHash()) return fmt.Errorf("still have %d txes in mempool", len(mem)) }, wait.MinerMempoolTimeout) From 76eeae32d6a7af2c5691273ab7deae6f05984b43 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Sat, 7 Dec 2024 18:04:13 +0800 Subject: [PATCH 63/64] itest: document and fix wallet UTXO flake --- itest/lnd_multi-hop_force_close_test.go | 34 +++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/itest/lnd_multi-hop_force_close_test.go b/itest/lnd_multi-hop_force_close_test.go index fde18c67db..4284631e86 100644 --- a/itest/lnd_multi-hop_force_close_test.go +++ b/itest/lnd_multi-hop_force_close_test.go @@ -679,8 +679,6 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest, alice, bob, carol := nodes[0], nodes[1], nodes[2] bobChanPoint := chanPoints[1] - ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) - // For neutrino backend, we need to one more UTXO for Carol so she can // sweep her outputs. if ht.IsNeutrinoBackend() { @@ -690,6 +688,14 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest, // Fund Carol one UTXO so she can sweep outputs. ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) + // Carol should have enough wallet UTXOs here to sweep the HTLC in the + // end of this test. However, due to a known issue, Carol's wallet may + // report there's no UTXO available. For details, + // - https://github.com/lightningnetwork/lnd/issues/8786 + // + // TODO(yy): remove this step once the issue is resolved. + ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) + // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint @@ -1633,6 +1639,22 @@ func runLocalClaimIncomingHTLC(ht *lntest.HarnessTest, // Fund Carol one UTXO so she can sweep outputs. ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) + // Carol should have enough wallet UTXOs here to sweep the HTLC in the + // end of this test. However, due to a known issue, Carol's wallet may + // report there's no UTXO available. For details, + // - https://github.com/lightningnetwork/lnd/issues/8786 + // + // TODO(yy): remove this step once the issue is resolved. + ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) + + // Bob should have enough wallet UTXOs here to sweep the HTLC in the + // end of this test. However, due to a known issue, Bob's wallet may + // report there's no UTXO available. For details, + // - https://github.com/lightningnetwork/lnd/issues/8786 + // + // TODO(yy): remove this step once the issue is resolved. + ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) + // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint @@ -2603,6 +2625,14 @@ func runLocalPreimageClaimLeased(ht *lntest.HarnessTest, // Fund Carol one UTXO so she can sweep outputs. ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) + // Carol should have enough wallet UTXOs here to sweep the HTLC in the + // end of this test. However, due to a known issue, Carol's wallet may + // report there's no UTXO available. For details, + // - https://github.com/lightningnetwork/lnd/issues/8786 + // + // TODO(yy): remove this step once the issue is resolved. + ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) + // With the network active, we'll now add a new hodl invoice at Carol's // end. Make sure the cltv expiry delta is large enough, otherwise Bob // won't send out the outgoing htlc. From 2913f6e4c9b55d806491ca530973ca5e3da05752 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 10 Dec 2024 15:43:49 +0800 Subject: [PATCH 64/64] itest: fix flake in `testCoopCloseWithExternalDeliveryImpl` The response from `ClosedChannels` may not be up-to-date, so we wrap it inside a wait closure. --- .../lnd_coop_close_external_delivery_test.go | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/itest/lnd_coop_close_external_delivery_test.go b/itest/lnd_coop_close_external_delivery_test.go index 8341a2f650..eea09a48d9 100644 --- a/itest/lnd_coop_close_external_delivery_test.go +++ b/itest/lnd_coop_close_external_delivery_test.go @@ -1,11 +1,13 @@ package itest import ( + "fmt" "testing" "github.com/btcsuite/btcd/btcutil" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntest" + "github.com/lightningnetwork/lnd/lntest/wait" "github.com/stretchr/testify/require" ) @@ -114,11 +116,20 @@ func testCoopCloseWithExternalDeliveryImpl(ht *lntest.HarnessTest, // assertion. We want to ensure that even though alice's delivery // address is set to an address in bob's wallet, we should still show // the balance as settled. - closed := alice.RPC.ClosedChannels(&lnrpc.ClosedChannelsRequest{ - Cooperative: true, - }) - - // The settled balance should never be zero at this point. - require.NotZero(ht, len(closed.Channels)) - require.NotZero(ht, closed.Channels[0].SettledBalance) + err = wait.NoError(func() error { + closed := alice.RPC.ClosedChannels(&lnrpc.ClosedChannelsRequest{ + Cooperative: true, + }) + + if len(closed.Channels) == 0 { + return fmt.Errorf("expected closed channel not found") + } + + if closed.Channels[0].SettledBalance == 0 { + return fmt.Errorf("expected settled balance to be zero") + } + + return nil + }, defaultTimeout) + require.NoError(ht, err, "timeout checking closed channels") }