From 476434f5461cd3abdc87a90ccd09e58d09fc5000 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 9 Aug 2022 19:04:36 +0800 Subject: [PATCH] lntemp+itest: refactor `testSwitchOfflineDelivery` --- lntemp/harness_assertion.go | 3 + lntest/itest/list_on_test.go | 4 + lntest/itest/lnd_switch_test.go | 278 ++------------------------ lntest/itest/lnd_test_list_on_test.go | 4 - 4 files changed, 26 insertions(+), 263 deletions(-) diff --git a/lntemp/harness_assertion.go b/lntemp/harness_assertion.go index e2d7c05e3..b57875dde 100644 --- a/lntemp/harness_assertion.go +++ b/lntemp/harness_assertion.go @@ -127,6 +127,9 @@ func (h *HarnessTest) ConnectNodesPerm(a, b *node.HarnessNode) { func (h *HarnessTest) DisconnectNodes(a, b *node.HarnessNode) { bobInfo := b.RPC.GetInfo() a.RPC.DisconnectPeer(bobInfo.IdentityPubkey) + + // Assert disconnected. + h.AssertPeerNotConnected(a, b) } // EnsureConnected will try to connect to two nodes, returning no error if they diff --git a/lntest/itest/list_on_test.go b/lntest/itest/list_on_test.go index 5f3112974..6fba40711 100644 --- a/lntest/itest/list_on_test.go +++ b/lntest/itest/list_on_test.go @@ -373,4 +373,8 @@ var allTestCasesTemp = []*lntemp.TestCase{ Name: "switch circuit persistence", TestFunc: testSwitchCircuitPersistence, }, + { + Name: "switch offline delivery", + TestFunc: testSwitchOfflineDelivery, + }, } diff --git a/lntest/itest/lnd_switch_test.go b/lntest/itest/lnd_switch_test.go index 73b7c8a44..3a2a0958e 100644 --- a/lntest/itest/lnd_switch_test.go +++ b/lntest/itest/lnd_switch_test.go @@ -10,7 +10,6 @@ import ( "github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest/wait" - "github.com/stretchr/testify/require" ) const ( @@ -100,244 +99,41 @@ func testSwitchCircuitPersistence(ht *lntemp.HarnessTest) { // 2. Carol --- Dave X Alice --- Bob disconnect intermediaries // 3. Carol --- Dave X Alice <-- Bob settle last hop // 4. Carol <-- Dave <-- Alice --- Bob reconnect, expect settle to propagate -func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) { - ctxb := context.Background() - - const chanAmt = btcutil.Amount(1000000) - const pushAmt = btcutil.Amount(900000) - var networkChans []*lnrpc.ChannelPoint - - // Open a channel with 100k satoshis between Alice and Bob with Alice - // being the sole funder of the channel. - chanPointAlice := openChannelAndAssert( - t, net, net.Alice, net.Bob, - lntest.OpenChannelParams{ - Amt: chanAmt, - PushAmt: pushAmt, - }, - ) - networkChans = append(networkChans, chanPointAlice) - - aliceChanTXID, err := lnrpc.GetChanPointFundingTxid(chanPointAlice) - if err != nil { - t.Fatalf("unable to get txid: %v", err) - } - aliceFundPoint := wire.OutPoint{ - Hash: *aliceChanTXID, - Index: chanPointAlice.OutputIndex, - } - - // As preliminary setup, we'll create two new nodes: Carol and Dave, - // such that we now have a 4 ndoe, 3 channel topology. Dave will make - // a channel with Alice, and Carol with Dave. After this setup, the - // network topology should now look like: - // Carol -> Dave -> Alice -> Bob - // - // First, we'll create Dave and establish a channel to Alice. - dave := net.NewNode(t.t, "Dave", nil) - defer shutdownAndAssert(net, t, dave) - - net.ConnectNodes(t.t, dave, net.Alice) - net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, dave) - - chanPointDave := openChannelAndAssert( - t, net, dave, net.Alice, - lntest.OpenChannelParams{ - Amt: chanAmt, - PushAmt: pushAmt, - }, - ) - networkChans = append(networkChans, chanPointDave) - daveChanTXID, err := lnrpc.GetChanPointFundingTxid(chanPointDave) - if err != nil { - t.Fatalf("unable to get txid: %v", err) - } - daveFundPoint := wire.OutPoint{ - Hash: *daveChanTXID, - Index: chanPointDave.OutputIndex, - } - - // Next, we'll create Carol and establish a channel to from her to - // Dave. Carol is started in htlchodl mode so that we can disconnect the - // intermediary hops before starting the settle. - carol := net.NewNode(t.t, "Carol", []string{"--hodl.exit-settle"}) - defer shutdownAndAssert(net, t, carol) - - net.ConnectNodes(t.t, carol, dave) - net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, carol) - - chanPointCarol := openChannelAndAssert( - t, net, carol, dave, - lntest.OpenChannelParams{ - Amt: chanAmt, - PushAmt: pushAmt, - }, - ) - networkChans = append(networkChans, chanPointCarol) - - carolChanTXID, err := lnrpc.GetChanPointFundingTxid(chanPointCarol) - if err != nil { - t.Fatalf("unable to get txid: %v", err) - } - carolFundPoint := wire.OutPoint{ - Hash: *carolChanTXID, - Index: chanPointCarol.OutputIndex, - } - - // Wait for all nodes to have seen all channels. - nodes := []*lntest.HarnessNode{net.Alice, net.Bob, carol, dave} - nodeNames := []string{"Alice", "Bob", "Carol", "Dave"} - for _, chanPoint := range networkChans { - for i, node := range nodes { - txid, err := lnrpc.GetChanPointFundingTxid(chanPoint) - if err != nil { - t.Fatalf("unable to get txid: %v", err) - } - point := wire.OutPoint{ - Hash: *txid, - Index: chanPoint.OutputIndex, - } - - err = node.WaitForNetworkChannelOpen(chanPoint) - if err != nil { - t.Fatalf("%s(%d): timeout waiting for "+ - "channel(%s) open: %v", nodeNames[i], - node.NodeID, point, err) - } - } - } - - // Create 5 invoices for Carol, which expect a payment from Bob for 1k - // satoshis with a different preimage each time. - const numPayments = 5 - const paymentAmt = 1000 - payReqs, _, _, err := createPayReqs( - carol, paymentAmt, numPayments, - ) - if err != nil { - t.Fatalf("unable to create pay reqs: %v", err) - } - - // We'll wait for all parties to recognize the new channels within the - // network. - err = dave.WaitForNetworkChannelOpen(chanPointDave) - if err != nil { - t.Fatalf("dave didn't advertise his channel: %v", err) - } - err = carol.WaitForNetworkChannelOpen(chanPointCarol) - if err != nil { - t.Fatalf("carol didn't advertise her channel in time: %v", - err) - } - - // Make sure all nodes are fully synced before we continue. - for _, node := range nodes { - err := node.WaitForBlockchainSync() - if err != nil { - t.Fatalf("unable to wait for sync: %v", err) - } - } - - // Using Carol as the source, pay to the 5 invoices from Bob created - // above. - err = completePaymentRequests( - net.Bob, net.Bob.RouterClient, payReqs, false, - ) - if err != nil { - t.Fatalf("unable to send payments: %v", err) - } - - // Wait for all of the payments to reach Carol. - var predErr error - err = wait.Predicate(func() bool { - predErr = assertNumActiveHtlcs(nodes, numPayments) - return predErr == nil - }, defaultTimeout) - if err != nil { - t.Fatalf("htlc mismatch: %v", predErr) - } - - peerReq := &lnrpc.PeerEventSubscription{} - peerClient, err := dave.SubscribePeerEvents(ctxb, peerReq) - require.NoError(t.t, err) +func testSwitchOfflineDelivery(ht *lntemp.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. - if err := net.DisconnectNodes(dave, net.Alice); err != nil { - t.Fatalf("unable to disconnect alice from dave: %v", err) - } - - // Wait to receive the PEER_OFFLINE event before reconnecting them. - peerEvent, err := peerClient.Recv() - require.NoError(t.t, err) - require.Equal(t.t, lnrpc.PeerEvent_PEER_OFFLINE, peerEvent.GetType()) + ht.DisconnectNodes(s.dave, s.alice) // Then, reconnect them to ensure Dave doesn't just fail back the htlc. - // We use EnsureConnected here in case they have already re-connected. - net.EnsureConnected(t.t, dave, net.Alice) + ht.ConnectNodes(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 // for the duration of the interval. - err = wait.Invariant(func() bool { - predErr = assertNumActiveHtlcs(nodes, numPayments) - return predErr == nil - }, defaultTimeout) - if err != nil { - t.Fatalf("htlc change: %v", predErr) - } + s.assertHTLCs(ht, numPayments) // Now, disconnect Dave from Alice again before settling back the // payment. - if err := net.DisconnectNodes(dave, net.Alice); err != nil { - t.Fatalf("unable to disconnect alice from dave: %v", err) - } - - // Wait to receive the PEER_ONLINE and then the PEER_OFFLINE event - // before advancing. - peerEvent2, err := peerClient.Recv() - require.NoError(t.t, err) - require.Equal(t.t, lnrpc.PeerEvent_PEER_ONLINE, peerEvent2.GetType()) - - peerEvent3, err := peerClient.Recv() - require.NoError(t.t, err) - require.Equal(t.t, lnrpc.PeerEvent_PEER_OFFLINE, peerEvent3.GetType()) + ht.DisconnectNodes(s.dave, s.alice) // Now restart carol without hodl mode, to settle back the outstanding // payments. - carol.SetExtraArgs(nil) - if err := net.RestartNode(carol, nil); err != nil { - t.Fatalf("Node restart failed: %v", err) - } + s.carol.SetExtraArgs(nil) + ht.RestartNode(s.carol) // Wait for Carol to report no outstanding htlcs. - carolNode := []*lntest.HarnessNode{carol} - err = wait.Predicate(func() bool { - predErr = assertNumActiveHtlcs(carolNode, 0) - return predErr == nil - }, defaultTimeout) - if err != nil { - t.Fatalf("htlc mismatch: %v", predErr) - } - - // Make sure all nodes are fully synced again. - for _, node := range nodes { - err := node.WaitForBlockchainSync() - if err != nil { - t.Fatalf("unable to wait for sync: %v", err) - } - } + ht.AssertNumActiveHtlcs(s.carol, 0) // Now that the settles have reached Dave, reconnect him with Alice, // allowing the settles to return to the sender. - net.EnsureConnected(t.t, dave, net.Alice) + ht.EnsureConnected(s.dave, s.alice) // Wait until all outstanding htlcs in the network have been settled. - err = wait.Predicate(func() bool { - return assertNumActiveHtlcs(nodes, 0) == nil - }, defaultTimeout) - if err != nil { - t.Fatalf("htlc mismatch: %v", predErr) - } + s.assertHTLCs(ht, 0) // When asserting the amount of satoshis moved, we'll factor in the // default base fee, as we didn't modify the fee structure when @@ -351,18 +147,7 @@ func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) { // transaction, in channel Bob->Alice->David->Carol, order is Carol, // David, Alice, Bob. var amountPaid = int64(5000) - assertAmountPaid(t, "Dave(local) => Carol(remote)", carol, - carolFundPoint, int64(0), amountPaid) - assertAmountPaid(t, "Dave(local) => Carol(remote)", dave, - carolFundPoint, amountPaid, int64(0)) - assertAmountPaid(t, "Alice(local) => Dave(remote)", dave, - daveFundPoint, int64(0), amountPaid+(baseFee*numPayments)) - assertAmountPaid(t, "Alice(local) => Dave(remote)", net.Alice, - daveFundPoint, amountPaid+(baseFee*numPayments), int64(0)) - assertAmountPaid(t, "Bob(local) => Alice(remote)", net.Alice, - aliceFundPoint, int64(0), amountPaid+((baseFee*numPayments)*2)) - assertAmountPaid(t, "Bob(local) => Alice(remote)", net.Bob, - aliceFundPoint, amountPaid+(baseFee*numPayments)*2, int64(0)) + s.assertAmoutPaid(ht, amountPaid, numPayments) // Lastly, we will send one more payment to ensure all channels are // still functioning properly. @@ -370,40 +155,15 @@ func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) { Memo: "testing", Value: paymentAmt, } - ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) - resp, err := carol.AddInvoice(ctxt, finalInvoice) - if err != nil { - t.Fatalf("unable to add invoice: %v", err) - } - - payReqs = []string{resp.PaymentRequest} + resp := s.carol.RPC.AddInvoice(finalInvoice) + payReqs := []string{resp.PaymentRequest} // Using Carol as the source, pay to the 5 invoices from Bob created // above. - err = completePaymentRequests( - net.Bob, net.Bob.RouterClient, payReqs, true, - ) - if err != nil { - t.Fatalf("unable to send payments: %v", err) - } + ht.CompletePaymentRequests(s.bob, payReqs) amountPaid = int64(6000) - assertAmountPaid(t, "Dave(local) => Carol(remote)", carol, - carolFundPoint, int64(0), amountPaid) - assertAmountPaid(t, "Dave(local) => Carol(remote)", dave, - carolFundPoint, amountPaid, int64(0)) - assertAmountPaid(t, "Alice(local) => Dave(remote)", dave, - daveFundPoint, int64(0), amountPaid+(baseFee*(numPayments+1))) - assertAmountPaid(t, "Alice(local) => Dave(remote)", net.Alice, - daveFundPoint, amountPaid+(baseFee*(numPayments+1)), int64(0)) - assertAmountPaid(t, "Bob(local) => Alice(remote)", net.Alice, - aliceFundPoint, int64(0), amountPaid+((baseFee*(numPayments+1))*2)) - assertAmountPaid(t, "Bob(local) => Alice(remote)", net.Bob, - aliceFundPoint, amountPaid+(baseFee*(numPayments+1))*2, int64(0)) - - closeChannelAndAssert(t, net, net.Alice, chanPointAlice, false) - closeChannelAndAssert(t, net, dave, chanPointDave, false) - closeChannelAndAssert(t, net, carol, chanPointCarol, false) + s.assertAmoutPaid(ht, amountPaid, numPayments+1) } // testSwitchOfflineDeliveryPersistence constructs a set of multihop payments, diff --git a/lntest/itest/lnd_test_list_on_test.go b/lntest/itest/lnd_test_list_on_test.go index 0772e4716..91441307d 100644 --- a/lntest/itest/lnd_test_list_on_test.go +++ b/lntest/itest/lnd_test_list_on_test.go @@ -28,10 +28,6 @@ var allTestCases = []*testCase{ name: "async bidirectional payments", test: testBidirectionalAsyncPayments, }, - { - name: "switch offline delivery", - test: testSwitchOfflineDelivery, - }, { name: "switch offline delivery persistence", test: testSwitchOfflineDeliveryPersistence,