diff --git a/lnd_test.go b/lnd_test.go index 6f2ab9cd..4cceb16e 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -2080,7 +2080,6 @@ func testNodeAnnouncement(net *networkHarness, t *harnessTest) { ipAddresses := map[string]bool{ "192.168.1.1:8333": true, "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8337": true, - "127.0.0.1:8335": true, } var lndArgs []string @@ -2118,8 +2117,11 @@ func testNodeAnnouncement(net *networkHarness, t *harnessTest) { if ipAddresses[parts[3]] { delete(ipAddresses, parts[3]) } else { - t.Fatalf("unexpected IP address: %v", - parts[3]) + if !strings.HasPrefix(parts[3], + "127.0.0.1:") { + t.Fatalf("unexpected IP: %v", + parts[3]) + } } } } diff --git a/networktest.go b/networktest.go index 49044530..db8443c0 100644 --- a/networktest.go +++ b/networktest.go @@ -133,6 +133,9 @@ func newLightningNode(rpcConfig *btcrpcclient.ConnConfig, lndArgs []string) (*li numActiveNodes++ + lndArgs = append(lndArgs, "--externalip=127.0.0.1:"+ + strconv.Itoa(cfg.PeerPort)) + return &lightningNode{ cfg: cfg, p2pAddr: net.JoinHostPort("127.0.0.1", strconv.Itoa(cfg.PeerPort)), diff --git a/server.go b/server.go index 3bfcca12..a5c49e87 100644 --- a/server.go +++ b/server.go @@ -243,33 +243,107 @@ func newServer(listenAddrs []string, notifier chainntnfs.ChainNotifier, // In order to promote liveness of our active channels, instruct the // connection manager to attempt to establish and maintain persistent // connections to all our direct channel counterparties. + + // nodeAddrsMap stores the combination of node public keys and + // addresses that we'll attempt to reconnect to. PubKey strings are + // used as keys since other PubKey forms can't be compared. + nodeAddrsMap := map[string]*nodeAddresses{} + + // Iterate through the list of LinkNodes to find addresses we should + // attempt to connect to based on our set of previous connections. Set + // the reconnection port to the default peer port. linkNodes, err := s.chanDB.FetchAllLinkNodes() if err != nil && err != channeldb.ErrLinkNodesNotFound { return nil, err } for _, node := range linkNodes { - pubStr := string(node.IdentityPub.SerializeCompressed()) - - // In case a node has multiple addresses, attempt to connect to - // each of them. for _, address := range node.Addresses { - // Create a wrapper address which couples the IP and the pubkey - // so the brontide authenticated connection can be established. + if address.Port == 0 { + address.Port = defaultPeerPort + } + } + pubStr := string(node.IdentityPub.SerializeCompressed()) + nodeAddrs := &nodeAddresses{ + pubKey: node.IdentityPub, + addresses: node.Addresses, + } + nodeAddrsMap[pubStr] = nodeAddrs + } + + // After checking our previous connections for addresses to connect to, + // iterate through the nodes in our channel graph to find addresses + // that have been added via NodeAnnouncement messages. + sourceNode, err := chanGraph.SourceNode() + if err != nil { + return nil, err + } + err = sourceNode.ForEachChannel(nil, func(_ *channeldb.ChannelEdgeInfo, + policy *channeldb.ChannelEdgePolicy) error { + pubStr := string(policy.Node.PubKey.SerializeCompressed()) + + // Add addresses from channel graph/NodeAnnouncements to the + // list of addresses we'll connect to. If there are duplicates + // that have different ports specified, the port from the + // channel graph should supersede the port from the link node. + var addrs []*net.TCPAddr + linkNodeAddrs, ok := nodeAddrsMap[pubStr] + if ok { + for _, lnAddress := range linkNodeAddrs.addresses { + var addrMatched bool + for _, polAddress := range policy.Node.Addresses { + polTCPAddr, ok := + polAddress.(*net.TCPAddr) + if ok && polTCPAddr.IP.Equal(lnAddress.IP) { + addrMatched = true + addrs = append(addrs, polTCPAddr) + } + } + if !addrMatched { + addrs = append(addrs, lnAddress) + } + } + } else { + for _, addr := range policy.Node.Addresses { + polTCPAddr, ok := addr.(*net.TCPAddr) + if ok { + addrs = append(addrs, polTCPAddr) + } + } + } + + nodeAddrsMap[pubStr] = &nodeAddresses{ + pubKey: policy.Node.PubKey, + addresses: addrs, + } + + return nil + }) + if err != nil && err != channeldb.ErrGraphNoEdgesFound { + return nil, err + } + + // Iterate through the combined list of addresses from prior links and + // node announcements and attempt to reconnect to each node. + for pubStr, nodeAddr := range nodeAddrsMap { + for _, address := range nodeAddr.addresses { + // Create a wrapper address which couples the IP and + // the pubkey so the brontide authenticated connection + // can be established. lnAddr := &lnwire.NetAddress{ - IdentityKey: node.IdentityPub, + IdentityKey: nodeAddr.pubKey, Address: address, } - srvrLog.Debugf("Attempting persistent connection to channel "+ - "peer %v", lnAddr) - - // Send the persistent connection request to the connection - // manager, saving the request itself so we can cancel/restart - // the process as needed. - // TODO(roasbeef): use default addr + srvrLog.Debugf("Attempting persistent connection to "+ + "channel peer %v", lnAddr) + // Send the persistent connection request to + // the connection manager, saving the request + // itself so we can cancel/restart the process + // as needed. connReq := &connmgr.ConnReq{ Addr: lnAddr, Permanent: true, } + s.persistentConnReqs[pubStr] = append(s.persistentConnReqs[pubStr], connReq) go s.connMgr.Connect(connReq) @@ -398,6 +472,11 @@ type sendReq struct { errChan chan error } +type nodeAddresses struct { + pubKey *btcec.PublicKey + addresses []*net.TCPAddr +} + // sendToPeer send a message to the server telling it to send the specific set // of message to a particular peer. If the peer connect be found, then this // method will return a non-nil error.