|
@ -39,6 +39,8 @@ const ( |
|
|
defaultSeedDisconnectWaitPeriod = 2 * time.Minute // disconnect after this
|
|
|
defaultSeedDisconnectWaitPeriod = 2 * time.Minute // disconnect after this
|
|
|
defaultCrawlPeerInterval = 2 * time.Minute // dont redial for this. TODO: back-off
|
|
|
defaultCrawlPeerInterval = 2 * time.Minute // dont redial for this. TODO: back-off
|
|
|
defaultCrawlPeersPeriod = 30 * time.Second // check some peers every this
|
|
|
defaultCrawlPeersPeriod = 30 * time.Second // check some peers every this
|
|
|
|
|
|
|
|
|
|
|
|
maxAttemptsToDial = 16 // ~ 35h in total (last attempt - 18h sleep)
|
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
// PEXReactor handles PEX (peer exchange) and ensures that an
|
|
|
// PEXReactor handles PEX (peer exchange) and ensures that an
|
|
@ -61,7 +63,7 @@ type PEXReactor struct { |
|
|
requestsSent *cmn.CMap // ID->struct{}: unanswered send requests
|
|
|
requestsSent *cmn.CMap // ID->struct{}: unanswered send requests
|
|
|
lastReceivedRequests *cmn.CMap // ID->time.Time: last time peer requested from us
|
|
|
lastReceivedRequests *cmn.CMap // ID->time.Time: last time peer requested from us
|
|
|
|
|
|
|
|
|
attemptsToDial sync.Map // dial addr -> number of attempts to dial (for exponential backoff)
|
|
|
|
|
|
|
|
|
attemptsToDial sync.Map // dial address (string) -> number of attempts (int) to dial (for exponential backoff)
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// PEXReactorConfig holds reactor specific configuration data.
|
|
|
// PEXReactorConfig holds reactor specific configuration data.
|
|
@ -365,22 +367,25 @@ func (r *PEXReactor) ensurePeers() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (r *PEXReactor) dialPeer(addr *p2p.NetAddress) { |
|
|
func (r *PEXReactor) dialPeer(addr *p2p.NetAddress) { |
|
|
// 1s == (1e9 ns) == (1 Billion ns)
|
|
|
|
|
|
billionNs := float64(time.Second.Nanoseconds()) |
|
|
|
|
|
|
|
|
attempts := r.AttemptsToDial(addr) |
|
|
|
|
|
|
|
|
|
|
|
if attempts > maxAttemptsToDial { |
|
|
|
|
|
r.Logger.Error("Reached max attempts to dial", "addr", addr, "attempts", attempts) |
|
|
|
|
|
r.book.MarkBad(addr) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// exponential backoff if it's not our first attempt to dial given address
|
|
|
// exponential backoff if it's not our first attempt to dial given address
|
|
|
var attempts int |
|
|
|
|
|
if lAttempts, attempted := r.attemptsToDial.Load(addr.DialString()); attempted { |
|
|
|
|
|
attempts = lAttempts.(int) |
|
|
|
|
|
jitterSeconds := time.Duration(rand.Float64() * billionNs) |
|
|
|
|
|
|
|
|
if attempts != 0 { |
|
|
|
|
|
jitterSeconds := time.Duration(rand.Float64() * float64(time.Second)) // 1s == (1e9 ns)
|
|
|
backoffDuration := jitterSeconds + ((1 << uint(attempts)) * time.Second) |
|
|
backoffDuration := jitterSeconds + ((1 << uint(attempts)) * time.Second) |
|
|
r.Logger.Debug(fmt.Sprintf("Dialing %v", addr), "attempts", attempts, "backoff_duration", backoffDuration) |
|
|
|
|
|
|
|
|
r.Logger.Debug("Sleeping before dialing", "addr", addr, "dur", backoffDuration) |
|
|
time.Sleep(backoffDuration) |
|
|
time.Sleep(backoffDuration) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
err := r.Switch.DialPeerWithAddress(addr, false) |
|
|
err := r.Switch.DialPeerWithAddress(addr, false) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
r.Logger.Error("Dialing failed", "err", err) |
|
|
|
|
|
|
|
|
r.Logger.Error("Dialing failed", "addr", addr, "err", err, "attempts", attempts) |
|
|
// TODO: detect more "bad peer" scenarios
|
|
|
// TODO: detect more "bad peer" scenarios
|
|
|
if _, ok := err.(p2p.ErrSwitchAuthenticationFailure); ok { |
|
|
if _, ok := err.(p2p.ErrSwitchAuthenticationFailure); ok { |
|
|
r.book.MarkBad(addr) |
|
|
r.book.MarkBad(addr) |
|
|