Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Make voter electing staisfy finality #120

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,13 @@ build-linux:
if [ ! -d $(SRCPATH)/crypto/bls/internal/bls-eth-go-binary ]; then \
mkdir -p $(SRCPATH)/crypto/bls/internal && \
git clone https://github.com/herumi/mcl $(SRCPATH)/crypto/bls/internal/mcl && \
cd $(SRCPATH)/crypto/bls/internal/mcl && \
git reset --hard 10621c6299d3db1c88fd0c27e63654edada08049 && \
git clone https://github.com/herumi/bls $(SRCPATH)/crypto/bls/internal/bls && \
git clone https://github.com/herumi/bls-eth-go-binary $(SRCPATH)/crypto/bls/internal/bls-eth-go-binary; \
git clone https://github.com/herumi/bls-eth-go-binary $(SRCPATH)/crypto/bls/internal/bls-eth-go-binary && \
cd $(SRCPATH)/crypto/bls/internal/bls-eth-go-binary && \
git reset --hard 41fc56eba7b48e65e410ef11cf5042d62e887017 && \
cd $(SRCPATH); \
fi

# Build Linux binary
Expand Down
19 changes: 3 additions & 16 deletions consensus/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1924,8 +1924,7 @@ func proposeBlock(t *testing.T, cs *State, round int, vssMap map[crypto.PubKey]*
func TestStateFullRoundWithSelectedVoter(t *testing.T) {
cs, vss := randStateWithVoterParams(10, &types.VoterParams{
VoterElectionThreshold: 5,
MaxTolerableByzantinePercentage: 20,
ElectionPrecision: 2})
MaxTolerableByzantinePercentage: 20})
vss[0].Height = 1 // this is needed because of `incrementHeight(vss[1:]...)` of randStateWithVoterParams()
vssMap := makeVssMap(vss)
height, round := cs.Height, cs.Round
Expand Down Expand Up @@ -2014,8 +2013,7 @@ func TestStateBadVoterWithSelectedVoter(t *testing.T) {
// making him having 1/3 + 1 voting power of total
cs, vss := randStateWithVoterParams(9, &types.VoterParams{
VoterElectionThreshold: 5,
MaxTolerableByzantinePercentage: 20,
ElectionPrecision: 5})
MaxTolerableByzantinePercentage: 20})

assert.True(t, cs.Voters.Size() >= 4)

Expand Down Expand Up @@ -2154,8 +2152,7 @@ func TestStateAllVoterToSelectedVoter(t *testing.T) {
startValidators := 5
cs, vss := randStateWithVoterParamsWithApp(startValidators, &types.VoterParams{
VoterElectionThreshold: int32(startValidators),
MaxTolerableByzantinePercentage: 20,
ElectionPrecision: 2},
MaxTolerableByzantinePercentage: 20},
"TestStateAllVoterToSelectedVoter")
vss[0].Height = 1 // this is needed because of `incrementHeight(vss[1:]...)` of randStateWithVoterParams()
vssMap := makeVssMap(vss)
Expand Down Expand Up @@ -2208,13 +2205,6 @@ func TestStateAllVoterToSelectedVoter(t *testing.T) {
ensureNewRound(newRoundCh, height+1, 0)

endHeight := 20
voterCount := make([]int, endHeight-1)
for i := 0; i < len(voterCount); i++ {
voterCount[i] = int(types.CalNumOfVoterToElect(int64(startValidators+i), 0.2, 0.99))
if voterCount[i] < startValidators {
voterCount[i] = startValidators
}
}
for i := 2; i <= endHeight; i++ { // height 2~10
height = cs.Height
privPubKey, _ = cs.privValidator.GetPubKey()
Expand All @@ -2229,9 +2219,6 @@ func TestStateAllVoterToSelectedVoter(t *testing.T) {
voters = cs.Voters
voterPrivVals = votersPrivVals(voters, vssMap)

// verify voters count
assert.True(t, voters.Size() == voterCount[i-2])

signAddVotes(cs, types.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(types.BlockPartSizeBytes).Header(),
voterPrivVals...)

Expand Down
4 changes: 2 additions & 2 deletions libs/cmap/cmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ func TestContains(t *testing.T) {
func BenchmarkCMapHas(b *testing.B) {
m := NewCMap()
for i := 0; i < 1000; i++ {
m.Set(string(i), i)
m.Set(string(rune(i)), i)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
m.Has(string(i))
m.Has(string(rune(i)))
}
}
2 changes: 1 addition & 1 deletion libs/pubsub/pubsub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ func benchmarkNClients(n int, b *testing.B) {
s.PublishWithEvents(
ctx,
"Gamora",
map[string][]string{"abci.Account.Owner": {"Ivan"}, "abci.Invoices.Number": {string(i)}},
map[string][]string{"abci.Account.Owner": {"Ivan"}, "abci.Invoices.Number": {string(rune(i))}},
)
}
}
Expand Down
93 changes: 3 additions & 90 deletions libs/rand/sampling.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
type Candidate interface {
Priority() uint64
LessThan(other Candidate) bool
SetWinPoint(winPoint int64)
SetWinPoint(winPoint float64)
}

// Select a specified number of candidates randomly from the candidate set based on each priority. This function is
Expand Down Expand Up @@ -65,20 +65,8 @@ func RandomSamplingWithPriority(
totalPriority, actualTotalPriority, seed, sampleSize, undrawn, undrawn, thresholds[undrawn], len(candidates)))
}

func moveWinnerToLast(candidates []Candidate, winner int) {
winnerCandidate := candidates[winner]
copy(candidates[winner:], candidates[winner+1:])
candidates[len(candidates)-1] = winnerCandidate
}

const uint64Mask = uint64(0x7FFFFFFFFFFFFFFF)

// precisionForSelection is a value to be corrected to increase precision when calculating voting power as an integer.
const precisionForSelection = uint64(1000)

// precisionCorrectionForSelection is a value corrected for accuracy of voting power
const precisionCorrectionForSelection = uint64(1000)

var divider *big.Int

func init() {
Expand All @@ -94,83 +82,8 @@ func randomThreshold(seed *uint64, total uint64) uint64 {
return a.Uint64()
}

func RandomSamplingWithoutReplacement(
seed uint64, candidates []Candidate, minSamplingCount int) (winners []Candidate) {

if len(candidates) < minSamplingCount {
panic(fmt.Sprintf("The number of candidates(%d) cannot be less minSamplingCount %d",
len(candidates), minSamplingCount))
}

totalPriority := sumTotalPriority(candidates)
candidates = sort(candidates)
winnersPriority := uint64(0)
losersPriorities := make([]uint64, len(candidates))
winnerNum := 0
for winnerNum < minSamplingCount {
if totalPriority-winnersPriority == 0 {
// it's possible if some candidates have zero priority
// if then, we can't elect voter any more; we should holt electing not to fall in infinity loop
break
}
threshold := randomThreshold(&seed, totalPriority-winnersPriority)
cumulativePriority := uint64(0)
found := false
for i, candidate := range candidates[:len(candidates)-winnerNum] {
if threshold < cumulativePriority+candidate.Priority() {
moveWinnerToLast(candidates, i)
winnersPriority += candidate.Priority()
losersPriorities[winnerNum] = totalPriority - winnersPriority
winnerNum++
found = true
break
}
cumulativePriority += candidate.Priority()
}

if !found {
panic(fmt.Sprintf("Cannot find random sample. winnerNum=%d, minSamplingCount=%d, "+
"winnersPriority=%d, totalPriority=%d, threshold=%d",
winnerNum, minSamplingCount, winnersPriority, totalPriority, threshold))
}
}
correction := new(big.Int).SetUint64(totalPriority)
correction = correction.Mul(correction, new(big.Int).SetUint64(precisionForSelection))
compensationProportions := make([]big.Int, winnerNum)
for i := winnerNum - 2; i >= 0; i-- {
additionalCompensation := new(big.Int).Div(correction, new(big.Int).SetUint64(losersPriorities[i]))
compensationProportions[i].Add(&compensationProportions[i+1], additionalCompensation)
}
winners = candidates[len(candidates)-winnerNum:]
winPoints := make([]*big.Int, len(winners))
totalWinPoint := new(big.Int)
for i, winner := range winners {
winPoints[i] = new(big.Int).SetUint64(winner.Priority())
winPoints[i].Mul(winPoints[i], &compensationProportions[i])
winPoints[i].Add(winPoints[i], correction)
totalWinPoint.Add(totalWinPoint, winPoints[i])
}
recalibration := new(big.Int).Div(correction, new(big.Int).SetUint64(precisionCorrectionForSelection))
for i, winner := range winners {
winPoint := new(big.Int)
winPoint.Mul(recalibration, winPoints[i])
winPoint.Div(winPoint, totalWinPoint)
winner.SetWinPoint(winPoint.Int64())
}
return winners
}

// sumTotalPriority calculate the sum of all candidate's priority(weight)
// and the sum should be less then or equal to MaxUint64
// TODO We need to check the total weight doesn't over MaxUint64 in somewhere not here.
func sumTotalPriority(candidates []Candidate) (sum uint64) {
for _, candi := range candidates {
sum += candi.Priority()
}
if sum == 0 {
panic("all candidates have zero priority")
}
return
func RandomThreshold(seed *uint64, total uint64) uint64 {
return randomThreshold(seed, total)
}

// SplitMix64
Expand Down
Loading