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 <lightclient@protonmail.com>
pull/30311/head
Felix Lange 3 months ago committed by GitHub
parent 7a149a159a
commit 6eb42a6b4f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 67
      eth/backend.go
  2. 14
      eth/protocols/eth/discovery.go
  3. 3
      eth/protocols/eth/handler.go
  4. 11
      eth/protocols/snap/handler.go

@ -64,15 +64,13 @@ type Config = ethconfig.Config
// Ethereum implements the Ethereum full node service. // Ethereum implements the Ethereum full node service.
type Ethereum struct { type Ethereum struct {
config *ethconfig.Config // core protocol objects
config *ethconfig.Config
txPool *txpool.TxPool
blockchain *core.BlockChain
// Handlers handler *handler
txPool *txpool.TxPool discmix *enode.FairMix
blockchain *core.BlockChain
handler *handler
ethDialCandidates enode.Iterator
snapDialCandidates enode.Iterator
// DB interfaces // DB interfaces
chainDb ethdb.Database // Block chain database chainDb ethdb.Database // Block chain database
@ -162,6 +160,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
bloomRequests: make(chan chan *bloombits.Retrieval), bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms),
p2pServer: stack.Server(), p2pServer: stack.Server(),
discmix: enode.NewFairMix(0),
shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb),
} }
bcVersion := rawdb.ReadDatabaseVersion(chainDb) bcVersion := rawdb.ReadDatabaseVersion(chainDb)
@ -266,17 +265,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
} }
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, config.GPO, config.Miner.GasPrice) eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, config.GPO, config.Miner.GasPrice)
// Setup DNS discovery iterators.
dnsclient := dnsdisc.NewClient(dnsdisc.Config{})
eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...)
if err != nil {
return nil, err
}
eth.snapDialCandidates, err = dnsclient.NewIterator(eth.config.SnapDiscoveryURLs...)
if err != nil {
return nil, err
}
// Start the RPC service // Start the RPC service
eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID) eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID)
@ -359,9 +347,9 @@ func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer }
// Protocols returns all the currently configured // Protocols returns all the currently configured
// network protocols to start. // network protocols to start.
func (s *Ethereum) Protocols() []p2p.Protocol { func (s *Ethereum) Protocols() []p2p.Protocol {
protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates) protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.discmix)
if s.config.SnapshotCache > 0 { if s.config.SnapshotCache > 0 {
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler))...)
} }
return protos return protos
} }
@ -369,7 +357,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
// Start implements node.Lifecycle, starting all internal goroutines needed by the // Start implements node.Lifecycle, starting all internal goroutines needed by the
// Ethereum protocol implementation. // Ethereum protocol implementation.
func (s *Ethereum) Start() error { func (s *Ethereum) Start() error {
eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) s.setupDiscovery()
// Start the bloom bits servicing goroutines // Start the bloom bits servicing goroutines
s.startBloomHandlers(params.BloomBitsBlocks) s.startBloomHandlers(params.BloomBitsBlocks)
@ -382,12 +370,43 @@ func (s *Ethereum) Start() error {
return nil return nil
} }
func (s *Ethereum) setupDiscovery() error {
eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode())
// Add eth nodes from DNS.
dnsclient := dnsdisc.NewClient(dnsdisc.Config{})
if len(s.config.EthDiscoveryURLs) > 0 {
iter, err := dnsclient.NewIterator(s.config.EthDiscoveryURLs...)
if err != nil {
return err
}
s.discmix.AddSource(iter)
}
// Add snap nodes from DNS.
if len(s.config.SnapDiscoveryURLs) > 0 {
iter, err := dnsclient.NewIterator(s.config.SnapDiscoveryURLs...)
if err != nil {
return err
}
s.discmix.AddSource(iter)
}
// Add DHT nodes from discv5.
if s.p2pServer.DiscoveryV5() != nil {
filter := eth.NewNodeFilter(s.blockchain)
iter := enode.Filter(s.p2pServer.DiscoveryV5().RandomNodes(), filter)
s.discmix.AddSource(iter)
}
return nil
}
// Stop implements node.Lifecycle, terminating all internal goroutines used by the // Stop implements node.Lifecycle, terminating all internal goroutines used by the
// Ethereum protocol. // Ethereum protocol.
func (s *Ethereum) Stop() error { func (s *Ethereum) Stop() error {
// Stop all the peer-related stuff first. // Stop all the peer-related stuff first.
s.ethDialCandidates.Close() s.discmix.Close()
s.snapDialCandidates.Close()
s.handler.Stop() s.handler.Stop()
// Then stop everything else. // Then stop everything else.

@ -64,3 +64,17 @@ func currentENREntry(chain *core.BlockChain) *enrEntry {
ForkID: forkid.NewID(chain.Config(), chain.Genesis(), head.Number.Uint64(), head.Time), ForkID: forkid.NewID(chain.Config(), chain.Genesis(), head.Number.Uint64(), head.Time),
} }
} }
// NewNodeFilter returns a filtering function that returns whether the provided
// enode advertises a forkid compatible with the current chain.
func NewNodeFilter(chain *core.BlockChain) func(*enode.Node) bool {
filter := forkid.NewFilter(chain)
return func(n *enode.Node) bool {
var entry enrEntry
if err := n.Load(entry); err != nil {
return false
}
err := filter(entry.ForkID)
return err == nil
}
}

@ -113,8 +113,7 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2
PeerInfo: func(id enode.ID) interface{} { PeerInfo: func(id enode.ID) interface{} {
return backend.PeerInfo(id) return backend.PeerInfo(id)
}, },
Attributes: []enr.Entry{currentENREntry(backend.Chain())}, Attributes: []enr.Entry{currentENREntry(backend.Chain())},
DialCandidates: dnsdisc,
}) })
} }
return protocols return protocols

@ -82,13 +82,7 @@ type Backend interface {
} }
// MakeProtocols constructs the P2P protocol definitions for `snap`. // MakeProtocols constructs the P2P protocol definitions for `snap`.
func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol { func MakeProtocols(backend Backend) []p2p.Protocol {
// Filter the discovery iterator for nodes advertising snap support.
dnsdisc = enode.Filter(dnsdisc, func(n *enode.Node) bool {
var snap enrEntry
return n.Load(&snap) == nil
})
protocols := make([]p2p.Protocol, len(ProtocolVersions)) protocols := make([]p2p.Protocol, len(ProtocolVersions))
for i, version := range ProtocolVersions { for i, version := range ProtocolVersions {
version := version // Closure version := version // Closure
@ -108,8 +102,7 @@ func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol {
PeerInfo: func(id enode.ID) interface{} { PeerInfo: func(id enode.ID) interface{} {
return backend.PeerInfo(id) return backend.PeerInfo(id)
}, },
Attributes: []enr.Entry{&enrEntry{}}, Attributes: []enr.Entry{&enrEntry{}},
DialCandidates: dnsdisc,
} }
} }
return protocols return protocols

Loading…
Cancel
Save