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 }