neoneo-go/pkg/core/entities/validator_state.go
Vsevolod Brekelov ec17654986 core: refactoring blockchain state and storage
add dao which takes care about all CRUD operations on storage
remove blockchain state since everything is stored on change
remove storage operations from structs(entities)
move structs to entities package
2019-12-11 13:05:31 +03:00

99 lines
2.7 KiB
Go

package entities
import (
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util"
)
// ValidatorState holds the state of a validator.
type ValidatorState struct {
PublicKey *keys.PublicKey
Registered bool
Votes util.Fixed8
}
// RegisteredAndHasVotes returns true or false whether Validator is registered and has votes.
func (vs *ValidatorState) RegisteredAndHasVotes() bool {
return vs.Registered && vs.Votes > util.Fixed8(0)
}
// EncodeBinary encodes ValidatorState to the given BinWriter.
func (vs *ValidatorState) EncodeBinary(bw *io.BinWriter) {
vs.PublicKey.EncodeBinary(bw)
bw.WriteLE(vs.Registered)
bw.WriteLE(vs.Votes)
}
// DecodeBinary decodes ValidatorState from the given BinReader.
func (vs *ValidatorState) DecodeBinary(reader *io.BinReader) {
vs.PublicKey = &keys.PublicKey{}
vs.PublicKey.DecodeBinary(reader)
reader.ReadLE(&vs.Registered)
reader.ReadLE(&vs.Votes)
}
// 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 []*ValidatorState) 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 []*ValidatorState) map[*ValidatorState]float64 {
var validatorsWithVotes []*ValidatorState
var amount float64
weightedVotes := make(map[*ValidatorState]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[*ValidatorState]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
}