From 1098aef26a2018853dfd6d217ab7f950f9fab379 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 18 Oct 2019 12:18:26 +0200 Subject: [PATCH] cmd/devp2p: improve crawl timestamp handling --- cmd/devp2p/crawl.go | 28 +++++++++++++++------------- cmd/devp2p/nodeset.go | 18 ++++++++++++------ cmd/devp2p/nodesetcmd.go | 2 +- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/cmd/devp2p/crawl.go b/cmd/devp2p/crawl.go index ae14425503..27755f0d00 100644 --- a/cmd/devp2p/crawl.go +++ b/cmd/devp2p/crawl.go @@ -111,38 +111,40 @@ func (c *crawler) runIterator(done chan<- enode.Iterator, it enode.Iterator) { } func (c *crawler) updateNode(n *enode.Node) { - existing, ok := c.output[n.ID()] + node, ok := c.output[n.ID()] // Skip validation of recently-seen nodes. - if ok && time.Since(existing.LastSeen) < c.revalidateInterval { + if ok && time.Since(node.LastCheck) < c.revalidateInterval { return } // Request the node record. nn, err := c.disc.RequestENR(n) + node.LastCheck = truncNow() if err != nil { - if existing.Checks == 0 { + if node.Score == 0 { + // Node doesn't implement EIP-868. log.Debug("Skipping node", "id", n.ID()) return } - existing.Checks /= 2 + node.Score /= 2 } else { - if !ok { - existing.FirstSeen = truncNow() + node.N = nn + node.Seq = nn.Seq() + node.Score++ + if node.FirstResponse.IsZero() { + node.FirstResponse = node.LastCheck } - existing.N = nn - existing.Seq = nn.Seq() - existing.LastSeen = truncNow() - existing.Checks++ + node.LastResponse = node.LastCheck } // Store/update node in output set. - if existing.Checks <= 0 { + if node.Score <= 0 { log.Info("Removing node", "id", n.ID()) delete(c.output, n.ID()) } else { - log.Info("Updating node", "id", n.ID(), "seq", existing.Seq, "checks", existing.Checks) - c.output[n.ID()] = existing + log.Info("Updating node", "id", n.ID(), "seq", n.Seq(), "score", node.Score) + c.output[n.ID()] = node } } diff --git a/cmd/devp2p/nodeset.go b/cmd/devp2p/nodeset.go index 94177c53eb..2d86c3f65a 100644 --- a/cmd/devp2p/nodeset.go +++ b/cmd/devp2p/nodeset.go @@ -36,11 +36,17 @@ const jsonIndent = " " type nodeSet map[enode.ID]nodeJSON type nodeJSON struct { - Seq uint64 `json:"seq"` - N *enode.Node `json:"record"` - FirstSeen time.Time `json:"firstSeen,omitempty"` - LastSeen time.Time `json:"lastSeen,omitempty"` - Checks int `json:"checks"` + Seq uint64 `json:"seq"` + N *enode.Node `json:"record"` + + // The score tracks how many liveness checks were performed. It is incremented by one + // every time the node passes a check, and halved every time it doesn't. + Score int `json:"score,omitempty"` + // These two track the time of last successful contact. + FirstResponse time.Time `json:"firstResponse,omitempty"` + LastResponse time.Time `json:"lastResponse,omitempty"` + // This one tracks the time of our last attempt to contact the node. + LastCheck time.Time `json:"lastCheck,omitempty"` } func loadNodesJSON(file string) nodeSet { @@ -79,7 +85,7 @@ func (ns nodeSet) nodes() []*enode.Node { func (ns nodeSet) add(nodes ...*enode.Node) { for _, n := range nodes { - ns[n.ID()] = nodeJSON{Seq: n.Seq(), N: n, FirstSeen: truncNow()} + ns[n.ID()] = nodeJSON{Seq: n.Seq(), N: n} } } diff --git a/cmd/devp2p/nodesetcmd.go b/cmd/devp2p/nodesetcmd.go index 5fc065946b..802cedf086 100644 --- a/cmd/devp2p/nodesetcmd.go +++ b/cmd/devp2p/nodesetcmd.go @@ -148,7 +148,7 @@ func minAgeFilter(args []string) (nodeFilter, error) { return nil, err } f := func(n nodeJSON) bool { - age := n.LastSeen.Sub(n.FirstSeen) + age := n.LastResponse.Sub(n.FirstResponse) return age >= minage } return f, nil