network: add a timer to check for peers

Consider initial connection phase for public networks:
 * simultaneous connections to seeds
 * very quick handshakes
 * got five handshaked peers and some getaddr requests sent
 * but addr replies won't trigger new connections
 * so we can stay with just five connections until any of them breaks or a
   (long) address checking timer fires

This new timers solves the problem, it's adaptive at the same time. If we have
enough peers we won't be waking up often.
This commit is contained in:
Roman Khimov 2022-11-17 17:32:05 +03:00
parent 23f118a1a9
commit 1c7487b8e4

View file

@ -400,10 +400,12 @@ func (s *Server) ConnectedPeers() []string {
func (s *Server) run() { func (s *Server) run() {
var ( var (
peerCheckTime = s.TimePerBlock * peerTimeFactor peerCheckTime = s.TimePerBlock * peerTimeFactor
peerCheckTimeout bool addrCheckTimeout bool
timer = time.NewTimer(peerCheckTime) addrTimer = time.NewTimer(peerCheckTime)
peerTimer = time.NewTimer(s.ProtoTickInterval)
) )
defer timer.Stop() defer addrTimer.Stop()
defer peerTimer.Stop()
go s.runProto() go s.runProto()
for loopCnt := 0; ; loopCnt++ { for loopCnt := 0; ; loopCnt++ {
var ( var (
@ -412,11 +414,15 @@ func (s *Server) run() {
optimalN = s.discovery.GetFanOut() * 2 optimalN = s.discovery.GetFanOut() * 2
// Real number of peers. // Real number of peers.
peerN = s.HandshakedPeersCount() peerN = s.HandshakedPeersCount()
// Timeout value for the next peerTimer, long one by default.
peerT = peerCheckTime
) )
if peerN < s.MinPeers { if peerN < s.MinPeers {
// Starting up or going below the minimum -> quickly get many new peers. // Starting up or going below the minimum -> quickly get many new peers.
s.discovery.RequestRemote(s.AttemptConnPeers) s.discovery.RequestRemote(s.AttemptConnPeers)
// Check/retry new connections soon.
peerT = s.ProtoTickInterval
} else if s.MinPeers > 0 && loopCnt%s.MinPeers == 0 && optimalN > peerN && optimalN < s.MaxPeers && optimalN < netSize { } else if s.MinPeers > 0 && loopCnt%s.MinPeers == 0 && optimalN > peerN && optimalN < s.MaxPeers && optimalN < netSize {
// Having some number of peers, but probably can get some more, the network is big. // Having some number of peers, but probably can get some more, the network is big.
// It also allows to start picking up new peers proactively, before we suddenly have <s.MinPeers of them. // It also allows to start picking up new peers proactively, before we suddenly have <s.MinPeers of them.
@ -427,16 +433,18 @@ func (s *Server) run() {
s.discovery.RequestRemote(connN) s.discovery.RequestRemote(connN)
} }
if peerCheckTimeout || s.discovery.PoolCount() < s.AttemptConnPeers { if addrCheckTimeout || s.discovery.PoolCount() < s.AttemptConnPeers {
s.broadcastHPMessage(NewMessage(CMDGetAddr, payload.NewNullPayload())) s.broadcastHPMessage(NewMessage(CMDGetAddr, payload.NewNullPayload()))
peerCheckTimeout = false addrCheckTimeout = false
} }
select { select {
case <-s.quit: case <-s.quit:
return return
case <-timer.C: case <-addrTimer.C:
peerCheckTimeout = true addrCheckTimeout = true
timer.Reset(peerCheckTime) addrTimer.Reset(peerCheckTime)
case <-peerTimer.C:
peerTimer.Reset(peerT)
case p := <-s.register: case p := <-s.register:
s.lock.Lock() s.lock.Lock()
s.peers[p] = true s.peers[p] = true