[quorum] Optimize counting up of already voted voters (#2000)

* [quorum] Optimize counting up of already voted voters

* [quorum] By Mask cache of computation not needed - talked w/Chao
pull/2007/head
Edgar Aroutiounian 5 years ago committed by GitHub
parent c79e8a8687
commit 53a86a144a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      consensus/consensus_service.go
  2. 11
      consensus/quorum/one-node-one-vote.go
  3. 115
      consensus/quorum/one-node-staked-vote.go
  4. 12
      consensus/quorum/quorum.go
  5. 4
      consensus/view_change.go
  6. 4
      consensus/votepower/roster.go

@ -197,7 +197,7 @@ func (consensus *Consensus) ResetState() {
consensus.blockHash = [32]byte{}
consensus.blockHeader = []byte{}
consensus.block = []byte{}
consensus.Decider.Reset([]quorum.Phase{quorum.Prepare, quorum.Commit})
consensus.Decider.ResetPrepareAndCommitVotes()
members := consensus.Decider.Participants()
prepareBitmap, _ := bls_cosi.NewMask(members, nil)
commitBitmap, _ := bls_cosi.NewMask(members, nil)

@ -44,7 +44,8 @@ func (v *uniformVoteWeight) IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool {
return false
}
utils.Logger().Debug().
Msgf("[IsQuorumAchievedByMask] have enough voting power: need %+v, have %+v", threshold, currentTotalPower)
Msgf("[IsQuorumAchievedByMask] have enough voting power: need %+v, have %+v",
threshold, currentTotalPower)
return true
}
@ -130,3 +131,11 @@ func (v *uniformVoteWeight) AmIMemberOfCommitee() bool {
}
return false
}
func (v *uniformVoteWeight) ResetPrepareAndCommitVotes() {
v.reset([]Phase{Prepare, Commit})
}
func (v *uniformVoteWeight) ResetViewChangeVotes() {
v.reset([]Phase{ViewChange})
}

@ -19,9 +19,6 @@ var (
totalShare = numeric.MustNewDecFromStr("1.00")
)
// TODO Test the case where we have 33 nodes, 68/33 will give precision hell and it should trigger
// the 100% mismatch err.
// TallyResult is the result of when we calculate voting power,
// recall that it happens to us at epoch change
type TallyResult struct {
@ -29,12 +26,24 @@ type TallyResult struct {
theirPercent numeric.Dec
}
type voteBox struct {
voters map[shard.BlsPublicKey]struct{}
currentTotal numeric.Dec
}
type box struct {
Prepare *voteBox
Commit *voteBox
ViewChange *voteBox
}
type stakedVoteWeight struct {
SignatureReader
DependencyInjectionWriter
DependencyInjectionReader
slash.ThresholdDecider
roster votepower.Roster
ballotBox box
}
// Policy ..
@ -83,39 +92,56 @@ func (v *stakedVoteWeight) IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool {
func (v *stakedVoteWeight) computeCurrentTotalPower(p Phase) (*numeric.Dec, error) {
w := shard.BlsPublicKey{}
members := v.Participants()
currentTotalPower := numeric.ZeroDec()
ballot := func() *voteBox {
switch p {
case Prepare:
return v.ballotBox.Prepare
case Commit:
return v.ballotBox.Commit
case ViewChange:
return v.ballotBox.ViewChange
default:
// Should not happen
return nil
}
}()
for i := range members {
if v.ReadSignature(p, members[i]) != nil {
w.FromLibBLSPublicKey(members[i])
if _, didVote := ballot.voters[w]; !didVote &&
v.ReadSignature(p, members[i]) != nil {
err := w.FromLibBLSPublicKey(members[i])
if err != nil {
return nil, err
}
currentTotalPower = currentTotalPower.Add(
ballot.currentTotal = ballot.currentTotal.Add(
v.roster.Voters[w].EffectivePercent,
)
ballot.voters[w] = struct{}{}
}
}
return &currentTotalPower, nil
return &ballot.currentTotal, nil
}
// ComputeTotalPowerByMask computes the total power indicated by bitmap mask
func (v *stakedVoteWeight) computeTotalPowerByMask(mask *bls_cosi.Mask) *numeric.Dec {
currentTotalPower := numeric.ZeroDec()
pubKeys := mask.Publics
for _, key := range pubKeys {
w := shard.BlsPublicKey{}
err := w.FromLibBLSPublicKey(key)
currentTotal := numeric.ZeroDec()
for i := range pubKeys {
err := w.FromLibBLSPublicKey(pubKeys[i])
if err != nil {
return nil
}
if enabled, err := mask.KeyEnabled(key); err == nil && enabled {
currentTotalPower = currentTotalPower.Add(
if enabled, err := mask.KeyEnabled(pubKeys[i]); err == nil && enabled {
currentTotal = currentTotal.Add(
v.roster.Voters[w].EffectivePercent,
)
}
}
return &currentTotalPower
return &currentTotal
}
// QuorumThreshold ..
@ -135,43 +161,6 @@ func (v *stakedVoteWeight) IsRewardThresholdAchieved() bool {
return reached.GTE(ninetyPercent)
}
// Award ..
// func (v *stakedVoteWeight) Award(
// Pie numeric.Dec,
// earners []common.Address,
// hook func(earner common.Address, due *big.Int),
// ) numeric.Dec {
// payout := big.NewInt(0)
// last := big.NewInt(0)
// count := big.NewInt(int64(len(earners)))
// // proportional := map[common.Address]numeric.Dec{}
// for _, voter := range v.voters {
// if voter.isHarmonyNode == false {
// // proportional[details.earningAccount] = details.effective.QuoTruncate(
// // v.stakedTotal,
// // )
// }
// }
// // TODO Finish implementing this logic w/Chao
// for i := 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), diff)
// payout = big.NewInt(0).Add(payout, diff)
// last = cur
// }
// return payout
// }
var (
errSumOfVotingPowerNotOne = errors.New("sum of total votes do not sum to 100 percent")
errSumOfOursAndTheirsNotOne = errors.New(
@ -183,7 +172,8 @@ func (v *stakedVoteWeight) SetVoters(
staked shard.SlotList,
) (*TallyResult, error) {
s, _ := v.ShardIDProvider()()
v.Reset([]Phase{Prepare, Commit, ViewChange})
v.ResetPrepareAndCommitVotes()
v.ResetViewChangeVotes()
roster, err := votepower.Compute(staked)
if err != nil {
@ -283,3 +273,26 @@ func (v *stakedVoteWeight) AmIMemberOfCommitee() bool {
_, ok := v.roster.Voters[w]
return ok
}
func newBox() *voteBox {
return &voteBox{map[shard.BlsPublicKey]struct{}{}, numeric.ZeroDec()}
}
func newBallotBox() box {
return box{
Prepare: newBox(),
Commit: newBox(),
ViewChange: newBox(),
}
}
func (v *stakedVoteWeight) ResetPrepareAndCommitVotes() {
v.reset([]Phase{Prepare, Commit})
v.ballotBox.Prepare = newBox()
v.ballotBox.Commit = newBox()
}
func (v *stakedVoteWeight) ResetViewChangeVotes() {
v.reset([]Phase{ViewChange})
v.ballotBox.ViewChange = newBox()
}

@ -76,7 +76,7 @@ type SignatoryTracker interface {
AddSignature(p Phase, PubKey *bls.PublicKey, sig *bls.Sign)
// Caller assumes concurrency protection
SignersCount(Phase) int64
Reset([]Phase)
reset([]Phase)
}
// SignatureReader ..
@ -114,10 +114,12 @@ type Decider interface {
SetVoters(shard.SlotList) (*TallyResult, error)
Policy() Policy
IsQuorumAchieved(Phase) bool
IsQuorumAchievedByMask(*bls_cosi.Mask) bool
IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool
QuorumThreshold() numeric.Dec
AmIMemberOfCommitee() bool
IsRewardThresholdAchieved() bool
ResetPrepareAndCommitVotes()
ResetViewChangeVotes()
}
// These maps represent the signatories (validators), keys are BLS public keys
@ -216,7 +218,7 @@ func (s *cIdentities) AddSignature(p Phase, PubKey *bls.PublicKey, sig *bls.Sign
}
}
func (s *cIdentities) Reset(ps []Phase) {
func (s *cIdentities) reset(ps []Phase) {
for i := range ps {
switch m := map[string]*bls.Sign{}; ps[i] {
case Prepare:
@ -311,13 +313,13 @@ func NewDecider(p Policy) Decider {
c.DependencyInjectionWriter, c.DependencyInjectionReader, c,
}
case SuperMajorityStake:
roster := votepower.NewRoster()
return &stakedVoteWeight{
c.SignatureReader,
c.DependencyInjectionWriter,
c.DependencyInjectionWriter.(DependencyInjectionReader),
c.SignatureReader.(slash.ThresholdDecider),
*roster,
*votepower.NewRoster(),
newBallotBox(),
}
default:
// Should not be possible

@ -94,12 +94,10 @@ func (consensus *Consensus) ResetViewChangeState() {
consensus.bhpSigs = map[uint64]map[string]*bls.Sign{}
consensus.nilSigs = map[uint64]map[string]*bls.Sign{}
consensus.viewIDSigs = map[uint64]map[string]*bls.Sign{}
consensus.bhpBitmap = map[uint64]*bls_cosi.Mask{}
consensus.nilBitmap = map[uint64]*bls_cosi.Mask{}
consensus.viewIDBitmap = map[uint64]*bls_cosi.Mask{}
consensus.Decider.Reset([]quorum.Phase{quorum.ViewChange})
consensus.Decider.ResetViewChangeVotes()
}
func createTimeout() map[TimeoutType]*utils.Timeout {

@ -162,9 +162,6 @@ func Compute(staked shard.SlotList) (*Roster, error) {
theirPercentage = theirPercentage.Add(member.EffectivePercent)
lastStakedVoter = &member
} else { // Our node
// TODO See the todo on where this called in one-node-staked-vote,
// need to have these two values of our
// percentage and hmy percentage sum to 1
member.EffectivePercent = HarmonysShare.Quo(ourCount)
ourPercentage = ourPercentage.Add(member.EffectivePercent)
}
@ -198,7 +195,6 @@ func Compute(staked shard.SlotList) (*Roster, error) {
roster.OurVotingPowerTotalPercentage = ourPercentage
roster.TheirVotingPowerTotalPercentage = theirPercentage
return roster, nil
}

Loading…
Cancel
Save