diff --git a/cmd/devp2p/internal/v5test/discv5tests.go b/cmd/devp2p/internal/v5test/discv5tests.go index 9644880a9a..4397c82d02 100644 --- a/cmd/devp2p/internal/v5test/discv5tests.go +++ b/cmd/devp2p/internal/v5test/discv5tests.go @@ -321,6 +321,9 @@ func (s *Suite) TestFindnodeZeroDistance(t *utesting.T) { } func (s *Suite) TestUnsolicitedNodes(t *utesting.T) { + t.Log(`This test sends an unsolicited NODES response advertising a fake node. +The remote node should neither contact the injected node nor return it from later FINDNODE queries.`) + conn, l1 := s.listen1(t) defer conn.close() @@ -339,15 +342,36 @@ func (s *Suite) TestUnsolicitedNodes(t *utesting.T) { RespCount: 1, Nodes: []*enr.Record{fakeConn.localNode.Node().Record()}, } + t.Log("sending unsolicited NODES response with injected node") conn.write(l1, unsolicited, nil) - results, err := conn.findnode(l1, []uint{uint(enode.LogDist(fakeConn.localNode.ID(), s.Dest.ID()))}) - if err != nil { + const contactWindow = 500 * time.Millisecond + buf := make([]byte, 1280) + if err := fakeL.SetReadDeadline(time.Now().Add(contactWindow)); err != nil { t.Fatal(err) } - for _, n := range results { - if n.ID() == fakeConn.localNode.ID() { - t.Fatal("FINDNODE result contains node from unsolicited NODES response") + if n, from, err := fakeL.ReadFrom(buf); err == nil { + t.Fatalf("remote contacted injected node after unsolicited NODES: %d bytes from %v", n, from) + } else if !netutil.IsTimeout(err) { + t.Fatalf("waiting for unexpected contact failed: %v", err) + } + + dist := uint(enode.LogDist(fakeConn.localNode.ID(), s.Dest.ID())) + const maxAttempts = 3 + const retryInterval = 200 * time.Millisecond + for attempt := 1; attempt <= maxAttempts; attempt++ { + results, err := conn.findnode(l1, []uint{dist}) + if err != nil { + t.Fatal(err) + } + for _, n := range results { + if n.ID() == fakeConn.localNode.ID() { + t.Fatalf("attempt %d: FINDNODE result contains node from unsolicited NODES response", attempt) + } + } + t.Logf("attempt %d: injected node not returned in FINDNODE results", attempt) + if attempt < maxAttempts { + time.Sleep(retryInterval) } } }