|
|
|
package quorum
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"math/big"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/harmony-one/bls/ffi/go/bls"
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
// Policy ..
|
|
|
|
func (v *uniformVoteWeight) Policy() Policy {
|
|
|
|
return SuperMajorityVote
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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, debug bool) bool {
|
|
|
|
threshold := v.TwoThirdsSignersCount()
|
|
|
|
currentTotalPower := utils.CountOneBits(mask.Bitmap)
|
|
|
|
if currentTotalPower < threshold {
|
|
|
|
utils.Logger().Warn().
|
|
|
|
Msgf("[IsQuorumAchievedByMask] Not enough voting power: need %+v, have %+v", threshold, currentTotalPower)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
utils.Logger().Debug().
|
|
|
|
Msgf("[IsQuorumAchievedByMask] have enough voting power: need %+v, have %+v",
|
|
|
|
threshold, currentTotalPower)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// QuorumThreshold ..
|
|
|
|
func (v *uniformVoteWeight) QuorumThreshold() numeric.Dec {
|
|
|
|
return numeric.NewDec(v.TwoThirdsSignersCount())
|
|
|
|
}
|
|
|
|
|
|
|
|
// RewardThreshold ..
|
|
|
|
func (v *uniformVoteWeight) IsRewardThresholdAchieved() bool {
|
|
|
|
return v.SignersCount(Commit) >= (v.ParticipantsCount() * 9 / 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *uniformVoteWeight) SetVoters(
|
|
|
|
shard.SlotList, bool,
|
|
|
|
) (*TallyResult, error) {
|
|
|
|
// NO-OP do not add anything here
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToggleActive for uniform vote is a no-op, always says that voter is active
|
|
|
|
func (v *uniformVoteWeight) ToggleActive(*bls.PublicKey) bool {
|
|
|
|
// NO-OP do not add anything here
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Award ..
|
|
|
|
func (v *uniformVoteWeight) Award(
|
|
|
|
// Here hook is the callback which gets the amount the earner is due in just reward
|
|
|
|
// up to the hook to do side-effects like write the statedb
|
|
|
|
Pie *big.Int,
|
|
|
|
earners shard.SlotList,
|
|
|
|
hook func(earner common.Address, due *big.Int),
|
|
|
|
) *big.Int {
|
|
|
|
payout := big.NewInt(0)
|
|
|
|
last := big.NewInt(0)
|
|
|
|
count := big.NewInt(int64(len(earners)))
|
|
|
|
|
|
|
|
for i, account := range earners {
|
|
|
|
cur := big.NewInt(0)
|
|
|
|
cur.Mul(Pie, big.NewInt(int64(i+1))).Div(cur, count)
|
|
|
|
diff := big.NewInt(0).Sub(cur, last)
|
|
|
|
hook(common.Address(account.EcdsaAddress), diff)
|
|
|
|
payout = big.NewInt(0).Add(payout, diff)
|
|
|
|
last = cur
|
|
|
|
}
|
|
|
|
|
|
|
|
return payout
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *uniformVoteWeight) JSON() string {
|
|
|
|
s, _ := v.ShardIDProvider()()
|
|
|
|
|
|
|
|
type t struct {
|
|
|
|
Policy string `json"policy"`
|
|
|
|
ShardID uint32 `json:"shard-id"`
|
|
|
|
Count int `json:"count"`
|
|
|
|
Participants []string `json:"committee-members"`
|
|
|
|
}
|
|
|
|
|
|
|
|
members := v.DumpParticipants()
|
|
|
|
b1, _ := json.Marshal(t{v.Policy().String(), s, len(members), members})
|
|
|
|
return string(b1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *uniformVoteWeight) AmIMemberOfCommitee() bool {
|
|
|
|
pubKeyFunc := v.MyPublicKey()
|
|
|
|
if pubKeyFunc == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
identity, _ := pubKeyFunc()
|
|
|
|
everyone := v.DumpParticipants()
|
|
|
|
myVoterID := identity.SerializeToHexStr()
|
|
|
|
for i := range everyone {
|
|
|
|
if everyone[i] == myVoterID {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *uniformVoteWeight) ResetPrepareAndCommitVotes() {
|
|
|
|
v.reset([]Phase{Prepare, Commit})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *uniformVoteWeight) ResetViewChangeVotes() {
|
|
|
|
v.reset([]Phase{ViewChange})
|
|
|
|
}
|