2019-11-28 16:06:09 +00:00
|
|
|
package state
|
2018-03-21 16:11:04 +00:00
|
|
|
|
|
|
|
import (
|
2019-08-27 13:29:42 +00:00
|
|
|
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
2019-11-11 15:25:28 +00:00
|
|
|
"github.com/CityOfZion/neo-go/pkg/io"
|
2018-03-21 16:11:04 +00:00
|
|
|
"github.com/CityOfZion/neo-go/pkg/util"
|
|
|
|
)
|
|
|
|
|
2020-02-12 17:54:48 +00:00
|
|
|
// MaxValidatorsVoted limits the number of validators that one can vote for.
|
|
|
|
const MaxValidatorsVoted = 1024
|
|
|
|
|
2019-11-28 16:06:09 +00:00
|
|
|
// Validator holds the state of a validator.
|
|
|
|
type Validator struct {
|
2019-08-27 13:29:42 +00:00
|
|
|
PublicKey *keys.PublicKey
|
2018-03-21 16:11:04 +00:00
|
|
|
Registered bool
|
|
|
|
Votes util.Fixed8
|
|
|
|
}
|
2019-11-11 15:25:28 +00:00
|
|
|
|
2020-02-12 17:54:48 +00:00
|
|
|
// ValidatorsCount represents votes with particular number of consensus nodes
|
|
|
|
// for this number to be changeable by the voting system.
|
|
|
|
type ValidatorsCount [MaxValidatorsVoted]util.Fixed8
|
|
|
|
|
2019-11-11 15:25:28 +00:00
|
|
|
// RegisteredAndHasVotes returns true or false whether Validator is registered and has votes.
|
2019-11-28 16:06:09 +00:00
|
|
|
func (vs *Validator) RegisteredAndHasVotes() bool {
|
2019-11-11 15:25:28 +00:00
|
|
|
return vs.Registered && vs.Votes > util.Fixed8(0)
|
|
|
|
}
|
|
|
|
|
2020-02-12 15:10:23 +00:00
|
|
|
// UnregisteredAndHasNoVotes returns true when Validator is not registered and has no votes.
|
|
|
|
func (vs *Validator) UnregisteredAndHasNoVotes() bool {
|
|
|
|
return !vs.Registered && vs.Votes == 0
|
|
|
|
}
|
|
|
|
|
2019-11-28 16:06:09 +00:00
|
|
|
// EncodeBinary encodes Validator to the given BinWriter.
|
|
|
|
func (vs *Validator) EncodeBinary(bw *io.BinWriter) {
|
2019-11-11 15:25:28 +00:00
|
|
|
vs.PublicKey.EncodeBinary(bw)
|
2019-12-12 15:52:23 +00:00
|
|
|
bw.WriteBool(vs.Registered)
|
|
|
|
vs.Votes.EncodeBinary(bw)
|
2019-11-11 15:25:28 +00:00
|
|
|
}
|
|
|
|
|
2019-11-28 16:06:09 +00:00
|
|
|
// DecodeBinary decodes Validator from the given BinReader.
|
|
|
|
func (vs *Validator) DecodeBinary(reader *io.BinReader) {
|
2019-11-11 15:25:28 +00:00
|
|
|
vs.PublicKey = &keys.PublicKey{}
|
|
|
|
vs.PublicKey.DecodeBinary(reader)
|
2019-12-12 15:52:23 +00:00
|
|
|
vs.Registered = reader.ReadBool()
|
|
|
|
vs.Votes.DecodeBinary(reader)
|
2019-11-11 15:25:28 +00:00
|
|
|
}
|
2019-11-18 14:59:43 +00:00
|
|
|
|
2020-02-12 17:54:48 +00:00
|
|
|
// EncodeBinary encodes ValidatorCount to the given BinWriter.
|
|
|
|
func (vc *ValidatorsCount) EncodeBinary(w *io.BinWriter) {
|
|
|
|
for i := range vc {
|
|
|
|
vc[i].EncodeBinary(w)
|
|
|
|
}
|
2019-11-18 14:59:43 +00:00
|
|
|
}
|
|
|
|
|
2020-02-12 17:54:48 +00:00
|
|
|
// DecodeBinary decodes ValidatorCount from the given BinReader.
|
|
|
|
func (vc *ValidatorsCount) DecodeBinary(r *io.BinReader) {
|
|
|
|
for i := range vc {
|
|
|
|
vc[i].DecodeBinary(r)
|
|
|
|
}
|
|
|
|
}
|
2019-11-18 14:59:43 +00:00
|
|
|
|
2020-02-12 17:54:48 +00:00
|
|
|
// 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
|
|
|
|
)
|
2019-11-18 14:59:43 +00:00
|
|
|
|
2020-02-12 17:54:48 +00:00
|
|
|
for i := range vc {
|
|
|
|
overallSum += vc[i]
|
2019-11-18 14:59:43 +00:00
|
|
|
}
|
|
|
|
|
2020-02-12 17:54:48 +00:00
|
|
|
for i := range vc {
|
|
|
|
if slidingRatio >= upperThreshold {
|
2019-11-18 14:59:43 +00:00
|
|
|
break
|
|
|
|
}
|
2020-02-12 17:54:48 +00:00
|
|
|
weight := vc[i]
|
|
|
|
slidingSum += weight
|
|
|
|
previousRatio := slidingRatio
|
|
|
|
slidingRatio = slidingSum.FloatValue() / overallSum.FloatValue()
|
2019-11-18 14:59:43 +00:00
|
|
|
|
2020-02-12 17:54:48 +00:00
|
|
|
if slidingRatio <= lowerThreshold {
|
2019-11-18 14:59:43 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-02-12 17:54:48 +00:00
|
|
|
if previousRatio < lowerThreshold {
|
|
|
|
if slidingRatio > upperThreshold {
|
|
|
|
weight = util.Fixed8FromFloat((upperThreshold - lowerThreshold) * overallSum.FloatValue())
|
2019-11-18 14:59:43 +00:00
|
|
|
} else {
|
2020-02-12 17:54:48 +00:00
|
|
|
weight = util.Fixed8FromFloat((slidingRatio - lowerThreshold) * overallSum.FloatValue())
|
2019-11-18 14:59:43 +00:00
|
|
|
}
|
2020-02-12 17:54:48 +00:00
|
|
|
} else if slidingRatio > upperThreshold {
|
|
|
|
weight = util.Fixed8FromFloat((upperThreshold - previousRatio) * overallSum.FloatValue())
|
2019-11-18 14:59:43 +00:00
|
|
|
}
|
|
|
|
sumWeight += weight
|
2020-02-12 17:54:48 +00:00
|
|
|
// Votes with N values get stored with N-1 index, thus +1 here.
|
|
|
|
sumValue += util.Fixed8(i+1) * weight
|
2019-11-18 14:59:43 +00:00
|
|
|
}
|
|
|
|
if sumValue == 0 || sumWeight == 0 {
|
|
|
|
return 0
|
|
|
|
}
|
2020-02-12 17:54:48 +00:00
|
|
|
return int(sumValue / sumWeight)
|
2019-11-18 14:59:43 +00:00
|
|
|
}
|