forked from TrueCloudLab/neoneo-go
c8a248596e
We were completely lacking ValidatorsCount that is supposed to track the number of votes with particular count of consensus nodes which in theory can change the number of active consensus nodes (if it ever to exceed the number of standby validators), so we were not producing the right count and based on that not giving the right set of validators. Fixes #512.
108 lines
3 KiB
Go
108 lines
3 KiB
Go
package state
|
|
|
|
import (
|
|
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
|
"github.com/CityOfZion/neo-go/pkg/io"
|
|
"github.com/CityOfZion/neo-go/pkg/util"
|
|
)
|
|
|
|
// MaxValidatorsVoted limits the number of validators that one can vote for.
|
|
const MaxValidatorsVoted = 1024
|
|
|
|
// Validator holds the state of a validator.
|
|
type Validator struct {
|
|
PublicKey *keys.PublicKey
|
|
Registered bool
|
|
Votes util.Fixed8
|
|
}
|
|
|
|
// ValidatorsCount represents votes with particular number of consensus nodes
|
|
// for this number to be changeable by the voting system.
|
|
type ValidatorsCount [MaxValidatorsVoted]util.Fixed8
|
|
|
|
// RegisteredAndHasVotes returns true or false whether Validator is registered and has votes.
|
|
func (vs *Validator) RegisteredAndHasVotes() bool {
|
|
return vs.Registered && vs.Votes > util.Fixed8(0)
|
|
}
|
|
|
|
// UnregisteredAndHasNoVotes returns true when Validator is not registered and has no votes.
|
|
func (vs *Validator) UnregisteredAndHasNoVotes() bool {
|
|
return !vs.Registered && vs.Votes == 0
|
|
}
|
|
|
|
// EncodeBinary encodes Validator to the given BinWriter.
|
|
func (vs *Validator) EncodeBinary(bw *io.BinWriter) {
|
|
vs.PublicKey.EncodeBinary(bw)
|
|
bw.WriteBool(vs.Registered)
|
|
vs.Votes.EncodeBinary(bw)
|
|
}
|
|
|
|
// DecodeBinary decodes Validator from the given BinReader.
|
|
func (vs *Validator) DecodeBinary(reader *io.BinReader) {
|
|
vs.PublicKey = &keys.PublicKey{}
|
|
vs.PublicKey.DecodeBinary(reader)
|
|
vs.Registered = reader.ReadBool()
|
|
vs.Votes.DecodeBinary(reader)
|
|
}
|
|
|
|
// EncodeBinary encodes ValidatorCount to the given BinWriter.
|
|
func (vc *ValidatorsCount) EncodeBinary(w *io.BinWriter) {
|
|
for i := range vc {
|
|
vc[i].EncodeBinary(w)
|
|
}
|
|
}
|
|
|
|
// DecodeBinary decodes ValidatorCount from the given BinReader.
|
|
func (vc *ValidatorsCount) DecodeBinary(r *io.BinReader) {
|
|
for i := range vc {
|
|
vc[i].DecodeBinary(r)
|
|
}
|
|
}
|
|
|
|
// GetWeightedAverage returns an average count of validators that's been voted
|
|
// for not counting 1/4 of minimum and maximum numbers.
|
|
func (vc *ValidatorsCount) GetWeightedAverage() int {
|
|
const (
|
|
lowerThreshold = 0.25
|
|
upperThreshold = 0.75
|
|
)
|
|
var (
|
|
sumWeight, sumValue, overallSum, slidingSum util.Fixed8
|
|
slidingRatio float64
|
|
)
|
|
|
|
for i := range vc {
|
|
overallSum += vc[i]
|
|
}
|
|
|
|
for i := range vc {
|
|
if slidingRatio >= upperThreshold {
|
|
break
|
|
}
|
|
weight := vc[i]
|
|
slidingSum += weight
|
|
previousRatio := slidingRatio
|
|
slidingRatio = slidingSum.FloatValue() / overallSum.FloatValue()
|
|
|
|
if slidingRatio <= lowerThreshold {
|
|
continue
|
|
}
|
|
|
|
if previousRatio < lowerThreshold {
|
|
if slidingRatio > upperThreshold {
|
|
weight = util.Fixed8FromFloat((upperThreshold - lowerThreshold) * overallSum.FloatValue())
|
|
} else {
|
|
weight = util.Fixed8FromFloat((slidingRatio - lowerThreshold) * overallSum.FloatValue())
|
|
}
|
|
} else if slidingRatio > upperThreshold {
|
|
weight = util.Fixed8FromFloat((upperThreshold - previousRatio) * overallSum.FloatValue())
|
|
}
|
|
sumWeight += weight
|
|
// Votes with N values get stored with N-1 index, thus +1 here.
|
|
sumValue += util.Fixed8(i+1) * weight
|
|
}
|
|
if sumValue == 0 || sumWeight == 0 {
|
|
return 0
|
|
}
|
|
return int(sumValue / sumWeight)
|
|
}
|