-
Notifications
You must be signed in to change notification settings - Fork 4
/
vote.go
109 lines (90 loc) · 2.62 KB
/
vote.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package avalanche
// Vote represents a single vote for a target
type Vote struct {
err uint32 // this is called "error" in abc for some reason
hash Hash
}
// NewVote creates a new Vote for the given hash
func NewVote(err uint32, hash Hash) Vote {
return Vote{err, hash}
}
// GetHash returns the target hash
func (v Vote) GetHash() Hash {
return v.hash
}
// GetError returns the vote
func (v Vote) GetError() uint32 {
return v.err
}
// VoteRecord keeps track of a series of votes for a target
type VoteRecord struct {
votes uint8
consider uint8
confidence uint16
}
// NewVoteRecord instantiates a new base record for voting on a target
// `accepted` indicates whether or not the initial state should be acceptance
func NewVoteRecord(accepted bool) *VoteRecord {
return &VoteRecord{confidence: boolToUint16(accepted)}
}
// isAccepted returns whether or not the voted state is acceptance or not
func (vr VoteRecord) isAccepted() bool {
return (vr.confidence & 0x01) == 1
}
// getConfidence returns the confidence in the current state's finalization
func (vr VoteRecord) getConfidence() uint16 {
return vr.confidence >> 1
}
// hasFinalized returns whether or not the record has finalized a state
func (vr VoteRecord) hasFinalized() bool {
return vr.getConfidence() >= AvalancheFinalizationScore
}
// regsiterVote adds a new vote for an item and update confidence accordingly.
// Returns true if the acceptance or finalization state changed.
func (vr *VoteRecord) regsiterVote(err uint32) bool {
vr.votes = (vr.votes << 1) | boolToUint8(err == 0)
vr.consider = (vr.consider << 1) | boolToUint8(int32(err) >= 0)
yes := countBits8(vr.votes&vr.consider&0xff) > 6
// The round is inconclusive
if !yes && countBits8((-vr.votes-1)&vr.consider&0xff) <= 6 {
return false
}
// Vote is conclusive and agrees with our current state
if vr.isAccepted() == yes {
vr.confidence += 2
return vr.getConfidence() == AvalancheFinalizationScore
}
// Vote is conclusive but does not agree with our current state
vr.confidence = boolToUint16(yes)
return true
}
func (vr *VoteRecord) status() (status Status) {
finalized := vr.hasFinalized()
accepted := vr.isAccepted()
switch {
case !finalized && accepted:
status = StatusAccepted
case !finalized && !accepted:
status = StatusRejected
case finalized && accepted:
status = StatusFinalized
case finalized && !accepted:
status = StatusInvalid
}
return status
}
func countBits8(i uint8) (count int) {
for ; i > 0; i &= (i - 1) {
count++
}
return count
}
func boolToUint8(b bool) uint8 {
if b {
return 1
}
return 0
}
func boolToUint16(b bool) uint16 {
return uint16(boolToUint8(b))
}