mirror of
https://github.com/fluencelabs/tendermint
synced 2025-08-01 04:31:57 +00:00
@@ -48,12 +48,17 @@ func NewValidatorSet(vals []*Validator) *ValidatorSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// incrementAccum and update the proposer
|
// incrementAccum and update the proposer
|
||||||
// TODO: mind the overflow when times and votingPower shares too large.
|
|
||||||
func (valSet *ValidatorSet) IncrementAccum(times int) {
|
func (valSet *ValidatorSet) IncrementAccum(times int) {
|
||||||
// Add VotingPower * times to each validator and order into heap.
|
// Add VotingPower * times to each validator and order into heap.
|
||||||
validatorsHeap := cmn.NewHeap()
|
validatorsHeap := cmn.NewHeap()
|
||||||
for _, val := range valSet.Validators {
|
for _, val := range valSet.Validators {
|
||||||
val.Accum += val.VotingPower * int64(times) // TODO: mind overflow
|
res, overflow := signedMulWithOverflowCheck(val.VotingPower, int64(times))
|
||||||
|
// check for overflow both multiplication and sum
|
||||||
|
if !overflow && val.Accum <= mostPositive-res {
|
||||||
|
val.Accum += res
|
||||||
|
} else {
|
||||||
|
val.Accum = mostPositive
|
||||||
|
}
|
||||||
validatorsHeap.Push(val, accumComparable{val})
|
validatorsHeap.Push(val, accumComparable{val})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +68,13 @@ func (valSet *ValidatorSet) IncrementAccum(times int) {
|
|||||||
if i == times-1 {
|
if i == times-1 {
|
||||||
valSet.Proposer = mostest
|
valSet.Proposer = mostest
|
||||||
}
|
}
|
||||||
mostest.Accum -= int64(valSet.TotalVotingPower())
|
|
||||||
|
// mind underflow
|
||||||
|
if mostest.Accum >= mostNegative+valSet.TotalVotingPower() {
|
||||||
|
mostest.Accum -= valSet.TotalVotingPower()
|
||||||
|
} else {
|
||||||
|
mostest.Accum = mostNegative
|
||||||
|
}
|
||||||
validatorsHeap.Update(mostest, accumComparable{mostest})
|
validatorsHeap.Update(mostest, accumComparable{mostest})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +128,13 @@ func (valSet *ValidatorSet) Size() int {
|
|||||||
func (valSet *ValidatorSet) TotalVotingPower() int64 {
|
func (valSet *ValidatorSet) TotalVotingPower() int64 {
|
||||||
if valSet.totalVotingPower == 0 {
|
if valSet.totalVotingPower == 0 {
|
||||||
for _, val := range valSet.Validators {
|
for _, val := range valSet.Validators {
|
||||||
valSet.totalVotingPower += val.VotingPower
|
// mind overflow
|
||||||
|
if valSet.totalVotingPower <= mostPositive-val.VotingPower {
|
||||||
|
valSet.totalVotingPower += val.VotingPower
|
||||||
|
} else {
|
||||||
|
valSet.totalVotingPower = mostPositive
|
||||||
|
return valSet.totalVotingPower
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return valSet.totalVotingPower
|
return valSet.totalVotingPower
|
||||||
@@ -425,3 +442,23 @@ func RandValidatorSet(numValidators int, votingPower int64) (*ValidatorSet, []*P
|
|||||||
sort.Sort(PrivValidatorsByAddress(privValidators))
|
sort.Sort(PrivValidatorsByAddress(privValidators))
|
||||||
return valSet, privValidators
|
return valSet, privValidators
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mostNegative int64 = -mostPositive - 1
|
||||||
|
const mostPositive int64 = 1<<63 - 1
|
||||||
|
|
||||||
|
func signedMulWithOverflowCheck(a, b int64) (int64, bool) {
|
||||||
|
if a == 0 || b == 0 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
if a == 1 {
|
||||||
|
return b, false
|
||||||
|
}
|
||||||
|
if b == 1 {
|
||||||
|
return a, false
|
||||||
|
}
|
||||||
|
if a == mostNegative || b == mostNegative {
|
||||||
|
return -1, true
|
||||||
|
}
|
||||||
|
c := a * b
|
||||||
|
return c, c/b != a
|
||||||
|
}
|
||||||
|
@@ -5,8 +5,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/tendermint/go-crypto"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/tendermint/go-wire"
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
wire "github.com/tendermint/go-wire"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -190,6 +191,45 @@ func TestProposerSelection3(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidatorSetIncrementAccumOverflows(t *testing.T) {
|
||||||
|
// NewValidatorSet calls IncrementAccum(1)
|
||||||
|
vset := NewValidatorSet([]*Validator{
|
||||||
|
// too much voting power
|
||||||
|
0: {Address: []byte("a"), VotingPower: mostPositive, Accum: 0},
|
||||||
|
// too big accum
|
||||||
|
1: {Address: []byte("b"), VotingPower: 10, Accum: mostPositive},
|
||||||
|
// almost too big accum
|
||||||
|
2: {Address: []byte("c"), VotingPower: 10, Accum: mostPositive - 5},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, int64(0), vset.Validators[0].Accum, "0") // because we decrement val with most voting power
|
||||||
|
assert.Equal(t, mostPositive, vset.Validators[1].Accum, "1")
|
||||||
|
assert.Equal(t, mostPositive, vset.Validators[2].Accum, "2")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidatorSetIncrementAccumUnderflows(t *testing.T) {
|
||||||
|
// NewValidatorSet calls IncrementAccum(1)
|
||||||
|
vset := NewValidatorSet([]*Validator{
|
||||||
|
0: {Address: []byte("a"), VotingPower: mostPositive, Accum: mostNegative},
|
||||||
|
1: {Address: []byte("b"), VotingPower: 1, Accum: mostNegative},
|
||||||
|
})
|
||||||
|
|
||||||
|
vset.IncrementAccum(5)
|
||||||
|
|
||||||
|
assert.Equal(t, mostNegative, vset.Validators[0].Accum, "0")
|
||||||
|
assert.Equal(t, mostNegative, vset.Validators[1].Accum, "1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidatorSetTotalVotingPowerOverflows(t *testing.T) {
|
||||||
|
vset := NewValidatorSet([]*Validator{
|
||||||
|
{Address: []byte("a"), VotingPower: mostPositive, Accum: 0},
|
||||||
|
{Address: []byte("b"), VotingPower: mostPositive, Accum: 0},
|
||||||
|
{Address: []byte("c"), VotingPower: mostPositive, Accum: 0},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, mostPositive, vset.TotalVotingPower())
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkValidatorSetCopy(b *testing.B) {
|
func BenchmarkValidatorSetCopy(b *testing.B) {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
vset := NewValidatorSet([]*Validator{})
|
vset := NewValidatorSet([]*Validator{})
|
||||||
|
Reference in New Issue
Block a user