Skip to content

Commit 6eb42a6

Browse files
fjllightclient
andauthored
eth: dial nodes from discv5 (#30302)
Here I am adding a discv5 nodes source into the p2p dial iterator. It's an improved version of #29533. Unlike discv4, the discv5 random nodes iterator will always provide full ENRs. This means we can apply filtering to the results and will only try dialing nodes which explictly opt into the eth protocol with a matching chain. I have also removed the dial iterator from snap. We don't have an official DNS list for snap anymore, and I doubt anyone else is running one. While we could potentially filter for snap on discv5, there will be very few nodes announcing it, and the extra iterator would just stall the dialer. --------- Co-authored-by: lightclient <[email protected]>
1 parent 7a149a1 commit 6eb42a6

File tree

4 files changed

+60
-35
lines changed

4 files changed

+60
-35
lines changed

eth/backend.go

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,13 @@ type Config = ethconfig.Config
6464

6565
// Ethereum implements the Ethereum full node service.
6666
type Ethereum struct {
67-
config *ethconfig.Config
67+
// core protocol objects
68+
config *ethconfig.Config
69+
txPool *txpool.TxPool
70+
blockchain *core.BlockChain
6871

69-
// Handlers
70-
txPool *txpool.TxPool
71-
72-
blockchain *core.BlockChain
73-
handler *handler
74-
ethDialCandidates enode.Iterator
75-
snapDialCandidates enode.Iterator
72+
handler *handler
73+
discmix *enode.FairMix
7674

7775
// DB interfaces
7876
chainDb ethdb.Database // Block chain database
@@ -162,6 +160,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
162160
bloomRequests: make(chan chan *bloombits.Retrieval),
163161
bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms),
164162
p2pServer: stack.Server(),
163+
discmix: enode.NewFairMix(0),
165164
shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb),
166165
}
167166
bcVersion := rawdb.ReadDatabaseVersion(chainDb)
@@ -266,17 +265,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
266265
}
267266
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, config.GPO, config.Miner.GasPrice)
268267

269-
// Setup DNS discovery iterators.
270-
dnsclient := dnsdisc.NewClient(dnsdisc.Config{})
271-
eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...)
272-
if err != nil {
273-
return nil, err
274-
}
275-
eth.snapDialCandidates, err = dnsclient.NewIterator(eth.config.SnapDiscoveryURLs...)
276-
if err != nil {
277-
return nil, err
278-
}
279-
280268
// Start the RPC service
281269
eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID)
282270

@@ -359,17 +347,17 @@ func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer }
359347
// Protocols returns all the currently configured
360348
// network protocols to start.
361349
func (s *Ethereum) Protocols() []p2p.Protocol {
362-
protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates)
350+
protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.discmix)
363351
if s.config.SnapshotCache > 0 {
364-
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...)
352+
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler))...)
365353
}
366354
return protos
367355
}
368356

369357
// Start implements node.Lifecycle, starting all internal goroutines needed by the
370358
// Ethereum protocol implementation.
371359
func (s *Ethereum) Start() error {
372-
eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode())
360+
s.setupDiscovery()
373361

374362
// Start the bloom bits servicing goroutines
375363
s.startBloomHandlers(params.BloomBitsBlocks)
@@ -382,12 +370,43 @@ func (s *Ethereum) Start() error {
382370
return nil
383371
}
384372

373+
func (s *Ethereum) setupDiscovery() error {
374+
eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode())
375+
376+
// Add eth nodes from DNS.
377+
dnsclient := dnsdisc.NewClient(dnsdisc.Config{})
378+
if len(s.config.EthDiscoveryURLs) > 0 {
379+
iter, err := dnsclient.NewIterator(s.config.EthDiscoveryURLs...)
380+
if err != nil {
381+
return err
382+
}
383+
s.discmix.AddSource(iter)
384+
}
385+
386+
// Add snap nodes from DNS.
387+
if len(s.config.SnapDiscoveryURLs) > 0 {
388+
iter, err := dnsclient.NewIterator(s.config.SnapDiscoveryURLs...)
389+
if err != nil {
390+
return err
391+
}
392+
s.discmix.AddSource(iter)
393+
}
394+
395+
// Add DHT nodes from discv5.
396+
if s.p2pServer.DiscoveryV5() != nil {
397+
filter := eth.NewNodeFilter(s.blockchain)
398+
iter := enode.Filter(s.p2pServer.DiscoveryV5().RandomNodes(), filter)
399+
s.discmix.AddSource(iter)
400+
}
401+
402+
return nil
403+
}
404+
385405
// Stop implements node.Lifecycle, terminating all internal goroutines used by the
386406
// Ethereum protocol.
387407
func (s *Ethereum) Stop() error {
388408
// Stop all the peer-related stuff first.
389-
s.ethDialCandidates.Close()
390-
s.snapDialCandidates.Close()
409+
s.discmix.Close()
391410
s.handler.Stop()
392411

393412
// Then stop everything else.

eth/protocols/eth/discovery.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,17 @@ func currentENREntry(chain *core.BlockChain) *enrEntry {
6464
ForkID: forkid.NewID(chain.Config(), chain.Genesis(), head.Number.Uint64(), head.Time),
6565
}
6666
}
67+
68+
// NewNodeFilter returns a filtering function that returns whether the provided
69+
// enode advertises a forkid compatible with the current chain.
70+
func NewNodeFilter(chain *core.BlockChain) func(*enode.Node) bool {
71+
filter := forkid.NewFilter(chain)
72+
return func(n *enode.Node) bool {
73+
var entry enrEntry
74+
if err := n.Load(entry); err != nil {
75+
return false
76+
}
77+
err := filter(entry.ForkID)
78+
return err == nil
79+
}
80+
}

eth/protocols/eth/handler.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,7 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2
113113
PeerInfo: func(id enode.ID) interface{} {
114114
return backend.PeerInfo(id)
115115
},
116-
Attributes: []enr.Entry{currentENREntry(backend.Chain())},
117-
DialCandidates: dnsdisc,
116+
Attributes: []enr.Entry{currentENREntry(backend.Chain())},
118117
})
119118
}
120119
return protocols

eth/protocols/snap/handler.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,7 @@ type Backend interface {
8282
}
8383

8484
// MakeProtocols constructs the P2P protocol definitions for `snap`.
85-
func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol {
86-
// Filter the discovery iterator for nodes advertising snap support.
87-
dnsdisc = enode.Filter(dnsdisc, func(n *enode.Node) bool {
88-
var snap enrEntry
89-
return n.Load(&snap) == nil
90-
})
91-
85+
func MakeProtocols(backend Backend) []p2p.Protocol {
9286
protocols := make([]p2p.Protocol, len(ProtocolVersions))
9387
for i, version := range ProtocolVersions {
9488
version := version // Closure
@@ -108,8 +102,7 @@ func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol {
108102
PeerInfo: func(id enode.ID) interface{} {
109103
return backend.PeerInfo(id)
110104
},
111-
Attributes: []enr.Entry{&enrEntry{}},
112-
DialCandidates: dnsdisc,
105+
Attributes: []enr.Entry{&enrEntry{}},
113106
}
114107
}
115108
return protocols

0 commit comments

Comments
 (0)