github.com/decred/dcrlnd@v0.7.6/lntest/itest/lnd_channel_graph_test.go (about)

     1  package itest
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"io"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/decred/dcrd/dcrutil/v4"
    12  	"github.com/decred/dcrlnd/chainreg"
    13  	"github.com/decred/dcrlnd/lnrpc"
    14  	"github.com/decred/dcrlnd/lnrpc/routerrpc"
    15  	"github.com/decred/dcrlnd/lntest"
    16  	"github.com/decred/dcrlnd/lntest/wait"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  // testUpdateChanStatus checks that calls to the UpdateChanStatus RPC update
    21  // the channel graph as expected, and that channel state is properly updated
    22  // in the presence of interleaved node disconnects / reconnects.
    23  func testUpdateChanStatus(net *lntest.NetworkHarness, t *harnessTest) {
    24  	ctxb := context.Background()
    25  
    26  	// Create two fresh nodes and open a channel between them.
    27  	alice := net.NewNode(t.t, "Alice", []string{
    28  		"--minbackoff=10s",
    29  		"--chan-enable-timeout=1.5s",
    30  		"--chan-disable-timeout=3s",
    31  		"--chan-status-sample-interval=.5s",
    32  	})
    33  	defer shutdownAndAssert(net, t, alice)
    34  
    35  	bob := net.NewNode(t.t, "Bob", []string{
    36  		"--minbackoff=10s",
    37  		"--chan-enable-timeout=1.5s",
    38  		"--chan-disable-timeout=3s",
    39  		"--chan-status-sample-interval=.5s",
    40  	})
    41  	defer shutdownAndAssert(net, t, bob)
    42  
    43  	// Connect Alice to Bob.
    44  	net.ConnectNodes(t.t, alice, bob)
    45  
    46  	// Give Alice some coins so she can fund a channel.
    47  	net.SendCoins(t.t, dcrutil.AtomsPerCoin, alice)
    48  
    49  	// Open a channel with 100k satoshis between Alice and Bob with Alice
    50  	// being the sole funder of the channel.
    51  	chanAmt := dcrutil.Amount(100000)
    52  	chanPoint := openChannelAndAssert(
    53  		t, net, alice, bob, lntest.OpenChannelParams{
    54  			Amt: chanAmt,
    55  		},
    56  	)
    57  
    58  	// Wait for Alice and Bob to receive the channel edge from the
    59  	// funding manager.
    60  	err := alice.WaitForNetworkChannelOpen(chanPoint)
    61  	require.NoError(t.t, err, "alice didn't see the alice->bob channel")
    62  
    63  	err = bob.WaitForNetworkChannelOpen(chanPoint)
    64  	require.NoError(t.t, err, "bob didn't see the alice->bob channel")
    65  
    66  	// Launch a node for Carol which will connect to Alice and Bob in order
    67  	// to receive graph updates. This will ensure that the channel updates
    68  	// are propagated throughout the network.
    69  	carol := net.NewNode(t.t, "Carol", nil)
    70  	defer shutdownAndAssert(net, t, carol)
    71  
    72  	// Connect both Alice and Bob to the new node Carol, so she can sync her
    73  	// graph.
    74  	net.ConnectNodes(t.t, alice, carol)
    75  	net.ConnectNodes(t.t, bob, carol)
    76  	waitForGraphSync(t, carol)
    77  
    78  	// assertChannelUpdate checks that the required policy update has
    79  	// happened on the given node.
    80  	assertChannelUpdate := func(node *lntest.HarnessNode,
    81  		policy *lnrpc.RoutingPolicy) {
    82  
    83  		require.NoError(
    84  			t.t, carol.WaitForChannelPolicyUpdate(
    85  				node.PubKeyStr, policy, chanPoint, false,
    86  			), "error while waiting for channel update",
    87  		)
    88  	}
    89  
    90  	// sendReq sends an UpdateChanStatus request to the given node.
    91  	sendReq := func(node *lntest.HarnessNode, chanPoint *lnrpc.ChannelPoint,
    92  		action routerrpc.ChanStatusAction) {
    93  
    94  		req := &routerrpc.UpdateChanStatusRequest{
    95  			ChanPoint: chanPoint,
    96  			Action:    action,
    97  		}
    98  		ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
    99  		defer cancel()
   100  
   101  		_, err = node.RouterClient.UpdateChanStatus(ctxt, req)
   102  		require.NoErrorf(t.t, err, "UpdateChanStatus")
   103  	}
   104  
   105  	// assertEdgeDisabled ensures that a given node has the correct
   106  	// Disabled state for a channel.
   107  	assertEdgeDisabled := func(node *lntest.HarnessNode,
   108  		chanPoint *lnrpc.ChannelPoint, disabled bool) {
   109  
   110  		outPoint, err := lntest.MakeOutpoint(chanPoint)
   111  		require.NoError(t.t, err)
   112  
   113  		err = wait.NoError(func() error {
   114  			req := &lnrpc.ChannelGraphRequest{
   115  				IncludeUnannounced: true,
   116  			}
   117  			ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
   118  			defer cancel()
   119  
   120  			chanGraph, err := node.DescribeGraph(ctxt, req)
   121  			if err != nil {
   122  				return fmt.Errorf("unable to query node %v's "+
   123  					"graph: %v", node, err)
   124  			}
   125  			numEdges := len(chanGraph.Edges)
   126  			if numEdges != 1 {
   127  				return fmt.Errorf("expected to find 1 edge in "+
   128  					"the graph, found %d", numEdges)
   129  			}
   130  			edge := chanGraph.Edges[0]
   131  			if edge.ChanPoint != outPoint.String() {
   132  				return fmt.Errorf("expected chan_point %v, "+
   133  					"got %v", outPoint, edge.ChanPoint)
   134  			}
   135  			var policy *lnrpc.RoutingPolicy
   136  			if node.PubKeyStr == edge.Node1Pub {
   137  				policy = edge.Node1Policy
   138  			} else {
   139  				policy = edge.Node2Policy
   140  			}
   141  			if disabled != policy.Disabled {
   142  				return fmt.Errorf("expected policy.Disabled "+
   143  					"to be %v, but policy was %v", disabled,
   144  					policy)
   145  			}
   146  
   147  			return nil
   148  		}, defaultTimeout)
   149  		require.NoError(t.t, err)
   150  	}
   151  
   152  	// When updating the state of the channel between Alice and Bob, we
   153  	// should expect to see channel updates with the default routing
   154  	// policy. The value of "Disabled" will depend on the specific
   155  	// scenario being tested.
   156  	expectedPolicy := &lnrpc.RoutingPolicy{
   157  		FeeBaseMAtoms:      int64(chainreg.DefaultDecredBaseFeeMAtoms),
   158  		FeeRateMilliMAtoms: int64(chainreg.DefaultDecredFeeRate),
   159  		TimeLockDelta:      chainreg.DefaultDecredTimeLockDelta,
   160  		MinHtlc:            1000, // default value
   161  		MaxHtlcMAtoms:      calculateMaxHtlc(chanAmt),
   162  	}
   163  
   164  	// Initially, the channel between Alice and Bob should not be
   165  	// disabled.
   166  	assertEdgeDisabled(alice, chanPoint, false)
   167  
   168  	// Manually disable the channel and ensure that a "Disabled = true"
   169  	// update is propagated.
   170  	sendReq(alice, chanPoint, routerrpc.ChanStatusAction_DISABLE)
   171  	expectedPolicy.Disabled = true
   172  	assertChannelUpdate(alice, expectedPolicy)
   173  
   174  	// Re-enable the channel and ensure that a "Disabled = false" update
   175  	// is propagated.
   176  	sendReq(alice, chanPoint, routerrpc.ChanStatusAction_ENABLE)
   177  	expectedPolicy.Disabled = false
   178  	assertChannelUpdate(alice, expectedPolicy)
   179  
   180  	// Manually enabling a channel should NOT prevent subsequent
   181  	// disconnections from automatically disabling the channel again
   182  	// (we don't want to clutter the network with channels that are
   183  	// falsely advertised as enabled when they don't work).
   184  	require.NoError(t.t, net.DisconnectNodes(alice, bob))
   185  	expectedPolicy.Disabled = true
   186  	assertChannelUpdate(alice, expectedPolicy)
   187  	assertChannelUpdate(bob, expectedPolicy)
   188  
   189  	// Reconnecting the nodes should propagate a "Disabled = false" update.
   190  	net.EnsureConnected(t.t, alice, bob)
   191  	expectedPolicy.Disabled = false
   192  	assertChannelUpdate(alice, expectedPolicy)
   193  	assertChannelUpdate(bob, expectedPolicy)
   194  
   195  	// Manually disabling the channel should prevent a subsequent
   196  	// disconnect / reconnect from re-enabling the channel on
   197  	// Alice's end. Note the asymmetry between manual enable and
   198  	// manual disable!
   199  	sendReq(alice, chanPoint, routerrpc.ChanStatusAction_DISABLE)
   200  
   201  	// Alice sends out the "Disabled = true" update in response to
   202  	// the ChanStatusAction_DISABLE request.
   203  	expectedPolicy.Disabled = true
   204  	assertChannelUpdate(alice, expectedPolicy)
   205  
   206  	require.NoError(t.t, net.DisconnectNodes(alice, bob))
   207  
   208  	// Bob sends a "Disabled = true" update upon detecting the
   209  	// disconnect.
   210  	expectedPolicy.Disabled = true
   211  	assertChannelUpdate(bob, expectedPolicy)
   212  
   213  	// Bob sends a "Disabled = false" update upon detecting the
   214  	// reconnect.
   215  	net.EnsureConnected(t.t, alice, bob)
   216  	expectedPolicy.Disabled = false
   217  	assertChannelUpdate(bob, expectedPolicy)
   218  
   219  	// However, since we manually disabled the channel on Alice's end,
   220  	// the policy on Alice's end should still be "Disabled = true". Again,
   221  	// note the asymmetry between manual enable and manual disable!
   222  	assertEdgeDisabled(alice, chanPoint, true)
   223  
   224  	require.NoError(t.t, net.DisconnectNodes(alice, bob))
   225  
   226  	// Bob sends a "Disabled = true" update upon detecting the
   227  	// disconnect.
   228  	expectedPolicy.Disabled = true
   229  	assertChannelUpdate(bob, expectedPolicy)
   230  
   231  	// After restoring automatic channel state management on Alice's end,
   232  	// BOTH Alice and Bob should set the channel state back to "enabled"
   233  	// on reconnect.
   234  	sendReq(alice, chanPoint, routerrpc.ChanStatusAction_AUTO)
   235  	net.EnsureConnected(t.t, alice, bob)
   236  
   237  	expectedPolicy.Disabled = false
   238  	assertChannelUpdate(alice, expectedPolicy)
   239  	assertChannelUpdate(bob, expectedPolicy)
   240  	assertEdgeDisabled(alice, chanPoint, false)
   241  }
   242  
   243  // testUnannouncedChannels checks unannounced channels are not returned by
   244  // describeGraph RPC request unless explicitly asked for.
   245  func testUnannouncedChannels(net *lntest.NetworkHarness, t *harnessTest) {
   246  	ctxb := context.Background()
   247  
   248  	amount := defaultChanAmt
   249  
   250  	// Open a channel between Alice and Bob, ensuring the
   251  	// channel has been opened properly.
   252  	chanOpenUpdate := openChannelStream(
   253  		t, net, net.Alice, net.Bob,
   254  		lntest.OpenChannelParams{
   255  			Amt: amount,
   256  		},
   257  	)
   258  
   259  	// Mine 2 blocks, and check that the channel is opened but not yet
   260  	// announced to the network.
   261  	mineBlocks(t, net, 2, 1)
   262  
   263  	// One block is enough to make the channel ready for use, since the
   264  	// nodes have defaultNumConfs=1 set.
   265  	fundingChanPoint, err := net.WaitForChannelOpen(chanOpenUpdate)
   266  	if err != nil {
   267  		t.Fatalf("error while waiting for channel open: %v", err)
   268  	}
   269  
   270  	// Alice should have 1 edge in her graph.
   271  	req := &lnrpc.ChannelGraphRequest{
   272  		IncludeUnannounced: true,
   273  	}
   274  	ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
   275  	chanGraph, err := net.Alice.DescribeGraph(ctxt, req)
   276  	if err != nil {
   277  		t.Fatalf("unable to query alice's graph: %v", err)
   278  	}
   279  
   280  	numEdges := len(chanGraph.Edges)
   281  	if numEdges != 1 {
   282  		t.Fatalf("expected to find 1 edge in the graph, found %d", numEdges)
   283  	}
   284  
   285  	// Channels should not be announced yet, hence Alice should have no
   286  	// announced edges in her graph.
   287  	req.IncludeUnannounced = false
   288  	ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
   289  	chanGraph, err = net.Alice.DescribeGraph(ctxt, req)
   290  	if err != nil {
   291  		t.Fatalf("unable to query alice's graph: %v", err)
   292  	}
   293  
   294  	numEdges = len(chanGraph.Edges)
   295  	if numEdges != 0 {
   296  		t.Fatalf("expected to find 0 announced edges in the graph, found %d",
   297  			numEdges)
   298  	}
   299  
   300  	// Mine 4 more blocks, and check that the channel is now announced.
   301  	mineBlocks(t, net, 4, 0)
   302  
   303  	// Give the network a chance to learn that auth proof is confirmed.
   304  	var predErr error
   305  	err = wait.Predicate(func() bool {
   306  		// The channel should now be announced. Check that Alice has 1
   307  		// announced edge.
   308  		req.IncludeUnannounced = false
   309  		ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
   310  		chanGraph, err = net.Alice.DescribeGraph(ctxt, req)
   311  		if err != nil {
   312  			predErr = fmt.Errorf("unable to query alice's graph: %v", err)
   313  			return false
   314  		}
   315  
   316  		numEdges = len(chanGraph.Edges)
   317  		if numEdges != 1 {
   318  			predErr = fmt.Errorf("expected to find 1 announced edge in "+
   319  				"the graph, found %d", numEdges)
   320  			return false
   321  		}
   322  		return true
   323  	}, defaultTimeout)
   324  	if err != nil {
   325  		t.Fatalf("%v", predErr)
   326  	}
   327  
   328  	// The channel should now be announced. Check that Alice has 1 announced
   329  	// edge.
   330  	req.IncludeUnannounced = false
   331  	ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
   332  	chanGraph, err = net.Alice.DescribeGraph(ctxt, req)
   333  	if err != nil {
   334  		t.Fatalf("unable to query alice's graph: %v", err)
   335  	}
   336  
   337  	numEdges = len(chanGraph.Edges)
   338  	if numEdges != 1 {
   339  		t.Fatalf("expected to find 1 announced edge in the graph, found %d",
   340  			numEdges)
   341  	}
   342  
   343  	// Close the channel used during the test.
   344  	closeChannelAndAssert(t, net, net.Alice, fundingChanPoint, false)
   345  }
   346  
   347  func testGraphTopologyNotifications(net *lntest.NetworkHarness, t *harnessTest) {
   348  	t.t.Run("pinned", func(t *testing.T) {
   349  		ht := newHarnessTest(t, net)
   350  		testGraphTopologyNtfns(net, ht, true)
   351  	})
   352  	t.t.Run("unpinned", func(t *testing.T) {
   353  		ht := newHarnessTest(t, net)
   354  		testGraphTopologyNtfns(net, ht, false)
   355  	})
   356  }
   357  
   358  func testGraphTopologyNtfns(net *lntest.NetworkHarness, t *harnessTest, pinned bool) {
   359  	ctxb := context.Background()
   360  
   361  	const chanAmt = defaultChanAmt
   362  
   363  	// Spin up Bob first, since we will need to grab his pubkey when
   364  	// starting Alice to test pinned syncing.
   365  	bob := net.NewNode(t.t, "bob", nil)
   366  	defer shutdownAndAssert(net, t, bob)
   367  
   368  	ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
   369  	bobInfo, err := bob.GetInfo(ctxt, &lnrpc.GetInfoRequest{})
   370  	require.NoError(t.t, err)
   371  	bobPubkey := bobInfo.IdentityPubkey
   372  
   373  	// For unpinned syncing, start Alice as usual. Otherwise grab Bob's
   374  	// pubkey to include in his pinned syncer set.
   375  	var aliceArgs []string
   376  	if pinned {
   377  		aliceArgs = []string{
   378  			"--numgraphsyncpeers=0",
   379  			fmt.Sprintf("--gossip.pinned-syncers=%s", bobPubkey),
   380  		}
   381  	}
   382  
   383  	alice := net.NewNode(t.t, "alice", aliceArgs)
   384  	defer shutdownAndAssert(net, t, alice)
   385  
   386  	// Connect Alice and Bob.
   387  	net.EnsureConnected(t.t, alice, bob)
   388  
   389  	// Alice stimmy.
   390  	net.SendCoins(t.t, dcrutil.AtomsPerCoin, alice)
   391  
   392  	// Bob stimmy.
   393  	net.SendCoins(t.t, dcrutil.AtomsPerCoin, bob)
   394  
   395  	// Assert that Bob has the correct sync type before proceeeding.
   396  	if pinned {
   397  		assertSyncType(t, alice, bobPubkey, lnrpc.Peer_PINNED_SYNC)
   398  	} else {
   399  		assertSyncType(t, alice, bobPubkey, lnrpc.Peer_ACTIVE_SYNC)
   400  	}
   401  
   402  	// Regardless of syncer type, ensure that both peers report having
   403  	// completed their initial sync before continuing to make a channel.
   404  	waitForGraphSync(t, alice)
   405  
   406  	// Let Alice subscribe to graph notifications.
   407  	graphSub := subscribeGraphNotifications(ctxb, t, alice)
   408  	defer close(graphSub.quit)
   409  
   410  	// Open a new channel between Alice and Bob.
   411  	chanPoint := openChannelAndAssert(
   412  		t, net, alice, bob,
   413  		lntest.OpenChannelParams{
   414  			Amt: chanAmt,
   415  		},
   416  	)
   417  
   418  	// The channel opening above should have triggered a few notifications
   419  	// sent to the notification client. We'll expect two channel updates,
   420  	// and two node announcements.
   421  	var numChannelUpds int
   422  	var numNodeAnns int
   423  	for numChannelUpds < 2 && numNodeAnns < 2 {
   424  		select {
   425  		// Ensure that a new update for both created edges is properly
   426  		// dispatched to our registered client.
   427  		case graphUpdate := <-graphSub.updateChan:
   428  			// Process all channel updates prsented in this update
   429  			// message.
   430  			for _, chanUpdate := range graphUpdate.ChannelUpdates {
   431  				switch chanUpdate.AdvertisingNode {
   432  				case alice.PubKeyStr:
   433  				case bob.PubKeyStr:
   434  				default:
   435  					t.Fatalf("unknown advertising node: %v",
   436  						chanUpdate.AdvertisingNode)
   437  				}
   438  				switch chanUpdate.ConnectingNode {
   439  				case alice.PubKeyStr:
   440  				case bob.PubKeyStr:
   441  				default:
   442  					t.Fatalf("unknown connecting node: %v",
   443  						chanUpdate.ConnectingNode)
   444  				}
   445  
   446  				if chanUpdate.Capacity != int64(chanAmt) {
   447  					t.Fatalf("channel capacities mismatch:"+
   448  						" expected %v, got %v", chanAmt,
   449  						dcrutil.Amount(chanUpdate.Capacity))
   450  				}
   451  				numChannelUpds++
   452  			}
   453  
   454  			for _, nodeUpdate := range graphUpdate.NodeUpdates {
   455  				switch nodeUpdate.IdentityKey {
   456  				case alice.PubKeyStr:
   457  				case bob.PubKeyStr:
   458  				default:
   459  					t.Fatalf("unknown node: %v",
   460  						nodeUpdate.IdentityKey)
   461  				}
   462  				numNodeAnns++
   463  			}
   464  		case err := <-graphSub.errChan:
   465  			t.Fatalf("unable to recv graph update: %v", err)
   466  		case <-time.After(time.Second * 10):
   467  			t.Fatalf("timeout waiting for graph notifications, "+
   468  				"only received %d/2 chanupds and %d/2 nodeanns",
   469  				numChannelUpds, numNodeAnns)
   470  		}
   471  	}
   472  
   473  	_, blockHeight, err := net.Miner.Node.GetBestBlock(context.Background())
   474  	if err != nil {
   475  		t.Fatalf("unable to get current blockheight %v", err)
   476  	}
   477  
   478  	// Now we'll test that updates are properly sent after channels are closed
   479  	// within the network.
   480  	closeChannelAndAssert(t, net, alice, chanPoint, false)
   481  
   482  	// Now that the channel has been closed, we should receive a
   483  	// notification indicating so.
   484  out:
   485  	for {
   486  		select {
   487  		case graphUpdate := <-graphSub.updateChan:
   488  			if len(graphUpdate.ClosedChans) != 1 {
   489  				continue
   490  			}
   491  
   492  			closedChan := graphUpdate.ClosedChans[0]
   493  			if closedChan.ClosedHeight != uint32(blockHeight+1) {
   494  				t.Fatalf("close heights of channel mismatch: "+
   495  					"expected %v, got %v", blockHeight+1,
   496  					closedChan.ClosedHeight)
   497  			}
   498  			chanPointTxid, err := lnrpc.GetChanPointFundingTxid(chanPoint)
   499  			if err != nil {
   500  				t.Fatalf("unable to get txid: %v", err)
   501  			}
   502  			closedChanTxid, err := lnrpc.GetChanPointFundingTxid(
   503  				closedChan.ChanPoint,
   504  			)
   505  			if err != nil {
   506  				t.Fatalf("unable to get txid: %v", err)
   507  			}
   508  			if !bytes.Equal(closedChanTxid[:], chanPointTxid[:]) {
   509  				t.Fatalf("channel point hash mismatch: "+
   510  					"expected %v, got %v", chanPointTxid,
   511  					closedChanTxid)
   512  			}
   513  			if closedChan.ChanPoint.OutputIndex != chanPoint.OutputIndex {
   514  				t.Fatalf("output index mismatch: expected %v, "+
   515  					"got %v", chanPoint.OutputIndex,
   516  					closedChan.ChanPoint)
   517  			}
   518  
   519  			break out
   520  
   521  		case err := <-graphSub.errChan:
   522  			t.Fatalf("unable to recv graph update: %v", err)
   523  		case <-time.After(time.Second * 10):
   524  			t.Fatalf("notification for channel closure not " +
   525  				"sent")
   526  		}
   527  	}
   528  
   529  	// For the final portion of the test, we'll ensure that once a new node
   530  	// appears in the network, the proper notification is dispatched. Note
   531  	// that a node that does not have any channels open is ignored, so first
   532  	// we disconnect Alice and Bob, open a channel between Bob and Carol,
   533  	// and finally connect Alice to Bob again.
   534  	if err := net.DisconnectNodes(alice, bob); err != nil {
   535  		t.Fatalf("unable to disconnect alice and bob: %v", err)
   536  	}
   537  	carol := net.NewNode(t.t, "Carol", nil)
   538  	defer shutdownAndAssert(net, t, carol)
   539  
   540  	net.ConnectNodes(t.t, bob, carol)
   541  	chanPoint = openChannelAndAssert(
   542  		t, net, bob, carol,
   543  		lntest.OpenChannelParams{
   544  			Amt: chanAmt,
   545  		},
   546  	)
   547  
   548  	// Reconnect Alice and Bob. This should result in the nodes syncing up
   549  	// their respective graph state, with the new addition being the
   550  	// existence of Carol in the graph, and also the channel between Bob
   551  	// and Carol. Note that we will also receive a node announcement from
   552  	// Bob, since a node will update its node announcement after a new
   553  	// channel is opened.
   554  	net.EnsureConnected(t.t, alice, bob)
   555  
   556  	// We should receive an update advertising the newly connected node,
   557  	// Bob's new node announcement, and the channel between Bob and Carol.
   558  	numNodeAnns = 0
   559  	numChannelUpds = 0
   560  	for numChannelUpds < 2 && numNodeAnns < 1 {
   561  		select {
   562  		case graphUpdate := <-graphSub.updateChan:
   563  			for _, nodeUpdate := range graphUpdate.NodeUpdates {
   564  				switch nodeUpdate.IdentityKey {
   565  				case carol.PubKeyStr:
   566  				case bob.PubKeyStr:
   567  				default:
   568  					t.Fatalf("unknown node update pubey: %v",
   569  						nodeUpdate.IdentityKey)
   570  				}
   571  				numNodeAnns++
   572  			}
   573  
   574  			for _, chanUpdate := range graphUpdate.ChannelUpdates {
   575  				switch chanUpdate.AdvertisingNode {
   576  				case carol.PubKeyStr:
   577  				case bob.PubKeyStr:
   578  				default:
   579  					t.Fatalf("unknown advertising node: %v",
   580  						chanUpdate.AdvertisingNode)
   581  				}
   582  				switch chanUpdate.ConnectingNode {
   583  				case carol.PubKeyStr:
   584  				case bob.PubKeyStr:
   585  				default:
   586  					t.Fatalf("unknown connecting node: %v",
   587  						chanUpdate.ConnectingNode)
   588  				}
   589  
   590  				if chanUpdate.Capacity != int64(chanAmt) {
   591  					t.Fatalf("channel capacities mismatch:"+
   592  						" expected %v, got %v", chanAmt,
   593  						dcrutil.Amount(chanUpdate.Capacity))
   594  				}
   595  				numChannelUpds++
   596  			}
   597  		case err := <-graphSub.errChan:
   598  			t.Fatalf("unable to recv graph update: %v", err)
   599  		case <-time.After(time.Second * 10):
   600  			t.Fatalf("timeout waiting for graph notifications, "+
   601  				"only received %d/2 chanupds and %d/2 nodeanns",
   602  				numChannelUpds, numNodeAnns)
   603  		}
   604  	}
   605  
   606  	// Close the channel between Bob and Carol.
   607  	closeChannelAndAssert(t, net, bob, chanPoint, false)
   608  }
   609  
   610  // testNodeAnnouncement ensures that when a node is started with one or more
   611  // external IP addresses specified on the command line, that those addresses
   612  // announced to the network and reported in the network graph.
   613  func testNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
   614  	ctxb := context.Background()
   615  
   616  	aliceSub := subscribeGraphNotifications(ctxb, t, net.Alice)
   617  	defer close(aliceSub.quit)
   618  
   619  	advertisedAddrs := []string{
   620  		"192.168.1.1:8333",
   621  		"[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8337",
   622  		"bkb6azqggsaiskzi.onion:9735",
   623  		"fomvuglh6h6vcag73xo5t5gv56ombih3zr2xvplkpbfd7wrog4swjwid.onion:1234",
   624  	}
   625  
   626  	var lndArgs []string
   627  	for _, addr := range advertisedAddrs {
   628  		lndArgs = append(lndArgs, "--externalip="+addr)
   629  	}
   630  
   631  	dave := net.NewNode(t.t, "Dave", lndArgs)
   632  	defer shutdownAndAssert(net, t, dave)
   633  
   634  	// We must let Dave have an open channel before he can send a node
   635  	// announcement, so we open a channel with Bob,
   636  	net.ConnectNodes(t.t, net.Bob, dave)
   637  
   638  	// Alice shouldn't receive any new updates yet since the channel has yet
   639  	// to be opened.
   640  	select {
   641  	case <-aliceSub.updateChan:
   642  		t.Fatalf("received unexpected update from dave")
   643  	case <-time.After(time.Second):
   644  	}
   645  
   646  	// We'll then go ahead and open a channel between Bob and Dave. This
   647  	// ensures that Alice receives the node announcement from Bob as part of
   648  	// the announcement broadcast.
   649  	chanPoint := openChannelAndAssert(
   650  		t, net, net.Bob, dave,
   651  		lntest.OpenChannelParams{
   652  			Amt: 1000000,
   653  		},
   654  	)
   655  
   656  	assertAddrs := func(addrsFound []string, targetAddrs ...string) {
   657  		addrs := make(map[string]struct{}, len(addrsFound))
   658  		for _, addr := range addrsFound {
   659  			addrs[addr] = struct{}{}
   660  		}
   661  
   662  		for _, addr := range targetAddrs {
   663  			if _, ok := addrs[addr]; !ok {
   664  				t.Fatalf("address %v not found in node "+
   665  					"announcement", addr)
   666  			}
   667  		}
   668  	}
   669  
   670  	waitForAddrsInUpdate := func(graphSub graphSubscription,
   671  		nodePubKey string, targetAddrs ...string) {
   672  
   673  		for {
   674  			select {
   675  			case graphUpdate := <-graphSub.updateChan:
   676  				for _, update := range graphUpdate.NodeUpdates {
   677  					if update.IdentityKey == nodePubKey {
   678  						assertAddrs(
   679  							update.Addresses,
   680  							targetAddrs...,
   681  						)
   682  						return
   683  					}
   684  				}
   685  			case err := <-graphSub.errChan:
   686  				t.Fatalf("unable to recv graph update: %v", err)
   687  			case <-time.After(defaultTimeout):
   688  				t.Fatalf("did not receive node ann update")
   689  			}
   690  		}
   691  	}
   692  
   693  	// We'll then wait for Alice to receive Dave's node announcement
   694  	// including the expected advertised addresses from Bob since they
   695  	// should already be connected.
   696  	waitForAddrsInUpdate(
   697  		aliceSub, dave.PubKeyStr, advertisedAddrs...,
   698  	)
   699  
   700  	// Close the channel between Bob and Dave.
   701  	closeChannelAndAssert(t, net, net.Bob, chanPoint, false)
   702  }
   703  
   704  // graphSubscription houses the proxied update and error chans for a node's
   705  // graph subscriptions.
   706  type graphSubscription struct {
   707  	updateChan chan *lnrpc.GraphTopologyUpdate
   708  	errChan    chan error
   709  	quit       chan struct{}
   710  }
   711  
   712  // subscribeGraphNotifications subscribes to channel graph updates and launches
   713  // a goroutine that forwards these to the returned channel.
   714  func subscribeGraphNotifications(ctxb context.Context, t *harnessTest,
   715  	node *lntest.HarnessNode) graphSubscription {
   716  
   717  	// We'll first start by establishing a notification client which will
   718  	// send us notifications upon detected changes in the channel graph.
   719  	req := &lnrpc.GraphTopologySubscription{}
   720  	ctx, cancelFunc := context.WithCancel(ctxb)
   721  	topologyClient, err := node.SubscribeChannelGraph(ctx, req)
   722  	require.NoError(t.t, err, "unable to create topology client")
   723  
   724  	// We'll launch a goroutine that will be responsible for proxying all
   725  	// notifications recv'd from the client into the channel below.
   726  	errChan := make(chan error, 1)
   727  	quit := make(chan struct{})
   728  	graphUpdates := make(chan *lnrpc.GraphTopologyUpdate, 20)
   729  	go func() {
   730  		for {
   731  			defer cancelFunc()
   732  
   733  			select {
   734  			case <-quit:
   735  				return
   736  			default:
   737  				graphUpdate, err := topologyClient.Recv()
   738  				select {
   739  				case <-quit:
   740  					return
   741  				default:
   742  				}
   743  
   744  				if err == io.EOF {
   745  					return
   746  				} else if err != nil {
   747  					select {
   748  					case errChan <- err:
   749  					case <-quit:
   750  					}
   751  					return
   752  				}
   753  
   754  				select {
   755  				case graphUpdates <- graphUpdate:
   756  				case <-quit:
   757  					return
   758  				}
   759  			}
   760  		}
   761  	}()
   762  
   763  	return graphSubscription{
   764  		updateChan: graphUpdates,
   765  		errChan:    errChan,
   766  		quit:       quit,
   767  	}
   768  }