diff --git a/discovery/bootstrapper.go b/discovery/bootstrapper.go index e53ecfe3..5ead175c 100644 --- a/discovery/bootstrapper.go +++ b/discovery/bootstrapper.go @@ -379,135 +379,146 @@ func (d *DNSSeedBootstrapper) SampleNodeAddrs(numAddrs uint32, var netAddrs []*lnwire.NetAddress - // We'll continue this loop until we reach our target address limit. - // Each SRV query to the seed will return 25 random nodes, so we can - // continue to query until we reach our target. + // We'll try all the registered DNS seeds, exiting early if one of them + // gives us all the peers we need. + // + // TODO(roasbeef): should combine results from both search: - for uint32(len(netAddrs)) < numAddrs { - for _, dnsSeedTuple := range d.dnsSeeds { - // We'll first query the seed with an SRV record so we - // can obtain a random sample of the encoded public - // keys of nodes. We use the lndLookupSRV function for - // this task. - primarySeed := dnsSeedTuple[0] - _, addrs, err := d.net.LookupSRV("nodes", "tcp", primarySeed) - if err != nil { - log.Tracef("Unable to lookup SRV records via "+ - "primary seed: %v", err) + for _, dnsSeedTuple := range d.dnsSeeds { + // We'll first query the seed with an SRV record so we can + // obtain a random sample of the encoded public keys of nodes. + // We use the lndLookupSRV function for this task. + primarySeed := dnsSeedTuple[0] + _, addrs, err := d.net.LookupSRV("nodes", "tcp", primarySeed) + if err != nil { + log.Tracef("Unable to lookup SRV records via "+ + "primary seed (%v): %v", primarySeed, err) - log.Trace("Falling back to secondary") + log.Trace("Falling back to secondary") - // If the host of the secondary seed is blank, - // then we'll bail here as we can't proceed. - if dnsSeedTuple[1] == "" { - return nil, fmt.Errorf("Secondary seed is blank") - } - - // If we get an error when trying to query via - // the primary seed, we'll fallback to the - // secondary seed before concluding failure. - soaShim := dnsSeedTuple[1] - addrs, err = d.fallBackSRVLookup( - soaShim, primarySeed, - ) - if err != nil { - return nil, err - } - log.Tracef("Successfully queried fallback DNS seed") + // If the host of the secondary seed is blank, then + // we'll bail here as we can't proceed. + if dnsSeedTuple[1] == "" { + log.Tracef("DNS seed %v has no secondary, "+ + "skipping fallback", primarySeed) + continue } - log.Tracef("Retrieved SRV records from dns seed: %v", - spew.Sdump(addrs)) + // If we get an error when trying to query via the + // primary seed, we'll fallback to the secondary seed + // before concluding failure. + soaShim := dnsSeedTuple[1] + addrs, err = d.fallBackSRVLookup( + soaShim, primarySeed, + ) + if err != nil { + log.Tracef("Unable to query fall "+ + "back dns seed (%v): %v", soaShim, err) + continue + } - // Next, we'll need to issue an A record request for - // each of the nodes, skipping it if nothing comes - // back. - for _, nodeSrv := range addrs { - if uint32(len(netAddrs)) >= numAddrs { - break search - } + log.Tracef("Successfully queried fallback DNS seed") + } - // With the SRV target obtained, we'll now - // perform another query to obtain the IP - // address for the matching bech32 encoded node - // key. We use the lndLookup function for this - // task. - bechNodeHost := nodeSrv.Target - addrs, err := d.net.LookupHost(bechNodeHost) - if err != nil { - return nil, err - } + log.Tracef("Retrieved SRV records from dns seed: %v", + newLogClosure(func() string { + return spew.Sdump(addrs) + }), + ) - if len(addrs) == 0 { - log.Tracef("No addresses for %v, skipping", - bechNodeHost) + // Next, we'll need to issue an A record request for each of + // the nodes, skipping it if nothing comes back. + for _, nodeSrv := range addrs { + if uint32(len(netAddrs)) >= numAddrs { + break search + } + + // With the SRV target obtained, we'll now perform + // another query to obtain the IP address for the + // matching bech32 encoded node key. We use the + // lndLookup function for this task. + bechNodeHost := nodeSrv.Target + addrs, err := d.net.LookupHost(bechNodeHost) + if err != nil { + return nil, err + } + + if len(addrs) == 0 { + log.Tracef("No addresses for %v, skipping", + bechNodeHost) + continue + } + + log.Tracef("Attempting to convert: %v", bechNodeHost) + + // If the host isn't correctly formatted, then we'll + // skip it. + if len(bechNodeHost) == 0 || + !strings.Contains(bechNodeHost, ".") { + + continue + } + + // If we have a set of valid addresses, then we'll need + // to parse the public key from the original bech32 + // encoded string. + bechNode := strings.Split(bechNodeHost, ".") + _, nodeBytes5Bits, err := bech32.Decode(bechNode[0]) + if err != nil { + return nil, err + } + + // Once we have the bech32 decoded pubkey, we'll need + // to convert the 5-bit word grouping into our regular + // 8-bit word grouping so we can convert it into a + // public key. + nodeBytes, err := bech32.ConvertBits( + nodeBytes5Bits, 5, 8, false, + ) + if err != nil { + return nil, err + } + nodeKey, err := btcec.ParsePubKey( + nodeBytes, btcec.S256(), + ) + if err != nil { + return nil, err + } + + // If we have an ignore list, and this node is in the + // ignore list, then we'll go to the next candidate. + if ignore != nil { + nID := autopilot.NewNodeID(nodeKey) + if _, ok := ignore[nID]; ok { continue } - - log.Tracef("Attempting to convert: %v", bechNodeHost) - - // If we have a set of valid addresses, then - // we'll need to parse the public key from the - // original bech32 encoded string. - bechNode := strings.Split(bechNodeHost, ".") - _, nodeBytes5Bits, err := bech32.Decode(bechNode[0]) - if err != nil { - return nil, err - } - - // Once we have the bech32 decoded pubkey, - // we'll need to convert the 5-bit word - // grouping into our regular 8-bit word - // grouping so we can convert it into a public - // key. - nodeBytes, err := bech32.ConvertBits( - nodeBytes5Bits, 5, 8, false, - ) - if err != nil { - return nil, err - } - nodeKey, err := btcec.ParsePubKey( - nodeBytes, btcec.S256(), - ) - if err != nil { - return nil, err - } - - // If we have an ignore list, and this node is - // in the ignore list, then we'll go to the - // next candidate. - if ignore != nil { - nID := autopilot.NewNodeID(nodeKey) - if _, ok := ignore[nID]; ok { - continue - } - } - - // Finally we'll convert the host:port peer to - // a proper TCP address to use within the - // lnwire.NetAddress. We don't need to use - // the lndResolveTCP function here because we - // already have the host:port peer. - addr := net.JoinHostPort(addrs[0], - strconv.FormatUint(uint64(nodeSrv.Port), 10)) - tcpAddr, err := net.ResolveTCPAddr("tcp", addr) - if err != nil { - return nil, err - } - - // Finally, with all the information parsed, - // we'll return this fully valid address as a - // connection attempt. - lnAddr := &lnwire.NetAddress{ - IdentityKey: nodeKey, - Address: tcpAddr, - } - - log.Tracef("Obtained %v as valid reachable "+ - "node", lnAddr) - - netAddrs = append(netAddrs, lnAddr) } + + // Finally we'll convert the host:port peer to a proper + // TCP address to use within the lnwire.NetAddress. We + // don't need to use the lndResolveTCP function here + // because we already have the host:port peer. + addr := net.JoinHostPort( + addrs[0], + strconv.FormatUint(uint64(nodeSrv.Port), 10), + ) + tcpAddr, err := net.ResolveTCPAddr("tcp", addr) + if err != nil { + return nil, err + } + + // Finally, with all the information parsed, we'll + // return this fully valid address as a connection + // attempt. + lnAddr := &lnwire.NetAddress{ + IdentityKey: nodeKey, + Address: tcpAddr, + } + + log.Tracef("Obtained %v as valid reachable "+ + "node", lnAddr) + + netAddrs = append(netAddrs, lnAddr) } }