Skip to content

Commit 435b278

Browse files
fjlatif-konasl
authored andcommitted
cmd/utils: use eth DNS tree for snap discovery (ethereum#22808)
This removes auto-configuration of the snap.*.ethdisco.net DNS discovery tree. Since measurements have shown that > 75% of nodes in all.*.ethdisco.net support snap, we have decided to retire the dedicated index for snap and just use the eth tree instead. The dial iterators of eth and snap now use the same DNS tree in the default configuration, so both iterators should use the same DNS discovery client instance. This ensures that the record cache and rate limit are shared. Records will not be requested multiple times. While testing the change, I noticed that duplicate DNS requests do happen even when the client instance is shared. This is because the two iterators request the tree root, link tree root, and first levels of the tree in lockstep. To avoid this problem, the change also adds a singleflight.Group instance in the client. When one iterator attempts to resolve an entry which is already being resolved, the singleflight object waits for the existing resolve call to finish and returns the entry to both places.
1 parent d6a7a7e commit 435b278

File tree

7 files changed

+48
-39
lines changed

7 files changed

+48
-39
lines changed

cmd/utils/flags.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,11 +1694,7 @@ func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) {
16941694
}
16951695
if url := params.KnownDNSNetwork(genesis, protocol); url != "" {
16961696
cfg.EthDiscoveryURLs = []string{url}
1697-
}
1698-
if cfg.SyncMode == downloader.SnapSync {
1699-
if url := params.KnownDNSNetwork(genesis, "snap"); url != "" {
1700-
cfg.SnapDiscoveryURLs = []string{url}
1701-
}
1697+
cfg.SnapDiscoveryURLs = cfg.EthDiscoveryURLs
17021698
}
17031699
}
17041700

eth/backend.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import (
5252
"github.com/ethereum/go-ethereum/miner"
5353
"github.com/ethereum/go-ethereum/node"
5454
"github.com/ethereum/go-ethereum/p2p"
55+
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
5556
"github.com/ethereum/go-ethereum/p2p/enode"
5657
"github.com/ethereum/go-ethereum/params"
5758
"github.com/ethereum/go-ethereum/rlp"
@@ -246,14 +247,17 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
246247
}
247248
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
248249

249-
eth.ethDialCandidates, err = setupDiscovery(eth.config.EthDiscoveryURLs)
250+
// Setup DNS discovery iterators.
251+
dnsclient := dnsdisc.NewClient(dnsdisc.Config{})
252+
eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...)
250253
if err != nil {
251254
return nil, err
252255
}
253-
eth.snapDialCandidates, err = setupDiscovery(eth.config.SnapDiscoveryURLs)
256+
eth.snapDialCandidates, err = dnsclient.NewIterator(eth.config.SnapDiscoveryURLs...)
254257
if err != nil {
255258
return nil, err
256259
}
260+
257261
// Start the RPC service
258262
eth.netRPCService = ethapi.NewPublicNetAPI(eth.p2pServer, config.NetworkId)
259263

@@ -551,6 +555,8 @@ func (s *Ethereum) Start() error {
551555
// Ethereum protocol.
552556
func (s *Ethereum) Stop() error {
553557
// Stop all the peer-related stuff first.
558+
s.ethDialCandidates.Close()
559+
s.snapDialCandidates.Close()
554560
s.handler.Stop()
555561

556562
// Then stop everything else.

eth/discovery.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package eth
1919
import (
2020
"github.com/ethereum/go-ethereum/core"
2121
"github.com/ethereum/go-ethereum/core/forkid"
22-
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
2322
"github.com/ethereum/go-ethereum/p2p/enode"
2423
"github.com/ethereum/go-ethereum/rlp"
2524
)
@@ -62,13 +61,3 @@ func (eth *Ethereum) currentEthEntry() *ethEntry {
6261
return &ethEntry{ForkID: forkid.NewID(eth.blockchain.Config(), eth.blockchain.Genesis().Hash(),
6362
eth.blockchain.CurrentHeader().Number.Uint64())}
6463
}
65-
66-
// setupDiscovery creates the node discovery source for the `eth` and `snap`
67-
// protocols.
68-
func setupDiscovery(urls []string) (enode.Iterator, error) {
69-
if len(urls) == 0 {
70-
return nil, nil
71-
}
72-
client := dnsdisc.NewClient(dnsdisc.Config{})
73-
return client.NewIterator(urls...)
74-
}

eth/protocols/snap/handler.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ type Backend interface {
8484

8585
// MakeProtocols constructs the P2P protocol definitions for `snap`.
8686
func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol {
87+
// Filter the discovery iterator for nodes advertising snap support.
88+
dnsdisc = enode.Filter(dnsdisc, func(n *enode.Node) bool {
89+
var snap enrEntry
90+
return n.Load(&snap) == nil
91+
})
92+
8793
protocols := make([]p2p.Protocol, len(ProtocolVersions))
8894
for i, version := range ProtocolVersions {
8995
version := version // Closure

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ require (
6060
github.com/tklauser/go-sysconf v0.3.5 // indirect
6161
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
6262
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
63+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
6364
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988
6465
golang.org/x/text v0.3.4
6566
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
455455
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
456456
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
457457
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
458+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
459+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
458460
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
459461
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
460462
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

p2p/dnsdisc/client.go

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,17 @@ import (
3232
"github.com/ethereum/go-ethereum/p2p/enode"
3333
"github.com/ethereum/go-ethereum/p2p/enr"
3434
lru "github.com/hashicorp/golang-lru"
35+
"golang.org/x/sync/singleflight"
3536
"golang.org/x/time/rate"
3637
)
3738

3839
// Client discovers nodes by querying DNS servers.
3940
type Client struct {
40-
cfg Config
41-
clock mclock.Clock
42-
entries *lru.Cache
43-
ratelimit *rate.Limiter
41+
cfg Config
42+
clock mclock.Clock
43+
entries *lru.Cache
44+
ratelimit *rate.Limiter
45+
singleflight singleflight.Group
4446
}
4547

4648
// Config holds configuration options for the client.
@@ -135,17 +137,20 @@ func (c *Client) NewIterator(urls ...string) (enode.Iterator, error) {
135137

136138
// resolveRoot retrieves a root entry via DNS.
137139
func (c *Client) resolveRoot(ctx context.Context, loc *linkEntry) (rootEntry, error) {
138-
txts, err := c.cfg.Resolver.LookupTXT(ctx, loc.domain)
139-
c.cfg.Logger.Trace("Updating DNS discovery root", "tree", loc.domain, "err", err)
140-
if err != nil {
141-
return rootEntry{}, err
142-
}
143-
for _, txt := range txts {
144-
if strings.HasPrefix(txt, rootPrefix) {
145-
return parseAndVerifyRoot(txt, loc)
140+
e, err, _ := c.singleflight.Do(loc.str, func() (interface{}, error) {
141+
txts, err := c.cfg.Resolver.LookupTXT(ctx, loc.domain)
142+
c.cfg.Logger.Trace("Updating DNS discovery root", "tree", loc.domain, "err", err)
143+
if err != nil {
144+
return rootEntry{}, err
146145
}
147-
}
148-
return rootEntry{}, nameError{loc.domain, errNoRoot}
146+
for _, txt := range txts {
147+
if strings.HasPrefix(txt, rootPrefix) {
148+
return parseAndVerifyRoot(txt, loc)
149+
}
150+
}
151+
return rootEntry{}, nameError{loc.domain, errNoRoot}
152+
})
153+
return e.(rootEntry), err
149154
}
150155

151156
func parseAndVerifyRoot(txt string, loc *linkEntry) (rootEntry, error) {
@@ -168,17 +173,21 @@ func (c *Client) resolveEntry(ctx context.Context, domain, hash string) (entry,
168173
if err := c.ratelimit.Wait(ctx); err != nil {
169174
return nil, err
170175
}
171-
172176
cacheKey := truncateHash(hash)
173177
if e, ok := c.entries.Get(cacheKey); ok {
174178
return e.(entry), nil
175179
}
176-
e, err := c.doResolveEntry(ctx, domain, hash)
177-
if err != nil {
178-
return nil, err
179-
}
180-
c.entries.Add(cacheKey, e)
181-
return e, nil
180+
181+
ei, err, _ := c.singleflight.Do(cacheKey, func() (interface{}, error) {
182+
e, err := c.doResolveEntry(ctx, domain, hash)
183+
if err != nil {
184+
return nil, err
185+
}
186+
c.entries.Add(cacheKey, e)
187+
return e, nil
188+
})
189+
e, _ := ei.(entry)
190+
return e, err
182191
}
183192

184193
// doResolveEntry fetches an entry via DNS.

0 commit comments

Comments
 (0)