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,135 +379,146 @@ 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 can
// We'll first query the seed with an SRV record so we // obtain a random sample of the encoded public keys of nodes.
// can obtain a random sample of the encoded public // We use the lndLookupSRV function for this task.
// keys of nodes. We use the lndLookupSRV function for primarySeed := dnsSeedTuple[0]
// this task. _, addrs, err := d.net.LookupSRV("nodes", "tcp", primarySeed)
primarySeed := dnsSeedTuple[0] if err != nil {
_, addrs, err := d.net.LookupSRV("nodes", "tcp", primarySeed) log.Tracef("Unable to lookup SRV records via "+
if err != nil { "primary seed (%v): %v", primarySeed, err)
log.Tracef("Unable to lookup SRV records via "+
"primary seed: %v", 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
// 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")
} }
log.Tracef("Retrieved SRV records from dns seed: %v", // If we get an error when trying to query via the
spew.Sdump(addrs)) // 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 log.Tracef("Successfully queried fallback DNS seed")
// 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 log.Tracef("Retrieved SRV records from dns seed: %v",
// perform another query to obtain the IP newLogClosure(func() string {
// address for the matching bech32 encoded node return spew.Sdump(addrs)
// 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 { // Next, we'll need to issue an A record request for each of
log.Tracef("No addresses for %v, skipping", // the nodes, skipping it if nothing comes back.
bechNodeHost) 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 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)
} }
} }