-
Notifications
You must be signed in to change notification settings - Fork 2
/
verifier.go
86 lines (74 loc) · 2.67 KB
/
verifier.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
package quorum
import (
"math/big"
"github.com/PositionExchange/posichain/consensus/votepower"
bls_cosi "github.com/PositionExchange/posichain/crypto/bls"
"github.com/PositionExchange/posichain/numeric"
"github.com/PositionExchange/posichain/shard"
"github.com/pkg/errors"
)
// Verifier is the interface to verify the whether the quorum is achieved by mask at each epoch.
// TODO: Add some unit tests to make sure Verifier get exactly the same result as Decider
type Verifier interface {
IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool
}
// NewVerifier creates the quorum verifier for the given committee, epoch and whether the scenario
// is staking.
func NewVerifier(committee *shard.Committee, epoch *big.Int, isStaking bool) (Verifier, error) {
if isStaking {
return newStakeVerifier(committee, epoch)
}
return newUniformVerifier(committee)
}
// stakeVerifier is the quorum verifier for staking period. Each validator has staked token as
// a voting power of the final result.
type stakeVerifier struct {
r votepower.Roster
}
// newStakeVerifier creates a stake verifier from the given committee
func newStakeVerifier(committee *shard.Committee, epoch *big.Int) (*stakeVerifier, error) {
r, err := votepower.Compute(committee, epoch)
if err != nil {
return nil, errors.Wrap(err, "compute staking vote-power")
}
return &stakeVerifier{
r: *r,
}, nil
}
// IsQuorumAchievedByMask returns whether the quorum is achieved with the provided mask
func (sv *stakeVerifier) IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool {
if mask == nil {
return false
}
vp := sv.r.VotePowerByMask(mask)
return vp.GT(sv.threshold())
}
func (sv *stakeVerifier) threshold() numeric.Dec {
return twoThird
}
// uniformVerifier is the quorum verifier for non-staking period. All nodes has a uniform voting power.
type uniformVerifier struct {
pubKeyCnt int64
}
func newUniformVerifier(committee *shard.Committee) (*uniformVerifier, error) {
keys, err := committee.BLSPublicKeys()
if err != nil {
return nil, err
}
return &uniformVerifier{
pubKeyCnt: int64(len(keys)),
}, nil
}
// IsQuorumAchievedByMask returns whether the quorum is achieved with the provided mask,
// which is whether more than (2/3+1) nodes is included in mask.
func (uv *uniformVerifier) IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool {
got := int64(len(mask.Publics))
exp := uv.thresholdKeyCount()
// Theoretically speaking, greater or equal will do the work. But current logic is more strict
// without equal, thus conform to current logic implemented.
// (engineImpl.VerifySeal, uniformVoteWeight.IsQuorumAchievedByMask)
return got > exp
}
func (uv *uniformVerifier) thresholdKeyCount() int64 {
return uv.pubKeyCnt*2/3 + 1
}