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>
This commit is contained in:
parent
7a149a159a
commit
6eb42a6b4f
@ -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…
Reference in New Issue
Block a user