revert table modification

Signed-off-by: Chen Kai <281165273grape@gmail.com>
This commit is contained in:
Chen Kai 2024-12-10 14:13:18 +08:00
parent c3669fd24c
commit 5095282864
12 changed files with 220 additions and 220 deletions

View file

@ -24,30 +24,30 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode"
)
// Lookup performs a network search for nodes close to the given target. It approaches the
// lookup performs a network search for nodes close to the given target. It approaches the
// target by querying nodes that are closer to it on each iteration. The given target does
// not need to be an actual node identifier.
type Lookup struct {
type lookup struct {
tab *Table
queryfunc queryFunc
replyCh chan []*enode.Node
cancelCh <-chan struct{}
asked, seen map[enode.ID]bool
result NodesByDistance
result nodesByDistance
replyBuffer []*enode.Node
queries int
}
type queryFunc func(*enode.Node) ([]*enode.Node, error)
func NewLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *Lookup {
it := &Lookup{
func newLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *lookup {
it := &lookup{
tab: tab,
queryfunc: q,
asked: make(map[enode.ID]bool),
seen: make(map[enode.ID]bool),
result: NodesByDistance{Target: target},
replyCh: make(chan []*enode.Node, Alpha),
result: nodesByDistance{target: target},
replyCh: make(chan []*enode.Node, alpha),
cancelCh: ctx.Done(),
queries: -1,
}
@ -57,16 +57,16 @@ func NewLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *L
return it
}
// Run runs the lookup to completion and returns the closest nodes found.
func (it *Lookup) Run() []*enode.Node {
// run runs the lookup to completion and returns the closest nodes found.
func (it *lookup) run() []*enode.Node {
for it.advance() {
}
return it.result.Entries
return it.result.entries
}
// advance advances the lookup until any new nodes have been found.
// It returns false when the lookup has ended.
func (it *Lookup) advance() bool {
func (it *lookup) advance() bool {
for it.startQueries() {
select {
case nodes := <-it.replyCh:
@ -74,7 +74,7 @@ func (it *Lookup) advance() bool {
for _, n := range nodes {
if n != nil && !it.seen[n.ID()] {
it.seen[n.ID()] = true
it.result.Push(n, BucketSize)
it.result.push(n, bucketSize)
it.replyBuffer = append(it.replyBuffer, n)
}
}
@ -89,7 +89,7 @@ func (it *Lookup) advance() bool {
return false
}
func (it *Lookup) shutdown() {
func (it *lookup) shutdown() {
for it.queries > 0 {
<-it.replyCh
it.queries--
@ -98,28 +98,28 @@ func (it *Lookup) shutdown() {
it.replyBuffer = nil
}
func (it *Lookup) startQueries() bool {
func (it *lookup) startQueries() bool {
if it.queryfunc == nil {
return false
}
// The first query returns nodes from the local table.
if it.queries == -1 {
closest := it.tab.FindnodeByID(it.result.Target, BucketSize, false)
closest := it.tab.findnodeByID(it.result.target, bucketSize, false)
// Avoid finishing the lookup too quickly if table is empty. It'd be better to wait
// for the table to fill in this case, but there is no good mechanism for that
// yet.
if len(closest.Entries) == 0 {
if len(closest.entries) == 0 {
it.slowdown()
}
it.queries = 1
it.replyCh <- closest.Entries
it.replyCh <- closest.entries
return true
}
// Ask the closest nodes that we haven't asked yet.
for i := 0; i < len(it.result.Entries) && it.queries < Alpha; i++ {
n := it.result.Entries[i]
for i := 0; i < len(it.result.entries) && it.queries < alpha; i++ {
n := it.result.entries[i]
if !it.asked[n.ID()] {
it.asked[n.ID()] = true
it.queries++
@ -130,7 +130,7 @@ func (it *Lookup) startQueries() bool {
return it.queries > 0
}
func (it *Lookup) slowdown() {
func (it *lookup) slowdown() {
sleep := time.NewTimer(1 * time.Second)
defer sleep.Stop()
select {
@ -139,9 +139,9 @@ func (it *Lookup) slowdown() {
}
}
func (it *Lookup) query(n *enode.Node, reply chan<- []*enode.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.
if !errors.Is(err, errClosed) { // avoid recording failures on shutdown.
success := len(r) > 0
it.tab.trackRequest(n, success, r)
if err != nil {
@ -158,10 +158,10 @@ type lookupIterator struct {
nextLookup lookupFunc
ctx context.Context
cancel func()
lookup *Lookup
lookup *lookup
}
type lookupFunc func(ctx context.Context) *Lookup
type lookupFunc func(ctx context.Context) *lookup
func newLookupIterator(ctx context.Context, next lookupFunc) *lookupIterator {
ctx, cancel := context.WithCancel(ctx)

View file

@ -54,27 +54,27 @@ func (n *tableNode) String() string {
return n.Node.String()
}
// NodesByDistance is a list of nodes, ordered by distance to target.
type NodesByDistance struct {
Entries []*enode.Node
Target enode.ID
// nodesByDistance is a list of nodes, ordered by distance to target.
type nodesByDistance struct {
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 *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
// push adds the given node to the list, keeping the total size below maxElems.
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
})
end := len(h.Entries)
if len(h.Entries) < maxElems {
h.Entries = append(h.Entries, n)
end := len(h.entries)
if len(h.entries) < maxElems {
h.entries = append(h.entries, n)
}
if ix < end {
// Slide existing entries down to make room.
// This will overwrite the entry we just appended.
copy(h.Entries[ix+1:], h.Entries[ix:])
h.Entries[ix] = n
copy(h.entries[ix+1:], h.entries[ix:])
h.entries[ix] = n
}
}

View file

@ -39,8 +39,8 @@ import (
)
const (
Alpha = 3 // Kademlia concurrency factor
BucketSize = 16 // Kademlia bucket size
alpha = 3 // Kademlia concurrency factor
bucketSize = 16 // Kademlia bucket size
maxReplacements = 10 // Size of per-bucket replacement list
// We keep buckets for the upper 1/15 of distances because
@ -92,9 +92,9 @@ type Table struct {
type transport interface {
Self() *enode.Node
RequestENR(*enode.Node) (*enode.Node, error)
LookupRandom() []*enode.Node
LookupSelf() []*enode.Node
Ping(*enode.Node) (seq uint64, err error)
lookupRandom() []*enode.Node
lookupSelf() []*enode.Node
ping(*enode.Node) (seq uint64, err error)
}
// bucket contains nodes, ordered by their last activity. the entry
@ -118,7 +118,7 @@ type trackRequestOp struct {
success bool
}
func NewTable(t transport, db *enode.DB, cfg Config) (*Table, error) {
func newTable(t transport, db *enode.DB, cfg Config) (*Table, error) {
cfg = cfg.withDefaults()
tab := &Table{
net: t,
@ -178,8 +178,8 @@ func (tab *Table) self() *enode.Node {
return tab.net.Self()
}
// GetNode returns the node with the given ID or nil if it isn't in the table.
func (tab *Table) GetNode(id enode.ID) *enode.Node {
// getNode returns the node with the given ID or nil if it isn't in the table.
func (tab *Table) getNode(id enode.ID) *enode.Node {
tab.mutex.Lock()
defer tab.mutex.Unlock()
@ -192,8 +192,8 @@ func (tab *Table) GetNode(id enode.ID) *enode.Node {
return nil
}
// Close terminates the network listener and flushes the node database.
func (tab *Table) Close() {
// close terminates the network listener and flushes the node database.
func (tab *Table) close() {
close(tab.closeReq)
<-tab.closed
}
@ -237,40 +237,40 @@ func (tab *Table) refresh() <-chan struct{} {
return done
}
// FindnodeByID returns the n nodes in the table that are closest to the given id.
// findnodeByID returns the n nodes in the table that are closest to the given id.
// This is used by the FINDNODE/v4 handler.
//
// The preferLive parameter says whether the caller wants liveness-checked results. If
// preferLive is true and the table contains any verified nodes, the result will not
// contain unverified nodes. However, if there are no verified nodes at all, the result
// will contain unverified nodes.
func (tab *Table) FindnodeByID(target enode.ID, nresults int, preferLive bool) *NodesByDistance {
func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) *nodesByDistance {
tab.mutex.Lock()
defer tab.mutex.Unlock()
// Scan all buckets. There might be a better way to do this, but there aren't that many
// buckets, so this solution should be fine. The worst-case complexity of this loop
// is O(tab.len() * nresults).
nodes := &NodesByDistance{Target: target}
liveNodes := &NodesByDistance{Target: target}
nodes := &nodesByDistance{target: target}
liveNodes := &nodesByDistance{target: target}
for _, b := range &tab.buckets {
for _, n := range b.entries {
nodes.Push(n.Node, nresults)
nodes.push(n.Node, nresults)
if preferLive && n.isValidatedLive {
liveNodes.Push(n.Node, nresults)
liveNodes.push(n.Node, nresults)
}
}
}
if preferLive && len(liveNodes.Entries) > 0 {
if preferLive && len(liveNodes.entries) > 0 {
return liveNodes
}
return nodes
}
// AppendBucketNodes adds nodes at the given distance to the result slice.
// appendBucketNodes adds nodes at the given distance to the result slice.
// This is used by the FINDNODE/v5 handler.
func (tab *Table) AppendBucketNodes(dist uint, result []*enode.Node, checkLive bool) []*enode.Node {
func (tab *Table) appendBucketNodes(dist uint, result []*enode.Node, checkLive bool) []*enode.Node {
if dist > 256 {
return result
}
@ -304,12 +304,12 @@ func (tab *Table) len() (n int) {
return n
}
// AddFoundNode adds a node which may not be live. If the bucket has space available,
// addFoundNode adds a node which may not be live. If the bucket has space available,
// adding the node succeeds immediately. Otherwise, the node is added to the replacements
// list.
//
// The caller must not hold tab.mutex.
func (tab *Table) AddFoundNode(n *enode.Node, forceSetLive bool) bool {
func (tab *Table) addFoundNode(n *enode.Node, forceSetLive bool) bool {
op := addNodeOp{node: n, isInbound: false, forceSetLive: forceSetLive}
select {
case tab.addNodeCh <- op:
@ -319,7 +319,7 @@ func (tab *Table) AddFoundNode(n *enode.Node, forceSetLive bool) bool {
}
}
// AddInboundNode adds a node from an inbound contact. If the bucket has no space, the
// addInboundNode adds a node from an inbound contact. If the bucket has no space, the
// node is added to the replacements list.
//
// There is an additional safety measure: if the table is still initializing the node is
@ -327,7 +327,7 @@ func (tab *Table) AddFoundNode(n *enode.Node, forceSetLive bool) bool {
// repeatedly.
//
// The caller must not hold tab.mutex.
func (tab *Table) AddInboundNode(n *enode.Node) bool {
func (tab *Table) addInboundNode(n *enode.Node) bool {
op := addNodeOp{node: n, isInbound: true}
select {
case tab.addNodeCh <- op:
@ -345,8 +345,8 @@ func (tab *Table) trackRequest(n *enode.Node, success bool, foundNodes []*enode.
}
}
// Loop is the main loop of Table.
func (tab *Table) Loop() {
// loop is the main loop of Table.
func (tab *Table) loop() {
var (
refresh = time.NewTimer(tab.nextRefreshTime())
refreshDone = make(chan struct{}) // where doRefresh reports completion
@ -429,7 +429,7 @@ func (tab *Table) doRefresh(done chan struct{}) {
tab.loadSeedNodes()
// Run self lookup to discover new neighbor nodes.
tab.net.LookupSelf()
tab.net.lookupSelf()
// The Kademlia paper specifies that the bucket refresh should
// perform a lookup in the least recently used bucket. We cannot
@ -438,7 +438,7 @@ func (tab *Table) doRefresh(done chan struct{}) {
// sha3 preimage that falls into a chosen bucket.
// We perform a few lookups with a random target instead.
for i := 0; i < 3; i++ {
tab.net.LookupRandom()
tab.net.lookupRandom()
}
}
@ -521,7 +521,7 @@ func (tab *Table) handleAddNode(req addNodeOp) bool {
// Already in bucket.
return false
}
if len(b.entries) >= BucketSize {
if len(b.entries) >= bucketSize {
// Bucket full, maybe add as replacement.
tab.addReplacement(b, req.node)
return false
@ -674,7 +674,7 @@ func (tab *Table) handleTrackRequest(op trackRequestOp) {
// many times, but only if there are enough other nodes in the bucket. This latter
// condition specifically exists to make bootstrapping in smaller test networks more
// reliable.
if fails >= maxFindnodeFailures && len(b.entries) >= BucketSize/4 {
if fails >= maxFindnodeFailures && len(b.entries) >= bucketSize/4 {
tab.deleteInBucket(b, op.node.ID())
}
@ -695,41 +695,8 @@ func pushNode(list []*tableNode, n *tableNode, max int) ([]*tableNode, *tableNod
return list, removed
}
// WaitInit waits until the table is initialized.
func (tab *Table) WaitInit() {
<-tab.initDone
}
// NodeIds returns the node IDs in the table.
func (tab *Table) NodeIds() [][]string {
tab.mutex.Lock()
defer tab.mutex.Unlock()
nodes := make([][]string, 0)
for _, b := range &tab.buckets {
bucketNodes := make([]string, 0)
for _, n := range b.entries {
bucketNodes = append(bucketNodes, "0x"+n.ID().String())
}
nodes = append(nodes, bucketNodes)
}
return nodes
}
// Config returns the table's configuration.
func (tab *Table) Config() Config {
return tab.cfg
}
// DeleteNode removes a node from the table.
func (tab *Table) DeleteNode(n *enode.Node) {
tab.mutex.Lock()
defer tab.mutex.Unlock()
b := tab.bucket(n.ID())
tab.deleteInBucket(b, n.ID())
}
// NodeList returns all nodes contained in the table.
func (tab *Table) NodeList() []*enode.Node {
// nodeList returns all nodes contained in the table.
func (tab *Table) nodeList() []*enode.Node {
if !tab.isInitDone() {
return nil
}
@ -745,3 +712,25 @@ func (tab *Table) NodeList() []*enode.Node {
}
return nodes
}
// nodeIds returns the node IDs in the table.
func (tab *Table) nodeIds() [][]string {
tab.mutex.Lock()
defer tab.mutex.Unlock()
nodes := make([][]string, 0)
for _, b := range &tab.buckets {
bucketNodes := make([]string, 0)
for _, n := range b.entries {
bucketNodes = append(bucketNodes, "0x"+n.ID().String())
}
nodes = append(nodes, bucketNodes)
}
return nodes
}
func (tab *Table) deleteNode(n *enode.Node) {
tab.mutex.Lock()
defer tab.mutex.Unlock()
b := tab.bucket(n.ID())
tab.deleteInBucket(b, n.ID())
}

View file

@ -111,7 +111,7 @@ func (tr *tableRevalidation) startRequest(tab *Table, n *tableNode) {
func (tab *Table) doRevalidate(resp revalidationResponse, node *enode.Node) {
// Ping the selected node and wait for a pong response.
remoteSeq, err := tab.net.Ping(node)
remoteSeq, err := tab.net.ping(node)
resp.didRespond = err == nil
// Also fetch record if the node replied and returned a higher sequence number.

View file

@ -63,7 +63,7 @@ func TestRevalidation_nodeRemoved(t *testing.T) {
tr.handleResponse(tab, resp)
// Ensure the node was not re-added to the table.
if tab.GetNode(node.ID()) != nil {
if tab.getNode(node.ID()) != nil {
t.Fatal("node was re-added to Table")
}
if tr.fast.contains(node.ID()) || tr.slow.contains(node.ID()) {

View file

@ -59,7 +59,7 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding
Log: testlog.Logger(t, log.LevelTrace),
})
defer db.Close()
defer tab.Close()
defer tab.close()
<-tab.initDone
@ -79,7 +79,7 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding
transport.dead[replacementNode.ID()] = !newNodeIsResponding
// Add replacement node to table.
tab.AddFoundNode(replacementNode, false)
tab.addFoundNode(replacementNode, false)
t.Log("last:", last.ID())
t.Log("replacement:", replacementNode.ID())
@ -108,7 +108,7 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding
// Check bucket content.
tab.mutex.Lock()
defer tab.mutex.Unlock()
wantSize := BucketSize
wantSize := bucketSize
if !lastInBucketIsResponding && !newNodeIsResponding {
wantSize--
}
@ -150,11 +150,11 @@ func TestTable_IPLimit(t *testing.T) {
transport := newPingRecorder()
tab, db := newTestTable(transport, Config{})
defer db.Close()
defer tab.Close()
defer tab.close()
for i := 0; i < tableIPLimit+1; i++ {
n := nodeAtDistance(tab.self().ID(), i, net.IP{172, 0, 1, byte(i)})
tab.AddFoundNode(n, false)
tab.addFoundNode(n, false)
}
if tab.len() > tableIPLimit {
t.Errorf("too many nodes in table")
@ -167,12 +167,12 @@ func TestTable_BucketIPLimit(t *testing.T) {
transport := newPingRecorder()
tab, db := newTestTable(transport, Config{})
defer db.Close()
defer tab.Close()
defer tab.close()
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, false)
tab.addFoundNode(n, false)
}
if tab.len() > bucketIPLimit {
t.Errorf("too many nodes in table")
@ -204,11 +204,11 @@ func TestTable_findnodeByID(t *testing.T) {
transport := newPingRecorder()
tab, db := newTestTable(transport, Config{})
defer db.Close()
defer tab.Close()
defer tab.close()
fillTable(tab, test.All, true)
// check that closest(Target, N) returns nodes
result := tab.FindnodeByID(test.Target, test.N, false).Entries
result := tab.findnodeByID(test.Target, test.N, false).entries
if hasDuplicates(result) {
t.Errorf("result contains duplicates")
return false
@ -264,7 +264,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value {
t := &closeTest{
Self: gen(enode.ID{}, rand).(enode.ID),
Target: gen(enode.ID{}, rand).(enode.ID),
N: rand.Intn(BucketSize),
N: rand.Intn(bucketSize),
}
for _, id := range gen([]enode.ID{}, rand).([]enode.ID) {
r := new(enr.Record)
@ -279,20 +279,20 @@ func TestTable_addInboundNode(t *testing.T) {
tab, db := newTestTable(newPingRecorder(), Config{})
<-tab.initDone
defer db.Close()
defer tab.Close()
defer tab.close()
// 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, false)
tab.AddFoundNode(n2, false)
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(n2v2)
tab.addInboundNode(n2v2)
checkBucketContent(t, tab, []*enode.Node{n1, n2v2})
// Try updating n2 without sequence number change. The update is accepted
@ -301,7 +301,7 @@ 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(n2v3)
tab.addInboundNode(n2v3)
checkBucketContent(t, tab, []*enode.Node{n1, n2v3})
}
@ -309,20 +309,20 @@ func TestTable_addFoundNode(t *testing.T) {
tab, db := newTestTable(newPingRecorder(), Config{})
<-tab.initDone
defer db.Close()
defer tab.Close()
defer tab.close()
// 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, false)
tab.AddFoundNode(n2, false)
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(n2v2, false)
tab.addFoundNode(n2v2, false)
checkBucketContent(t, tab, []*enode.Node{n1, n2v2})
// Try updating n2 without a sequence number change.
@ -331,7 +331,7 @@ 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(n2v3, false)
tab.addFoundNode(n2v3, false)
checkBucketContent(t, tab, []*enode.Node{n1, n2v2})
}
@ -340,18 +340,18 @@ func TestTable_addInboundNodeUpdateV4Accept(t *testing.T) {
tab, db := newTestTable(newPingRecorder(), Config{})
<-tab.initDone
defer db.Close()
defer tab.Close()
defer tab.close()
// Add a v4 node.
key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3")
n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000)
tab.AddInboundNode(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(n1v2)
tab.addInboundNode(n1v2)
checkBucketContent(t, tab, []*enode.Node{n1v2})
}
@ -361,18 +361,18 @@ func TestTable_addFoundNodeV4UpdateReject(t *testing.T) {
tab, db := newTestTable(newPingRecorder(), Config{})
<-tab.initDone
defer db.Close()
defer tab.Close()
defer tab.close()
// Add a v4 node.
key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3")
n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000)
tab.AddFoundNode(n1, false)
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(n1v2, false)
tab.addFoundNode(n1v2, false)
checkBucketContent(t, tab, []*enode.Node{n1})
}
@ -407,14 +407,14 @@ func TestTable_revalidateSyncRecord(t *testing.T) {
})
<-tab.initDone
defer db.Close()
defer tab.Close()
defer tab.close()
// Insert a node.
var r enr.Record
r.Set(enr.IP(net.IP{127, 0, 0, 1}))
id := enode.ID{1}
n1 := enode.SignNull(&r, id)
tab.AddFoundNode(n1, false)
tab.addFoundNode(n1, false)
// Update the node record.
r.Set(enr.WithEntry("foo", "bar"))
@ -426,7 +426,7 @@ func TestTable_revalidateSyncRecord(t *testing.T) {
waitForRevalidationPing(t, transport, tab, n2.ID())
waitForRevalidationPing(t, transport, tab, n2.ID())
intable := tab.GetNode(id)
intable := tab.getNode(id)
if !reflect.DeepEqual(intable, n2) {
t.Fatalf("table contains old record with seq %d, want seq %d", intable.Seq(), n2.Seq())
}
@ -448,22 +448,22 @@ func TestNodesPush(t *testing.T) {
// Insert all permutations into lists with size limit 3.
for _, nodes := range perm {
list := NodesByDistance{Target: target}
list := nodesByDistance{target: target}
for _, n := range nodes {
list.Push(n, 3)
list.push(n, 3)
}
if !slices.EqualFunc(list.Entries, perm[0], nodeIDEqual) {
if !slices.EqualFunc(list.entries, perm[0], nodeIDEqual) {
t.Fatal("not equal")
}
}
// Insert all permutations into lists with size limit 2.
for _, nodes := range perm {
list := NodesByDistance{Target: target}
list := nodesByDistance{target: target}
for _, n := range nodes {
list.Push(n, 2)
list.push(n, 2)
}
if !slices.EqualFunc(list.Entries, perm[0][:2], nodeIDEqual) {
if !slices.EqualFunc(list.entries, perm[0][:2], nodeIDEqual) {
t.Fatal("not equal")
}
}

View file

@ -45,14 +45,14 @@ func init() {
func newTestTable(t transport, cfg Config) (*Table, *enode.DB) {
tab, db := newInactiveTestTable(t, cfg)
go tab.Loop()
go tab.loop()
return tab, db
}
// newInactiveTestTable creates a Table without running the main loop.
func newInactiveTestTable(t transport, cfg Config) (*Table, *enode.DB) {
db, _ := enode.OpenDB("")
tab, _ := NewTable(t, db, cfg)
tab, _ := newTable(t, db, cfg)
return tab, db
}
@ -64,7 +64,7 @@ func nodeAtDistance(base enode.ID, ld int, ip net.IP) *enode.Node {
return enode.SignNull(&r, idAtDistance(base, ld))
}
// nodesAtDistance creates n nodes for which enode.LogDist(base, Node.ID()) == 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 {
@ -110,20 +110,20 @@ func intIP(i int) net.IP {
func fillBucket(tab *Table, id enode.ID) (last *tableNode) {
ld := enode.LogDist(tab.self().ID(), id)
b := tab.bucket(id)
for len(b.entries) < BucketSize {
for len(b.entries) < bucketSize {
node := nodeAtDistance(tab.self().ID(), ld, intIP(ld))
if !tab.AddFoundNode(node, false) {
if !tab.addFoundNode(node, false) {
panic("node not added")
}
}
return b.entries[BucketSize-1]
return b.entries[bucketSize-1]
}
// 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 []*enode.Node, setLive bool) {
for _, n := range nodes {
tab.AddFoundNode(n, setLive)
tab.addFoundNode(n, setLive)
}
}
@ -160,8 +160,8 @@ func (t *pingRecorder) updateRecord(n *enode.Node) {
// Stubs to satisfy the transport interface.
func (t *pingRecorder) Self() *enode.Node { return nullNode }
func (t *pingRecorder) LookupSelf() []*enode.Node { return nil }
func (t *pingRecorder) LookupRandom() []*enode.Node { return nil }
func (t *pingRecorder) lookupSelf() []*enode.Node { return nil }
func (t *pingRecorder) lookupRandom() []*enode.Node { return nil }
func (t *pingRecorder) waitPing(timeout time.Duration) *enode.Node {
t.mu.Lock()
@ -190,7 +190,7 @@ func (t *pingRecorder) waitPing(timeout time.Duration) *enode.Node {
}
// ping simulates a ping request.
func (t *pingRecorder) Ping(n *enode.Node) (seq uint64, err error) {
func (t *pingRecorder) ping(n *enode.Node) (seq uint64, err error) {
t.mu.Lock()
defer t.mu.Unlock()

View file

@ -59,8 +59,8 @@ func TestUDPv4_Lookup(t *testing.T) {
for _, e := range results {
t.Logf(" ld=%d, %x", enode.LogDist(lookupTestnet.target.ID(), e.ID()), e.ID().Bytes())
}
if len(results) != BucketSize {
t.Errorf("wrong number of results: got %d, want %d", len(results), BucketSize)
if len(results) != bucketSize {
t.Errorf("wrong number of results: got %d, want %d", len(results), bucketSize)
}
checkLookupResults(t, lookupTestnet, results)
}

View file

@ -43,8 +43,8 @@ var (
errUnknownNode = errors.New("unknown node")
errTimeout = errors.New("RPC timeout")
errClockWarp = errors.New("reply deadline too far in the future")
ErrClosed = errors.New("socket closed")
ErrLowPort = errors.New("low port")
errClosed = errors.New("socket closed")
errLowPort = errors.New("low port")
errNoUDPEndpoint = errors.New("node has no UDP endpoint")
)
@ -143,12 +143,12 @@ func ListenV4(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) {
log: cfg.Log,
}
tab, err := NewTable(t, ln.Database(), cfg)
tab, err := newTable(t, ln.Database(), cfg)
if err != nil {
return nil, err
}
t.tab = tab
go tab.Loop()
go tab.loop()
t.wg.Add(2)
go t.loop()
@ -167,7 +167,7 @@ func (t *UDPv4) Close() {
t.cancelCloseCtx()
t.conn.Close()
t.wg.Wait()
t.tab.Close()
t.tab.close()
})
}
@ -179,7 +179,7 @@ func (t *UDPv4) Resolve(n *enode.Node) *enode.Node {
return rn
}
// Check table for the ID, we might have a newer version there.
if intable := t.tab.GetNode(n.ID()); intable != nil && intable.Seq() > n.Seq() {
if intable := t.tab.getNode(n.ID()); intable != nil && intable.Seq() > n.Seq() {
n = intable
if rn, err := t.RequestENR(n); err == nil {
return rn
@ -212,12 +212,12 @@ func (t *UDPv4) ourEndpoint() v4wire.Endpoint {
// PingWithoutResp sends a ping message to the given node.
func (t *UDPv4) PingWithoutResp(n *enode.Node) error {
_, err := t.Ping(n)
_, err := t.ping(n)
return err
}
// ping sends a ping message to the given node and waits for a reply.
func (t *UDPv4) Ping(n *enode.Node) (seq uint64, err error) {
func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) {
addr, ok := n.UDPEndpoint()
if !ok {
return 0, errNoUDPEndpoint
@ -271,7 +271,7 @@ func (t *UDPv4) LookupPubkey(key *ecdsa.PublicKey) []*enode.Node {
// case and run the bootstrapping logic.
<-t.tab.refresh()
}
return t.newLookup(t.closeCtx, v4wire.EncodePubkey(key)).Run()
return t.newLookup(t.closeCtx, v4wire.EncodePubkey(key)).run()
}
// RandomNodes is an iterator yielding nodes from a random walk of the DHT.
@ -280,25 +280,25 @@ func (t *UDPv4) RandomNodes() enode.Iterator {
}
// lookupRandom implements transport.
func (t *UDPv4) LookupRandom() []*enode.Node {
return t.newRandomLookup(t.closeCtx).Run()
func (t *UDPv4) lookupRandom() []*enode.Node {
return t.newRandomLookup(t.closeCtx).run()
}
// lookupSelf implements transport.
func (t *UDPv4) LookupSelf() []*enode.Node {
func (t *UDPv4) lookupSelf() []*enode.Node {
pubkey := v4wire.EncodePubkey(&t.priv.PublicKey)
return t.newLookup(t.closeCtx, pubkey).Run()
return t.newLookup(t.closeCtx, pubkey).run()
}
func (t *UDPv4) newRandomLookup(ctx context.Context) *Lookup {
func (t *UDPv4) newRandomLookup(ctx context.Context) *lookup {
var target v4wire.Pubkey
crand.Read(target[:])
return t.newLookup(ctx, target)
}
func (t *UDPv4) newLookup(ctx context.Context, targetKey v4wire.Pubkey) *Lookup {
func (t *UDPv4) newLookup(ctx context.Context, targetKey v4wire.Pubkey) *lookup {
target := enode.ID(crypto.Keccak256Hash(targetKey[:]))
it := NewLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) {
it := newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) {
addr, ok := n.UDPEndpoint()
if !ok {
return nil, errNoUDPEndpoint
@ -315,7 +315,7 @@ func (t *UDPv4) findnode(toid enode.ID, toAddrPort netip.AddrPort, target v4wire
// Add a matcher for 'neighbours' replies to the pending reply queue. The matcher is
// active until enough nodes have been received.
nodes := make([]*enode.Node, 0, BucketSize)
nodes := make([]*enode.Node, 0, bucketSize)
nreceived := 0
rm := t.pending(toid, toAddrPort.Addr(), v4wire.NeighborsPacket, func(r v4wire.Packet) (matched bool, requestDone bool) {
reply := r.(*v4wire.Neighbors)
@ -328,7 +328,7 @@ func (t *UDPv4) findnode(toid enode.ID, toAddrPort netip.AddrPort, target v4wire
}
nodes = append(nodes, n)
}
return true, nreceived >= BucketSize
return true, nreceived >= bucketSize
})
t.send(toAddrPort, toid, &v4wire.Findnode{
Target: target,
@ -400,7 +400,7 @@ func (t *UDPv4) pending(id enode.ID, ip netip.Addr, ptype byte, callback replyMa
case t.addReplyMatcher <- p:
// loop will handle it
case <-t.closeCtx.Done():
ch <- ErrClosed
ch <- errClosed
}
return p
}
@ -461,7 +461,7 @@ func (t *UDPv4) loop() {
select {
case <-t.closeCtx.Done():
for el := plist.Front(); el != nil; el = el.Next() {
el.Value.(*replyMatcher).errc <- ErrClosed
el.Value.(*replyMatcher).errc <- errClosed
}
return
@ -599,7 +599,7 @@ func (t *UDPv4) ensureBond(toid enode.ID, toaddr netip.AddrPort) {
func (t *UDPv4) nodeFromRPC(sender netip.AddrPort, rn v4wire.Node) (*enode.Node, error) {
if rn.UDP <= 1024 {
return nil, ErrLowPort
return nil, errLowPort
}
if err := netutil.CheckRelayIP(sender.Addr().AsSlice(), rn.IP); err != nil {
return nil, err
@ -692,10 +692,10 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from netip.AddrPort, fromID enode
n := enode.NewV4(h.senderKey, fromIP, int(req.From.TCP), int(from.Port()))
if time.Since(t.db.LastPongReceived(n.ID(), from.Addr())) > bondExpiration {
t.sendPing(fromID, from, func() {
t.tab.AddInboundNode(n)
t.tab.addInboundNode(n)
})
} else {
t.tab.AddInboundNode(n)
t.tab.addInboundNode(n)
}
// Update node database and endpoint predictor.
@ -747,7 +747,7 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from netip.AddrPort, fromID e
// Determine closest nodes.
target := enode.ID(crypto.Keccak256Hash(req.Target[:]))
preferLive := !t.tab.cfg.NoFindnodeLivenessCheck
closest := t.tab.FindnodeByID(target, BucketSize, preferLive).Entries
closest := t.tab.findnodeByID(target, bucketSize, preferLive).entries
// Send neighbors in chunks with at most maxNeighbors per packet
// to stay below the packet size limit.

View file

@ -112,7 +112,7 @@ func (test *udpTest) waitPacketOut(validate interface{}) (closed bool) {
test.t.Helper()
dgram, err := test.pipe.receive()
if err == ErrClosed {
if err == errClosed {
return true
} else if err != nil {
test.t.Error("packet receive error:", err)
@ -151,7 +151,7 @@ func TestUDPv4_pingTimeout(t *testing.T) {
key := newkey()
toaddr := &net.UDPAddr{IP: net.ParseIP("1.2.3.4"), Port: 2222}
node := enode.NewV4(&key.PublicKey, toaddr.IP, 0, toaddr.Port)
if _, err := test.udp.Ping(node); err != errTimeout {
if _, err := test.udp.ping(node); err != errTimeout {
t.Error("expected timeout error, got", err)
}
}
@ -256,9 +256,9 @@ func TestUDPv4_findnode(t *testing.T) {
// put a few nodes into the table. their exact
// distribution shouldn't matter much, although we need to
// take care not to overflow any bucket.
nodes := &NodesByDistance{Target: testTarget.ID()}
nodes := &nodesByDistance{target: testTarget.ID()}
live := make(map[enode.ID]bool)
numCandidates := 2 * BucketSize
numCandidates := 2 * bucketSize
for i := 0; i < numCandidates; i++ {
key := newkey()
ip := net.IP{10, 13, 0, byte(i)}
@ -267,8 +267,8 @@ func TestUDPv4_findnode(t *testing.T) {
if i > numCandidates/2 {
live[n.ID()] = true
}
test.table.AddFoundNode(n, live[n.ID()])
nodes.Push(n, numCandidates)
test.table.addFoundNode(n, live[n.ID()])
nodes.push(n, numCandidates)
}
// ensure there's a bond with the test node,
@ -277,7 +277,7 @@ func TestUDPv4_findnode(t *testing.T) {
test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.Addr(), time.Now())
// check that closest neighbors are returned.
expected := test.table.FindnodeByID(testTarget.ID(), BucketSize, true)
expected := test.table.findnodeByID(testTarget.ID(), bucketSize, true)
test.packetIn(nil, &v4wire.Findnode{Target: testTarget, Expiration: futureExp})
waitNeighbors := func(want []*enode.Node) {
test.waitPacketOut(func(p *v4wire.Neighbors, to netip.AddrPort, hash []byte) {
@ -287,7 +287,7 @@ func TestUDPv4_findnode(t *testing.T) {
}
for i, n := range p.Nodes {
if n.ID.ID() != want[i].ID() {
t.Errorf("result mismatch at %d:\n got: %v\n want: %v", i, n, expected.Entries[i])
t.Errorf("result mismatch at %d:\n got: %v\n want: %v", i, n, expected.entries[i])
}
if !live[n.ID.ID()] {
t.Errorf("result includes dead node %v", n.ID.ID())
@ -296,7 +296,7 @@ func TestUDPv4_findnode(t *testing.T) {
})
}
// Receive replies.
want := expected.Entries
want := expected.entries
if len(want) > v4wire.MaxNeighbors {
waitNeighbors(want[:v4wire.MaxNeighbors])
want = want[v4wire.MaxNeighbors:]
@ -644,7 +644,7 @@ func (c *dgramPipe) receive() (dgram, error) {
c.cond.Wait()
}
if c.closed {
return dgram{}, ErrClosed
return dgram{}, errClosed
}
if timedOut {
return dgram{}, errTimeout

View file

@ -141,7 +141,7 @@ func ListenV5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) {
if err != nil {
return nil, err
}
go t.tab.Loop()
go t.tab.loop()
t.wg.Add(2)
go t.readLoop()
go t.dispatch()
@ -181,7 +181,7 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) {
cancelCloseCtx: cancelCloseCtx,
}
t.talk = newTalkSystem(t)
tab, err := NewTable(t, t.db, cfg)
tab, err := newTable(t, t.db, cfg)
if err != nil {
return nil, err
}
@ -201,20 +201,20 @@ func (t *UDPv5) Close() {
t.conn.Close()
t.talk.wait()
t.wg.Wait()
t.tab.Close()
t.tab.close()
})
}
// PingWithoutResp sends a ping message to the given node.
func (t *UDPv5) PingWithoutResp(n *enode.Node) error {
_, err := t.Ping(n)
_, err := t.ping(n)
return err
}
// Resolve searches for a specific node with the given ID and tries to get the most recent
// version of the node record for it. It returns n if the node could not be resolved.
func (t *UDPv5) Resolve(n *enode.Node) *enode.Node {
if intable := t.tab.GetNode(n.ID()); intable != nil && intable.Seq() > n.Seq() {
if intable := t.tab.getNode(n.ID()); intable != nil && intable.Seq() > n.Seq() {
n = intable
}
// Try asking directly. This works if the node is still responding on the endpoint we have.
@ -238,7 +238,7 @@ func (t *UDPv5) ResolveNodeId(id enode.ID) *enode.Node {
return t.Self()
}
n := t.tab.GetNode(id)
n := t.tab.getNode(id)
if n != nil {
// Try asking directly. This works if the Node is still responding on the endpoint we have.
if resp, err := t.RequestENR(n); err == nil {
@ -263,11 +263,22 @@ func (t *UDPv5) ResolveNodeId(id enode.ID) *enode.Node {
// AllNodes returns all the nodes stored in the local table.
func (t *UDPv5) AllNodes() []*enode.Node {
return t.tab.NodeList()
return t.tab.nodeList()
}
// RoutingTableInfo returns the routing table information. Used for Portal discv5 RoutingTableInfo API.
func (t *UDPv5) RoutingTableInfo() [][]string {
return t.tab.NodeIds()
return t.tab.nodeIds()
}
// AddKnownNode adds a node to the routing table. Used for Portal discv5 AddEnr API.
func (t *UDPv5) AddKnownNode(n *enode.Node) bool {
return t.tab.addFoundNode(n, true)
}
// DeleteNode removes a node from the routing table. Used for Portal discv5 DeleteEnr API.
func (t *UDPv5) DeleteNode(n *enode.Node) {
t.tab.deleteNode(n)
}
// LocalNode returns the current local Node running the
@ -323,29 +334,29 @@ func (t *UDPv5) RandomNodes() enode.Iterator {
// Lookup performs a recursive lookup for the given target.
// It returns the closest nodes to target.
func (t *UDPv5) Lookup(target enode.ID) []*enode.Node {
return t.newLookup(t.closeCtx, target).Run()
return t.newLookup(t.closeCtx, target).run()
}
// lookupRandom looks up a random target.
// This is needed to satisfy the transport interface.
func (t *UDPv5) LookupRandom() []*enode.Node {
return t.newRandomLookup(t.closeCtx).Run()
func (t *UDPv5) lookupRandom() []*enode.Node {
return t.newRandomLookup(t.closeCtx).run()
}
// lookupSelf looks up our own node ID.
// This is needed to satisfy the transport interface.
func (t *UDPv5) LookupSelf() []*enode.Node {
return t.newLookup(t.closeCtx, t.Self().ID()).Run()
func (t *UDPv5) lookupSelf() []*enode.Node {
return t.newLookup(t.closeCtx, t.Self().ID()).run()
}
func (t *UDPv5) newRandomLookup(ctx context.Context) *Lookup {
func (t *UDPv5) newRandomLookup(ctx context.Context) *lookup {
var target enode.ID
crand.Read(target[:])
return t.newLookup(ctx, target)
}
func (t *UDPv5) newLookup(ctx context.Context, target enode.ID) *Lookup {
return NewLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) {
func (t *UDPv5) newLookup(ctx context.Context, target enode.ID) *lookup {
return newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) {
return t.lookupWorker(n, target)
})
}
@ -354,20 +365,20 @@ func (t *UDPv5) newLookup(ctx context.Context, target enode.ID) *Lookup {
func (t *UDPv5) lookupWorker(destNode *enode.Node, target enode.ID) ([]*enode.Node, error) {
var (
dists = LookupDistances(target, destNode.ID())
nodes = NodesByDistance{Target: target}
nodes = nodesByDistance{target: target}
err error
)
var r []*enode.Node
r, err = t.Findnode(destNode, dists)
if errors.Is(err, ErrClosed) {
if errors.Is(err, errClosed) {
return nil, err
}
for _, n := range r {
if n.ID() != t.Self().ID() {
nodes.Push(n, findnodeResultLimit)
nodes.push(n, findnodeResultLimit)
}
}
return nodes.Entries, err
return nodes.entries, err
}
// LookupDistances computes the distance parameter for FINDNODE calls to dest.
@ -388,7 +399,7 @@ func LookupDistances(target, dest enode.ID) (dists []uint) {
}
// ping calls PING on a node and waits for a PONG response.
func (t *UDPv5) Ping(n *enode.Node) (uint64, error) {
func (t *UDPv5) ping(n *enode.Node) (uint64, error) {
pong, err := t.PingWithResp(n)
if err != nil {
return 0, err
@ -475,7 +486,7 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s
return nil, errors.New("not contained in netrestrict list")
}
if node.UDP() <= 1024 {
return nil, ErrLowPort
return nil, errLowPort
}
if distances != nil {
nd := enode.LogDist(c.id, node.ID())
@ -519,7 +530,7 @@ func (t *UDPv5) initCall(c *callV5, responseType byte, packet v5wire.Packet) {
select {
case t.callCh <- c:
case <-t.closeCtx.Done():
c.err <- ErrClosed
c.err <- errClosed
}
}
@ -612,12 +623,12 @@ func (t *UDPv5) dispatch() {
close(t.readNextCh)
for id, queue := range t.callQueue {
for _, c := range queue {
c.err <- ErrClosed
c.err <- errClosed
}
delete(t.callQueue, id)
}
for id, c := range t.activeCallByNode {
c.err <- ErrClosed
c.err <- errClosed
delete(t.activeCallByNode, id)
delete(t.activeCallByAuth, c.nonce)
}
@ -774,7 +785,7 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr netip.AddrPort) error {
}
if fromNode != nil {
// Handshake succeeded, add to table.
t.tab.AddInboundNode(fromNode)
t.tab.addInboundNode(fromNode)
t.putCache(fromAddr.String(), fromNode)
}
if packet.Kind() != v5wire.WhoareyouPacket {
@ -809,7 +820,7 @@ func (t *UDPv5) handleCallResponse(fromID enode.ID, fromAddr netip.AddrPort, p v
// GetNode looks for a node record in table and database.
func (t *UDPv5) GetNode(id enode.ID) *enode.Node {
if n := t.tab.GetNode(id); n != nil {
if n := t.tab.getNode(id); n != nil {
return n
}
if n := t.localNode.Database().Node(id); n != nil {
@ -934,7 +945,7 @@ func (t *UDPv5) collectTableNodes(rip netip.Addr, distances []uint, limit int) [
processed[dist] = struct{}{}
checkLive := !t.tab.cfg.NoFindnodeLivenessCheck
for _, n := range t.tab.AppendBucketNodes(dist, bn[:0], checkLive) {
for _, n := range t.tab.appendBucketNodes(dist, bn[:0], checkLive) {
// Apply some pre-checks to avoid sending invalid nodes.
// Note liveness is checked by appendLiveNodes.
if netutil.CheckRelayAddr(rip, n.IPAddr()) != nil {

View file

@ -143,7 +143,7 @@ func TestUDPv5_unknownPacket(t *testing.T) {
// Make Node known.
n := test.getNode(test.remotekey, test.remoteaddr).Node()
test.table.AddFoundNode(n, false)
test.table.addFoundNode(n, false)
test.packetIn(&v5wire.Unknown{Nonce: nonce})
test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) {
@ -237,7 +237,7 @@ func TestUDPv5_pingCall(t *testing.T) {
// This ping times out.
go func() {
_, err := test.udp.Ping(remote)
_, err := test.udp.ping(remote)
done <- err
}()
test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) {})
@ -247,7 +247,7 @@ func TestUDPv5_pingCall(t *testing.T) {
// This ping works.
go func() {
_, err := test.udp.Ping(remote)
_, err := test.udp.ping(remote)
done <- err
}()
test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) {
@ -259,7 +259,7 @@ func TestUDPv5_pingCall(t *testing.T) {
// This ping gets a reply from the wrong endpoint.
go func() {
_, err := test.udp.Ping(remote)
_, err := test.udp.ping(remote)
done <- err
}()
test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) {
@ -330,11 +330,11 @@ func TestUDPv5_callResend(t *testing.T) {
remote := test.getNode(test.remotekey, test.remoteaddr).Node()
done := make(chan error, 2)
go func() {
_, err := test.udp.Ping(remote)
_, err := test.udp.ping(remote)
done <- err
}()
go func() {
_, err := test.udp.Ping(remote)
_, err := test.udp.ping(remote)
done <- err
}()
@ -367,7 +367,7 @@ func TestUDPv5_multipleHandshakeRounds(t *testing.T) {
remote := test.getNode(test.remotekey, test.remoteaddr).Node()
done := make(chan error, 1)
go func() {
_, err := test.udp.Ping(remote)
_, err := test.udp.ping(remote)
done <- err
}()
@ -817,7 +817,7 @@ func (test *udpV5Test) waitPacketOut(validate interface{}) (closed bool) {
exptype := fn.Type().In(0)
dgram, err := test.pipe.receive()
if err == ErrClosed {
if err == errClosed {
return true
}
if err == errTimeout {