p2p: dial off of iterator

This commit is contained in:
Felix Lange 2019-07-07 23:59:16 +02:00
parent a6b300dd74
commit b317a484d2
4 changed files with 101 additions and 229 deletions

View file

@ -17,12 +17,14 @@
package p2p package p2p
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"net" "net"
"time" "time"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discutil"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/p2p/netutil"
) )
@ -33,12 +35,9 @@ const (
// private networks. // private networks.
dialHistoryExpiration = inboundThrottleTime + 5*time.Second dialHistoryExpiration = inboundThrottleTime + 5*time.Second
// Discovery lookups are throttled and can only run discoveryTimeout = 4 * time.Second
// once every few seconds.
lookupInterval = 4 * time.Second
// If no peers are found for this amount of time, the initial bootnodes are // If no peers are found for this amount of time, the initial bootnodes are dialed.
// attempted to be connected.
fallbackInterval = 20 * time.Second fallbackInterval = 20 * time.Second
// Endpoint resolution is throttled with bounded backoff. // Endpoint resolution is throttled with bounded backoff.
@ -69,7 +68,6 @@ func (t TCPDialer) Dial(dest *enode.Node) (net.Conn, error) {
// of the main loop in Server.run. // of the main loop in Server.run.
type dialstate struct { type dialstate struct {
maxDynDials int maxDynDials int
ntab discoverTable
netrestrict *netutil.Netlist netrestrict *netutil.Netlist
self enode.ID self enode.ID
bootnodes []*enode.Node // default dials when there are no peers bootnodes []*enode.Node // default dials when there are no peers
@ -79,18 +77,10 @@ type dialstate struct {
lookupRunning bool lookupRunning bool
dialing map[enode.ID]connFlag dialing map[enode.ID]connFlag
lookupBuf []*enode.Node // current discovery lookup results lookupBuf []*enode.Node // current discovery lookup results
randomNodes []*enode.Node // filled from Table
static map[enode.ID]*dialTask static map[enode.ID]*dialTask
hist expHeap hist expHeap
} }
type discoverTable interface {
Close()
Resolve(*enode.Node) *enode.Node
LookupRandom() []*enode.Node
ReadRandomNodes([]*enode.Node) int
}
type task interface { type task interface {
Do(*Server) Do(*Server)
} }
@ -108,6 +98,7 @@ type dialTask struct {
// Only one discoverTask is active at any time. // Only one discoverTask is active at any time.
// discoverTask.Do performs a random lookup. // discoverTask.Do performs a random lookup.
type discoverTask struct { type discoverTask struct {
want int
results []*enode.Node results []*enode.Node
} }
@ -117,17 +108,15 @@ type waitExpireTask struct {
time.Duration time.Duration
} }
func newDialState(self enode.ID, ntab discoverTable, maxdyn int, cfg *Config) *dialstate { func newDialState(self enode.ID, maxdyn int, cfg *Config) *dialstate {
s := &dialstate{ s := &dialstate{
maxDynDials: maxdyn, maxDynDials: maxdyn,
ntab: ntab,
self: self, self: self,
netrestrict: cfg.NetRestrict, netrestrict: cfg.NetRestrict,
log: cfg.Logger, log: cfg.Logger,
static: make(map[enode.ID]*dialTask), static: make(map[enode.ID]*dialTask),
dialing: make(map[enode.ID]connFlag), dialing: make(map[enode.ID]connFlag),
bootnodes: make([]*enode.Node, len(cfg.BootstrapNodes)), bootnodes: make([]*enode.Node, len(cfg.BootstrapNodes)),
randomNodes: make([]*enode.Node, maxdyn/2),
} }
copy(s.bootnodes, cfg.BootstrapNodes) copy(s.bootnodes, cfg.BootstrapNodes)
if s.log == nil { if s.log == nil {
@ -206,17 +195,7 @@ func (s *dialstate) newTasks(nRunning int, peers map[enode.ID]*Peer, now time.Ti
needDynDials-- needDynDials--
} }
} }
// Use random nodes from the table for half of the necessary
// dynamic dials.
randomCandidates := needDynDials / 2
if randomCandidates > 0 {
n := s.ntab.ReadRandomNodes(s.randomNodes)
for i := 0; i < randomCandidates && i < n; i++ {
if addDial(dynDialedConn, s.randomNodes[i]) {
needDynDials--
}
}
}
// Create dynamic dials from random lookup results, removing tried // Create dynamic dials from random lookup results, removing tried
// items from the result buffer. // items from the result buffer.
i := 0 i := 0
@ -226,10 +205,11 @@ func (s *dialstate) newTasks(nRunning int, peers map[enode.ID]*Peer, now time.Ti
} }
} }
s.lookupBuf = s.lookupBuf[:copy(s.lookupBuf, s.lookupBuf[i:])] s.lookupBuf = s.lookupBuf[:copy(s.lookupBuf, s.lookupBuf[i:])]
// Launch a discovery lookup if more candidates are needed. // Launch a discovery lookup if more candidates are needed.
if len(s.lookupBuf) < needDynDials && !s.lookupRunning { if len(s.lookupBuf) < needDynDials && !s.lookupRunning {
s.lookupRunning = true s.lookupRunning = true
newtasks = append(newtasks, &discoverTask{}) newtasks = append(newtasks, &discoverTask{want: needDynDials - len(s.lookupBuf)})
} }
// Launch a timer to wait for the next node to expire if all // Launch a timer to wait for the next node to expire if all
@ -351,21 +331,17 @@ func (t *dialTask) String() string {
} }
func (t *discoverTask) Do(srv *Server) { func (t *discoverTask) Do(srv *Server) {
// newTasks generates a lookup task whenever dynamic dials are ctx, cancel := context.WithTimeout(context.Background(), discoveryTimeout)
// necessary. Lookups need to take some time, otherwise the defer cancel()
// event loop spins too fast. t.results = discutil.ReadNodes(ctx, srv.discmix, t.want)
next := srv.lastLookup.Add(lookupInterval)
if now := time.Now(); now.Before(next) {
time.Sleep(next.Sub(now))
}
srv.lastLookup = time.Now()
t.results = srv.ntab.LookupRandom()
} }
func (t *discoverTask) String() string { func (t *discoverTask) String() string {
s := "discovery lookup" s := "discovery lookup"
if len(t.results) > 0 { if len(t.results) > 0 {
s += fmt.Sprintf(" (%d results)", len(t.results)) s += fmt.Sprintf(" (%d results)", len(t.results))
} else {
s += fmt.Sprintf(" (want %d)", t.want)
} }
return s return s
} }

View file

@ -29,7 +29,6 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/enr"
"github.com/ethereum/go-ethereum/p2p/netutil"
) )
func init() { func init() {
@ -81,19 +80,11 @@ func runDialTest(t *testing.T, test dialtest) {
} }
} }
type fakeTable []*enode.Node
func (t fakeTable) Self() *enode.Node { return new(enode.Node) }
func (t fakeTable) Close() {}
func (t fakeTable) LookupRandom() []*enode.Node { return nil }
func (t fakeTable) Resolve(*enode.Node) *enode.Node { return nil }
func (t fakeTable) ReadRandomNodes(buf []*enode.Node) int { return copy(buf, t) }
// This test checks that dynamic dials are launched from discovery results. // This test checks that dynamic dials are launched from discovery results.
func TestDialStateDynDial(t *testing.T) { func TestDialStateDynDial(t *testing.T) {
config := &Config{Logger: testlog.Logger(t, log.LvlTrace)} config := &Config{Logger: testlog.Logger(t, log.LvlTrace)}
runDialTest(t, dialtest{ runDialTest(t, dialtest{
init: newDialState(enode.ID{}, fakeTable{}, 5, config), init: newDialState(enode.ID{}, 5, config),
rounds: []round{ rounds: []round{
// A discovery query is launched. // A discovery query is launched.
{ {
@ -102,7 +93,9 @@ func TestDialStateDynDial(t *testing.T) {
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}}, {rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}}, {rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
}, },
new: []task{&discoverTask{}}, new: []task{
&discoverTask{want: 3},
},
}, },
// Dynamic dials are launched when it completes. // Dynamic dials are launched when it completes.
{ {
@ -188,7 +181,7 @@ func TestDialStateDynDial(t *testing.T) {
}, },
new: []task{ new: []task{
&dialTask{flags: dynDialedConn, dest: newNode(uintID(7), nil)}, &dialTask{flags: dynDialedConn, dest: newNode(uintID(7), nil)},
&discoverTask{}, &discoverTask{want: 2},
}, },
}, },
// Peer 7 is connected, but there still aren't enough dynamic peers // Peer 7 is connected, but there still aren't enough dynamic peers
@ -218,7 +211,7 @@ func TestDialStateDynDial(t *testing.T) {
&discoverTask{}, &discoverTask{},
}, },
new: []task{ new: []task{
&discoverTask{}, &discoverTask{want: 2},
}, },
}, },
}, },
@ -235,29 +228,22 @@ func TestDialStateDynDialBootnode(t *testing.T) {
}, },
Logger: testlog.Logger(t, log.LvlTrace), Logger: testlog.Logger(t, log.LvlTrace),
} }
table := fakeTable{
newNode(uintID(4), nil),
newNode(uintID(5), nil),
newNode(uintID(6), nil),
newNode(uintID(7), nil),
newNode(uintID(8), nil),
}
runDialTest(t, dialtest{ runDialTest(t, dialtest{
init: newDialState(enode.ID{}, table, 5, config), init: newDialState(enode.ID{}, 5, config),
rounds: []round{ rounds: []round{
// 2 dynamic dials attempted, bootnodes pending fallback interval
{ {
new: []task{ new: []task{
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, &discoverTask{want: 5},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
&discoverTask{},
}, },
}, },
// No dials succeed, bootnodes still pending fallback interval
{ {
done: []task{ done: []task{
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)}, &discoverTask{
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)}, results: []*enode.Node{
newNode(uintID(4), nil),
newNode(uintID(5), nil),
},
},
}, },
}, },
// No dials succeed, bootnodes still pending fallback interval // No dials succeed, bootnodes still pending fallback interval
@ -313,101 +299,6 @@ func TestDialStateDynDialBootnode(t *testing.T) {
}) })
} }
func TestDialStateDynDialFromTable(t *testing.T) {
// This table always returns the same random nodes
// in the order given below.
table := fakeTable{
newNode(uintID(1), nil),
newNode(uintID(2), nil),
newNode(uintID(3), nil),
newNode(uintID(4), nil),
newNode(uintID(5), nil),
newNode(uintID(6), nil),
newNode(uintID(7), nil),
newNode(uintID(8), nil),
}
runDialTest(t, dialtest{
init: newDialState(enode.ID{}, table, 10, &Config{Logger: testlog.Logger(t, log.LvlTrace)}),
rounds: []round{
// 5 out of 8 of the nodes returned by ReadRandomNodes are dialed.
{
new: []task{
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
&discoverTask{},
},
},
// Dialing nodes 1,2 succeeds. Dials from the lookup are launched.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
},
done: []task{
&dialTask{flags: dynDialedConn, dest: newNode(uintID(1), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(2), nil)},
&discoverTask{results: []*enode.Node{
newNode(uintID(10), nil),
newNode(uintID(11), nil),
newNode(uintID(12), nil),
}},
},
new: []task{
&dialTask{flags: dynDialedConn, dest: newNode(uintID(10), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(11), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(12), nil)},
&discoverTask{},
},
},
// Dialing nodes 3,4,5 fails. The dials from the lookup succeed.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}},
},
done: []task{
&dialTask{flags: dynDialedConn, dest: newNode(uintID(3), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(4), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(5), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(10), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(11), nil)},
&dialTask{flags: dynDialedConn, dest: newNode(uintID(12), nil)},
},
},
// Waiting for expiry. No waitExpireTask is launched because the
// discovery query is still running.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}},
},
},
// Nodes 3,4 are not tried again because only the first two
// returned random nodes (nodes 1,2) are tried and they're
// already connected.
{
peers: []*Peer{
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(1), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(2), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(10), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(11), nil)}},
{rw: &conn{flags: dynDialedConn, node: newNode(uintID(12), nil)}},
},
},
},
})
}
func newNode(id enode.ID, ip net.IP) *enode.Node { func newNode(id enode.ID, ip net.IP) *enode.Node {
var r enr.Record var r enr.Record
if ip != nil { if ip != nil {
@ -416,35 +307,35 @@ func newNode(id enode.ID, ip net.IP) *enode.Node {
return enode.SignNull(&r, id) return enode.SignNull(&r, id)
} }
// This test checks that candidates that do not match the netrestrict list are not dialed. // // This test checks that candidates that do not match the netrestrict list are not dialed.
func TestDialStateNetRestrict(t *testing.T) { // func TestDialStateNetRestrict(t *testing.T) {
// This table always returns the same random nodes // // This table always returns the same random nodes
// in the order given below. // // in the order given below.
table := fakeTable{ // table := fakeTable{
newNode(uintID(1), net.ParseIP("127.0.0.1")), // newNode(uintID(1), net.ParseIP("127.0.0.1")),
newNode(uintID(2), net.ParseIP("127.0.0.2")), // newNode(uintID(2), net.ParseIP("127.0.0.2")),
newNode(uintID(3), net.ParseIP("127.0.0.3")), // newNode(uintID(3), net.ParseIP("127.0.0.3")),
newNode(uintID(4), net.ParseIP("127.0.0.4")), // newNode(uintID(4), net.ParseIP("127.0.0.4")),
newNode(uintID(5), net.ParseIP("127.0.2.5")), // newNode(uintID(5), net.ParseIP("127.0.2.5")),
newNode(uintID(6), net.ParseIP("127.0.2.6")), // newNode(uintID(6), net.ParseIP("127.0.2.6")),
newNode(uintID(7), net.ParseIP("127.0.2.7")), // newNode(uintID(7), net.ParseIP("127.0.2.7")),
newNode(uintID(8), net.ParseIP("127.0.2.8")), // newNode(uintID(8), net.ParseIP("127.0.2.8")),
} // }
restrict := new(netutil.Netlist) // restrict := new(netutil.Netlist)
restrict.Add("127.0.2.0/24") // restrict.Add("127.0.2.0/24")
//
runDialTest(t, dialtest{ // runDialTest(t, dialtest{
init: newDialState(enode.ID{}, table, 10, &Config{NetRestrict: restrict}), // init: newDialState(enode.ID{}, table, 10, &Config{NetRestrict: restrict}),
rounds: []round{ // rounds: []round{
{ // {
new: []task{ // new: []task{
&dialTask{flags: dynDialedConn, dest: table[4]}, // &dialTask{flags: dynDialedConn, dest: table[4]},
&discoverTask{}, // &discoverTask{},
}, // },
}, // },
}, // },
}) // })
} // }
// This test checks that static dials are launched. // This test checks that static dials are launched.
func TestDialStateStaticDial(t *testing.T) { func TestDialStateStaticDial(t *testing.T) {
@ -459,7 +350,7 @@ func TestDialStateStaticDial(t *testing.T) {
Logger: testlog.Logger(t, log.LvlTrace), Logger: testlog.Logger(t, log.LvlTrace),
} }
runDialTest(t, dialtest{ runDialTest(t, dialtest{
init: newDialState(enode.ID{}, fakeTable{}, 0, config), init: newDialState(enode.ID{}, 0, config),
rounds: []round{ rounds: []round{
// Static dials are launched for the nodes that // Static dials are launched for the nodes that
// aren't yet connected. // aren't yet connected.
@ -544,7 +435,7 @@ func TestDialStateCache(t *testing.T) {
Logger: testlog.Logger(t, log.LvlTrace), Logger: testlog.Logger(t, log.LvlTrace),
} }
runDialTest(t, dialtest{ runDialTest(t, dialtest{
init: newDialState(enode.ID{}, fakeTable{}, 0, config), init: newDialState(enode.ID{}, 0, config),
rounds: []round{ rounds: []round{
// Static dials are launched for the nodes that // Static dials are launched for the nodes that
// aren't yet connected. // aren't yet connected.
@ -612,36 +503,36 @@ func TestDialStateCache(t *testing.T) {
}) })
} }
func TestDialResolve(t *testing.T) { // func TestDialResolve(t *testing.T) {
config := &Config{ // config := &Config{
Logger: testlog.Logger(t, log.LvlTrace), // Logger: testlog.Logger(t, log.LvlTrace),
Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}}, // Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}},
} // }
resolved := newNode(uintID(1), net.IP{127, 0, 55, 234}) // resolved := newNode(uintID(1), net.IP{127, 0, 55, 234})
table := &resolveMock{answer: resolved} // table := &resolveMock{answer: resolved}
state := newDialState(enode.ID{}, table, 0, config) // state := newDialState(enode.ID{}, table, 0, config)
//
// Check that the task is generated with an incomplete ID. // // Check that the task is generated with an incomplete ID.
dest := newNode(uintID(1), nil) // dest := newNode(uintID(1), nil)
state.addStatic(dest) // state.addStatic(dest)
tasks := state.newTasks(0, nil, time.Time{}) // tasks := state.newTasks(0, nil, time.Time{})
if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) { // if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) {
t.Fatalf("expected dial task, got %#v", tasks) // t.Fatalf("expected dial task, got %#v", tasks)
} // }
//
// Now run the task, it should resolve the ID once. // // Now run the task, it should resolve the ID once.
srv := &Server{ntab: table, log: config.Logger, Config: *config} // srv := &Server{ntab: table, log: config.Logger, Config: *config}
tasks[0].Do(srv) // tasks[0].Do(srv)
if !reflect.DeepEqual(table.resolveCalls, []*enode.Node{dest}) { // if !reflect.DeepEqual(table.resolveCalls, []*enode.Node{dest}) {
t.Fatalf("wrong resolve calls, got %v", table.resolveCalls) // t.Fatalf("wrong resolve calls, got %v", table.resolveCalls)
} // }
//
// Report it as done to the dialer, which should update the static node record. // // Report it as done to the dialer, which should update the static node record.
state.taskDone(tasks[0], time.Now()) // state.taskDone(tasks[0], time.Now())
if state.static[uintID(1)].dest != resolved { // if state.static[uintID(1)].dest != resolved {
t.Fatalf("state.dest not updated") // t.Fatalf("state.dest not updated")
} // }
} // }
// compares task lists but doesn't care about the order. // compares task lists but doesn't care about the order.
func sametasks(a, b []task) bool { func sametasks(a, b []task) bool {

View file

@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discutil"
"github.com/ethereum/go-ethereum/p2p/discv5" "github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/enr"
@ -167,16 +168,18 @@ type Server struct {
lock sync.Mutex // protects running lock sync.Mutex // protects running
running bool running bool
nodedb *enode.DB
localnode *enode.LocalNode
ntab discoverTable
listener net.Listener listener net.Listener
ourHandshake *protoHandshake ourHandshake *protoHandshake
DiscV5 *discv5.Network
loopWG sync.WaitGroup // loop, listenLoop loopWG sync.WaitGroup // loop, listenLoop
peerFeed event.Feed peerFeed event.Feed
log log.Logger log log.Logger
nodedb *enode.DB
localnode *enode.LocalNode
ntab *discover.UDPv4
DiscV5 *discv5.Network
discmix *discutil.FairMix
// Channels into the run loop. // Channels into the run loop.
quit chan struct{} quit chan struct{}
addstatic chan *enode.Node addstatic chan *enode.Node
@ -465,7 +468,7 @@ func (srv *Server) Start() (err error) {
} }
dynPeers := srv.maxDialedConns() dynPeers := srv.maxDialedConns()
dialer := newDialState(srv.localnode.ID(), srv.ntab, dynPeers, &srv.Config) dialer := newDialState(srv.localnode.ID(), dynPeers, &srv.Config)
srv.loopWG.Add(1) srv.loopWG.Add(1)
go srv.run(dialer) go srv.run(dialer)
return nil return nil
@ -517,6 +520,8 @@ func (srv *Server) setupLocalNode() error {
} }
func (srv *Server) setupDiscovery() error { func (srv *Server) setupDiscovery() error {
srv.discmix = discutil.NewFairMix(fallbackInterval)
if srv.NoDiscovery && !srv.DiscoveryV5 { if srv.NoDiscovery && !srv.DiscoveryV5 {
return nil return nil
} }
@ -558,7 +563,9 @@ func (srv *Server) setupDiscovery() error {
return err return err
} }
srv.ntab = ntab srv.ntab = ntab
srv.discmix.AddSource(ntab.RandomNodes())
} }
// Discovery V5 // Discovery V5
if srv.DiscoveryV5 { if srv.DiscoveryV5 {
var ntab *discv5.Network var ntab *discv5.Network

View file

@ -234,7 +234,6 @@ func TestServerTaskScheduling(t *testing.T) {
localnode: enode.NewLocalNode(db, newkey()), localnode: enode.NewLocalNode(db, newkey()),
nodedb: db, nodedb: db,
quit: make(chan struct{}), quit: make(chan struct{}),
ntab: fakeTable{},
running: true, running: true,
log: log.New(), log: log.New(),
} }
@ -282,7 +281,6 @@ func TestServerManyTasks(t *testing.T) {
quit: make(chan struct{}), quit: make(chan struct{}),
localnode: enode.NewLocalNode(db, newkey()), localnode: enode.NewLocalNode(db, newkey()),
nodedb: db, nodedb: db,
ntab: fakeTable{},
running: true, running: true,
log: log.New(), log: log.New(),
} }