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
// 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)
}
}