OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / connmgr / dynamicbanscore.go
1 // Copyright (c) 2016 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
4
5 package connmgr
6
7 import (
8         "fmt"
9         "math"
10         "sync"
11         "time"
12 )
13
14 const (
15         // Halflife defines the time (in seconds) by which the transient part
16         // of the ban score decays to one half of it's original value.
17         Halflife = 60
18
19         // lambda is the decaying constant.
20         lambda = math.Ln2 / Halflife
21
22         // Lifetime defines the maximum age of the transient part of the ban
23         // score to be considered a non-zero score (in seconds).
24         Lifetime = 1800
25
26         // precomputedLen defines the amount of decay factors (one per second) that
27         // should be precomputed at initialization.
28         precomputedLen = 64
29 )
30
31 // precomputedFactor stores precomputed exponential decay factors for the first
32 // 'precomputedLen' seconds starting from t == 0.
33 var precomputedFactor [precomputedLen]float64
34
35 // init precomputes decay factors.
36 func init() {
37         for i := range precomputedFactor {
38                 precomputedFactor[i] = math.Exp(-1.0 * float64(i) * lambda)
39         }
40 }
41
42 // decayFactor returns the decay factor at t seconds, using precalculated values
43 // if available, or calculating the factor if needed.
44 func decayFactor(t int64) float64 {
45         if t < precomputedLen {
46                 return precomputedFactor[t]
47         }
48         return math.Exp(-1.0 * float64(t) * lambda)
49 }
50
51 // DynamicBanScore provides dynamic ban scores consisting of a persistent and a
52 // decaying component. The persistent score could be utilized to create simple
53 // additive banning policies similar to those found in other bitcoin node
54 // implementations.
55 //
56 // The decaying score enables the creation of evasive logic which handles
57 // misbehaving peers (especially application layer DoS attacks) gracefully
58 // by disconnecting and banning peers attempting various kinds of flooding.
59 // DynamicBanScore allows these two approaches to be used in tandem.
60 //
61 // Zero value: Values of type DynamicBanScore are immediately ready for use upon
62 // declaration.
63 type DynamicBanScore struct {
64         lastUnix   int64
65         transient  float64
66         persistent uint32
67         mtx        sync.Mutex
68 }
69
70 // String returns the ban score as a human-readable string.
71 func (s *DynamicBanScore) String() string {
72         s.mtx.Lock()
73         r := fmt.Sprintf("persistent %v + transient %v at %v = %v as of now",
74                 s.persistent, s.transient, s.lastUnix, s.Int())
75         s.mtx.Unlock()
76         return r
77 }
78
79 // Int returns the current ban score, the sum of the persistent and decaying
80 // scores.
81 //
82 // This function is safe for concurrent access.
83 func (s *DynamicBanScore) Int() uint32 {
84         s.mtx.Lock()
85         r := s.int(time.Now())
86         s.mtx.Unlock()
87         return r
88 }
89
90 // Increase increases both the persistent and decaying scores by the values
91 // passed as parameters. The resulting score is returned.
92 //
93 // This function is safe for concurrent access.
94 func (s *DynamicBanScore) Increase(persistent, transient uint32) uint32 {
95         s.mtx.Lock()
96         r := s.increase(persistent, transient, time.Now())
97         s.mtx.Unlock()
98         return r
99 }
100
101 // Reset set both persistent and decaying scores to zero.
102 //
103 // This function is safe for concurrent access.
104 func (s *DynamicBanScore) Reset() {
105         s.mtx.Lock()
106         s.persistent = 0
107         s.transient = 0
108         s.lastUnix = 0
109         s.mtx.Unlock()
110 }
111
112 // int returns the ban score, the sum of the persistent and decaying scores at a
113 // given point in time.
114 //
115 // This function is not safe for concurrent access. It is intended to be used
116 // internally and during testing.
117 func (s *DynamicBanScore) int(t time.Time) uint32 {
118         dt := t.Unix() - s.lastUnix
119         if s.transient < 1 || dt < 0 || Lifetime < dt {
120                 return s.persistent
121         }
122         return s.persistent + uint32(s.transient*decayFactor(dt))
123 }
124
125 // increase increases the persistent, the decaying or both scores by the values
126 // passed as parameters. The resulting score is calculated as if the action was
127 // carried out at the point time represented by the third parameter. The
128 // resulting score is returned.
129 //
130 // This function is not safe for concurrent access.
131 func (s *DynamicBanScore) increase(persistent, transient uint32, t time.Time) uint32 {
132         s.persistent += persistent
133         tu := t.Unix()
134         dt := tu - s.lastUnix
135
136         if transient > 0 {
137                 if Lifetime < dt {
138                         s.transient = 0
139                 } else if s.transient > 1 && dt > 0 {
140                         s.transient *= decayFactor(dt)
141                 }
142                 s.transient += float64(transient)
143                 s.lastUnix = tu
144         }
145         return s.persistent + uint32(s.transient)
146 }