From 7bebcd10434efbda6302eba25c0b59c90bd5530f Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Tue, 29 Apr 2025 11:03:02 +0200 Subject: [PATCH 1/2] eth: add multiple parallel lookup in discovery Signed-off-by: Csaba Kiraly --- eth/backend.go | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 7616ec9d3137..5b57e2718717 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -73,6 +73,13 @@ const ( // We expect a normal source to produce ~10 candidates per second. discmixTimeout = 100 * time.Millisecond + // discoveryParallelLookups is the number of parallel lookups to perform by DHT + // sources (disc/v4 and disc/v5). We set this number large enough to be able to + // feed the dial queue with enough peers. Since the whole discovery process is triggered + // only when dial candidates are needed, we can keep this number high without worrying + // about overloading the DHT. + discoveryParallelLookups = 3 + // discoveryPrefetchBuffer is the number of peers to pre-fetch from a discovery // source. It is useful to avoid the negative effects of potential longer timeouts // in the discovery, keeping dial progress while waiting for the next batch of @@ -532,7 +539,6 @@ func (s *Ethereum) setupDiscovery() error { // Add DHT nodes from discv4. if s.p2pServer.DiscoveryV4() != nil { - iter := s.p2pServer.DiscoveryV4().RandomNodes() resolverFunc := func(ctx context.Context, enr *enode.Node) *enode.Node { // RequestENR does not yet support context. It will simply time out. // If the ENR can't be resolved, RequestENR will return nil. We don't @@ -540,18 +546,27 @@ func (s *Ethereum) setupDiscovery() error { nn, _ := s.p2pServer.DiscoveryV4().RequestENR(enr) return nn } - iter = enode.AsyncFilter(iter, resolverFunc, maxParallelENRRequests) - iter = enode.Filter(iter, eth.NewNodeFilter(s.blockchain)) - iter = enode.NewBufferIter(iter, discoveryPrefetchBuffer) - s.discmix.AddSource(iter) + fairmix := enode.NewFairMix(0) + for i := 0; i < discoveryParallelLookups; i++ { + iter := s.p2pServer.DiscoveryV4().RandomNodes() + iter = enode.AsyncFilter(iter, resolverFunc, maxParallelENRRequests) + iter = enode.Filter(iter, eth.NewNodeFilter(s.blockchain)) + iter = enode.NewBufferIter(iter, discoveryPrefetchBuffer) + fairmix.AddSource(iter) + } + s.discmix.AddSource(fairmix) } // Add DHT nodes from discv5. if s.p2pServer.DiscoveryV5() != nil { - filter := eth.NewNodeFilter(s.blockchain) - iter := enode.Filter(s.p2pServer.DiscoveryV5().RandomNodes(), filter) - iter = enode.NewBufferIter(iter, discoveryPrefetchBuffer) - s.discmix.AddSource(iter) + fairmix := enode.NewFairMix(0) + for i := 0; i < discoveryParallelLookups; i++ { + iter := s.p2pServer.DiscoveryV5().RandomNodes() + iter = enode.Filter(iter, eth.NewNodeFilter(s.blockchain)) + iter = enode.NewBufferIter(iter, discoveryPrefetchBuffer) + fairmix.AddSource(iter) + } + s.discmix.AddSource(fairmix) } return nil From e5af7d1c65c6f8c450b113af40cf7ac8b92448ac Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Fri, 15 Aug 2025 13:45:30 +0200 Subject: [PATCH 2/2] eth: reduce parallel lookups to 2 Signed-off-by: Csaba Kiraly --- eth/backend.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 5b57e2718717..b648c537ad06 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -77,8 +77,10 @@ const ( // sources (disc/v4 and disc/v5). We set this number large enough to be able to // feed the dial queue with enough peers. Since the whole discovery process is triggered // only when dial candidates are needed, we can keep this number high without worrying - // about overloading the DHT. - discoveryParallelLookups = 3 + // about overloading the DHT. Only caveat is that in a small network, where maxpeers is + // higher than the actual number of nodes, this may lead to continuous lookups. We don't + // yet have a self-tuning solution for this, so we keep the value at 2. + discoveryParallelLookups = 2 // discoveryPrefetchBuffer is the number of peers to pre-fetch from a discovery // source. It is useful to avoid the negative effects of potential longer timeouts