[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.blockHash = [32]byte{}
consensus.blockHeader = []byte{} consensus.blockHeader = []byte{}
consensus.block = []byte{} consensus.block = []byte{}
consensus.Decider.Reset([]quorum.Phase{quorum.Prepare, quorum.Commit}) consensus.Decider.ResetPrepareAndCommitVotes()
members := consensus.Decider.Participants() members := consensus.Decider.Participants()
prepareBitmap, _ := bls_cosi.NewMask(members, nil) prepareBitmap, _ := bls_cosi.NewMask(members, nil)
commitBitmap, _ := 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 return false
} }
utils.Logger().Debug(). 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 return true
} }
@ -130,3 +131,11 @@ func (v *uniformVoteWeight) AmIMemberOfCommitee() bool {
} }
return false 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") 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, // TallyResult is the result of when we calculate voting power,
// recall that it happens to us at epoch change // recall that it happens to us at epoch change
type TallyResult struct { type TallyResult struct {
@ -29,12 +26,24 @@ type TallyResult struct {
theirPercent numeric.Dec 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 { type stakedVoteWeight struct {
SignatureReader SignatureReader
DependencyInjectionWriter DependencyInjectionWriter
DependencyInjectionReader DependencyInjectionReader
slash.ThresholdDecider slash.ThresholdDecider
roster votepower.Roster roster votepower.Roster
ballotBox box
} }
// Policy .. // Policy ..
@ -83,39 +92,56 @@ func (v *stakedVoteWeight) IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool {
func (v *stakedVoteWeight) computeCurrentTotalPower(p Phase) (*numeric.Dec, error) { func (v *stakedVoteWeight) computeCurrentTotalPower(p Phase) (*numeric.Dec, error) {
w := shard.BlsPublicKey{} w := shard.BlsPublicKey{}
members := v.Participants() 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 { 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]) err := w.FromLibBLSPublicKey(members[i])
if err != nil { if err != nil {
return nil, err return nil, err
} }
currentTotalPower = currentTotalPower.Add( ballot.currentTotal = ballot.currentTotal.Add(
v.roster.Voters[w].EffectivePercent, 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 // ComputeTotalPowerByMask computes the total power indicated by bitmap mask
func (v *stakedVoteWeight) computeTotalPowerByMask(mask *bls_cosi.Mask) *numeric.Dec { func (v *stakedVoteWeight) computeTotalPowerByMask(mask *bls_cosi.Mask) *numeric.Dec {
currentTotalPower := numeric.ZeroDec()
pubKeys := mask.Publics pubKeys := mask.Publics
for _, key := range pubKeys {
w := shard.BlsPublicKey{} w := shard.BlsPublicKey{}
err := w.FromLibBLSPublicKey(key) currentTotal := numeric.ZeroDec()
for i := range pubKeys {
err := w.FromLibBLSPublicKey(pubKeys[i])
if err != nil { if err != nil {
return nil return nil
} }
if enabled, err := mask.KeyEnabled(key); err == nil && enabled { if enabled, err := mask.KeyEnabled(pubKeys[i]); err == nil && enabled {
currentTotalPower = currentTotalPower.Add( currentTotal = currentTotal.Add(
v.roster.Voters[w].EffectivePercent, v.roster.Voters[w].EffectivePercent,
) )
} }
} }
return &currentTotalPower return &currentTotal
} }
// QuorumThreshold .. // QuorumThreshold ..
@ -135,43 +161,6 @@ func (v *stakedVoteWeight) IsRewardThresholdAchieved() bool {
return reached.GTE(ninetyPercent) 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 ( var (
errSumOfVotingPowerNotOne = errors.New("sum of total votes do not sum to 100 percent") errSumOfVotingPowerNotOne = errors.New("sum of total votes do not sum to 100 percent")
errSumOfOursAndTheirsNotOne = errors.New( errSumOfOursAndTheirsNotOne = errors.New(
@ -183,7 +172,8 @@ func (v *stakedVoteWeight) SetVoters(
staked shard.SlotList, staked shard.SlotList,
) (*TallyResult, error) { ) (*TallyResult, error) {
s, _ := v.ShardIDProvider()() s, _ := v.ShardIDProvider()()
v.Reset([]Phase{Prepare, Commit, ViewChange}) v.ResetPrepareAndCommitVotes()
v.ResetViewChangeVotes()
roster, err := votepower.Compute(staked) roster, err := votepower.Compute(staked)
if err != nil { if err != nil {
@ -283,3 +273,26 @@ func (v *stakedVoteWeight) AmIMemberOfCommitee() bool {
_, ok := v.roster.Voters[w] _, ok := v.roster.Voters[w]
return ok 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) AddSignature(p Phase, PubKey *bls.PublicKey, sig *bls.Sign)
// Caller assumes concurrency protection // Caller assumes concurrency protection
SignersCount(Phase) int64 SignersCount(Phase) int64
Reset([]Phase) reset([]Phase)
} }
// SignatureReader .. // SignatureReader ..
@ -114,10 +114,12 @@ type Decider interface {
SetVoters(shard.SlotList) (*TallyResult, error) SetVoters(shard.SlotList) (*TallyResult, error)
Policy() Policy Policy() Policy
IsQuorumAchieved(Phase) bool IsQuorumAchieved(Phase) bool
IsQuorumAchievedByMask(*bls_cosi.Mask) bool IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool
QuorumThreshold() numeric.Dec QuorumThreshold() numeric.Dec
AmIMemberOfCommitee() bool AmIMemberOfCommitee() bool
IsRewardThresholdAchieved() bool IsRewardThresholdAchieved() bool
ResetPrepareAndCommitVotes()
ResetViewChangeVotes()
} }
// These maps represent the signatories (validators), keys are BLS public keys // 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 { for i := range ps {
switch m := map[string]*bls.Sign{}; ps[i] { switch m := map[string]*bls.Sign{}; ps[i] {
case Prepare: case Prepare:
@ -311,13 +313,13 @@ func NewDecider(p Policy) Decider {
c.DependencyInjectionWriter, c.DependencyInjectionReader, c, c.DependencyInjectionWriter, c.DependencyInjectionReader, c,
} }
case SuperMajorityStake: case SuperMajorityStake:
roster := votepower.NewRoster()
return &stakedVoteWeight{ return &stakedVoteWeight{
c.SignatureReader, c.SignatureReader,
c.DependencyInjectionWriter, c.DependencyInjectionWriter,
c.DependencyInjectionWriter.(DependencyInjectionReader), c.DependencyInjectionWriter.(DependencyInjectionReader),
c.SignatureReader.(slash.ThresholdDecider), c.SignatureReader.(slash.ThresholdDecider),
*roster, *votepower.NewRoster(),
newBallotBox(),
} }
default: default:
// Should not be possible // Should not be possible

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

@ -162,9 +162,6 @@ func Compute(staked shard.SlotList) (*Roster, error) {
theirPercentage = theirPercentage.Add(member.EffectivePercent) theirPercentage = theirPercentage.Add(member.EffectivePercent)
lastStakedVoter = &member lastStakedVoter = &member
} else { // Our node } 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) member.EffectivePercent = HarmonysShare.Quo(ourCount)
ourPercentage = ourPercentage.Add(member.EffectivePercent) ourPercentage = ourPercentage.Add(member.EffectivePercent)
} }
@ -198,7 +195,6 @@ func Compute(staked shard.SlotList) (*Roster, error) {
roster.OurVotingPowerTotalPercentage = ourPercentage roster.OurVotingPowerTotalPercentage = ourPercentage
roster.TheirVotingPowerTotalPercentage = theirPercentage roster.TheirVotingPowerTotalPercentage = theirPercentage
return roster, nil return roster, nil
} }

Loading…
Cancel
Save