eth/connmanager: randomize peer drop timers

Signed-off-by: Csaba Kiraly <csaba.kiraly@gmail.com>
This commit is contained in:
Csaba Kiraly 2025-03-29 08:07:36 +01:00
parent d46ef40900
commit 8bb7f1ed11

View file

@ -32,10 +32,12 @@ import (
) )
const ( const (
// Interval between peer drop events // Interval between peer drop events (uniform between min and max)
peerDropInterval = 5 * time.Minute peerDropIntervalMin = 3 * time.Minute
// Interval between peer drop events (uniform between min and max)
peerDropIntervalMax = 7 * time.Minute
// Avoid dropping peers for some time after connection // Avoid dropping peers for some time after connection
doNotDropBefore = 2 * peerDropInterval doNotDropBefore = 2 * peerDropIntervalMax
// How close to max should we initiate the drop timer. O should be fine, // How close to max should we initiate the drop timer. O should be fine,
// dropping when no more peers can be added. Larger numbers result in more // dropping when no more peers can be added. Larger numbers result in more
// aggressive drop behavior. // aggressive drop behavior.
@ -106,7 +108,11 @@ func newConnManager(config *connmanConfig) *connManager {
peerEventCh: make(chan *p2p.PeerEvent), peerEventCh: make(chan *p2p.PeerEvent),
shutdownCh: make(chan struct{}), shutdownCh: make(chan struct{}),
} }
cm.log.Info("New Connection Manager", "maxDialPeers", cm.maxDialPeers, "threshold", peerDropThreshold, "interval", peerDropInterval) if peerDropIntervalMin > peerDropIntervalMax {
panic("peerDropIntervalMin duration must be less than or equal to peerDropIntervalMax duration")
}
cm.log.Info("New Connection Manager", "maxDialPeers", cm.maxDialPeers, "threshold", peerDropThreshold,
"intervalMin", peerDropIntervalMin, "intervalMax", peerDropIntervalMax)
return cm return cm
} }
@ -165,6 +171,17 @@ func (cm *connManager) dropRandomPeer(dialed bool) bool {
return false return false
} }
// randomDuration generates a random duration between min and max.
// TODO: maybe we should move this to a common utlity package.
// TODO: panic might be too harsh, maybe return an error.
func randomDuration(rand *mrand.Rand, min, max time.Duration) time.Duration {
if min > max {
panic("min duration must be less than or equal to max duration")
}
nanos := rand.Int63n(max.Nanoseconds()-min.Nanoseconds()) + min.Nanoseconds()
return time.Duration(nanos)
}
// updatePeerDropTimers checks and starts/stops the timer for peer drop. // updatePeerDropTimers checks and starts/stops the timer for peer drop.
func (cm *connManager) updatePeerDropTimers(syncing bool) { func (cm *connManager) updatePeerDropTimers(syncing bool) {
numPeers, numDialed, numInbound := cm.numPeers() numPeers, numDialed, numInbound := cm.numPeers()
@ -175,13 +192,15 @@ func (cm *connManager) updatePeerDropTimers(syncing bool) {
if !syncing { if !syncing {
// If a drop was already scheduled, Schedule does nothing. // If a drop was already scheduled, Schedule does nothing.
if cm.maxDialPeers-numDialed <= peerDropThreshold { if cm.maxDialPeers-numDialed <= peerDropThreshold {
cm.peerDropDialedTimer.Schedule(cm.clock.Now().Add(peerDropInterval)) interval := randomDuration(cm.rand, peerDropIntervalMin, peerDropIntervalMax)
cm.peerDropDialedTimer.Schedule(cm.clock.Now().Add(interval))
} else { } else {
cm.peerDropDialedTimer.Stop() cm.peerDropDialedTimer.Stop()
} }
if cm.maxInboundPeers-numInbound <= peerDropThreshold { if cm.maxInboundPeers-numInbound <= peerDropThreshold {
cm.peerDropInboundTimer.Schedule(cm.clock.Now().Add(peerDropInterval)) interval := randomDuration(cm.rand, peerDropIntervalMin, peerDropIntervalMax)
cm.peerDropInboundTimer.Schedule(cm.clock.Now().Add(interval))
} else { } else {
cm.peerDropInboundTimer.Stop() cm.peerDropInboundTimer.Stop()
} }