mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
p2p/discover: WIP node refactoring
This commit is contained in:
parent
cc22e0cdf0
commit
b168d82446
10 changed files with 182 additions and 177 deletions
|
|
@ -29,16 +29,16 @@ import (
|
|||
// not need to be an actual node identifier.
|
||||
type lookup struct {
|
||||
tab *Table
|
||||
queryfunc func(*node) ([]*node, error)
|
||||
replyCh chan []*node
|
||||
queryfunc queryFunc
|
||||
replyCh chan []*enode.Node
|
||||
cancelCh <-chan struct{}
|
||||
asked, seen map[enode.ID]bool
|
||||
result nodesByDistance
|
||||
replyBuffer []*node
|
||||
replyBuffer []*enode.Node
|
||||
queries int
|
||||
}
|
||||
|
||||
type queryFunc func(*node) ([]*node, error)
|
||||
type queryFunc func(*enode.Node) ([]*enode.Node, error)
|
||||
|
||||
func newLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *lookup {
|
||||
it := &lookup{
|
||||
|
|
@ -47,7 +47,7 @@ func newLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *l
|
|||
asked: make(map[enode.ID]bool),
|
||||
seen: make(map[enode.ID]bool),
|
||||
result: nodesByDistance{target: target},
|
||||
replyCh: make(chan []*node, alpha),
|
||||
replyCh: make(chan []*enode.Node, alpha),
|
||||
cancelCh: ctx.Done(),
|
||||
queries: -1,
|
||||
}
|
||||
|
|
@ -61,7 +61,7 @@ func newLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *l
|
|||
func (it *lookup) run() []*enode.Node {
|
||||
for it.advance() {
|
||||
}
|
||||
return unwrapNodes(it.result.entries)
|
||||
return it.result.entries
|
||||
}
|
||||
|
||||
// advance advances the lookup until any new nodes have been found.
|
||||
|
|
@ -139,7 +139,7 @@ func (it *lookup) slowdown() {
|
|||
}
|
||||
}
|
||||
|
||||
func (it *lookup) query(n *node, reply chan<- []*node) {
|
||||
func (it *lookup) query(n *enode.Node, reply chan<- []*enode.Node) {
|
||||
r, err := it.queryfunc(n)
|
||||
if !errors.Is(err, errClosed) { // avoid recording failures on shutdown.
|
||||
success := len(r) > 0
|
||||
|
|
@ -154,7 +154,7 @@ func (it *lookup) query(n *node, reply chan<- []*node) {
|
|||
// lookupIterator performs lookup operations and iterates over all seen nodes.
|
||||
// When a lookup finishes, a new one is created through nextLookup.
|
||||
type lookupIterator struct {
|
||||
buffer []*node
|
||||
buffer []*enode.Node
|
||||
nextLookup lookupFunc
|
||||
ctx context.Context
|
||||
cancel func()
|
||||
|
|
@ -173,7 +173,7 @@ func (it *lookupIterator) Node() *enode.Node {
|
|||
if len(it.buffer) == 0 {
|
||||
return nil
|
||||
}
|
||||
return unwrapNode(it.buffer[0])
|
||||
return it.buffer[0]
|
||||
}
|
||||
|
||||
// Next moves to the next node.
|
||||
|
|
|
|||
|
|
@ -37,8 +37,7 @@ type BucketNode struct {
|
|||
Live bool `json:"live"`
|
||||
}
|
||||
|
||||
// node represents a host on the network.
|
||||
// The fields of Node may not be modified.
|
||||
// node is a node table entry.
|
||||
type node struct {
|
||||
*enode.Node
|
||||
revalList *revalidationList
|
||||
|
|
@ -75,26 +74,10 @@ func (e encPubkey) id() enode.ID {
|
|||
return enode.ID(crypto.Keccak256Hash(e[:]))
|
||||
}
|
||||
|
||||
func wrapNode(n *enode.Node) *node {
|
||||
return &node{Node: n}
|
||||
}
|
||||
|
||||
func wrapNodes(ns []*enode.Node) []*node {
|
||||
result := make([]*node, len(ns))
|
||||
for i, n := range ns {
|
||||
result[i] = wrapNode(n)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func unwrapNode(n *node) *enode.Node {
|
||||
return n.Node
|
||||
}
|
||||
|
||||
func unwrapNodes(ns []*node) []*enode.Node {
|
||||
result := make([]*enode.Node, len(ns))
|
||||
for i, n := range ns {
|
||||
result[i] = unwrapNode(n)
|
||||
result[i] = n.Node
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ const (
|
|||
type Table struct {
|
||||
mutex sync.Mutex // protects buckets, bucket content, nursery, rand
|
||||
buckets [nBuckets]*bucket // index of known nodes by distance
|
||||
nursery []*node // bootstrap nodes
|
||||
nursery []*enode.Node // bootstrap nodes
|
||||
rand reseedingRandom // source of randomness, periodically reseeded
|
||||
ips netutil.DistinctNetSet
|
||||
revalidation tableRevalidation
|
||||
|
|
@ -108,13 +108,14 @@ type bucket struct {
|
|||
}
|
||||
|
||||
type addNodeOp struct {
|
||||
node *node
|
||||
node *enode.Node
|
||||
isInbound bool
|
||||
forceSetLive bool // for tests
|
||||
}
|
||||
|
||||
type trackRequestOp struct {
|
||||
node *node
|
||||
foundNodes []*node
|
||||
node *enode.Node
|
||||
foundNodes []*enode.Node
|
||||
success bool
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +187,7 @@ func (tab *Table) getNode(id enode.ID) *enode.Node {
|
|||
b := tab.bucket(id)
|
||||
for _, e := range b.entries {
|
||||
if e.ID() == id {
|
||||
return unwrapNode(e)
|
||||
return e.Node
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
@ -202,7 +203,7 @@ func (tab *Table) close() {
|
|||
// are used to connect to the network if the table is empty and there
|
||||
// are no known nodes in the database.
|
||||
func (tab *Table) setFallbackNodes(nodes []*enode.Node) error {
|
||||
nursery := make([]*node, 0, len(nodes))
|
||||
nursery := make([]*enode.Node, 0, len(nodes))
|
||||
for _, n := range nodes {
|
||||
if err := n.ValidateComplete(); err != nil {
|
||||
return fmt.Errorf("bad bootstrap node %q: %v", n, err)
|
||||
|
|
@ -211,7 +212,7 @@ func (tab *Table) setFallbackNodes(nodes []*enode.Node) error {
|
|||
tab.log.Error("Bootstrap node filtered by netrestrict", "id", n.ID(), "ip", n.IP())
|
||||
continue
|
||||
}
|
||||
nursery = append(nursery, wrapNode(n))
|
||||
nursery = append(nursery, n)
|
||||
}
|
||||
tab.nursery = nursery
|
||||
return nil
|
||||
|
|
@ -255,9 +256,9 @@ func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) *
|
|||
liveNodes := &nodesByDistance{target: target}
|
||||
for _, b := range &tab.buckets {
|
||||
for _, n := range b.entries {
|
||||
nodes.push(n, nresults)
|
||||
nodes.push(n.Node, nresults)
|
||||
if preferLive && n.isValidatedLive {
|
||||
liveNodes.push(n, nresults)
|
||||
liveNodes.push(n.Node, nresults)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -309,8 +310,8 @@ func (tab *Table) len() (n int) {
|
|||
// list.
|
||||
//
|
||||
// The caller must not hold tab.mutex.
|
||||
func (tab *Table) addFoundNode(n *node) bool {
|
||||
op := addNodeOp{node: n, isInbound: false}
|
||||
func (tab *Table) addFoundNode(n *enode.Node, forceSetLive bool) bool {
|
||||
op := addNodeOp{node: n, isInbound: false, forceSetLive: forceSetLive}
|
||||
select {
|
||||
case tab.addNodeCh <- op:
|
||||
return <-tab.addNodeHandled
|
||||
|
|
@ -327,7 +328,7 @@ func (tab *Table) addFoundNode(n *node) bool {
|
|||
// repeatedly.
|
||||
//
|
||||
// The caller must not hold tab.mutex.
|
||||
func (tab *Table) addInboundNode(n *node) bool {
|
||||
func (tab *Table) addInboundNode(n *enode.Node) bool {
|
||||
op := addNodeOp{node: n, isInbound: true}
|
||||
select {
|
||||
case tab.addNodeCh <- op:
|
||||
|
|
@ -337,7 +338,7 @@ func (tab *Table) addInboundNode(n *node) bool {
|
|||
}
|
||||
}
|
||||
|
||||
func (tab *Table) trackRequest(n *node, success bool, foundNodes []*node) {
|
||||
func (tab *Table) trackRequest(n *enode.Node, success bool, foundNodes []*enode.Node) {
|
||||
op := trackRequestOp{n, foundNodes, success}
|
||||
select {
|
||||
case tab.trackRequestCh <- op:
|
||||
|
|
@ -443,13 +444,14 @@ func (tab *Table) doRefresh(done chan struct{}) {
|
|||
}
|
||||
|
||||
func (tab *Table) loadSeedNodes() {
|
||||
seeds := wrapNodes(tab.db.QuerySeeds(seedCount, seedMaxAge))
|
||||
seeds := tab.db.QuerySeeds(seedCount, seedMaxAge)
|
||||
seeds = append(seeds, tab.nursery...)
|
||||
for i := range seeds {
|
||||
seed := seeds[i]
|
||||
if tab.log.Enabled(context.Background(), log.LevelTrace) {
|
||||
age := time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP()))
|
||||
tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age)
|
||||
addr, _ := seed.UDPEndpoint()
|
||||
tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", addr, "age", age)
|
||||
}
|
||||
tab.handleAddNode(addNodeOp{node: seed, isInbound: false})
|
||||
}
|
||||
|
|
@ -513,7 +515,7 @@ func (tab *Table) handleAddNode(req addNodeOp) bool {
|
|||
}
|
||||
|
||||
b := tab.bucket(req.node.ID())
|
||||
n, _ := tab.bumpInBucket(b, req.node.Node, req.isInbound)
|
||||
n, _ := tab.bumpInBucket(b, req.node, req.isInbound)
|
||||
if n != nil {
|
||||
// Already in bucket.
|
||||
return false
|
||||
|
|
@ -529,15 +531,20 @@ func (tab *Table) handleAddNode(req addNodeOp) bool {
|
|||
}
|
||||
|
||||
// Add to bucket.
|
||||
b.entries = append(b.entries, req.node)
|
||||
b.replacements = deleteNode(b.replacements, req.node)
|
||||
tab.nodeAdded(b, req.node)
|
||||
wn := &node{Node: req.node}
|
||||
if req.forceSetLive {
|
||||
wn.livenessChecks = 1
|
||||
wn.isValidatedLive = true
|
||||
}
|
||||
b.entries = append(b.entries, wn)
|
||||
b.replacements = deleteNode(b.replacements, wn.ID())
|
||||
tab.nodeAdded(b, wn)
|
||||
return true
|
||||
}
|
||||
|
||||
// addReplacement adds n to the replacement cache of bucket b.
|
||||
func (tab *Table) addReplacement(b *bucket, n *node) {
|
||||
if contains(b.replacements, n.ID()) {
|
||||
func (tab *Table) addReplacement(b *bucket, n *enode.Node) {
|
||||
if containsID(b.replacements, n.ID()) {
|
||||
// TODO: update ENR
|
||||
return
|
||||
}
|
||||
|
|
@ -545,9 +552,9 @@ func (tab *Table) addReplacement(b *bucket, n *node) {
|
|||
return
|
||||
}
|
||||
|
||||
n.addedToTable = time.Now()
|
||||
wn := &node{Node: n, addedToTable: time.Now()}
|
||||
var removed *node
|
||||
b.replacements, removed = pushNode(b.replacements, n, maxReplacements)
|
||||
b.replacements, removed = pushNode(b.replacements, wn, maxReplacements)
|
||||
if removed != nil {
|
||||
tab.removeIP(b, removed.IP())
|
||||
}
|
||||
|
|
@ -672,11 +679,15 @@ func (tab *Table) handleTrackRequest(op trackRequestOp) {
|
|||
|
||||
// Add found nodes.
|
||||
for _, n := range op.foundNodes {
|
||||
tab.handleAddNode(addNodeOp{n, false})
|
||||
tab.handleAddNode(addNodeOp{n, false, false})
|
||||
}
|
||||
}
|
||||
|
||||
func contains(ns []*node, id enode.ID) bool {
|
||||
type nodeType interface {
|
||||
ID() enode.ID
|
||||
}
|
||||
|
||||
func containsID[N nodeType](ns []N, id enode.ID) bool {
|
||||
for _, n := range ns {
|
||||
if n.ID() == id {
|
||||
return true
|
||||
|
|
@ -697,23 +708,20 @@ func pushNode(list []*node, n *node, max int) ([]*node, *node) {
|
|||
}
|
||||
|
||||
// deleteNode removes n from list.
|
||||
func deleteNode(list []*node, n *node) []*node {
|
||||
for i := range list {
|
||||
if list[i].ID() == n.ID() {
|
||||
return append(list[:i], list[i+1:]...)
|
||||
}
|
||||
}
|
||||
return list
|
||||
func deleteNode[N nodeType](list []N, id enode.ID) []N {
|
||||
return slices.DeleteFunc(list, func(n N) bool {
|
||||
return n.ID() == id
|
||||
})
|
||||
}
|
||||
|
||||
// nodesByDistance is a list of nodes, ordered by distance to target.
|
||||
type nodesByDistance struct {
|
||||
entries []*node
|
||||
entries []*enode.Node
|
||||
target enode.ID
|
||||
}
|
||||
|
||||
// push adds the given node to the list, keeping the total size below maxElems.
|
||||
func (h *nodesByDistance) push(n *node, maxElems int) {
|
||||
func (h *nodesByDistance) push(n *enode.Node, maxElems int) {
|
||||
ix := sort.Search(len(h.entries), func(i int) bool {
|
||||
return enode.DistCmp(h.target, h.entries[i].ID(), n.ID()) > 0
|
||||
})
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"math/rand"
|
||||
"net"
|
||||
"reflect"
|
||||
"slices"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
"time"
|
||||
|
|
@ -64,7 +65,7 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding
|
|||
|
||||
// Fill up the sender's bucket.
|
||||
replacementNodeKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")
|
||||
replacementNode := wrapNode(enode.NewV4(&replacementNodeKey.PublicKey, net.IP{127, 0, 0, 1}, 99, 99))
|
||||
replacementNode := enode.NewV4(&replacementNodeKey.PublicKey, net.IP{127, 0, 0, 1}, 99, 99)
|
||||
last := fillBucket(tab, replacementNode.ID())
|
||||
tab.mutex.Lock()
|
||||
nodeEvents := newNodeEventRecorder(128)
|
||||
|
|
@ -78,7 +79,7 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding
|
|||
transport.dead[replacementNode.ID()] = !newNodeIsResponding
|
||||
|
||||
// Add replacement node to table.
|
||||
tab.addFoundNode(replacementNode)
|
||||
tab.addFoundNode(replacementNode, false)
|
||||
|
||||
t.Log("last:", last.ID())
|
||||
t.Log("replacement:", replacementNode.ID())
|
||||
|
|
@ -115,11 +116,11 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding
|
|||
if l := len(bucket.entries); l != wantSize {
|
||||
t.Errorf("wrong bucket size after revalidation: got %d, want %d", l, wantSize)
|
||||
}
|
||||
if ok := contains(bucket.entries, last.ID()); ok != lastInBucketIsResponding {
|
||||
if ok := containsID(bucket.entries, last.ID()); ok != lastInBucketIsResponding {
|
||||
t.Errorf("revalidated node found: %t, want: %t", ok, lastInBucketIsResponding)
|
||||
}
|
||||
wantNewEntry := newNodeIsResponding && !lastInBucketIsResponding
|
||||
if ok := contains(bucket.entries, replacementNode.ID()); ok != wantNewEntry {
|
||||
if ok := containsID(bucket.entries, replacementNode.ID()); ok != wantNewEntry {
|
||||
t.Errorf("replacement node found: %t, want: %t", ok, wantNewEntry)
|
||||
}
|
||||
}
|
||||
|
|
@ -153,7 +154,7 @@ func TestTable_IPLimit(t *testing.T) {
|
|||
|
||||
for i := 0; i < tableIPLimit+1; i++ {
|
||||
n := nodeAtDistance(tab.self().ID(), i, net.IP{172, 0, 1, byte(i)})
|
||||
tab.addFoundNode(n)
|
||||
tab.addFoundNode(n, false)
|
||||
}
|
||||
if tab.len() > tableIPLimit {
|
||||
t.Errorf("too many nodes in table")
|
||||
|
|
@ -171,7 +172,7 @@ func TestTable_BucketIPLimit(t *testing.T) {
|
|||
d := 3
|
||||
for i := 0; i < bucketIPLimit+1; i++ {
|
||||
n := nodeAtDistance(tab.self().ID(), d, net.IP{172, 0, 1, byte(i)})
|
||||
tab.addFoundNode(n)
|
||||
tab.addFoundNode(n, false)
|
||||
}
|
||||
if tab.len() > bucketIPLimit {
|
||||
t.Errorf("too many nodes in table")
|
||||
|
|
@ -232,7 +233,7 @@ func TestTable_findnodeByID(t *testing.T) {
|
|||
// check that the result nodes have minimum distance to target.
|
||||
for _, b := range tab.buckets {
|
||||
for _, n := range b.entries {
|
||||
if contains(result, n.ID()) {
|
||||
if containsID(result, n.ID()) {
|
||||
continue // don't run the check below for nodes in result
|
||||
}
|
||||
farthestResult := result[len(result)-1].ID()
|
||||
|
|
@ -255,7 +256,7 @@ func TestTable_findnodeByID(t *testing.T) {
|
|||
type closeTest struct {
|
||||
Self enode.ID
|
||||
Target enode.ID
|
||||
All []*node
|
||||
All []*enode.Node
|
||||
N int
|
||||
}
|
||||
|
||||
|
|
@ -268,8 +269,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value {
|
|||
for _, id := range gen([]enode.ID{}, rand).([]enode.ID) {
|
||||
r := new(enr.Record)
|
||||
r.Set(enr.IP(genIP(rand)))
|
||||
n := wrapNode(enode.SignNull(r, id))
|
||||
n.livenessChecks = 1
|
||||
n := enode.SignNull(r, id)
|
||||
t.All = append(t.All, n)
|
||||
}
|
||||
return reflect.ValueOf(t)
|
||||
|
|
@ -284,16 +284,16 @@ func TestTable_addInboundNode(t *testing.T) {
|
|||
// Insert two nodes.
|
||||
n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1})
|
||||
n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2})
|
||||
tab.addFoundNode(n1)
|
||||
tab.addFoundNode(n2)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1.Node, n2.Node})
|
||||
tab.addFoundNode(n1, false)
|
||||
tab.addFoundNode(n2, false)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1, n2})
|
||||
|
||||
// Add a changed version of n2. The bucket should be updated.
|
||||
newrec := n2.Record()
|
||||
newrec.Set(enr.IP{99, 99, 99, 99})
|
||||
n2v2 := enode.SignNull(newrec, n2.ID())
|
||||
tab.addInboundNode(wrapNode(n2v2))
|
||||
checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2})
|
||||
tab.addInboundNode(n2v2)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1, n2v2})
|
||||
|
||||
// Try updating n2 without sequence number change. The update is accepted
|
||||
// because it's inbound.
|
||||
|
|
@ -301,8 +301,8 @@ func TestTable_addInboundNode(t *testing.T) {
|
|||
newrec.Set(enr.IP{100, 100, 100, 100})
|
||||
newrec.SetSeq(n2.Seq())
|
||||
n2v3 := enode.SignNull(newrec, n2.ID())
|
||||
tab.addInboundNode(wrapNode(n2v3))
|
||||
checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v3})
|
||||
tab.addInboundNode(n2v3)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1, n2v3})
|
||||
}
|
||||
|
||||
func TestTable_addFoundNode(t *testing.T) {
|
||||
|
|
@ -314,16 +314,16 @@ func TestTable_addFoundNode(t *testing.T) {
|
|||
// Insert two nodes.
|
||||
n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1})
|
||||
n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2})
|
||||
tab.addFoundNode(n1)
|
||||
tab.addFoundNode(n2)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1.Node, n2.Node})
|
||||
tab.addFoundNode(n1, false)
|
||||
tab.addFoundNode(n2, false)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1, n2})
|
||||
|
||||
// Add a changed version of n2. The bucket should be updated.
|
||||
newrec := n2.Record()
|
||||
newrec.Set(enr.IP{99, 99, 99, 99})
|
||||
n2v2 := enode.SignNull(newrec, n2.ID())
|
||||
tab.addFoundNode(wrapNode(n2v2))
|
||||
checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2})
|
||||
tab.addFoundNode(n2v2, false)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1, n2v2})
|
||||
|
||||
// Try updating n2 without a sequence number change.
|
||||
// The update should not be accepted.
|
||||
|
|
@ -331,8 +331,8 @@ func TestTable_addFoundNode(t *testing.T) {
|
|||
newrec.Set(enr.IP{100, 100, 100, 100})
|
||||
newrec.SetSeq(n2.Seq())
|
||||
n2v3 := enode.SignNull(newrec, n2.ID())
|
||||
tab.addFoundNode(wrapNode(n2v3))
|
||||
checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2})
|
||||
tab.addFoundNode(n2v3, false)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1, n2v2})
|
||||
}
|
||||
|
||||
// This test checks that discv4 nodes can update their own endpoint via PING.
|
||||
|
|
@ -345,13 +345,13 @@ func TestTable_addInboundNodeUpdateV4Accept(t *testing.T) {
|
|||
// Add a v4 node.
|
||||
key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3")
|
||||
n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000)
|
||||
tab.addInboundNode(wrapNode(n1))
|
||||
tab.addInboundNode(n1)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1})
|
||||
|
||||
// Add an updated version with changed IP.
|
||||
// The update will be accepted because it is inbound.
|
||||
n1v2 := enode.NewV4(&key.PublicKey, net.IP{99, 99, 99, 99}, 9000, 9000)
|
||||
tab.addInboundNode(wrapNode(n1v2))
|
||||
tab.addInboundNode(n1v2)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1v2})
|
||||
}
|
||||
|
||||
|
|
@ -366,13 +366,13 @@ func TestTable_addFoundNodeV4UpdateReject(t *testing.T) {
|
|||
// Add a v4 node.
|
||||
key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3")
|
||||
n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000)
|
||||
tab.addFoundNode(wrapNode(n1))
|
||||
tab.addFoundNode(n1, false)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1})
|
||||
|
||||
// Add an updated version with changed IP.
|
||||
// The update won't be accepted because it isn't inbound.
|
||||
n1v2 := enode.NewV4(&key.PublicKey, net.IP{99, 99, 99, 99}, 9000, 9000)
|
||||
tab.addFoundNode(wrapNode(n1v2))
|
||||
tab.addFoundNode(n1v2, false)
|
||||
checkBucketContent(t, tab, []*enode.Node{n1})
|
||||
}
|
||||
|
||||
|
|
@ -413,8 +413,8 @@ func TestTable_revalidateSyncRecord(t *testing.T) {
|
|||
var r enr.Record
|
||||
r.Set(enr.IP(net.IP{127, 0, 0, 1}))
|
||||
id := enode.ID{1}
|
||||
n1 := wrapNode(enode.SignNull(&r, id))
|
||||
tab.addFoundNode(n1)
|
||||
n1 := enode.SignNull(&r, id)
|
||||
tab.addFoundNode(n1, false)
|
||||
|
||||
// Update the node record.
|
||||
r.Set(enr.WithEntry("foo", "bar"))
|
||||
|
|
@ -437,7 +437,7 @@ func TestNodesPush(t *testing.T) {
|
|||
n1 := nodeAtDistance(target, 255, intIP(1))
|
||||
n2 := nodeAtDistance(target, 254, intIP(2))
|
||||
n3 := nodeAtDistance(target, 253, intIP(3))
|
||||
perm := [][]*node{
|
||||
perm := [][]*enode.Node{
|
||||
{n3, n2, n1},
|
||||
{n3, n1, n2},
|
||||
{n2, n3, n1},
|
||||
|
|
@ -452,7 +452,7 @@ func TestNodesPush(t *testing.T) {
|
|||
for _, n := range nodes {
|
||||
list.push(n, 3)
|
||||
}
|
||||
if !slicesEqual(list.entries, perm[0], nodeIDEqual) {
|
||||
if !slices.EqualFunc(list.entries, perm[0], nodeIDEqual) {
|
||||
t.Fatal("not equal")
|
||||
}
|
||||
}
|
||||
|
|
@ -463,13 +463,13 @@ func TestNodesPush(t *testing.T) {
|
|||
for _, n := range nodes {
|
||||
list.push(n, 2)
|
||||
}
|
||||
if !slicesEqual(list.entries, perm[0][:2], nodeIDEqual) {
|
||||
if !slices.EqualFunc(list.entries, perm[0][:2], nodeIDEqual) {
|
||||
t.Fatal("not equal")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func nodeIDEqual(n1, n2 *node) bool {
|
||||
func nodeIDEqual[N nodeType](n1, n2 N) bool {
|
||||
return n1.ID() == n2.ID()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,18 +56,18 @@ func newInactiveTestTable(t transport, cfg Config) (*Table, *enode.DB) {
|
|||
}
|
||||
|
||||
// nodeAtDistance creates a node for which enode.LogDist(base, n.id) == ld.
|
||||
func nodeAtDistance(base enode.ID, ld int, ip net.IP) *node {
|
||||
func nodeAtDistance(base enode.ID, ld int, ip net.IP) *enode.Node {
|
||||
var r enr.Record
|
||||
r.Set(enr.IP(ip))
|
||||
r.Set(enr.UDP(30303))
|
||||
return wrapNode(enode.SignNull(&r, idAtDistance(base, ld)))
|
||||
return 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)))
|
||||
results[i] = nodeAtDistance(base, ld, intIP(i))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
|
@ -110,7 +110,7 @@ func fillBucket(tab *Table, id enode.ID) (last *node) {
|
|||
b := tab.bucket(id)
|
||||
for len(b.entries) < bucketSize {
|
||||
node := nodeAtDistance(tab.self().ID(), ld, intIP(ld))
|
||||
if !tab.addFoundNode(node) {
|
||||
if !tab.addFoundNode(node, false) {
|
||||
panic("node not added")
|
||||
}
|
||||
}
|
||||
|
|
@ -119,13 +119,11 @@ func fillBucket(tab *Table, id enode.ID) (last *node) {
|
|||
|
||||
// fillTable adds nodes the table to the end of their corresponding bucket
|
||||
// if the bucket is not full. The caller must not hold tab.mutex.
|
||||
func fillTable(tab *Table, nodes []*node, setLive bool) {
|
||||
func fillTable(tab *Table, nodes []*enode.Node, setLive bool) {
|
||||
for _, n := range nodes {
|
||||
if setLive {
|
||||
n.livenessChecks = 1
|
||||
n.isValidatedLive = true
|
||||
}
|
||||
tab.addFoundNode(n)
|
||||
tab.addFoundNode(n, setLive)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -219,7 +217,7 @@ func (t *pingRecorder) RequestENR(n *enode.Node) (*enode.Node, error) {
|
|||
return t.records[n.ID()], nil
|
||||
}
|
||||
|
||||
func hasDuplicates(slice []*node) bool {
|
||||
func hasDuplicates(slice []*enode.Node) bool {
|
||||
seen := make(map[enode.ID]bool, len(slice))
|
||||
for i, e := range slice {
|
||||
if e == nil {
|
||||
|
|
@ -261,14 +259,14 @@ func nodeEqual(n1 *enode.Node, n2 *enode.Node) bool {
|
|||
return n1.ID() == n2.ID() && n1.IP().Equal(n2.IP())
|
||||
}
|
||||
|
||||
func sortByID(nodes []*enode.Node) {
|
||||
slices.SortFunc(nodes, func(a, b *enode.Node) int {
|
||||
func sortByID[N nodeType](nodes []N) {
|
||||
slices.SortFunc(nodes, func(a, b N) int {
|
||||
return bytes.Compare(a.ID().Bytes(), b.ID().Bytes())
|
||||
})
|
||||
}
|
||||
|
||||
func sortedByDistanceTo(distbase enode.ID, slice []*node) bool {
|
||||
return slices.IsSortedFunc(slice, func(a, b *node) int {
|
||||
func sortedByDistanceTo(distbase enode.ID, slice []*enode.Node) bool {
|
||||
return slices.IsSortedFunc(slice, func(a, b *enode.Node) int {
|
||||
return enode.DistCmp(distbase, a.ID(), b.ID())
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ package discover
|
|||
import (
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ func TestUDPv4_Lookup(t *testing.T) {
|
|||
}
|
||||
|
||||
// Seed table with initial node.
|
||||
fillTable(test.table, []*node{wrapNode(lookupTestnet.node(256, 0))}, true)
|
||||
fillTable(test.table, []*enode.Node{lookupTestnet.node(256, 0)}, true)
|
||||
|
||||
// Start the lookup.
|
||||
resultC := make(chan []*enode.Node, 1)
|
||||
|
|
@ -70,9 +70,9 @@ func TestUDPv4_LookupIterator(t *testing.T) {
|
|||
defer test.close()
|
||||
|
||||
// Seed table with initial nodes.
|
||||
bootnodes := make([]*node, len(lookupTestnet.dists[256]))
|
||||
bootnodes := make([]*enode.Node, len(lookupTestnet.dists[256]))
|
||||
for i := range lookupTestnet.dists[256] {
|
||||
bootnodes[i] = wrapNode(lookupTestnet.node(256, i))
|
||||
bootnodes[i] = lookupTestnet.node(256, i)
|
||||
}
|
||||
fillTable(test.table, bootnodes, true)
|
||||
go serveTestnet(test, lookupTestnet)
|
||||
|
|
@ -105,9 +105,9 @@ func TestUDPv4_LookupIteratorClose(t *testing.T) {
|
|||
defer test.close()
|
||||
|
||||
// Seed table with initial nodes.
|
||||
bootnodes := make([]*node, len(lookupTestnet.dists[256]))
|
||||
bootnodes := make([]*enode.Node, len(lookupTestnet.dists[256]))
|
||||
for i := range lookupTestnet.dists[256] {
|
||||
bootnodes[i] = wrapNode(lookupTestnet.node(256, i))
|
||||
bootnodes[i] = lookupTestnet.node(256, i)
|
||||
}
|
||||
fillTable(test.table, bootnodes, true)
|
||||
go serveTestnet(test, lookupTestnet)
|
||||
|
|
@ -136,7 +136,7 @@ func TestUDPv4_LookupIteratorClose(t *testing.T) {
|
|||
|
||||
func serveTestnet(test *udpTest, testnet *preminedTestnet) {
|
||||
for done := false; !done; {
|
||||
done = test.waitPacketOut(func(p v4wire.Packet, to *net.UDPAddr, hash []byte) {
|
||||
done = test.waitPacketOut(func(p v4wire.Packet, to netip.AddrPort, hash []byte) {
|
||||
n, key := testnet.nodeByAddr(to)
|
||||
switch p.(type) {
|
||||
case *v4wire.Ping:
|
||||
|
|
@ -158,10 +158,10 @@ func checkLookupResults(t *testing.T, tn *preminedTestnet, results []*enode.Node
|
|||
for _, e := range results {
|
||||
t.Logf(" ld=%d, %x", enode.LogDist(tn.target.id(), e.ID()), e.ID().Bytes())
|
||||
}
|
||||
if hasDuplicates(wrapNodes(results)) {
|
||||
if hasDuplicates(results) {
|
||||
t.Errorf("result set contains duplicate entries")
|
||||
}
|
||||
if !sortedByDistanceTo(tn.target.id(), wrapNodes(results)) {
|
||||
if !sortedByDistanceTo(tn.target.id(), results) {
|
||||
t.Errorf("result set not sorted by distance to target")
|
||||
}
|
||||
wantNodes := tn.closest(len(results))
|
||||
|
|
@ -264,9 +264,10 @@ func (tn *preminedTestnet) node(dist, index int) *enode.Node {
|
|||
return n
|
||||
}
|
||||
|
||||
func (tn *preminedTestnet) nodeByAddr(addr *net.UDPAddr) (*enode.Node, *ecdsa.PrivateKey) {
|
||||
dist := int(addr.IP[1])<<8 + int(addr.IP[2])
|
||||
index := int(addr.IP[3])
|
||||
func (tn *preminedTestnet) nodeByAddr(addr netip.AddrPort) (*enode.Node, *ecdsa.PrivateKey) {
|
||||
ip := addr.Addr().As4()
|
||||
dist := int(ip[1])<<8 + int(ip[2])
|
||||
index := int(ip[3])
|
||||
key := tn.dists[dist][index]
|
||||
return tn.node(dist, index), key
|
||||
}
|
||||
|
|
@ -274,7 +275,7 @@ func (tn *preminedTestnet) nodeByAddr(addr *net.UDPAddr) (*enode.Node, *ecdsa.Pr
|
|||
func (tn *preminedTestnet) nodesAtDistance(dist int) []v4wire.Node {
|
||||
result := make([]v4wire.Node, len(tn.dists[dist]))
|
||||
for i := range result {
|
||||
result[i] = nodeToRPC(wrapNode(tn.node(dist, i)))
|
||||
result[i] = nodeToRPC(tn.node(dist, i))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -45,6 +46,7 @@ var (
|
|||
errClockWarp = errors.New("reply deadline too far in the future")
|
||||
errClosed = errors.New("socket closed")
|
||||
errLowPort = errors.New("low port")
|
||||
errNoUDPEndpoint = errors.New("node has no UDP endpoint")
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -290,20 +292,25 @@ func (t *UDPv4) newRandomLookup(ctx context.Context) *lookup {
|
|||
func (t *UDPv4) newLookup(ctx context.Context, targetKey encPubkey) *lookup {
|
||||
target := enode.ID(crypto.Keccak256Hash(targetKey[:]))
|
||||
ekey := v4wire.Pubkey(targetKey)
|
||||
it := newLookup(ctx, t.tab, target, func(n *node) ([]*node, error) {
|
||||
return t.findnode(n.ID(), n.addr(), ekey)
|
||||
it := newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) {
|
||||
addr, ok := n.UDPEndpoint()
|
||||
if !ok {
|
||||
return nil, errNoUDPEndpoint
|
||||
}
|
||||
return t.findnode(n.ID(), addr, ekey)
|
||||
})
|
||||
return it
|
||||
}
|
||||
|
||||
// findnode sends a findnode request to the given node and waits until
|
||||
// the node has sent up to k neighbors.
|
||||
func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target v4wire.Pubkey) ([]*node, error) {
|
||||
func (t *UDPv4) findnode(toid enode.ID, toAddrPort netip.AddrPort, target v4wire.Pubkey) ([]*enode.Node, error) {
|
||||
toaddr := &net.UDPAddr{IP: toAddrPort.Addr().AsSlice(), Port: int(toAddrPort.Port())}
|
||||
t.ensureBond(toid, toaddr)
|
||||
|
||||
// Add a matcher for 'neighbours' replies to the pending reply queue. The matcher is
|
||||
// active until enough nodes have been received.
|
||||
nodes := make([]*node, 0, bucketSize)
|
||||
nodes := make([]*enode.Node, 0, bucketSize)
|
||||
nreceived := 0
|
||||
rm := t.pending(toid, toaddr.IP, v4wire.NeighborsPacket, func(r v4wire.Packet) (matched bool, requestDone bool) {
|
||||
reply := r.(*v4wire.Neighbors)
|
||||
|
|
@ -579,7 +586,7 @@ func (t *UDPv4) ensureBond(toid enode.ID, toaddr *net.UDPAddr) {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *UDPv4) nodeFromRPC(sender *net.UDPAddr, rn v4wire.Node) (*node, error) {
|
||||
func (t *UDPv4) nodeFromRPC(sender *net.UDPAddr, rn v4wire.Node) (*enode.Node, error) {
|
||||
if rn.UDP <= 1024 {
|
||||
return nil, errLowPort
|
||||
}
|
||||
|
|
@ -593,12 +600,12 @@ func (t *UDPv4) nodeFromRPC(sender *net.UDPAddr, rn v4wire.Node) (*node, error)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n := wrapNode(enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP)))
|
||||
n := enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP))
|
||||
err = n.ValidateComplete()
|
||||
return n, err
|
||||
}
|
||||
|
||||
func nodeToRPC(n *node) v4wire.Node {
|
||||
func nodeToRPC(n *enode.Node) v4wire.Node {
|
||||
var key ecdsa.PublicKey
|
||||
var ekey v4wire.Pubkey
|
||||
if err := n.Load((*enode.Secp256k1)(&key)); err == nil {
|
||||
|
|
@ -670,7 +677,7 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I
|
|||
})
|
||||
|
||||
// Ping back if our last pong on file is too far in the past.
|
||||
n := wrapNode(enode.NewV4(h.senderKey, from.IP, int(req.From.TCP), from.Port))
|
||||
n := enode.NewV4(h.senderKey, from.IP, int(req.From.TCP), from.Port)
|
||||
if time.Since(t.db.LastPongReceived(n.ID(), from.IP)) > bondExpiration {
|
||||
t.sendPing(fromID, from, func() {
|
||||
t.tab.addInboundNode(n)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
|
|
@ -55,7 +56,7 @@ type udpTest struct {
|
|||
udp *UDPv4
|
||||
sent [][]byte
|
||||
localkey, remotekey *ecdsa.PrivateKey
|
||||
remoteaddr *net.UDPAddr
|
||||
remoteaddr netip.AddrPort
|
||||
}
|
||||
|
||||
func newUDPTest(t *testing.T) *udpTest {
|
||||
|
|
@ -64,7 +65,7 @@ func newUDPTest(t *testing.T) *udpTest {
|
|||
pipe: newpipe(),
|
||||
localkey: newkey(),
|
||||
remotekey: newkey(),
|
||||
remoteaddr: &net.UDPAddr{IP: net.IP{10, 0, 1, 99}, Port: 30303},
|
||||
remoteaddr: netip.AddrPortFrom(netip.MustParseAddr("10.0.1.99"), 30303),
|
||||
}
|
||||
|
||||
test.db, _ = enode.OpenDB("")
|
||||
|
|
@ -92,7 +93,7 @@ func (test *udpTest) packetIn(wantError error, data v4wire.Packet) {
|
|||
}
|
||||
|
||||
// handles a packet as if it had been sent to the transport by the key/endpoint.
|
||||
func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr *net.UDPAddr, data v4wire.Packet) {
|
||||
func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr netip.AddrPort, data v4wire.Packet) {
|
||||
test.t.Helper()
|
||||
|
||||
enc, _, err := v4wire.Encode(key, data)
|
||||
|
|
@ -100,7 +101,8 @@ func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr *
|
|||
test.t.Errorf("%s encode error: %v", data.Name(), err)
|
||||
}
|
||||
test.sent = append(test.sent, enc)
|
||||
if err = test.udp.handlePacket(addr, enc); err != wantError {
|
||||
udpaddr := &net.UDPAddr{IP: addr.Addr().AsSlice(), Port: int(addr.Port())}
|
||||
if err = test.udp.handlePacket(udpaddr, enc); err != wantError {
|
||||
test.t.Errorf("error mismatch: got %q, want %q", err, wantError)
|
||||
}
|
||||
}
|
||||
|
|
@ -236,7 +238,7 @@ func TestUDPv4_findnodeTimeout(t *testing.T) {
|
|||
test := newUDPTest(t)
|
||||
defer test.close()
|
||||
|
||||
toaddr := &net.UDPAddr{IP: net.ParseIP("1.2.3.4"), Port: 2222}
|
||||
toaddr := netip.AddrPortFrom(netip.MustParseAddr("1.2.3.4"), 2222)
|
||||
toid := enode.ID{1, 2, 3, 4}
|
||||
target := v4wire.Pubkey{4, 5, 6, 7}
|
||||
result, err := test.udp.findnode(toid, toaddr, target)
|
||||
|
|
@ -261,25 +263,24 @@ func TestUDPv4_findnode(t *testing.T) {
|
|||
for i := 0; i < numCandidates; i++ {
|
||||
key := newkey()
|
||||
ip := net.IP{10, 13, 0, byte(i)}
|
||||
n := wrapNode(enode.NewV4(&key.PublicKey, ip, 0, 2000))
|
||||
n := enode.NewV4(&key.PublicKey, ip, 0, 2000)
|
||||
// Ensure half of table content isn't verified live yet.
|
||||
if i > numCandidates/2 {
|
||||
n.isValidatedLive = true
|
||||
live[n.ID()] = true
|
||||
}
|
||||
test.table.addFoundNode(n, live[n.ID()])
|
||||
nodes.push(n, numCandidates)
|
||||
}
|
||||
fillTable(test.table, nodes.entries, false)
|
||||
|
||||
// ensure there's a bond with the test node,
|
||||
// findnode won't be accepted otherwise.
|
||||
remoteID := v4wire.EncodePubkey(&test.remotekey.PublicKey).ID()
|
||||
test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.IP, time.Now())
|
||||
test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.Addr().AsSlice(), time.Now())
|
||||
|
||||
// check that closest neighbors are returned.
|
||||
expected := test.table.findnodeByID(testTarget.ID(), bucketSize, true)
|
||||
test.packetIn(nil, &v4wire.Findnode{Target: testTarget, Expiration: futureExp})
|
||||
waitNeighbors := func(want []*node) {
|
||||
waitNeighbors := func(want []*enode.Node) {
|
||||
test.waitPacketOut(func(p *v4wire.Neighbors, to *net.UDPAddr, hash []byte) {
|
||||
if len(p.Nodes) != len(want) {
|
||||
t.Errorf("wrong number of results: got %d, want %d", len(p.Nodes), len(want))
|
||||
|
|
@ -309,10 +310,10 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) {
|
|||
defer test.close()
|
||||
|
||||
rid := enode.PubkeyToIDV4(&test.remotekey.PublicKey)
|
||||
test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.IP, time.Now())
|
||||
test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.Addr().AsSlice(), time.Now())
|
||||
|
||||
// queue a pending findnode request
|
||||
resultc, errc := make(chan []*node, 1), make(chan error, 1)
|
||||
resultc, errc := make(chan []*enode.Node, 1), make(chan error, 1)
|
||||
go func() {
|
||||
rid := encodePubkey(&test.remotekey.PublicKey).id()
|
||||
ns, err := test.udp.findnode(rid, test.remoteaddr, testTarget)
|
||||
|
|
@ -332,11 +333,11 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) {
|
|||
})
|
||||
|
||||
// send the reply as two packets.
|
||||
list := []*node{
|
||||
wrapNode(enode.MustParse("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304")),
|
||||
wrapNode(enode.MustParse("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303")),
|
||||
wrapNode(enode.MustParse("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17")),
|
||||
wrapNode(enode.MustParse("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303")),
|
||||
list := []*enode.Node{
|
||||
enode.MustParse("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304"),
|
||||
enode.MustParse("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303"),
|
||||
enode.MustParse("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17"),
|
||||
enode.MustParse("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303"),
|
||||
}
|
||||
rpclist := make([]v4wire.Node, len(list))
|
||||
for i := range list {
|
||||
|
|
@ -381,8 +382,8 @@ func TestUDPv4_pingMatchIP(t *testing.T) {
|
|||
test.packetIn(nil, &v4wire.Ping{From: testRemote, To: testLocalAnnounced, Version: 4, Expiration: futureExp})
|
||||
test.waitPacketOut(func(*v4wire.Pong, *net.UDPAddr, []byte) {})
|
||||
|
||||
test.waitPacketOut(func(p *v4wire.Ping, to *net.UDPAddr, hash []byte) {
|
||||
wrongAddr := &net.UDPAddr{IP: net.IP{33, 44, 1, 2}, Port: 30000}
|
||||
test.waitPacketOut(func(p *v4wire.Ping, to netip.AddrPort, hash []byte) {
|
||||
wrongAddr := netip.MustParseAddrPort("33.44.1.2:30000")
|
||||
test.packetInFrom(errUnsolicitedReply, test.remotekey, wrongAddr, &v4wire.Pong{
|
||||
ReplyTok: hash,
|
||||
To: testLocalAnnounced,
|
||||
|
|
@ -408,7 +409,8 @@ func TestUDPv4_successfulPing(t *testing.T) {
|
|||
}
|
||||
wantTo := v4wire.Endpoint{
|
||||
// The mirrored UDP address is the UDP packet sender
|
||||
IP: test.remoteaddr.IP, UDP: uint16(test.remoteaddr.Port),
|
||||
IP: test.remoteaddr.Addr().AsSlice(),
|
||||
UDP: test.remoteaddr.Port(),
|
||||
// The mirrored TCP port is the one from the ping packet
|
||||
TCP: testRemote.TCP,
|
||||
}
|
||||
|
|
@ -424,8 +426,8 @@ func TestUDPv4_successfulPing(t *testing.T) {
|
|||
}
|
||||
wantTo := v4wire.Endpoint{
|
||||
// The mirrored UDP address is the UDP packet sender.
|
||||
IP: test.remoteaddr.IP,
|
||||
UDP: uint16(test.remoteaddr.Port),
|
||||
IP: test.remoteaddr.Addr().AsSlice(),
|
||||
UDP: test.remoteaddr.Port(),
|
||||
TCP: 0,
|
||||
}
|
||||
if !reflect.DeepEqual(p.To, wantTo) {
|
||||
|
|
@ -442,10 +444,10 @@ func TestUDPv4_successfulPing(t *testing.T) {
|
|||
if n.ID() != rid {
|
||||
t.Errorf("node has wrong ID: got %v, want %v", n.ID(), rid)
|
||||
}
|
||||
if !n.IP().Equal(test.remoteaddr.IP) {
|
||||
t.Errorf("node has wrong IP: got %v, want: %v", n.IP(), test.remoteaddr.IP)
|
||||
if !n.IP().Equal(test.remoteaddr.Addr().AsSlice()) {
|
||||
t.Errorf("node has wrong IP: got %v, want: %v", n.IP(), test.remoteaddr.Addr())
|
||||
}
|
||||
if n.UDP() != test.remoteaddr.Port {
|
||||
if n.UDP() != int(test.remoteaddr.Port()) {
|
||||
t.Errorf("node has wrong UDP port: got %v, want: %v", n.UDP(), test.remoteaddr.Port)
|
||||
}
|
||||
if n.TCP() != int(testRemote.TCP) {
|
||||
|
|
@ -584,7 +586,7 @@ type dgramPipe struct {
|
|||
}
|
||||
|
||||
type dgram struct {
|
||||
to net.UDPAddr
|
||||
to netip.AddrPort
|
||||
data []byte
|
||||
}
|
||||
|
||||
|
|
@ -606,7 +608,12 @@ func (c *dgramPipe) WriteToUDP(b []byte, to *net.UDPAddr) (n int, err error) {
|
|||
if c.closed {
|
||||
return 0, errors.New("closed")
|
||||
}
|
||||
c.queue = append(c.queue, dgram{*to, b})
|
||||
addr, ok := netip.AddrFromSlice(to.IP)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("invalid destination IP addr %v", to.IP))
|
||||
}
|
||||
addrPort := netip.AddrPortFrom(addr, uint16(to.Port))
|
||||
c.queue = append(c.queue, dgram{addrPort, b})
|
||||
c.cond.Signal()
|
||||
return len(b), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ func (t *UDPv5) AllNodes() []*enode.Node {
|
|||
|
||||
for _, b := range &t.tab.buckets {
|
||||
for _, n := range b.entries {
|
||||
nodes = append(nodes, unwrapNode(n))
|
||||
nodes = append(nodes, n.Node)
|
||||
}
|
||||
}
|
||||
return nodes
|
||||
|
|
@ -314,26 +314,26 @@ func (t *UDPv5) newRandomLookup(ctx context.Context) *lookup {
|
|||
}
|
||||
|
||||
func (t *UDPv5) newLookup(ctx context.Context, target enode.ID) *lookup {
|
||||
return newLookup(ctx, t.tab, target, func(n *node) ([]*node, error) {
|
||||
return newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) {
|
||||
return t.lookupWorker(n, target)
|
||||
})
|
||||
}
|
||||
|
||||
// lookupWorker performs FINDNODE calls against a single node during lookup.
|
||||
func (t *UDPv5) lookupWorker(destNode *node, target enode.ID) ([]*node, error) {
|
||||
func (t *UDPv5) lookupWorker(destNode *enode.Node, target enode.ID) ([]*enode.Node, error) {
|
||||
var (
|
||||
dists = lookupDistances(target, destNode.ID())
|
||||
nodes = nodesByDistance{target: target}
|
||||
err error
|
||||
)
|
||||
var r []*enode.Node
|
||||
r, err = t.findnode(unwrapNode(destNode), dists)
|
||||
r, err = t.findnode(destNode, dists)
|
||||
if errors.Is(err, errClosed) {
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range r {
|
||||
if n.ID() != t.Self().ID() {
|
||||
nodes.push(wrapNode(n), findnodeResultLimit)
|
||||
nodes.push(n, findnodeResultLimit)
|
||||
}
|
||||
}
|
||||
return nodes.entries, err
|
||||
|
|
@ -699,7 +699,7 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error {
|
|||
}
|
||||
if fromNode != nil {
|
||||
// Handshake succeeded, add to table.
|
||||
t.tab.addInboundNode(wrapNode(fromNode))
|
||||
t.tab.addInboundNode(fromNode)
|
||||
}
|
||||
if packet.Kind() != v5wire.WhoareyouPacket {
|
||||
// WHOAREYOU logged separately to report errors.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"slices"
|
||||
"testing"
|
||||
|
|
@ -141,7 +142,7 @@ func TestUDPv5_unknownPacket(t *testing.T) {
|
|||
|
||||
// Make node known.
|
||||
n := test.getNode(test.remotekey, test.remoteaddr).Node()
|
||||
test.table.addFoundNode(wrapNode(n))
|
||||
test.table.addFoundNode(n, false)
|
||||
|
||||
test.packetIn(&v5wire.Unknown{Nonce: nonce})
|
||||
test.waitPacketOut(func(p *v5wire.Whoareyou, addr *net.UDPAddr, _ v5wire.Nonce) {
|
||||
|
|
@ -159,9 +160,9 @@ func TestUDPv5_findnodeHandling(t *testing.T) {
|
|||
nodes253 := nodesAtDistance(test.table.self().ID(), 253, 16)
|
||||
nodes249 := nodesAtDistance(test.table.self().ID(), 249, 4)
|
||||
nodes248 := nodesAtDistance(test.table.self().ID(), 248, 10)
|
||||
fillTable(test.table, wrapNodes(nodes253), true)
|
||||
fillTable(test.table, wrapNodes(nodes249), true)
|
||||
fillTable(test.table, wrapNodes(nodes248), true)
|
||||
fillTable(test.table, nodes253, true)
|
||||
fillTable(test.table, nodes249, true)
|
||||
fillTable(test.table, nodes248, true)
|
||||
|
||||
// Requesting with distance zero should return the node's own record.
|
||||
test.packetIn(&v5wire.Findnode{ReqID: []byte{0}, Distances: []uint{0}})
|
||||
|
|
@ -589,7 +590,7 @@ func TestUDPv5_lookup(t *testing.T) {
|
|||
|
||||
// Seed table with initial node.
|
||||
initialNode := lookupTestnet.node(256, 0)
|
||||
fillTable(test.table, []*node{wrapNode(initialNode)}, true)
|
||||
fillTable(test.table, []*enode.Node{initialNode}, true)
|
||||
|
||||
// Start the lookup.
|
||||
resultC := make(chan []*enode.Node, 1)
|
||||
|
|
@ -601,7 +602,7 @@ func TestUDPv5_lookup(t *testing.T) {
|
|||
// Answer lookup packets.
|
||||
asked := make(map[enode.ID]bool)
|
||||
for done := false; !done; {
|
||||
done = test.waitPacketOut(func(p v5wire.Packet, to *net.UDPAddr, _ v5wire.Nonce) {
|
||||
done = test.waitPacketOut(func(p v5wire.Packet, to netip.AddrPort, _ v5wire.Nonce) {
|
||||
recipient, key := lookupTestnet.nodeByAddr(to)
|
||||
switch p := p.(type) {
|
||||
case *v5wire.Ping:
|
||||
|
|
@ -688,9 +689,9 @@ type udpV5Test struct {
|
|||
db *enode.DB
|
||||
udp *UDPv5
|
||||
localkey, remotekey *ecdsa.PrivateKey
|
||||
remoteaddr *net.UDPAddr
|
||||
remoteaddr netip.AddrPort
|
||||
nodesByID map[enode.ID]*enode.LocalNode
|
||||
nodesByIP map[string]*enode.LocalNode
|
||||
nodesByIP map[netip.Addr]*enode.LocalNode
|
||||
}
|
||||
|
||||
// testCodec is the packet encoding used by protocol tests. This codec does not perform encryption.
|
||||
|
|
@ -778,7 +779,7 @@ func (test *udpV5Test) packetIn(packet v5wire.Packet) {
|
|||
}
|
||||
|
||||
// handles a packet as if it had been sent to the transport by the key/endpoint.
|
||||
func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr *net.UDPAddr, packet v5wire.Packet) {
|
||||
func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr netip.AddrPort, packet v5wire.Packet) {
|
||||
test.t.Helper()
|
||||
|
||||
ln := test.getNode(key, addr)
|
||||
|
|
@ -793,17 +794,17 @@ func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr *net.UDPAddr, pa
|
|||
}
|
||||
|
||||
// getNode ensures the test knows about a node at the given endpoint.
|
||||
func (test *udpV5Test) getNode(key *ecdsa.PrivateKey, addr *net.UDPAddr) *enode.LocalNode {
|
||||
func (test *udpV5Test) getNode(key *ecdsa.PrivateKey, addr netip.AddrPort) *enode.LocalNode {
|
||||
id := encodePubkey(&key.PublicKey).id()
|
||||
ln := test.nodesByID[id]
|
||||
if ln == nil {
|
||||
db, _ := enode.OpenDB("")
|
||||
ln = enode.NewLocalNode(db, key)
|
||||
ln.SetStaticIP(addr.IP)
|
||||
ln.Set(enr.UDP(addr.Port))
|
||||
ln.SetStaticIP(addr.Addr().AsSlice())
|
||||
ln.Set(enr.UDP(addr.Port()))
|
||||
test.nodesByID[id] = ln
|
||||
}
|
||||
test.nodesByIP[string(addr.IP)] = ln
|
||||
test.nodesByIP[string(addr.Addr().String())] = ln
|
||||
return ln
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue