p2p: add a 20 second warmup interval before dialing bootnodes

This commit is contained in:
Péter Szilágyi 2017-04-06 20:05:32 +03:00
parent 6afd4700b7
commit 7965e743aa
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
2 changed files with 30 additions and 4 deletions

View file

@ -38,6 +38,10 @@ const (
// once every few seconds. // once every few seconds.
lookupInterval = 4 * time.Second lookupInterval = 4 * time.Second
// If no peers are found for this amount of time, the initial bootnodes are
// attempted to be connected.
fallbackInterval = 20 * time.Second
// Endpoint resolution is throttled with bounded backoff. // Endpoint resolution is throttled with bounded backoff.
initialResolveDelay = 60 * time.Second initialResolveDelay = 60 * time.Second
maxResolveDelay = time.Hour maxResolveDelay = time.Hour
@ -53,11 +57,13 @@ type dialstate struct {
lookupRunning bool lookupRunning bool
dialing map[discover.NodeID]connFlag dialing map[discover.NodeID]connFlag
bootnodes []*discover.Node // default dials when there are no peers
lookupBuf []*discover.Node // current discovery lookup results lookupBuf []*discover.Node // current discovery lookup results
randomNodes []*discover.Node // filled from Table randomNodes []*discover.Node // filled from Table
static map[discover.NodeID]*dialTask static map[discover.NodeID]*dialTask
hist *dialHistory hist *dialHistory
start time.Time // time when the dialer was first used
bootnodes []*discover.Node // default dials when there are no peers
} }
type discoverTable interface { type discoverTable interface {
@ -133,6 +139,10 @@ func (s *dialstate) removeStatic(n *discover.Node) {
} }
func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now time.Time) []task { func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now time.Time) []task {
if s.start == (time.Time{}) {
s.start = now
}
var newtasks []task var newtasks []task
addDial := func(flag connFlag, n *discover.Node) bool { addDial := func(flag connFlag, n *discover.Node) bool {
if err := s.checkDial(n, peers); err != nil { if err := s.checkDial(n, peers); err != nil {
@ -175,7 +185,7 @@ func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now
// If we don't have any peers whatsoever, try to dial a random bootnode. This // If we don't have any peers whatsoever, try to dial a random bootnode. This
// scenario is useful for the testnet (and private networks) where the discovery // scenario is useful for the testnet (and private networks) where the discovery
// table might be full of mostly bad peers, making it hard to find good ones. // table might be full of mostly bad peers, making it hard to find good ones.
if len(peers) == 0 && len(s.bootnodes) > 0 && needDynDials > 0 { if len(peers) == 0 && len(s.bootnodes) > 0 && needDynDials > 0 && now.Sub(s.start) > fallbackInterval {
bootnode := s.bootnodes[0] bootnode := s.bootnodes[0]
s.bootnodes = append(s.bootnodes[:0], s.bootnodes[1:]...) s.bootnodes = append(s.bootnodes[:0], s.bootnodes[1:]...)
s.bootnodes = append(s.bootnodes, bootnode) s.bootnodes = append(s.bootnodes, bootnode)

View file

@ -236,13 +236,29 @@ func TestDialStateDynDialBootnode(t *testing.T) {
runDialTest(t, dialtest{ runDialTest(t, dialtest{
init: newDialState(nil, bootnodes, table, 5, nil), init: newDialState(nil, bootnodes, table, 5, nil),
rounds: []round{ rounds: []round{
// 1 out of 3 bootnodes are dialed on no peers, 2 other dynamic dials // 2 dynamic dials attempted, bootnodes pending fallback interval
{
new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&discoverTask{},
},
},
// No dials succeed, bootnodes still pending fallback interval
{
done: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
},
},
// No dials succeed, bootnodes still pending fallback interval
{},
// No dials succeed, 2 dynamic dials attempted and 1 bootnode too as fallback interval was reached
{ {
new: []task{ new: []task{
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}}, &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}}, &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}}, &dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
&discoverTask{},
}, },
}, },
// No dials succeed, 2nd bootnode is attempted // No dials succeed, 2nd bootnode is attempted