discovery: remove retries from DNS based SampleNodeAddrs, allow down seeds

In this commit, we modify the `SampleNodeAddrs` method to no longer
retry itself. Instead, we'll now leave this task to the caller of the
this method. Additionally, we'll no longer return with an error if we
can't hit a particular seed. Instead, we'll log the error and move onto
the next seed. Finally, we'll also no longer require that the DNS seed
has a secondary seed in order to support a wider array of DNS seeds.
This commit is contained in:
Olaoluwa Osuntokun 2019-06-27 18:48:57 -07:00
parent 7f48ff6717
commit 9c957193cf
No known key found for this signature in database
GPG Key ID: CE58F7F8E20FD9A2

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