diff --git a/discv5/crawler.go b/discv5/crawler.go index 56e35a9..f6e5b87 100644 --- a/discv5/crawler.go +++ b/discv5/crawler.go @@ -13,7 +13,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/p2p/host/basic" + basichost "github.com/libp2p/go-libp2p/p2p/host/basic" ma "github.com/multiformats/go-multiaddr" log "github.com/sirupsen/logrus" "go.uber.org/atomic" @@ -25,6 +25,8 @@ import ( "github.com/dennis-tra/nebula-crawler/discvx" ) +const MaxCrawlRetriesAfterTimeout = 2 // magic + type CrawlerConfig struct { DialTimeout time.Duration AddrDialType config.AddrType @@ -464,14 +466,14 @@ func (c *Crawler) crawlDiscV5(ctx context.Context, pi PeerInfo) chan DiscV5Resul // internally, so we won't gain much by spawning multiple parallel go // routines here. Stop the process as soon as we have received a timeout and // don't let the following calls time out as well. - for i := 0; i <= discvx.NBuckets; i++ { // 15 is maximum + for i := 0; i <= discvx.NBuckets; i++ { // 17 is maximum var neighbors []*enode.Node neighbors, err = c.listener.FindNode(pi.Node, []uint{uint(discvx.HashBits - i)}) if err != nil { if errors.Is(err, discvx.ErrTimeout) { timeouts += 1 - if timeouts < 2 { + if timeouts < MaxCrawlRetriesAfterTimeout { continue } } @@ -480,6 +482,7 @@ func (c *Crawler) crawlDiscV5(ctx context.Context, pi PeerInfo) chan DiscV5Resul err = fmt.Errorf("getting closest peer with CPL %d: %w", i, err) break } + timeouts = 0 if result.RespondedAt == nil { now := time.Now() @@ -510,6 +513,13 @@ func (c *Crawler) crawlDiscV5(ctx context.Context, pi PeerInfo) chan DiscV5Resul result.RoutingTable.Neighbors = append(result.RoutingTable.Neighbors, n) } + // if we have at least a successful result, delete error + // bitwise operation checks whether errorBits is a power of 2 minus 1, + // if not, then there was at least one successful result + if result.Error != nil && (result.RoutingTable.ErrorBits&(result.RoutingTable.ErrorBits+1)) == 0 { + result.Error = nil + } + // if there was a connection error, parse it to a known one if result.Error != nil { result.ErrorStr = db.NetError(result.Error)