package state
|
|
|
|
import (
|
|
"io"
|
|
|
|
. "github.com/tendermint/tendermint/binary"
|
|
. "github.com/tendermint/tendermint/common"
|
|
)
|
|
|
|
// Holds state for a Validator at a given height+round.
|
|
// Meant to be discarded every round of the consensus protocol.
|
|
// TODO consider moving this to another common types package.
|
|
type Validator struct {
|
|
Account
|
|
BondHeight uint32
|
|
VotingPower uint64
|
|
Accum int64
|
|
}
|
|
|
|
// Used to persist the state of ConsensusStateControl.
|
|
func ReadValidator(r io.Reader, n *int64, err *error) *Validator {
|
|
return &Validator{
|
|
Account: Account{
|
|
Id: ReadUInt64(r, n, err),
|
|
PubKey: ReadByteSlice(r, n, err),
|
|
},
|
|
BondHeight: ReadUInt32(r, n, err),
|
|
VotingPower: ReadUInt64(r, n, err),
|
|
Accum: ReadInt64(r, n, err),
|
|
}
|
|
}
|
|
|
|
// Creates a new copy of the validator so we can mutate accum.
|
|
func (v *Validator) Copy() *Validator {
|
|
return &Validator{
|
|
Account: v.Account,
|
|
BondHeight: v.BondHeight,
|
|
VotingPower: v.VotingPower,
|
|
Accum: v.Accum,
|
|
}
|
|
}
|
|
|
|
// Used to persist the state of ConsensusStateControl.
|
|
func (v *Validator) WriteTo(w io.Writer) (n int64, err error) {
|
|
WriteUInt64(w, v.Id, &n, &err)
|
|
WriteByteSlice(w, v.PubKey, &n, &err)
|
|
WriteUInt32(w, v.BondHeight, &n, &err)
|
|
WriteUInt64(w, v.VotingPower, &n, &err)
|
|
WriteInt64(w, v.Accum, &n, &err)
|
|
return
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Not goroutine-safe.
|
|
type ValidatorSet struct {
|
|
validators map[uint64]*Validator
|
|
}
|
|
|
|
func NewValidatorSet(validators map[uint64]*Validator) *ValidatorSet {
|
|
if validators == nil {
|
|
validators = make(map[uint64]*Validator)
|
|
}
|
|
return &ValidatorSet{
|
|
validators: validators,
|
|
}
|
|
}
|
|
|
|
func (v *ValidatorSet) IncrementAccum() {
|
|
totalDelta := int64(0)
|
|
for _, validator := range v.validators {
|
|
validator.Accum += int64(validator.VotingPower)
|
|
totalDelta += int64(validator.VotingPower)
|
|
}
|
|
proposer := v.GetProposer()
|
|
proposer.Accum -= totalDelta
|
|
// NOTE: sum(v) here should be zero.
|
|
if true {
|
|
totalAccum := int64(0)
|
|
for _, validator := range v.validators {
|
|
totalAccum += validator.Accum
|
|
}
|
|
if totalAccum != 0 {
|
|
Panicf("Total Accum of validators did not equal 0. Got: ", totalAccum)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (v *ValidatorSet) Copy() *ValidatorSet {
|
|
mapCopy := map[uint64]*Validator{}
|
|
for _, val := range v.validators {
|
|
mapCopy[val.Id] = val.Copy()
|
|
}
|
|
return &ValidatorSet{
|
|
validators: mapCopy,
|
|
}
|
|
}
|
|
|
|
func (v *ValidatorSet) Add(validator *Validator) {
|
|
v.validators[validator.Id] = validator
|
|
}
|
|
|
|
func (v *ValidatorSet) Get(id uint64) *Validator {
|
|
return v.validators[id]
|
|
}
|
|
|
|
func (v *ValidatorSet) Map() map[uint64]*Validator {
|
|
return v.validators
|
|
}
|
|
|
|
func (v *ValidatorSet) Size() int {
|
|
return len(v.validators)
|
|
}
|
|
|
|
// TODO: cache proposer. invalidate upon increment.
|
|
func (v *ValidatorSet) GetProposer() (proposer *Validator) {
|
|
highestAccum := int64(0)
|
|
for _, validator := range v.validators {
|
|
if validator.Accum > highestAccum {
|
|
highestAccum = validator.Accum
|
|
proposer = validator
|
|
} else if validator.Accum == highestAccum {
|
|
if validator.Id < proposer.Id { // Seniority
|
|
proposer = validator
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|