github.com/decred/dcrlnd@v0.7.6/chanfitness/rate_limit.go (about) 1 package chanfitness 2 3 import ( 4 "math" 5 "time" 6 ) 7 8 const ( 9 // rateLimitScale is the number of events we allow per rate limited 10 // tier. Increasing this value makes our rate limiting more lenient, 11 // decreasing it makes us less lenient. 12 rateLimitScale = 200 13 14 // flapCountCooldownFactor is the factor by which we decrease a peer's 15 // flap count if they have not flapped for the cooldown period. 16 flapCountCooldownFactor = 0.95 17 18 // flapCountCooldownPeriod is the amount of time that we require a peer 19 // has not flapped for before we reduce their all time flap count using 20 // our cooldown factor. 21 flapCountCooldownPeriod = time.Hour * 8 22 ) 23 24 // rateLimits is the set of rate limit tiers we apply to our peers based on 25 // their flap count. A peer can be placed in their tier by dividing their flap 26 // count by the rateLimitScale and returning the value at that index. 27 var rateLimits = []time.Duration{ 28 time.Second, 29 time.Second * 5, 30 time.Second * 30, 31 time.Minute, 32 time.Minute * 30, 33 time.Hour, 34 } 35 36 // getRateLimit returns the value of the rate limited tier that we are on based 37 // on current flap count. If a peer's flap count exceeds the top tier, we just 38 // return our highest tier. 39 func getRateLimit(flapCount int) time.Duration { 40 // Figure out the tier we fall into based on our current flap count. 41 tier := flapCount / rateLimitScale 42 43 // If we have more events than our number of tiers, we just use the 44 // last tier 45 tierLen := len(rateLimits) 46 if tier >= tierLen { 47 tier = tierLen - 1 48 } 49 50 return rateLimits[tier] 51 } 52 53 // cooldownFlapCount takes a timestamped flap count, and returns its value 54 // scaled down by our cooldown factor if at least our cooldown period has 55 // elapsed since the peer last flapped. We do this because we store all-time 56 // flap count for peers, and want to allow downgrading of peers that have not 57 // flapped for a long time. 58 func cooldownFlapCount(now time.Time, flapCount int, 59 lastFlap time.Time) int { 60 61 // Calculate time since our last flap, and the number of times we need 62 // to apply our cooldown factor. 63 timeSinceFlap := now.Sub(lastFlap) 64 65 // If our cooldown period has not elapsed yet, we just return our flap 66 // count. We allow fractional cooldown periods once this period has 67 // elapsed, so we do not want to apply a fractional cooldown before the 68 // full cooldown period has elapsed. 69 if timeSinceFlap < flapCountCooldownPeriod { 70 return flapCount 71 } 72 73 // Get the factor by which we need to cooldown our flap count. If 74 // insufficient time has passed to cooldown our flap count. Use use a 75 // float so that we allow fractional cooldown periods. 76 cooldownPeriods := float64(timeSinceFlap) / 77 float64(flapCountCooldownPeriod) 78 79 effectiveFactor := math.Pow(flapCountCooldownFactor, cooldownPeriods) 80 81 return int(float64(flapCount) * effectiveFactor) 82 }