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.
159 lines
4.4 KiB
159 lines
4.4 KiB
package quorum
|
|
|
|
import (
|
|
"encoding/json"
|
|
"math/big"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
bls_core "github.com/harmony-one/bls/ffi/go/bls"
|
|
"github.com/harmony-one/harmony/crypto/bls"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/harmony-one/harmony/consensus/votepower"
|
|
|
|
bls_cosi "github.com/harmony-one/harmony/crypto/bls"
|
|
"github.com/harmony-one/harmony/internal/utils"
|
|
"github.com/harmony-one/harmony/numeric"
|
|
"github.com/harmony-one/harmony/shard"
|
|
)
|
|
|
|
type uniformVoteWeight struct {
|
|
DependencyInjectionWriter
|
|
DependencyInjectionReader
|
|
SignatureReader
|
|
|
|
lastPowerSignersCountCache map[Phase]int64
|
|
lastParticipantsCount int64
|
|
}
|
|
|
|
// Policy ..
|
|
func (v *uniformVoteWeight) Policy() Policy {
|
|
return SuperMajorityVote
|
|
}
|
|
|
|
// AddNewVote ..
|
|
func (v *uniformVoteWeight) AddNewVote(
|
|
p Phase, pubKeys []*bls_cosi.PublicKeyWrapper,
|
|
sig *bls_core.Sign, headerHash common.Hash,
|
|
height, viewID uint64) (*votepower.Ballot, error) {
|
|
pubKeysBytes := make([]bls.SerializedPublicKey, len(pubKeys))
|
|
for i, pubKey := range pubKeys {
|
|
pubKeysBytes[i] = pubKey.Bytes
|
|
}
|
|
return v.submitVote(p, pubKeysBytes, sig, headerHash, height, viewID)
|
|
}
|
|
|
|
// IsQuorumAchieved ..
|
|
func (v *uniformVoteWeight) IsQuorumAchieved(p Phase) bool {
|
|
r := v.SignersCount(p) >= v.TwoThirdsSignersCount()
|
|
utils.Logger().Info().Str("phase", p.String()).
|
|
Int64("signers-count", v.SignersCount(p)).
|
|
Int64("threshold", v.TwoThirdsSignersCount()).
|
|
Int64("participants", v.ParticipantsCount()).
|
|
Msg("Quorum details")
|
|
return r
|
|
}
|
|
|
|
// IsQuorumAchivedByMask ..
|
|
func (v *uniformVoteWeight) IsQuorumAchievedByMask(mask *bls_cosi.Mask, height uint64) bool {
|
|
if mask == nil {
|
|
return false
|
|
}
|
|
threshold := v.TwoThirdsSignersCount()
|
|
currentTotalPower := utils.CountOneBits(mask.Bitmap)
|
|
if currentTotalPower < threshold {
|
|
const msg = "[IsQuorumAchievedByMask] Not enough voting power: need %+v, have %+v"
|
|
utils.Logger().Warn().Msgf(msg, threshold, currentTotalPower)
|
|
return false
|
|
}
|
|
const msg = "[IsQuorumAchievedByMask] have enough voting power: need %+v, have %+v"
|
|
utils.Logger().Debug().
|
|
Msgf(msg, threshold, currentTotalPower)
|
|
return true
|
|
}
|
|
|
|
// QuorumThreshold ..
|
|
func (v *uniformVoteWeight) QuorumThreshold(height uint64) numeric.Dec {
|
|
if fixed := tryFixedThreshold(height); fixed != nil {
|
|
return *fixed
|
|
}
|
|
return numeric.NewDec(v.TwoThirdsSignersCount())
|
|
}
|
|
|
|
// IsAllSigsCollected ..
|
|
func (v *uniformVoteWeight) IsAllSigsCollected() bool {
|
|
return v.SignersCount(Commit) == v.ParticipantsCount()
|
|
}
|
|
|
|
func (v *uniformVoteWeight) SetVoters(
|
|
subCommittee *shard.Committee, epoch *big.Int,
|
|
) (*TallyResult, error) {
|
|
// NO-OP do not add anything here
|
|
return nil, nil
|
|
}
|
|
|
|
func (v *uniformVoteWeight) String() string {
|
|
s, _ := json.Marshal(v)
|
|
return string(s)
|
|
}
|
|
|
|
func (v *uniformVoteWeight) MarshalJSON() ([]byte, error) {
|
|
type t struct {
|
|
Policy string `json:"policy"`
|
|
Count int `json:"count"`
|
|
Participants []string `json:"committee-members"`
|
|
}
|
|
keysDump := v.Participants()
|
|
keys := make([]string, len(keysDump))
|
|
for i := range keysDump {
|
|
keys[i] = keysDump[i].Bytes.Hex()
|
|
}
|
|
|
|
return json.Marshal(t{v.Policy().String(), len(keys), keys})
|
|
}
|
|
|
|
func (v *uniformVoteWeight) AmIMemberOfCommitee() bool {
|
|
pubKeyFunc := v.MyPublicKey()
|
|
if pubKeyFunc == nil {
|
|
return false
|
|
}
|
|
identity, _ := pubKeyFunc()
|
|
everyone := v.Participants()
|
|
for _, key := range identity {
|
|
for i := range everyone {
|
|
if key.Object.IsEqual(everyone[i].Object) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (v *uniformVoteWeight) ResetPrepareAndCommitVotes() {
|
|
v.lastPowerSignersCountCache[Prepare] = v.SignersCount(Prepare)
|
|
v.lastPowerSignersCountCache[Commit] = v.SignersCount(Commit)
|
|
v.lastParticipantsCount = v.ParticipantsCount()
|
|
|
|
v.reset([]Phase{Prepare, Commit})
|
|
}
|
|
|
|
func (v *uniformVoteWeight) ResetViewChangeVotes() {
|
|
v.lastPowerSignersCountCache[ViewChange] = v.SignersCount(ViewChange)
|
|
v.lastParticipantsCount = v.ParticipantsCount()
|
|
|
|
v.reset([]Phase{ViewChange})
|
|
}
|
|
|
|
func (v *uniformVoteWeight) CurrentTotalPower(p Phase) (*numeric.Dec, error) {
|
|
if v.lastParticipantsCount == 0 {
|
|
return nil, errors.New("uniformVoteWeight not cache last participants count")
|
|
}
|
|
|
|
if lastPowerSignersCount, ok := v.lastPowerSignersCountCache[p]; ok {
|
|
power := numeric.NewDec(lastPowerSignersCount).Quo(numeric.NewDec(v.lastParticipantsCount))
|
|
return &power, nil
|
|
} else {
|
|
return nil, errors.New("uniformVoteWeight not cache this phase")
|
|
}
|
|
}
|
|
|