The core protocol of WoopChain
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
woop/consensus/quorum/verifier.go

90 lines
2.8 KiB

package quorum
import (
"math/big"
"github.com/harmony-one/harmony/consensus/votepower"
bls_cosi "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/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, height uint64) 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, height uint64) bool {
if mask == nil {
return false
}
vp := sv.r.VotePowerByMask(mask)
return vp.GT(sv.threshold(height))
}
func (sv *stakeVerifier) threshold(height uint64) numeric.Dec {
if fixed := tryFixedThreshold(height); fixed != nil {
return *fixed
}
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, height uint64) 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
}