tendermint/types/validator_set.go

428 lines
13 KiB
Go
Raw Normal View History

package types
2014-10-11 21:27:58 -07:00
import (
"bytes"
2014-10-18 01:42:33 -07:00
"fmt"
"sort"
2014-10-18 01:42:33 -07:00
"strings"
2014-10-11 21:27:58 -07:00
"github.com/pkg/errors"
2017-04-21 15:12:54 -07:00
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/merkle"
2014-10-11 21:27:58 -07:00
)
// ValidatorSet represent a set of *Validator at a given height.
// The validators can be fetched by address or index.
2014-12-23 23:20:49 -08:00
// The index is in order of .Address, so the indices are fixed
// for all rounds of a given blockchain height.
// On the other hand, the .AccumPower of each validator and
// the designated .GetProposer() of a set changes every round,
// upon calling .IncrementAccum().
// NOTE: Not goroutine-safe.
// NOTE: All get/set to validators should copy the value for safety.
// TODO: consider validator Accum overflow
2014-10-11 21:27:58 -07:00
type ValidatorSet struct {
2017-05-14 10:10:58 -07:00
// NOTE: persisted via reflect, must be exported.
2017-05-12 13:22:22 -07:00
Validators []*Validator `json:"validators"`
Proposer *Validator `json:"proposer"`
2014-12-17 01:37:13 -08:00
// cached (unexported)
totalVotingPower int64
2014-10-11 21:27:58 -07:00
}
func NewValidatorSet(vals []*Validator) *ValidatorSet {
validators := make([]*Validator, len(vals))
for i, val := range vals {
validators[i] = val.Copy()
2014-10-11 21:27:58 -07:00
}
sort.Sort(ValidatorsByAddress(validators))
2015-10-28 10:49:35 -07:00
vs := &ValidatorSet{
2014-12-17 01:37:13 -08:00
Validators: validators,
2014-10-11 21:27:58 -07:00
}
2015-10-28 10:49:35 -07:00
if vals != nil {
vs.IncrementAccum(1)
}
2015-10-28 10:49:35 -07:00
return vs
2014-10-11 21:27:58 -07:00
}
// incrementAccum and update the proposer
// TODO: mind the overflow when times and votingPower shares too large.
func (valSet *ValidatorSet) IncrementAccum(times int) {
// Add VotingPower * times to each validator and order into heap.
validatorsHeap := cmn.NewHeap()
2014-12-17 01:37:13 -08:00
for _, val := range valSet.Validators {
val.Accum += val.VotingPower * int64(times) // TODO: mind overflow
validatorsHeap.Push(val, accumComparable{val})
}
// Decrement the validator with most accum times times
for i := 0; i < times; i++ {
mostest := validatorsHeap.Peek().(*Validator)
if i == times-1 {
valSet.Proposer = mostest
}
mostest.Accum -= int64(valSet.TotalVotingPower())
validatorsHeap.Update(mostest, accumComparable{mostest})
}
2014-10-11 21:27:58 -07:00
}
func (valSet *ValidatorSet) Copy() *ValidatorSet {
2014-12-17 01:37:13 -08:00
validators := make([]*Validator, len(valSet.Validators))
for i, val := range valSet.Validators {
// NOTE: must copy, since IncrementAccum updates in place.
validators[i] = val.Copy()
}
2014-10-11 21:27:58 -07:00
return &ValidatorSet{
2014-12-17 01:37:13 -08:00
Validators: validators,
Proposer: valSet.Proposer,
totalVotingPower: valSet.totalVotingPower,
2014-10-11 21:27:58 -07:00
}
}
func (valSet *ValidatorSet) HasAddress(address []byte) bool {
2014-12-17 01:37:13 -08:00
idx := sort.Search(len(valSet.Validators), func(i int) bool {
return bytes.Compare(address, valSet.Validators[i].Address) <= 0
})
return idx != len(valSet.Validators) && bytes.Equal(valSet.Validators[idx].Address, address)
2014-10-11 21:27:58 -07:00
}
func (valSet *ValidatorSet) GetByAddress(address []byte) (index int, val *Validator) {
2014-12-17 01:37:13 -08:00
idx := sort.Search(len(valSet.Validators), func(i int) bool {
return bytes.Compare(address, valSet.Validators[i].Address) <= 0
})
if idx != len(valSet.Validators) && bytes.Equal(valSet.Validators[idx].Address, address) {
return idx, valSet.Validators[idx].Copy()
} else {
return 0, nil
}
}
// GetByIndex returns the validator by index.
2017-10-31 12:32:07 -07:00
// It returns nil values if index < 0 or
// index >= len(ValidatorSet.Validators)
func (valSet *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator) {
2017-10-31 12:32:07 -07:00
if index < 0 || index >= len(valSet.Validators) {
return nil, nil
}
2014-12-17 01:37:13 -08:00
val = valSet.Validators[index]
return val.Address, val.Copy()
2014-10-11 21:27:58 -07:00
}
func (valSet *ValidatorSet) Size() int {
return len(valSet.Validators)
2014-10-11 21:27:58 -07:00
}
func (valSet *ValidatorSet) TotalVotingPower() int64 {
if valSet.totalVotingPower == 0 {
2014-12-17 01:37:13 -08:00
for _, val := range valSet.Validators {
valSet.totalVotingPower += val.VotingPower
}
}
return valSet.totalVotingPower
2014-10-11 21:27:58 -07:00
}
func (valSet *ValidatorSet) GetProposer() (proposer *Validator) {
if len(valSet.Validators) == 0 {
return nil
}
if valSet.Proposer == nil {
valSet.Proposer = valSet.findProposer()
}
return valSet.Proposer.Copy()
}
func (valSet *ValidatorSet) findProposer() *Validator {
var proposer *Validator
for _, val := range valSet.Validators {
if proposer == nil || !bytes.Equal(val.Address, proposer.Address) {
proposer = proposer.CompareAccum(val)
}
}
return proposer
2014-10-11 21:27:58 -07:00
}
func (valSet *ValidatorSet) Hash() []byte {
2014-12-17 01:37:13 -08:00
if len(valSet.Validators) == 0 {
return nil
}
2014-12-17 01:37:13 -08:00
hashables := make([]merkle.Hashable, len(valSet.Validators))
for i, val := range valSet.Validators {
hashables[i] = val
}
2015-06-18 20:19:39 -07:00
return merkle.SimpleHashFromHashables(hashables)
2014-10-11 21:27:58 -07:00
}
func (valSet *ValidatorSet) Add(val *Validator) (added bool) {
val = val.Copy()
2014-12-17 01:37:13 -08:00
idx := sort.Search(len(valSet.Validators), func(i int) bool {
return bytes.Compare(val.Address, valSet.Validators[i].Address) <= 0
})
2014-12-17 01:37:13 -08:00
if idx == len(valSet.Validators) {
valSet.Validators = append(valSet.Validators, val)
// Invalidate cache
valSet.Proposer = nil
valSet.totalVotingPower = 0
return true
} else if bytes.Equal(valSet.Validators[idx].Address, val.Address) {
2014-10-11 21:27:58 -07:00
return false
} else {
2015-01-16 01:06:15 -08:00
newValidators := make([]*Validator, len(valSet.Validators)+1)
copy(newValidators[:idx], valSet.Validators[:idx])
newValidators[idx] = val
copy(newValidators[idx+1:], valSet.Validators[idx:])
2014-12-17 01:37:13 -08:00
valSet.Validators = newValidators
// Invalidate cache
valSet.Proposer = nil
valSet.totalVotingPower = 0
return true
2014-10-11 21:27:58 -07:00
}
2014-10-12 21:14:10 -07:00
}
func (valSet *ValidatorSet) Update(val *Validator) (updated bool) {
index, sameVal := valSet.GetByAddress(val.Address)
if sameVal == nil {
2014-10-12 21:14:10 -07:00
return false
} else {
2014-12-17 01:37:13 -08:00
valSet.Validators[index] = val.Copy()
// Invalidate cache
valSet.Proposer = nil
valSet.totalVotingPower = 0
return true
2014-10-12 21:14:10 -07:00
}
2014-10-11 21:27:58 -07:00
}
func (valSet *ValidatorSet) Remove(address []byte) (val *Validator, removed bool) {
2014-12-17 01:37:13 -08:00
idx := sort.Search(len(valSet.Validators), func(i int) bool {
return bytes.Compare(address, valSet.Validators[i].Address) <= 0
})
if idx == len(valSet.Validators) || !bytes.Equal(valSet.Validators[idx].Address, address) {
return nil, false
} else {
2014-12-17 01:37:13 -08:00
removedVal := valSet.Validators[idx]
newValidators := valSet.Validators[:idx]
if idx+1 < len(valSet.Validators) {
newValidators = append(newValidators, valSet.Validators[idx+1:]...)
}
2014-12-17 01:37:13 -08:00
valSet.Validators = newValidators
// Invalidate cache
valSet.Proposer = nil
valSet.totalVotingPower = 0
return removedVal, true
}
2014-10-12 21:14:10 -07:00
}
func (valSet *ValidatorSet) Iterate(fn func(index int, val *Validator) bool) {
2014-12-17 01:37:13 -08:00
for i, val := range valSet.Validators {
stop := fn(i, val.Copy())
if stop {
break
}
}
2014-10-11 21:27:58 -07:00
}
2014-10-18 01:42:33 -07:00
// Verify that +2/3 of the set had signed the given signBytes
func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height int64, commit *Commit) error {
2016-04-02 09:10:16 -07:00
if valSet.Size() != len(commit.Precommits) {
return fmt.Errorf("Invalid commit -- wrong set size: %v vs %v", valSet.Size(), len(commit.Precommits))
2015-06-21 19:11:21 -07:00
}
2016-04-02 09:10:16 -07:00
if height != commit.Height() {
return fmt.Errorf("Invalid commit -- wrong height: %v vs %v", height, commit.Height())
}
talliedVotingPower := int64(0)
2016-04-02 09:10:16 -07:00
round := commit.Round()
2016-04-02 09:10:16 -07:00
for idx, precommit := range commit.Precommits {
2015-06-21 19:11:21 -07:00
// may be nil if validator skipped.
if precommit == nil {
continue
}
2015-06-21 19:11:21 -07:00
if precommit.Height != height {
2016-04-02 09:10:16 -07:00
return fmt.Errorf("Invalid commit -- wrong height: %v vs %v", height, precommit.Height)
}
2015-06-21 19:11:21 -07:00
if precommit.Round != round {
2016-04-02 09:10:16 -07:00
return fmt.Errorf("Invalid commit -- wrong round: %v vs %v", round, precommit.Round)
2015-06-21 19:11:21 -07:00
}
if precommit.Type != VoteTypePrecommit {
2016-04-02 09:10:16 -07:00
return fmt.Errorf("Invalid commit -- not precommit @ index %v", idx)
2015-06-21 19:11:21 -07:00
}
_, val := valSet.GetByIndex(idx)
2015-06-21 19:11:21 -07:00
// Validate signature
2015-11-01 11:34:08 -08:00
precommitSignBytes := SignBytes(chainID, precommit)
2015-06-05 14:15:40 -07:00
if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
2016-04-02 09:10:16 -07:00
return fmt.Errorf("Invalid commit -- invalid signature: %v", precommit)
}
2016-08-16 14:59:19 -07:00
if !blockID.Equals(precommit.BlockID) {
2015-06-21 19:11:21 -07:00
continue // Not an error, but doesn't count
}
// Good precommit!
talliedVotingPower += val.VotingPower
}
if talliedVotingPower > valSet.TotalVotingPower()*2/3 {
return nil
} else {
2016-04-02 09:10:16 -07:00
return fmt.Errorf("Invalid commit -- insufficient voting power: got %v, needed %v",
talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
}
}
// VerifyCommitAny will check to see if the set would
// be valid with a different validator set.
//
// valSet is the validator set that we know
// * over 2/3 of the power in old signed this block
//
// newSet is the validator set that signed this block
// * only votes from old are sufficient for 2/3 majority
// in the new set as well
//
// That means that:
// * 10% of the valset can't just declare themselves kings
// * If the validator set is 3x old size, we need more proof to trust
func (valSet *ValidatorSet) VerifyCommitAny(newSet *ValidatorSet, chainID string,
blockID BlockID, height int64, commit *Commit) error {
if newSet.Size() != len(commit.Precommits) {
return errors.Errorf("Invalid commit -- wrong set size: %v vs %v", newSet.Size(), len(commit.Precommits))
}
if height != commit.Height() {
return errors.Errorf("Invalid commit -- wrong height: %v vs %v", height, commit.Height())
}
oldVotingPower := int64(0)
newVotingPower := int64(0)
seen := map[int]bool{}
round := commit.Round()
for idx, precommit := range commit.Precommits {
// first check as in VerifyCommit
if precommit == nil {
continue
}
if precommit.Height != height {
// return certerr.ErrHeightMismatch(height, precommit.Height)
return errors.Errorf("Blocks don't match - %d vs %d", round, precommit.Round)
}
if precommit.Round != round {
return errors.Errorf("Invalid commit -- wrong round: %v vs %v", round, precommit.Round)
}
if precommit.Type != VoteTypePrecommit {
return errors.Errorf("Invalid commit -- not precommit @ index %v", idx)
}
if !blockID.Equals(precommit.BlockID) {
continue // Not an error, but doesn't count
}
// we only grab by address, ignoring unknown validators
vi, ov := valSet.GetByAddress(precommit.ValidatorAddress)
if ov == nil || seen[vi] {
continue // missing or double vote...
}
seen[vi] = true
// Validate signature old school
precommitSignBytes := SignBytes(chainID, precommit)
if !ov.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
return errors.Errorf("Invalid commit -- invalid signature: %v", precommit)
}
// Good precommit!
oldVotingPower += ov.VotingPower
// check new school
_, cv := newSet.GetByIndex(idx)
if cv.PubKey.Equals(ov.PubKey) {
// make sure this is properly set in the current block as well
newVotingPower += cv.VotingPower
}
}
if oldVotingPower <= valSet.TotalVotingPower()*2/3 {
return errors.Errorf("Invalid commit -- insufficient old voting power: got %v, needed %v",
oldVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
} else if newVotingPower <= newSet.TotalVotingPower()*2/3 {
return errors.Errorf("Invalid commit -- insufficient cur voting power: got %v, needed %v",
newVotingPower, (newSet.TotalVotingPower()*2/3 + 1))
}
return nil
2017-01-29 13:50:04 -08:00
}
func (valSet *ValidatorSet) String() string {
2014-12-23 01:35:54 -08:00
return valSet.StringIndented("")
2014-10-21 01:18:46 -07:00
}
2014-12-23 01:35:54 -08:00
func (valSet *ValidatorSet) StringIndented(indent string) string {
if valSet == nil {
return "nil-ValidatorSet"
}
2014-10-18 01:42:33 -07:00
valStrings := []string{}
valSet.Iterate(func(index int, val *Validator) bool {
2014-10-18 01:42:33 -07:00
valStrings = append(valStrings, val.String())
return false
})
return fmt.Sprintf(`ValidatorSet{
%s Proposer: %v
%s Validators:
%s %v
%s}`,
indent, valSet.GetProposer().String(),
2014-10-18 01:42:33 -07:00
indent,
indent, strings.Join(valStrings, "\n"+indent+" "),
indent)
}
//-------------------------------------
// Implements sort for sorting validators by address.
type ValidatorsByAddress []*Validator
func (vs ValidatorsByAddress) Len() int {
return len(vs)
}
func (vs ValidatorsByAddress) Less(i, j int) bool {
return bytes.Compare(vs[i].Address, vs[j].Address) == -1
}
func (vs ValidatorsByAddress) Swap(i, j int) {
it := vs[i]
vs[i] = vs[j]
vs[j] = it
}
//-------------------------------------
// Use with Heap for sorting validators by accum
type accumComparable struct {
*Validator
}
// We want to find the validator with the greatest accum.
func (ac accumComparable) Less(o interface{}) bool {
other := o.(accumComparable).Validator
larger := ac.CompareAccum(other)
return bytes.Equal(larger.Address, ac.Address)
}
//----------------------------------------
// For testing
2017-09-22 09:00:37 -07:00
// RandValidatorSet returns a randomized validator set, useful for testing.
// NOTE: PrivValidator are in order.
2017-09-22 09:00:37 -07:00
// UNSTABLE
2017-09-18 19:05:33 -07:00
func RandValidatorSet(numValidators int, votingPower int64) (*ValidatorSet, []*PrivValidatorFS) {
vals := make([]*Validator, numValidators)
2017-09-18 19:05:33 -07:00
privValidators := make([]*PrivValidatorFS, numValidators)
for i := 0; i < numValidators; i++ {
val, privValidator := RandValidator(false, votingPower)
vals[i] = val
privValidators[i] = privValidator
}
valSet := NewValidatorSet(vals)
sort.Sort(PrivValidatorsByAddress(privValidators))
return valSet, privValidators
}