From 07597711342d24207046bbffb5a39ae786064581 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 29 Jun 2021 04:22:43 +0800 Subject: [PATCH] itest: move channel openning related tests into one file This commit creates the file lnd_open_channel_test.go to hold channel opeopenning related tests. --- lntest/itest/lnd_open_channel_test.go | 424 ++++++++++++++++++++++++++ lntest/itest/lnd_test.go | 407 ------------------------ 2 files changed, 424 insertions(+), 407 deletions(-) create mode 100644 lntest/itest/lnd_open_channel_test.go diff --git a/lntest/itest/lnd_open_channel_test.go b/lntest/itest/lnd_open_channel_test.go new file mode 100644 index 000000000..98b8a1ecd --- /dev/null +++ b/lntest/itest/lnd_open_channel_test.go @@ -0,0 +1,424 @@ +package itest + +import ( + "context" + "fmt" + "time" + + "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/integration/rpctest" + "github.com/btcsuite/btcd/rpcclient" + "github.com/btcsuite/btcutil" + "github.com/lightningnetwork/lnd/funding" + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lntest" + "github.com/lightningnetwork/lnd/lntest/wait" + "github.com/stretchr/testify/require" +) + +// 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. +func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) { + // Skip test for neutrino, as we cannot disconnect the miner at will. + // TODO(halseth): remove when either can disconnect at will, or restart + // node with connection to new miner. + if net.BackendCfg.Name() == lntest.NeutrinoBackendName { + t.Skipf("skipping reorg test for neutrino backend") + } + + var ( + ctxb = context.Background() + temp = "temp" + ) + + // Set up a new miner that we can use to cause a reorg. + tempLogDir := fmt.Sprintf("%s/.tempminerlogs", lntest.GetLogDir()) + logFilename := "output-open_channel_reorg-temp_miner.log" + tempMiner, tempMinerCleanUp, err := lntest.NewMiner( + tempLogDir, logFilename, harnessNetParams, + &rpcclient.NotificationHandlers{}, lntest.GetBtcdBinary(), + ) + require.NoError(t.t, err, "failed to create temp miner") + defer func() { + require.NoError( + t.t, tempMinerCleanUp(), + "failed to clean up temp miner", + ) + }() + + // Setup the temp miner + require.NoError( + t.t, tempMiner.SetUp(false, 0), "unable to set up mining node", + ) + + // We start by connecting the new miner to our original miner, + // such that it will sync to our original chain. + err = net.Miner.Client.Node( + btcjson.NConnect, tempMiner.P2PAddress(), &temp, + ) + if err != nil { + t.Fatalf("unable to remove node: %v", err) + } + nodeSlice := []*rpctest.Harness{net.Miner, tempMiner} + if err := rpctest.JoinNodes(nodeSlice, rpctest.Blocks); err != nil { + t.Fatalf("unable to join node on blocks: %v", err) + } + + // The two miners should be on the same blockheight. + assertMinerBlockHeightDelta(t, net.Miner, tempMiner, 0) + + // We disconnect the two miners, such that we can mine two different + // chains and can cause a reorg later. + err = net.Miner.Client.Node( + btcjson.NDisconnect, tempMiner.P2PAddress(), &temp, + ) + if err != nil { + t.Fatalf("unable to remove node: %v", err) + } + + // Create a new channel that requires 1 confs before it's considered + // open, then broadcast the funding transaction + chanAmt := funding.MaxBtcFundingAmount + pushAmt := btcutil.Amount(0) + ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout) + pendingUpdate, err := net.OpenPendingChannel(ctxt, net.Alice, net.Bob, + chanAmt, pushAmt) + if err != nil { + t.Fatalf("unable to open channel: %v", err) + } + + // Wait for miner to have seen the funding tx. The temporary miner is + // disconnected, and won't see the transaction. + _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) + if err != nil { + t.Fatalf("failed to find funding tx in mempool: %v", err) + } + + // At this point, the channel's funding transaction will have been + // broadcast, but not confirmed, and the channel should be pending. + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + assertNumOpenChannelsPending(ctxt, t, net.Alice, net.Bob, 1) + + fundingTxID, err := chainhash.NewHash(pendingUpdate.Txid) + if err != nil { + t.Fatalf("unable to convert funding txid into chainhash.Hash:"+ + " %v", err) + } + + // We now cause a fork, by letting our original miner mine 10 blocks, + // and our new miner mine 15. This will also confirm our pending + // channel on the original miner's chain, which should be considered + // open. + block := mineBlocks(t, net, 10, 1)[0] + assertTxInBlock(t, block, fundingTxID) + if _, err := tempMiner.Client.Generate(15); err != nil { + t.Fatalf("unable to generate blocks: %v", err) + } + + // Ensure the chain lengths are what we expect, with the temp miner + // being 5 blocks ahead. + assertMinerBlockHeightDelta(t, net.Miner, tempMiner, 5) + + // Wait for Alice to sync to the original miner's chain. + _, minerHeight, err := net.Miner.Client.GetBestBlock() + if err != nil { + t.Fatalf("unable to get current blockheight %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = waitForNodeBlockHeight(ctxt, net.Alice, minerHeight) + if err != nil { + t.Fatalf("unable to sync to chain: %v", err) + } + + chanPoint := &lnrpc.ChannelPoint{ + FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{ + FundingTxidBytes: pendingUpdate.Txid, + }, + OutputIndex: pendingUpdate.OutputIndex, + } + + // Ensure channel is no longer pending. + assertNumOpenChannelsPending(ctxt, t, net.Alice, net.Bob, 0) + + // Wait for Alice and Bob to recognize and advertise the new channel + // generated above. + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint) + if err != nil { + t.Fatalf("alice didn't advertise channel before "+ + "timeout: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = net.Bob.WaitForNetworkChannelOpen(ctxt, chanPoint) + if err != nil { + t.Fatalf("bob didn't advertise channel before "+ + "timeout: %v", err) + } + + // Alice should now have 1 edge in her graph. + req := &lnrpc.ChannelGraphRequest{ + IncludeUnannounced: true, + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + chanGraph, err := net.Alice.DescribeGraph(ctxt, req) + if err != nil { + t.Fatalf("unable to query for alice's routing table: %v", err) + } + + numEdges := len(chanGraph.Edges) + if numEdges != 1 { + t.Fatalf("expected to find one edge in the graph, found %d", + numEdges) + } + + // Now we disconnect Alice's chain backend from the original miner, and + // connect the two miners together. Since the temporary miner knows + // about a longer chain, both miners should sync to that chain. + err = net.BackendCfg.DisconnectMiner() + if err != nil { + t.Fatalf("unable to remove node: %v", err) + } + + // Connecting to the temporary miner should now cause our original + // chain to be re-orged out. + err = net.Miner.Client.Node( + btcjson.NConnect, tempMiner.P2PAddress(), &temp, + ) + if err != nil { + t.Fatalf("unable to remove node: %v", err) + } + + nodes := []*rpctest.Harness{tempMiner, net.Miner} + if err := rpctest.JoinNodes(nodes, rpctest.Blocks); err != nil { + t.Fatalf("unable to join node on blocks: %v", err) + } + + // Once again they should be on the same chain. + assertMinerBlockHeightDelta(t, net.Miner, tempMiner, 0) + + // Now we disconnect the two miners, and connect our original miner to + // our chain backend once again. + err = net.Miner.Client.Node( + btcjson.NDisconnect, tempMiner.P2PAddress(), &temp, + ) + if err != nil { + t.Fatalf("unable to remove node: %v", err) + } + + err = net.BackendCfg.ConnectMiner() + if err != nil { + t.Fatalf("unable to remove node: %v", err) + } + + // This should have caused a reorg, and Alice should sync to the longer + // chain, where the funding transaction is not confirmed. + _, tempMinerHeight, err := tempMiner.Client.GetBestBlock() + if err != nil { + t.Fatalf("unable to get current blockheight %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = waitForNodeBlockHeight(ctxt, net.Alice, tempMinerHeight) + if err != nil { + t.Fatalf("unable to sync to chain: %v", err) + } + + // Since the fundingtx was reorged out, Alice should now have no edges + // in her graph. + req = &lnrpc.ChannelGraphRequest{ + IncludeUnannounced: true, + } + + var predErr error + err = wait.Predicate(func() bool { + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + chanGraph, err = net.Alice.DescribeGraph(ctxt, req) + if err != nil { + predErr = fmt.Errorf("unable to query for alice's routing table: %v", err) + return false + } + + numEdges = len(chanGraph.Edges) + if numEdges != 0 { + predErr = fmt.Errorf("expected to find no edge in the graph, found %d", + numEdges) + return false + } + return true + }, defaultTimeout) + if err != nil { + t.Fatalf(predErr.Error()) + } + + // Cleanup by mining the funding tx again, then closing the channel. + block = mineBlocks(t, net, 1, 1)[0] + assertTxInBlock(t, block, fundingTxID) + + ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) + closeReorgedChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false) +} + +// testBasicChannelCreationAndUpdates tests multiple channel opening and 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(net *lntest.NetworkHarness, t *harnessTest) { + ctxb := context.Background() + const ( + numChannels = 2 + amount = funding.MaxBtcFundingAmount + ) + + // Subscribe Bob and Alice to channel event notifications. + bobChanSub := subscribeChannelNotifications(ctxb, t, net.Bob) + defer close(bobChanSub.quit) + + aliceChanSub := subscribeChannelNotifications(ctxb, t, net.Alice) + defer close(aliceChanSub.quit) + + // Open the channel between Alice and Bob, asserting that the + // channel has been properly open on-chain. + chanPoints := make([]*lnrpc.ChannelPoint, numChannels) + for i := 0; i < numChannels; i++ { + ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout) + chanPoints[i] = openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, + lntest.OpenChannelParams{ + Amt: amount, + }, + ) + } + + // Since each of the channels just became open, Bob and Alice should + // each receive an open and an active notification for each channel. + var numChannelUpds int + const totalNtfns = 3 * numChannels + verifyOpenUpdatesReceived := func(sub channelSubscription) error { + numChannelUpds = 0 + for numChannelUpds < totalNtfns { + select { + case update := <-sub.updateChan: + switch update.Type { + case lnrpc.ChannelEventUpdate_PENDING_OPEN_CHANNEL: + if numChannelUpds%3 != 0 { + return fmt.Errorf("expected " + + "open or active" + + "channel ntfn, got pending open " + + "channel ntfn instead") + } + case lnrpc.ChannelEventUpdate_OPEN_CHANNEL: + if numChannelUpds%3 != 1 { + return fmt.Errorf("expected " + + "pending open or active" + + "channel ntfn, got open" + + "channel ntfn instead") + } + case lnrpc.ChannelEventUpdate_ACTIVE_CHANNEL: + if numChannelUpds%3 != 2 { + return fmt.Errorf("expected " + + "pending open or open" + + "channel ntfn, got active " + + "channel ntfn instead") + } + default: + return fmt.Errorf("update type mismatch: "+ + "expected open or active channel "+ + "notification, got: %v", + update.Type) + } + numChannelUpds++ + case <-time.After(time.Second * 10): + return fmt.Errorf("timeout waiting for channel "+ + "notifications, only received %d/%d "+ + "chanupds", numChannelUpds, + totalNtfns) + } + } + + return nil + } + + if err := verifyOpenUpdatesReceived(bobChanSub); err != nil { + t.Fatalf("error verifying open updates: %v", err) + } + if err := verifyOpenUpdatesReceived(aliceChanSub); err != nil { + t.Fatalf("error verifying open updates: %v", err) + } + + // Close the channel between Alice and Bob, asserting that the channel + // has been properly closed on-chain. + for i, chanPoint := range chanPoints { + ctx, _ := context.WithTimeout(context.Background(), defaultTimeout) + + // Force close half of the channels. + force := i%2 == 0 + closeChannelAndAssert(ctx, t, net, net.Alice, chanPoint, force) + if force { + cleanupForceClose(t, net, net.Alice, chanPoint) + } + } + + // verifyCloseUpdatesReceived is used to verify that Alice and Bob + // receive the correct channel updates in order. + verifyCloseUpdatesReceived := func(sub channelSubscription, + forceType lnrpc.ChannelCloseSummary_ClosureType, + closeInitiator lnrpc.Initiator) error { + + // Ensure one inactive and one closed notification is received for each + // closed channel. + numChannelUpds := 0 + for numChannelUpds < 2*numChannels { + expectedCloseType := lnrpc.ChannelCloseSummary_COOPERATIVE_CLOSE + + // Every other channel should be force closed. If this + // channel was force closed, set the expected close type + // the the type passed in. + force := (numChannelUpds/2)%2 == 0 + if force { + expectedCloseType = forceType + } + + select { + case chanUpdate := <-sub.updateChan: + err := verifyCloseUpdate( + chanUpdate, expectedCloseType, + closeInitiator, + ) + if err != nil { + return err + } + + numChannelUpds++ + case err := <-sub.errChan: + return err + case <-time.After(time.Second * 10): + return fmt.Errorf("timeout waiting "+ + "for channel notifications, only "+ + "received %d/%d chanupds", + numChannelUpds, 2*numChannels) + } + } + + return nil + } + + // Verify Bob receives all closed channel notifications. He should + // receive a remote force close notification for force closed channels. + // All channels (cooperatively and force closed) should have a remote + // close initiator because Alice closed the channels. + if err := verifyCloseUpdatesReceived(bobChanSub, + lnrpc.ChannelCloseSummary_REMOTE_FORCE_CLOSE, + lnrpc.Initiator_INITIATOR_REMOTE); err != nil { + t.Fatalf("errored verifying close updates: %v", err) + } + + // Verify Alice receives all closed channel notifications. She should + // receive a remote force close notification for force closed channels. + // All channels (cooperatively and force closed) should have a local + // close initiator because Alice closed the channels. + if err := verifyCloseUpdatesReceived(aliceChanSub, + lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE, + lnrpc.Initiator_INITIATOR_LOCAL); err != nil { + t.Fatalf("errored verifying close updates: %v", err) + } +} diff --git a/lntest/itest/lnd_test.go b/lntest/itest/lnd_test.go index 853af9955..cbe7e8781 100644 --- a/lntest/itest/lnd_test.go +++ b/lntest/itest/lnd_test.go @@ -14,7 +14,6 @@ import ( "testing" "time" - "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/integration/rpctest" "github.com/btcsuite/btcd/rpcclient" @@ -761,248 +760,6 @@ func waitForNodeBlockHeight(ctx context.Context, node *lntest.HarnessNode, return nil } -// 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. -func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) { - // Skip test for neutrino, as we cannot disconnect the miner at will. - // TODO(halseth): remove when either can disconnect at will, or restart - // node with connection to new miner. - if net.BackendCfg.Name() == lntest.NeutrinoBackendName { - t.Skipf("skipping reorg test for neutrino backend") - } - - var ( - ctxb = context.Background() - temp = "temp" - ) - - // Set up a new miner that we can use to cause a reorg. - tempLogDir := fmt.Sprintf("%s/.tempminerlogs", lntest.GetLogDir()) - logFilename := "output-open_channel_reorg-temp_miner.log" - tempMiner, tempMinerCleanUp, err := lntest.NewMiner( - tempLogDir, logFilename, harnessNetParams, - &rpcclient.NotificationHandlers{}, lntest.GetBtcdBinary(), - ) - require.NoError(t.t, err, "failed to create temp miner") - defer func() { - require.NoError( - t.t, tempMinerCleanUp(), - "failed to clean up temp miner", - ) - }() - - // Setup the temp miner - require.NoError( - t.t, tempMiner.SetUp(false, 0), "unable to set up mining node", - ) - - // We start by connecting the new miner to our original miner, - // such that it will sync to our original chain. - err = net.Miner.Client.Node( - btcjson.NConnect, tempMiner.P2PAddress(), &temp, - ) - if err != nil { - t.Fatalf("unable to remove node: %v", err) - } - nodeSlice := []*rpctest.Harness{net.Miner, tempMiner} - if err := rpctest.JoinNodes(nodeSlice, rpctest.Blocks); err != nil { - t.Fatalf("unable to join node on blocks: %v", err) - } - - // The two miners should be on the same blockheight. - assertMinerBlockHeightDelta(t, net.Miner, tempMiner, 0) - - // We disconnect the two miners, such that we can mine two different - // chains and can cause a reorg later. - err = net.Miner.Client.Node( - btcjson.NDisconnect, tempMiner.P2PAddress(), &temp, - ) - if err != nil { - t.Fatalf("unable to remove node: %v", err) - } - - // Create a new channel that requires 1 confs before it's considered - // open, then broadcast the funding transaction - chanAmt := funding.MaxBtcFundingAmount - pushAmt := btcutil.Amount(0) - ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout) - pendingUpdate, err := net.OpenPendingChannel(ctxt, net.Alice, net.Bob, - chanAmt, pushAmt) - if err != nil { - t.Fatalf("unable to open channel: %v", err) - } - - // Wait for miner to have seen the funding tx. The temporary miner is - // disconnected, and won't see the transaction. - _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) - if err != nil { - t.Fatalf("failed to find funding tx in mempool: %v", err) - } - - // At this point, the channel's funding transaction will have been - // broadcast, but not confirmed, and the channel should be pending. - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - assertNumOpenChannelsPending(ctxt, t, net.Alice, net.Bob, 1) - - fundingTxID, err := chainhash.NewHash(pendingUpdate.Txid) - if err != nil { - t.Fatalf("unable to convert funding txid into chainhash.Hash:"+ - " %v", err) - } - - // We now cause a fork, by letting our original miner mine 10 blocks, - // and our new miner mine 15. This will also confirm our pending - // channel on the original miner's chain, which should be considered - // open. - block := mineBlocks(t, net, 10, 1)[0] - assertTxInBlock(t, block, fundingTxID) - if _, err := tempMiner.Client.Generate(15); err != nil { - t.Fatalf("unable to generate blocks: %v", err) - } - - // Ensure the chain lengths are what we expect, with the temp miner - // being 5 blocks ahead. - assertMinerBlockHeightDelta(t, net.Miner, tempMiner, 5) - - // Wait for Alice to sync to the original miner's chain. - _, minerHeight, err := net.Miner.Client.GetBestBlock() - if err != nil { - t.Fatalf("unable to get current blockheight %v", err) - } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = waitForNodeBlockHeight(ctxt, net.Alice, minerHeight) - if err != nil { - t.Fatalf("unable to sync to chain: %v", err) - } - - chanPoint := &lnrpc.ChannelPoint{ - FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{ - FundingTxidBytes: pendingUpdate.Txid, - }, - OutputIndex: pendingUpdate.OutputIndex, - } - - // Ensure channel is no longer pending. - assertNumOpenChannelsPending(ctxt, t, net.Alice, net.Bob, 0) - - // Wait for Alice and Bob to recognize and advertise the new channel - // generated above. - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint) - if err != nil { - t.Fatalf("alice didn't advertise channel before "+ - "timeout: %v", err) - } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = net.Bob.WaitForNetworkChannelOpen(ctxt, chanPoint) - if err != nil { - t.Fatalf("bob didn't advertise channel before "+ - "timeout: %v", err) - } - - // Alice should now have 1 edge in her graph. - req := &lnrpc.ChannelGraphRequest{ - IncludeUnannounced: true, - } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - chanGraph, err := net.Alice.DescribeGraph(ctxt, req) - if err != nil { - t.Fatalf("unable to query for alice's routing table: %v", err) - } - - numEdges := len(chanGraph.Edges) - if numEdges != 1 { - t.Fatalf("expected to find one edge in the graph, found %d", - numEdges) - } - - // Now we disconnect Alice's chain backend from the original miner, and - // connect the two miners together. Since the temporary miner knows - // about a longer chain, both miners should sync to that chain. - err = net.BackendCfg.DisconnectMiner() - if err != nil { - t.Fatalf("unable to remove node: %v", err) - } - - // Connecting to the temporary miner should now cause our original - // chain to be re-orged out. - err = net.Miner.Client.Node( - btcjson.NConnect, tempMiner.P2PAddress(), &temp, - ) - if err != nil { - t.Fatalf("unable to remove node: %v", err) - } - - nodes := []*rpctest.Harness{tempMiner, net.Miner} - if err := rpctest.JoinNodes(nodes, rpctest.Blocks); err != nil { - t.Fatalf("unable to join node on blocks: %v", err) - } - - // Once again they should be on the same chain. - assertMinerBlockHeightDelta(t, net.Miner, tempMiner, 0) - - // Now we disconnect the two miners, and connect our original miner to - // our chain backend once again. - err = net.Miner.Client.Node( - btcjson.NDisconnect, tempMiner.P2PAddress(), &temp, - ) - if err != nil { - t.Fatalf("unable to remove node: %v", err) - } - - err = net.BackendCfg.ConnectMiner() - if err != nil { - t.Fatalf("unable to remove node: %v", err) - } - - // This should have caused a reorg, and Alice should sync to the longer - // chain, where the funding transaction is not confirmed. - _, tempMinerHeight, err := tempMiner.Client.GetBestBlock() - if err != nil { - t.Fatalf("unable to get current blockheight %v", err) - } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = waitForNodeBlockHeight(ctxt, net.Alice, tempMinerHeight) - if err != nil { - t.Fatalf("unable to sync to chain: %v", err) - } - - // Since the fundingtx was reorged out, Alice should now have no edges - // in her graph. - req = &lnrpc.ChannelGraphRequest{ - IncludeUnannounced: true, - } - - var predErr error - err = wait.Predicate(func() bool { - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - chanGraph, err = net.Alice.DescribeGraph(ctxt, req) - if err != nil { - predErr = fmt.Errorf("unable to query for alice's routing table: %v", err) - return false - } - - numEdges = len(chanGraph.Edges) - if numEdges != 0 { - predErr = fmt.Errorf("expected to find no edge in the graph, found %d", - numEdges) - return false - } - return true - }, defaultTimeout) - if err != nil { - t.Fatalf(predErr.Error()) - } - - // Cleanup by mining the funding tx again, then closing the channel. - block = mineBlocks(t, net, 1, 1)[0] - assertTxInBlock(t, block, fundingTxID) - - ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) - closeReorgedChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false) -} - // testDisconnectingTargetPeer performs a test which disconnects Alice-peer from // Bob-peer and then re-connects them again. We expect Alice to be able to // disconnect at any point. @@ -2220,170 +1977,6 @@ func subscribeChannelNotifications(ctxb context.Context, t *harnessTest, } } -// testBasicChannelCreationAndUpdates tests multiple channel opening and 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(net *lntest.NetworkHarness, t *harnessTest) { - ctxb := context.Background() - const ( - numChannels = 2 - amount = funding.MaxBtcFundingAmount - ) - - // Subscribe Bob and Alice to channel event notifications. - bobChanSub := subscribeChannelNotifications(ctxb, t, net.Bob) - defer close(bobChanSub.quit) - - aliceChanSub := subscribeChannelNotifications(ctxb, t, net.Alice) - defer close(aliceChanSub.quit) - - // Open the channel between Alice and Bob, asserting that the - // channel has been properly open on-chain. - chanPoints := make([]*lnrpc.ChannelPoint, numChannels) - for i := 0; i < numChannels; i++ { - ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout) - chanPoints[i] = openChannelAndAssert( - ctxt, t, net, net.Alice, net.Bob, - lntest.OpenChannelParams{ - Amt: amount, - }, - ) - } - - // Since each of the channels just became open, Bob and Alice should - // each receive an open and an active notification for each channel. - var numChannelUpds int - const totalNtfns = 3 * numChannels - verifyOpenUpdatesReceived := func(sub channelSubscription) error { - numChannelUpds = 0 - for numChannelUpds < totalNtfns { - select { - case update := <-sub.updateChan: - switch update.Type { - case lnrpc.ChannelEventUpdate_PENDING_OPEN_CHANNEL: - if numChannelUpds%3 != 0 { - return fmt.Errorf("expected " + - "open or active" + - "channel ntfn, got pending open " + - "channel ntfn instead") - } - case lnrpc.ChannelEventUpdate_OPEN_CHANNEL: - if numChannelUpds%3 != 1 { - return fmt.Errorf("expected " + - "pending open or active" + - "channel ntfn, got open" + - "channel ntfn instead") - } - case lnrpc.ChannelEventUpdate_ACTIVE_CHANNEL: - if numChannelUpds%3 != 2 { - return fmt.Errorf("expected " + - "pending open or open" + - "channel ntfn, got active " + - "channel ntfn instead") - } - default: - return fmt.Errorf("update type mismatch: "+ - "expected open or active channel "+ - "notification, got: %v", - update.Type) - } - numChannelUpds++ - case <-time.After(time.Second * 10): - return fmt.Errorf("timeout waiting for channel "+ - "notifications, only received %d/%d "+ - "chanupds", numChannelUpds, - totalNtfns) - } - } - - return nil - } - - if err := verifyOpenUpdatesReceived(bobChanSub); err != nil { - t.Fatalf("error verifying open updates: %v", err) - } - if err := verifyOpenUpdatesReceived(aliceChanSub); err != nil { - t.Fatalf("error verifying open updates: %v", err) - } - - // Close the channel between Alice and Bob, asserting that the channel - // has been properly closed on-chain. - for i, chanPoint := range chanPoints { - ctx, _ := context.WithTimeout(context.Background(), defaultTimeout) - - // Force close half of the channels. - force := i%2 == 0 - closeChannelAndAssert(ctx, t, net, net.Alice, chanPoint, force) - if force { - cleanupForceClose(t, net, net.Alice, chanPoint) - } - } - - // verifyCloseUpdatesReceived is used to verify that Alice and Bob - // receive the correct channel updates in order. - verifyCloseUpdatesReceived := func(sub channelSubscription, - forceType lnrpc.ChannelCloseSummary_ClosureType, - closeInitiator lnrpc.Initiator) error { - - // Ensure one inactive and one closed notification is received for each - // closed channel. - numChannelUpds := 0 - for numChannelUpds < 2*numChannels { - expectedCloseType := lnrpc.ChannelCloseSummary_COOPERATIVE_CLOSE - - // Every other channel should be force closed. If this - // channel was force closed, set the expected close type - // the the type passed in. - force := (numChannelUpds/2)%2 == 0 - if force { - expectedCloseType = forceType - } - - select { - case chanUpdate := <-sub.updateChan: - err := verifyCloseUpdate( - chanUpdate, expectedCloseType, - closeInitiator, - ) - if err != nil { - return err - } - - numChannelUpds++ - case err := <-sub.errChan: - return err - case <-time.After(time.Second * 10): - return fmt.Errorf("timeout waiting "+ - "for channel notifications, only "+ - "received %d/%d chanupds", - numChannelUpds, 2*numChannels) - } - } - - return nil - } - - // Verify Bob receives all closed channel notifications. He should - // receive a remote force close notification for force closed channels. - // All channels (cooperatively and force closed) should have a remote - // close initiator because Alice closed the channels. - if err := verifyCloseUpdatesReceived(bobChanSub, - lnrpc.ChannelCloseSummary_REMOTE_FORCE_CLOSE, - lnrpc.Initiator_INITIATOR_REMOTE); err != nil { - t.Fatalf("errored verifying close updates: %v", err) - } - - // Verify Alice receives all closed channel notifications. She should - // receive a remote force close notification for force closed channels. - // All channels (cooperatively and force closed) should have a local - // close initiator because Alice closed the channels. - if err := verifyCloseUpdatesReceived(aliceChanSub, - lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE, - lnrpc.Initiator_INITIATOR_LOCAL); err != nil { - t.Fatalf("errored verifying close updates: %v", err) - } -} - // testMaxPendingChannels checks that error is returned from remote peer if // max pending channel number was exceeded and that '--maxpendingchannels' flag // exists and works properly.