2015-08-10 20:38:45 -07:00
|
|
|
package types
|
2014-10-11 21:27:58 -07:00
|
|
|
|
|
|
|
import (
|
2014-12-09 18:49:04 -08:00
|
|
|
"bytes"
|
2014-10-18 01:42:33 -07:00
|
|
|
"fmt"
|
2014-11-05 03:08:29 -08:00
|
|
|
"sort"
|
2014-10-18 01:42:33 -07:00
|
|
|
"strings"
|
2014-10-11 21:27:58 -07:00
|
|
|
|
2017-05-12 13:22:22 -07:00
|
|
|
"github.com/tendermint/go-wire"
|
2017-04-21 15:12:54 -07:00
|
|
|
cmn "github.com/tendermint/tmlibs/common"
|
2017-04-21 15:16:05 -07:00
|
|
|
"github.com/tendermint/tmlibs/merkle"
|
2014-10-11 21:27:58 -07:00
|
|
|
)
|
|
|
|
|
2014-12-09 18:49:04 -08: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
|
2014-12-09 18:49:04 -08:00
|
|
|
// for all rounds of a given blockchain height.
|
|
|
|
// On the other hand, the .AccumPower of each validator and
|
2017-03-05 20:28:42 -08:00
|
|
|
// the designated .GetProposer() of a set changes every round,
|
2014-12-09 18:49:04 -08:00
|
|
|
// 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-11-05 03:08:29 -08:00
|
|
|
|
2014-12-17 01:37:13 -08:00
|
|
|
// cached (unexported)
|
2015-06-25 20:28:34 -07:00
|
|
|
totalVotingPower int64
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewValidatorSet(vals []*Validator) *ValidatorSet {
|
2014-11-05 03:08:29 -08:00
|
|
|
validators := make([]*Validator, len(vals))
|
|
|
|
for i, val := range vals {
|
|
|
|
validators[i] = val.Copy()
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
2014-12-16 05:40:17 -08: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)
|
|
|
|
}
|
2017-03-05 12:24:15 -08:00
|
|
|
|
2015-10-28 10:49:35 -07:00
|
|
|
return vs
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
|
|
|
|
2017-03-05 12:24:15 -08:00
|
|
|
// incrementAccum and update the proposer
|
2014-12-16 05:40:17 -08:00
|
|
|
// TODO: mind the overflow when times and votingPower shares too large.
|
2015-06-25 20:28:34 -07:00
|
|
|
func (valSet *ValidatorSet) IncrementAccum(times int) {
|
2014-12-16 05:40:17 -08:00
|
|
|
// Add VotingPower * times to each validator and order into heap.
|
2017-03-04 23:04:09 -08:00
|
|
|
validatorsHeap := cmn.NewHeap()
|
2014-12-17 01:37:13 -08:00
|
|
|
for _, val := range valSet.Validators {
|
2014-12-16 05:40:17 -08:00
|
|
|
val.Accum += int64(val.VotingPower) * int64(times) // TODO: mind overflow
|
2017-03-05 12:24:15 -08:00
|
|
|
validatorsHeap.Push(val, accumComparable{val})
|
2014-11-05 03:08:29 -08:00
|
|
|
}
|
2014-12-16 05:40:17 -08:00
|
|
|
|
2017-03-05 12:24:15 -08:00
|
|
|
// Decrement the validator with most accum times times
|
2015-06-25 20:28:34 -07:00
|
|
|
for i := 0; i < times; i++ {
|
2014-12-16 05:40:17 -08:00
|
|
|
mostest := validatorsHeap.Peek().(*Validator)
|
2015-04-19 09:55:06 -07:00
|
|
|
if i == times-1 {
|
2017-03-05 20:28:42 -08:00
|
|
|
valSet.Proposer = mostest
|
2015-04-19 09:55:06 -07:00
|
|
|
}
|
2014-12-16 05:40:17 -08:00
|
|
|
mostest.Accum -= int64(valSet.TotalVotingPower())
|
2017-03-05 12:24:15 -08:00
|
|
|
validatorsHeap.Update(mostest, accumComparable{mostest})
|
2014-12-16 05:40:17 -08:00
|
|
|
}
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
|
|
|
|
2014-12-09 18:49:04 -08: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 {
|
2014-11-05 03:08:29 -08:00
|
|
|
// 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,
|
2017-03-05 20:28:42 -08:00
|
|
|
Proposer: valSet.Proposer,
|
2014-12-09 18:49:04 -08:00
|
|
|
totalVotingPower: valSet.totalVotingPower,
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-09 18:49:04 -08: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
|
2014-11-05 03:08:29 -08:00
|
|
|
})
|
2017-05-29 20:11:40 -07:00
|
|
|
return idx != len(valSet.Validators) && bytes.Equal(valSet.Validators[idx].Address, address)
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
|
|
|
|
2015-06-25 20:28:34 -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
|
2014-11-05 03:08:29 -08:00
|
|
|
})
|
2017-05-29 20:11:40 -07:00
|
|
|
if idx != len(valSet.Validators) && bytes.Equal(valSet.Validators[idx].Address, address) {
|
2015-06-25 20:28:34 -07:00
|
|
|
return idx, valSet.Validators[idx].Copy()
|
2014-11-05 03:08:29 -08:00
|
|
|
} else {
|
|
|
|
return 0, nil
|
|
|
|
}
|
2014-10-24 14:37:12 -07:00
|
|
|
}
|
|
|
|
|
2015-06-25 20:28:34 -07:00
|
|
|
func (valSet *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator) {
|
2014-12-17 01:37:13 -08:00
|
|
|
val = valSet.Validators[index]
|
2014-12-09 18:49:04 -08:00
|
|
|
return val.Address, val.Copy()
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
|
|
|
|
2015-06-25 20:28:34 -07:00
|
|
|
func (valSet *ValidatorSet) Size() int {
|
|
|
|
return len(valSet.Validators)
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
|
|
|
|
2015-06-25 20:28:34 -07:00
|
|
|
func (valSet *ValidatorSet) TotalVotingPower() int64 {
|
2014-12-09 18:49:04 -08:00
|
|
|
if valSet.totalVotingPower == 0 {
|
2014-12-17 01:37:13 -08:00
|
|
|
for _, val := range valSet.Validators {
|
2014-12-09 18:49:04 -08:00
|
|
|
valSet.totalVotingPower += val.VotingPower
|
2014-11-05 03:08:29 -08:00
|
|
|
}
|
|
|
|
}
|
2014-12-09 18:49:04 -08:00
|
|
|
return valSet.totalVotingPower
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
|
|
|
|
2017-03-05 20:28:42 -08:00
|
|
|
func (valSet *ValidatorSet) GetProposer() (proposer *Validator) {
|
2015-07-10 09:55:23 -07:00
|
|
|
if len(valSet.Validators) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2017-03-05 20:28:42 -08:00
|
|
|
if valSet.Proposer == nil {
|
|
|
|
valSet.Proposer = valSet.findProposer()
|
2017-03-05 12:24:15 -08:00
|
|
|
}
|
2017-03-05 20:28:42 -08:00
|
|
|
return valSet.Proposer.Copy()
|
2017-03-05 12:24:15 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2014-11-05 03:08:29 -08:00
|
|
|
}
|
|
|
|
}
|
2017-03-05 12:24:15 -08:00
|
|
|
return proposer
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
|
|
|
|
2014-12-09 18:49:04 -08:00
|
|
|
func (valSet *ValidatorSet) Hash() []byte {
|
2014-12-17 01:37:13 -08:00
|
|
|
if len(valSet.Validators) == 0 {
|
2014-11-05 03:08:29 -08:00
|
|
|
return nil
|
|
|
|
}
|
2014-12-17 01:37:13 -08:00
|
|
|
hashables := make([]merkle.Hashable, len(valSet.Validators))
|
|
|
|
for i, val := range valSet.Validators {
|
2014-11-05 03:08:29 -08:00
|
|
|
hashables[i] = val
|
|
|
|
}
|
2015-06-18 20:19:39 -07:00
|
|
|
return merkle.SimpleHashFromHashables(hashables)
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
|
|
|
|
2014-12-09 18:49:04 -08:00
|
|
|
func (valSet *ValidatorSet) Add(val *Validator) (added bool) {
|
2014-11-05 03:08:29 -08:00
|
|
|
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-11-05 03:08:29 -08:00
|
|
|
})
|
2014-12-17 01:37:13 -08:00
|
|
|
if idx == len(valSet.Validators) {
|
|
|
|
valSet.Validators = append(valSet.Validators, val)
|
2014-11-05 03:08:29 -08:00
|
|
|
// Invalidate cache
|
2017-03-05 20:28:42 -08:00
|
|
|
valSet.Proposer = nil
|
2014-12-09 18:49:04 -08:00
|
|
|
valSet.totalVotingPower = 0
|
2014-11-05 03:08:29 -08:00
|
|
|
return true
|
2017-05-29 20:11:40 -07:00
|
|
|
} else if bytes.Equal(valSet.Validators[idx].Address, val.Address) {
|
2014-10-11 21:27:58 -07:00
|
|
|
return false
|
2014-11-05 03:08:29 -08:00
|
|
|
} 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
|
2014-11-05 03:08:29 -08:00
|
|
|
// Invalidate cache
|
2017-03-05 20:28:42 -08:00
|
|
|
valSet.Proposer = nil
|
2014-12-09 18:49:04 -08:00
|
|
|
valSet.totalVotingPower = 0
|
2014-11-05 03:08:29 -08:00
|
|
|
return true
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
2014-10-12 21:14:10 -07:00
|
|
|
}
|
|
|
|
|
2014-12-09 18:49:04 -08:00
|
|
|
func (valSet *ValidatorSet) Update(val *Validator) (updated bool) {
|
|
|
|
index, sameVal := valSet.GetByAddress(val.Address)
|
2014-11-05 03:08:29 -08:00
|
|
|
if sameVal == nil {
|
2014-10-12 21:14:10 -07:00
|
|
|
return false
|
2014-11-05 03:08:29 -08:00
|
|
|
} else {
|
2014-12-17 01:37:13 -08:00
|
|
|
valSet.Validators[index] = val.Copy()
|
2014-11-05 03:08:29 -08:00
|
|
|
// Invalidate cache
|
2017-03-05 20:28:42 -08:00
|
|
|
valSet.Proposer = nil
|
2014-12-09 18:49:04 -08:00
|
|
|
valSet.totalVotingPower = 0
|
2014-11-05 03:08:29 -08:00
|
|
|
return true
|
2014-10-12 21:14:10 -07:00
|
|
|
}
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
|
|
|
|
2014-12-09 18:49:04 -08: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
|
2014-11-05 03:08:29 -08:00
|
|
|
})
|
2017-05-29 20:11:40 -07:00
|
|
|
if idx == len(valSet.Validators) || !bytes.Equal(valSet.Validators[idx].Address, address) {
|
2014-11-05 03:08:29 -08:00
|
|
|
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-11-05 03:08:29 -08:00
|
|
|
}
|
2014-12-17 01:37:13 -08:00
|
|
|
valSet.Validators = newValidators
|
2014-11-05 03:08:29 -08:00
|
|
|
// Invalidate cache
|
2017-03-05 20:28:42 -08:00
|
|
|
valSet.Proposer = nil
|
2014-12-09 18:49:04 -08:00
|
|
|
valSet.totalVotingPower = 0
|
2014-11-05 03:08:29 -08:00
|
|
|
return removedVal, true
|
|
|
|
}
|
2014-10-12 21:14:10 -07:00
|
|
|
}
|
|
|
|
|
2015-06-25 20:28:34 -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 {
|
2015-06-25 20:28:34 -07:00
|
|
|
stop := fn(i, val.Copy())
|
2014-11-05 03:08:29 -08:00
|
|
|
if stop {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2014-10-11 21:27:58 -07:00
|
|
|
}
|
2014-10-18 01:42:33 -07:00
|
|
|
|
2015-03-25 11:33:39 -07:00
|
|
|
// Verify that +2/3 of the set had signed the given signBytes
|
2016-08-16 14:59:19 -07:00
|
|
|
func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height int, 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())
|
2015-03-25 11:33:39 -07:00
|
|
|
}
|
|
|
|
|
2015-06-25 20:28:34 -07:00
|
|
|
talliedVotingPower := int64(0)
|
2016-04-02 09:10:16 -07:00
|
|
|
round := commit.Round()
|
2015-03-25 11:33:39 -07:00
|
|
|
|
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 {
|
2015-03-25 11:33:39 -07:00
|
|
|
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-03-25 11:33:39 -07:00
|
|
|
}
|
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
|
|
|
}
|
2015-08-10 20:38:45 -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
|
|
|
}
|
2015-06-25 20:28:34 -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)
|
2015-03-25 11:33:39 -07:00
|
|
|
}
|
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!
|
2015-03-25 11:33:39 -07:00
|
|
|
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",
|
2015-03-25 11:33:39 -07:00
|
|
|
talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-29 13:50:04 -08:00
|
|
|
// Verify that +2/3 of this set had signed the given signBytes.
|
|
|
|
// Unlike VerifyCommit(), this function can verify commits with differeent sets.
|
|
|
|
func (valSet *ValidatorSet) VerifyCommitAny(chainID string, blockID BlockID, height int, commit *Commit) error {
|
|
|
|
panic("Not yet implemented")
|
|
|
|
/*
|
|
|
|
Start like:
|
|
|
|
|
|
|
|
FOR_LOOP:
|
|
|
|
for _, val := range vals {
|
|
|
|
if len(precommits) == 0 {
|
|
|
|
break FOR_LOOP
|
|
|
|
}
|
|
|
|
next := precommits[0]
|
|
|
|
switch bytes.Compare(val.Address(), next.ValidatorAddress) {
|
|
|
|
case -1:
|
|
|
|
continue FOR_LOOP
|
|
|
|
case 0:
|
|
|
|
signBytes := tm.SignBytes(next)
|
|
|
|
...
|
|
|
|
case 1:
|
|
|
|
... // error?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2017-03-05 12:24:15 -08:00
|
|
|
func (valSet *ValidatorSet) ToBytes() []byte {
|
|
|
|
buf, n, err := new(bytes.Buffer), new(int), new(error)
|
|
|
|
wire.WriteBinary(valSet, buf, n, err)
|
|
|
|
if *err != nil {
|
|
|
|
cmn.PanicCrisis(*err)
|
|
|
|
}
|
|
|
|
return buf.Bytes()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (valSet *ValidatorSet) FromBytes(b []byte) {
|
|
|
|
r, n, err := bytes.NewReader(b), new(int), new(error)
|
|
|
|
wire.ReadBinary(valSet, r, 0, n, err)
|
|
|
|
if *err != nil {
|
|
|
|
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
|
|
|
|
cmn.PanicCrisis(*err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-09 18:49: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 {
|
2015-07-10 09:55:23 -07:00
|
|
|
if valSet == nil {
|
|
|
|
return "nil-ValidatorSet"
|
|
|
|
}
|
2014-10-18 01:42:33 -07:00
|
|
|
valStrings := []string{}
|
2015-06-25 20:28:34 -07:00
|
|
|
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}`,
|
2017-03-05 20:28:42 -08:00
|
|
|
indent, valSet.GetProposer().String(),
|
2014-10-18 01:42:33 -07:00
|
|
|
indent,
|
|
|
|
indent, strings.Join(valStrings, "\n"+indent+" "),
|
|
|
|
indent)
|
|
|
|
|
|
|
|
}
|
2014-12-16 05:40:17 -08:00
|
|
|
|
|
|
|
//-------------------------------------
|
|
|
|
// 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
|
|
|
|
|
2017-03-05 12:24:15 -08:00
|
|
|
type accumComparable struct {
|
|
|
|
*Validator
|
|
|
|
}
|
2014-12-16 05:40:17 -08:00
|
|
|
|
|
|
|
// We want to find the validator with the greatest accum.
|
|
|
|
func (ac accumComparable) Less(o interface{}) bool {
|
2017-03-05 12:24:15 -08:00
|
|
|
other := o.(accumComparable).Validator
|
|
|
|
larger := ac.CompareAccum(other)
|
|
|
|
return bytes.Equal(larger.Address, ac.Address)
|
2014-12-16 05:40:17 -08:00
|
|
|
}
|
2015-12-31 15:02:38 -08:00
|
|
|
|
|
|
|
//----------------------------------------
|
|
|
|
// For testing
|
|
|
|
|
2016-07-01 14:47:31 -07:00
|
|
|
// NOTE: PrivValidator are in order.
|
2015-12-31 15:02:38 -08:00
|
|
|
func RandValidatorSet(numValidators int, votingPower int64) (*ValidatorSet, []*PrivValidator) {
|
|
|
|
vals := make([]*Validator, numValidators)
|
|
|
|
privValidators := make([]*PrivValidator, 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
|
|
|
|
}
|