forked from TrueCloudLab/neoneo-go
807309a0de
Simple as that: UnregisteredAndHasNoVotes != !RegisteredAndHasVotes Registered validators should stay in the DB, we might be in the process of updating votes for them and that starts with subtraction.
104 lines
2.9 KiB
Go
104 lines
2.9 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"
|
|
)
|
|
|
|
// Validator holds the state of a validator.
|
|
type Validator struct {
|
|
PublicKey *keys.PublicKey
|
|
Registered bool
|
|
Votes 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)
|
|
}
|
|
|
|
// GetValidatorsWeightedAverage applies weighted filter based on votes for validator and returns number of validators.
|
|
// Get back to it with further investigation in https://github.com/nspcc-dev/neo-go/issues/512.
|
|
func GetValidatorsWeightedAverage(validators []*Validator) int {
|
|
return int(weightedAverage(applyWeightedFilter(validators)))
|
|
}
|
|
|
|
// applyWeightedFilter is an implementation of the filter for validators votes.
|
|
// C# reference https://github.com/neo-project/neo/blob/41caff115c28d6c7665b2a7ac72967e7ce82e921/neo/Helper.cs#L273
|
|
func applyWeightedFilter(validators []*Validator) map[*Validator]float64 {
|
|
var validatorsWithVotes []*Validator
|
|
var amount float64
|
|
|
|
weightedVotes := make(map[*Validator]float64)
|
|
start := 0.25
|
|
end := 0.75
|
|
sum := float64(0)
|
|
current := float64(0)
|
|
|
|
for _, validator := range validators {
|
|
if validator.Votes > util.Fixed8(0) {
|
|
validatorsWithVotes = append(validatorsWithVotes, validator)
|
|
amount += validator.Votes.FloatValue()
|
|
}
|
|
}
|
|
|
|
for _, validator := range validatorsWithVotes {
|
|
if current >= end {
|
|
break
|
|
}
|
|
weight := validator.Votes.FloatValue()
|
|
sum += weight
|
|
old := current
|
|
current = sum / amount
|
|
|
|
if current <= start {
|
|
continue
|
|
}
|
|
|
|
if old < start {
|
|
if current > end {
|
|
weight = (end - start) * amount
|
|
} else {
|
|
weight = (current - start) * amount
|
|
}
|
|
} else if current > end {
|
|
weight = (end - old) * amount
|
|
}
|
|
weightedVotes[validator] = weight
|
|
}
|
|
return weightedVotes
|
|
}
|
|
|
|
func weightedAverage(weightedVotes map[*Validator]float64) float64 {
|
|
sumWeight := float64(0)
|
|
sumValue := float64(0)
|
|
for vState, weight := range weightedVotes {
|
|
sumWeight += weight
|
|
sumValue += vState.Votes.FloatValue() * weight
|
|
}
|
|
if sumValue == 0 || sumWeight == 0 {
|
|
return 0
|
|
}
|
|
return sumValue / sumWeight
|
|
}
|