p2p/discover: add initial discovery v5 implementation (#20750)

This adds an implementation of the current discovery v5 spec.

There is full integration with cmd/devp2p and enode.Iterator in this
version. In theory we could enable the new protocol as a replacement of
discovery v4 at any time. In practice, there will likely be a few more
changes to the spec and implementation before this can happen.
This commit is contained in:
Felix Lange
2020-04-08 09:57:23 +02:00
committed by GitHub
parent 671f22be38
commit b7394d7942
19 changed files with 2976 additions and 80 deletions

View File

@ -24,7 +24,6 @@ import (
"fmt"
"math/rand"
"net"
"reflect"
"sort"
"sync"
@ -56,6 +55,23 @@ func nodeAtDistance(base enode.ID, ld int, ip net.IP) *node {
return wrapNode(enode.SignNull(&r, idAtDistance(base, ld)))
}
// nodesAtDistance creates n nodes for which enode.LogDist(base, node.ID()) == ld.
func nodesAtDistance(base enode.ID, ld int, n int) []*enode.Node {
results := make([]*enode.Node, n)
for i := range results {
results[i] = unwrapNode(nodeAtDistance(base, ld, intIP(i)))
}
return results
}
func nodesToRecords(nodes []*enode.Node) []*enr.Record {
records := make([]*enr.Record, len(nodes))
for i := range nodes {
records[i] = nodes[i].Record()
}
return records
}
// idAtDistance returns a random hash such that enode.LogDist(a, b) == n
func idAtDistance(a enode.ID, n int) (b enode.ID) {
if n == 0 {
@ -173,9 +189,16 @@ func hasDuplicates(slice []*node) bool {
}
func checkNodesEqual(got, want []*enode.Node) error {
if reflect.DeepEqual(got, want) {
return nil
if len(got) == len(want) {
for i := range got {
if !nodeEqual(got[i], want[i]) {
goto NotEqual
}
return nil
}
}
NotEqual:
output := new(bytes.Buffer)
fmt.Fprintf(output, "got %d nodes:\n", len(got))
for _, n := range got {
@ -188,6 +211,10 @@ func checkNodesEqual(got, want []*enode.Node) error {
return errors.New(output.String())
}
func nodeEqual(n1 *enode.Node, n2 *enode.Node) bool {
return n1.ID() == n2.ID() && n1.IP().Equal(n2.IP())
}
func sortByID(nodes []*enode.Node) {
sort.Slice(nodes, func(i, j int) bool {
return string(nodes[i].ID().Bytes()) < string(nodes[j].ID().Bytes())