From b402bf66ee1c9da4ef99564eb1479f663504aa15 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 14 Aug 2024 19:25:38 +0200 Subject: [PATCH 1/6] eth: dial nodes from discv5 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. --- eth/backend.go | 61 ++++++++++++++++++++++------------ eth/protocols/eth/discovery.go | 12 +++++++ eth/protocols/eth/handler.go | 3 +- eth/protocols/snap/handler.go | 11 ++---- 4 files changed, 54 insertions(+), 33 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 442d408bb00d..01c74c40d08c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -23,6 +23,7 @@ import ( "math/big" "runtime" "sync" + "time" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" @@ -64,15 +65,13 @@ type Config = ethconfig.Config // Ethereum implements the Ethereum full node service. type Ethereum struct { + // core protocol objects config *ethconfig.Config - - // Handlers txPool *txpool.TxPool + blockchain *core.BlockChain - blockchain *core.BlockChain - handler *handler - ethDialCandidates enode.Iterator - snapDialCandidates enode.Iterator + handler *handler + discmix *enode.FairMix // DB interfaces chainDb ethdb.Database // Block chain database @@ -162,6 +161,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), p2pServer: stack.Server(), + discmix: enode.NewFairMix(2 * time.Second), shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), } bcVersion := rawdb.ReadDatabaseVersion(chainDb) @@ -266,17 +266,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } 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 eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID) @@ -359,9 +348,9 @@ func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } // Protocols returns all the currently configured // network protocols to start. 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 { - protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) + protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler))...) } return protos } @@ -369,7 +358,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol { // Start implements node.Lifecycle, starting all internal goroutines needed by the // Ethereum protocol implementation. func (s *Ethereum) Start() error { - eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) + s.setupDiscovery() // Start the bloom bits servicing goroutines s.startBloomHandlers(params.BloomBitsBlocks) @@ -382,12 +371,40 @@ func (s *Ethereum) Start() error { return nil } +func (s *Ethereum) setupDiscovery() error { + eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) + + 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) + } + + if len(s.config.SnapDiscoveryURLs) > 0 { + iter, err := dnsclient.NewIterator(s.config.SnapDiscoveryURLs...) + if err != nil { + return err + } + s.discmix.AddSource(iter) + } + + 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 // Ethereum protocol. func (s *Ethereum) Stop() error { // Stop all the peer-related stuff first. - s.ethDialCandidates.Close() - s.snapDialCandidates.Close() + s.discmix.Close() s.handler.Stop() // Then stop everything else. diff --git a/eth/protocols/eth/discovery.go b/eth/protocols/eth/discovery.go index a7bdd47daf07..73f39b630be6 100644 --- a/eth/protocols/eth/discovery.go +++ b/eth/protocols/eth/discovery.go @@ -64,3 +64,15 @@ func currentENREntry(chain *core.BlockChain) *enrEntry { ForkID: forkid.NewID(chain.Config(), chain.Genesis(), head.Number.Uint64(), head.Time), } } + +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 + } +} diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 2d69ecdc8366..ecf07b6a2cc9 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -113,8 +113,7 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2 PeerInfo: func(id enode.ID) interface{} { return backend.PeerInfo(id) }, - Attributes: []enr.Entry{currentENREntry(backend.Chain())}, - DialCandidates: dnsdisc, + Attributes: []enr.Entry{currentENREntry(backend.Chain())}, }) } return protocols diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 5cbe9d127056..a6c60bc0757f 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -82,13 +82,7 @@ type Backend interface { } // MakeProtocols constructs the P2P protocol definitions for `snap`. -func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []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 - }) - +func MakeProtocols(backend Backend) []p2p.Protocol { protocols := make([]p2p.Protocol, len(ProtocolVersions)) for i, version := range ProtocolVersions { version := version // Closure @@ -108,8 +102,7 @@ func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol { PeerInfo: func(id enode.ID) interface{} { return backend.PeerInfo(id) }, - Attributes: []enr.Entry{&enrEntry{}}, - DialCandidates: dnsdisc, + Attributes: []enr.Entry{&enrEntry{}}, } } return protocols From 0113cebed9733374e7b28fb240f568e7f34b6ca9 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Aug 2024 11:44:26 +0200 Subject: [PATCH 2/6] eth: gofmt --- eth/backend.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 01c74c40d08c..590b4b05b800 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -66,12 +66,12 @@ type Config = ethconfig.Config // Ethereum implements the Ethereum full node service. type Ethereum struct { // core protocol objects - config *ethconfig.Config - txPool *txpool.TxPool + config *ethconfig.Config + txPool *txpool.TxPool blockchain *core.BlockChain - handler *handler - discmix *enode.FairMix + handler *handler + discmix *enode.FairMix // DB interfaces chainDb ethdb.Database // Block chain database @@ -161,7 +161,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), p2pServer: stack.Server(), - discmix: enode.NewFairMix(2 * time.Second), + discmix: enode.NewFairMix(2 * time.Second), shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), } bcVersion := rawdb.ReadDatabaseVersion(chainDb) From 77d9ec95f609da2428da558fce237e65227ee933 Mon Sep 17 00:00:00 2001 From: lightclient Date: Thu, 15 Aug 2024 09:13:44 -0600 Subject: [PATCH 3/6] eth/protocols/eth: add doc for NewNodeFilter --- eth/protocols/eth/discovery.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eth/protocols/eth/discovery.go b/eth/protocols/eth/discovery.go index 73f39b630be6..075a85b69cdf 100644 --- a/eth/protocols/eth/discovery.go +++ b/eth/protocols/eth/discovery.go @@ -65,6 +65,8 @@ func currentENREntry(chain *core.BlockChain) *enrEntry { } } +// 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 { From b9be390e9a6c31c52d5c7abc8cdf4016cbd0fe6a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Aug 2024 17:32:17 +0200 Subject: [PATCH 4/6] eth: discmix timeout 0 zero --- eth/backend.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/backend.go b/eth/backend.go index 590b4b05b800..e9a778c3c864 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -161,7 +161,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), p2pServer: stack.Server(), - discmix: enode.NewFairMix(2 * time.Second), + discmix: enode.NewFairMix(0), shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), } bcVersion := rawdb.ReadDatabaseVersion(chainDb) From f24e8e7109115b9ef5379deec30b653014e89038 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Aug 2024 17:32:33 +0200 Subject: [PATCH 5/6] eth: fixup --- eth/backend.go | 1 - 1 file changed, 1 deletion(-) diff --git a/eth/backend.go b/eth/backend.go index e9a778c3c864..f7100ef4d8b8 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -23,7 +23,6 @@ import ( "math/big" "runtime" "sync" - "time" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" From 59f9ff5b32df5b51fe52a001194e8bff7b8d28e2 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Aug 2024 17:32:41 +0200 Subject: [PATCH 6/6] eth: add comments --- eth/backend.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/eth/backend.go b/eth/backend.go index f7100ef4d8b8..51011ed0b228 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -373,6 +373,7 @@ func (s *Ethereum) Start() error { 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...) @@ -382,6 +383,7 @@ func (s *Ethereum) setupDiscovery() error { 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 { @@ -390,6 +392,7 @@ func (s *Ethereum) setupDiscovery() error { 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)