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  }