OSDN Git Service

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