/
validators.go
73 lines (60 loc) · 1.63 KB
/
validators.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
package ibft
import (
"math"
"github.com/esportzvio/frietorchain/types"
"github.com/esportzvio/frietorchain/validators"
)
func CalcMaxFaultyNodes(s validators.Validators) int {
// N -> number of nodes in IBFT
// F -> number of faulty nodes
//
// N = 3F + 1
// => F = (N - 1) / 3
//
// IBFT tolerates 1 failure with 4 nodes
// 4 = 3 * 1 + 1
// To tolerate 2 failures, IBFT requires 7 nodes
// 7 = 3 * 2 + 1
// It should always take the floor of the result
return (s.Len() - 1) / 3
}
type QuorumImplementation func(validators.Validators) int
// LegacyQuorumSize returns the legacy quorum size for the given validator set
func LegacyQuorumSize(set validators.Validators) int {
// According to the IBFT spec, the number of valid messages
// needs to be 2F + 1
return 2*CalcMaxFaultyNodes(set) + 1
}
// OptimalQuorumSize returns the optimal quorum size for the given validator set
func OptimalQuorumSize(set validators.Validators) int {
// if the number of validators is less than 4,
// then the entire set is required
if CalcMaxFaultyNodes(set) == 0 {
/*
N: 1 -> Q: 1
N: 2 -> Q: 2
N: 3 -> Q: 3
*/
return set.Len()
}
// (quorum optimal) Q = ceil(2/3 * N)
return int(math.Ceil(2 * float64(set.Len()) / 3))
}
func CalcProposer(
validators validators.Validators,
round uint64,
lastProposer types.Address,
) validators.Validator {
var seed uint64
if lastProposer == types.ZeroAddress {
seed = round
} else {
offset := int64(0)
if index := validators.Index(lastProposer); index != -1 {
offset = index
}
seed = uint64(offset) + round + 1
}
pick := seed % uint64(validators.Len())
return validators.At(pick)
}