OSDN Git Service

Fix cast 19-digit uint64 to float64 precision loss (#1640)
authoryahtoo <yahtoo.ma@gmail.com>
Tue, 19 Mar 2019 05:52:29 +0000 (13:52 +0800)
committerPaladz <yzhu101@uottawa.ca>
Tue, 19 Mar 2019 05:52:29 +0000 (13:52 +0800)
var a uint64 = 18446744073709551615
float64(a) = 1.8446744073709552e+19
the precision of the last 2 digits is lost

netsync/peer.go
p2p/trust/banscore.go
p2p/trust/banscore_test.go [new file with mode: 0644]

index 586be2e..5f33616 100644 (file)
@@ -20,7 +20,7 @@ import (
 const (
        maxKnownTxs         = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
        maxKnownBlocks      = 1024  // Maximum block hashes to keep in the known list (prevent DOS)
-       defaultBanThreshold = uint64(100)
+       defaultBanThreshold = uint32(100)
 )
 
 //BasePeer is the interface for connection level peer
@@ -83,7 +83,7 @@ func (p *peer) Height() uint64 {
        return p.height
 }
 
-func (p *peer) addBanScore(persistent, transient uint64, reason string) bool {
+func (p *peer) addBanScore(persistent, transient uint32, reason string) bool {
        score := p.banScore.Increase(persistent, transient)
        if score > defaultBanThreshold {
                log.WithFields(log.Fields{
@@ -330,7 +330,7 @@ func newPeerSet(basePeerSet BasePeerSet) *peerSet {
        }
 }
 
-func (ps *peerSet) addBanScore(peerID string, persistent, transient uint64, reason string) {
+func (ps *peerSet) addBanScore(peerID string, persistent, transient uint32, reason string) {
        ps.mtx.Lock()
        peer := ps.peers[peerID]
        ps.mtx.Unlock()
index cd0b0e8..b5a307b 100644 (file)
@@ -59,7 +59,7 @@ func decayFactor(t int64) float64 {
 type DynamicBanScore struct {
        lastUnix   int64
        transient  float64
-       persistent uint64
+       persistent uint32
        mtx        sync.Mutex
 }
 
@@ -76,7 +76,7 @@ func (s *DynamicBanScore) String() string {
 // scores.
 //
 // This function is safe for concurrent access.
-func (s *DynamicBanScore) Int() uint64 {
+func (s *DynamicBanScore) Int() uint32 {
        s.mtx.Lock()
        r := s.int(time.Now())
        s.mtx.Unlock()
@@ -87,7 +87,7 @@ func (s *DynamicBanScore) Int() uint64 {
 // passed as parameters. The resulting score is returned.
 //
 // This function is safe for concurrent access.
-func (s *DynamicBanScore) Increase(persistent, transient uint64) uint64 {
+func (s *DynamicBanScore) Increase(persistent, transient uint32) uint32 {
        s.mtx.Lock()
        r := s.increase(persistent, transient, time.Now())
        s.mtx.Unlock()
@@ -110,12 +110,12 @@ func (s *DynamicBanScore) Reset() {
 //
 // This function is not safe for concurrent access. It is intended to be used
 // internally and during testing.
-func (s *DynamicBanScore) int(t time.Time) uint64 {
+func (s *DynamicBanScore) int(t time.Time) uint32 {
        dt := t.Unix() - s.lastUnix
        if s.transient < 1 || dt < 0 || Lifetime < dt {
                return s.persistent
        }
-       return s.persistent + uint64(s.transient*decayFactor(dt))
+       return s.persistent + uint32(s.transient*decayFactor(dt))
 }
 
 // increase increases the persistent, the decaying or both scores by the values
@@ -124,7 +124,7 @@ func (s *DynamicBanScore) int(t time.Time) uint64 {
 // resulting score is returned.
 //
 // This function is not safe for concurrent access.
-func (s *DynamicBanScore) increase(persistent, transient uint64, t time.Time) uint64 {
+func (s *DynamicBanScore) increase(persistent, transient uint32, t time.Time) uint32 {
        s.persistent += persistent
        tu := t.Unix()
        dt := tu - s.lastUnix
@@ -138,5 +138,5 @@ func (s *DynamicBanScore) increase(persistent, transient uint64, t time.Time) ui
                s.transient += float64(transient)
                s.lastUnix = tu
        }
-       return s.persistent + uint64(s.transient)
+       return s.persistent + uint32(s.transient)
 }
diff --git a/p2p/trust/banscore_test.go b/p2p/trust/banscore_test.go
new file mode 100644 (file)
index 0000000..2784afa
--- /dev/null
@@ -0,0 +1,79 @@
+package trust
+
+import (
+       "math"
+       "testing"
+       "time"
+)
+
+func TestInt(t *testing.T) {
+       var banScoreIntTests = []struct {
+               bs        DynamicBanScore
+               timeLapse int64
+               wantValue uint32
+       }{
+               {bs: DynamicBanScore{lastUnix: 0, transient: 50, persistent: 50}, timeLapse: 1, wantValue: 99},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 50, persistent: 50}, timeLapse: Lifetime, wantValue: 50},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 50, persistent: 50}, timeLapse: Lifetime + 1, wantValue: 50},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 50, persistent: 50}, timeLapse: -1, wantValue: 50},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 0, persistent: 0}, timeLapse: Lifetime + 1, wantValue: 0},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 0, persistent: math.MaxUint32}, timeLapse: 0, wantValue: math.MaxUint32},
+               {bs: DynamicBanScore{lastUnix: 0, transient: math.MaxUint32, persistent: 0}, timeLapse: Lifetime + 1, wantValue: 0},
+               {bs: DynamicBanScore{lastUnix: 0, transient: math.MaxUint32, persistent: 0}, timeLapse: 60, wantValue: math.MaxUint32 / 2},
+               {bs: DynamicBanScore{lastUnix: 0, transient: math.MaxUint32, persistent: math.MaxUint32}, timeLapse: 0, wantValue: math.MaxUint32 - 1},
+       }
+
+       Init()
+       for i, intTest := range banScoreIntTests {
+               rst := intTest.bs.int(time.Unix(intTest.timeLapse, 0))
+               if rst != intTest.wantValue {
+                       t.Fatal("test ban score int err.", "num:", i, "want:", intTest.wantValue, "got:", rst)
+               }
+       }
+}
+
+func TestIncrease(t *testing.T) {
+       var banScoreIncreaseTests = []struct {
+               bs            DynamicBanScore
+               transientAdd  uint32
+               persistentAdd uint32
+               timeLapse     int64
+               wantValue     uint32
+       }{
+               {bs: DynamicBanScore{lastUnix: 0, transient: 50, persistent: 50}, transientAdd: 50, persistentAdd: 50, timeLapse: 1, wantValue: 199},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 50, persistent: 50}, transientAdd: 50, persistentAdd: 50, timeLapse: Lifetime, wantValue: 150},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 50, persistent: 50}, transientAdd: 50, persistentAdd: 50, timeLapse: Lifetime + 1, wantValue: 150},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 50, persistent: 50}, transientAdd: 50, persistentAdd: 50, timeLapse: -1, wantValue: 200},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 0, persistent: 0}, transientAdd: math.MaxUint32, persistentAdd: 0, timeLapse: 60, wantValue: math.MaxUint32},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 0, persistent: 0}, transientAdd: 0, persistentAdd: math.MaxUint32, timeLapse: 60, wantValue: math.MaxUint32},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 0, persistent: 0}, transientAdd: 0, persistentAdd: math.MaxUint32, timeLapse: Lifetime + 1, wantValue: math.MaxUint32},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 0, persistent: 0}, transientAdd: math.MaxUint32, persistentAdd: 0, timeLapse: Lifetime + 1, wantValue: math.MaxUint32},
+               {bs: DynamicBanScore{lastUnix: 0, transient: math.MaxUint32, persistent: 0}, transientAdd: math.MaxUint32, persistentAdd: 0, timeLapse: Lifetime + 1, wantValue: math.MaxUint32},
+               {bs: DynamicBanScore{lastUnix: 0, transient: math.MaxUint32, persistent: 0}, transientAdd: math.MaxUint32, persistentAdd: 0, timeLapse: 0, wantValue: math.MaxUint32 - 1},
+               {bs: DynamicBanScore{lastUnix: 0, transient: 0, persistent: math.MaxUint32}, transientAdd: math.MaxUint32, persistentAdd: 0, timeLapse: Lifetime + 1, wantValue: math.MaxUint32 - 1},
+       }
+
+       Init()
+       for i, incTest := range banScoreIncreaseTests {
+               rst := incTest.bs.increase(incTest.persistentAdd, incTest.transientAdd, time.Unix(incTest.timeLapse, 0))
+               if rst != incTest.wantValue {
+                       t.Fatal("test ban score int err.", "num:", i, "want:", incTest.wantValue, "got:", rst)
+               }
+       }
+}
+
+func TestReset(t *testing.T) {
+       var bs DynamicBanScore
+       if bs.Int() != 0 {
+               t.Errorf("Initial state is not zero.")
+       }
+       bs.Increase(100, 0)
+       r := bs.Int()
+       if r != 100 {
+               t.Errorf("Unexpected result %d after ban score increase.", r)
+       }
+       bs.Reset()
+       if bs.Int() != 0 {
+               t.Errorf("Failed to reset ban score.")
+       }
+}