From 8cd3dec102ead23df9ca9fff5b3f4206b649da89 Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Thu, 28 May 2020 11:40:39 +0200 Subject: [PATCH] types: create ValidateBasic() funcs for validator and validator set (#4905) --- CHANGELOG_PENDING.md | 3 +- types/validator.go | 19 ++++++++++++ types/validator_set.go | 18 +++++++++++ types/validator_set_test.go | 58 +++++++++++++++++++++++++++++++++++ types/validator_test.go | 61 +++++++++++++++++++++++++++++++++++++ 5 files changed, 158 insertions(+), 1 deletion(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 9005545e4..805b10ce2 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -75,7 +75,8 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi - [p2p/conn] \#4795 Return err on `signChallenge()` instead of panic - [evidence] [\#4839](https://github.com/tendermint/tendermint/pull/4839) Reject duplicate evidence from being proposed (@cmwaters) - [rpc/core] [\#4844](https://github.com/tendermint/tendermint/pull/4844) Do not lock consensus state in `/validators`, `/consensus_params` and `/status` (@melekes) -- [evidence] [\#4892](https://github.com/tendermint/tendermint/pull/4892) Remove redundant header from phantom validator evidence @cmwaters +- [evidence] [\#4892](https://github.com/tendermint/tendermint/pull/4892) Remove redundant header from phantom validator evidence (@cmwaters) +- [types] [\#4905](https://github.com/tendermint/tendermint/pull/4905) Add ValidateBasic to validator and validator set (@cmwaters) ### BUG FIXES: diff --git a/types/validator.go b/types/validator.go index cdc5f6bf9..e3970e766 100644 --- a/types/validator.go +++ b/types/validator.go @@ -32,6 +32,25 @@ func NewValidator(pubKey crypto.PubKey, votingPower int64) *Validator { } } +func (v *Validator) ValidateBasic() error { + if v == nil { + return errors.New("nil validator") + } + if v.PubKey == nil { + return errors.New("validator does not have a public key") + } + + if v.VotingPower < 0 { + return errors.New("validator has negative voting power") + } + + if len(v.Address) != crypto.AddressSize { + return fmt.Errorf("validator address is the wrong size: %v", v.Address) + } + + return nil +} + // Creates a new copy of the validator so we can mutate ProposerPriority. // Panics if the validator is nil. func (v *Validator) Copy() *Validator { diff --git a/types/validator_set.go b/types/validator_set.go index 46e1cde75..940404f0f 100644 --- a/types/validator_set.go +++ b/types/validator_set.go @@ -79,6 +79,24 @@ func NewValidatorSet(valz []*Validator) *ValidatorSet { return vals } +func (vals *ValidatorSet) ValidateBasic() error { + if vals.IsNilOrEmpty() { + return errors.New("validator set is nil or empty") + } + + for idx, val := range vals.Validators { + if err := val.ValidateBasic(); err != nil { + return fmt.Errorf("invalid validator #%d: %w", idx, err) + } + } + + if err := vals.Proposer.ValidateBasic(); err != nil { + return fmt.Errorf("proposer failed validate basic, error: %w", err) + } + + return nil +} + // IsNilOrEmpty returns true if validator set is nil or empty. func (vals *ValidatorSet) IsNilOrEmpty() bool { return vals == nil || len(vals.Validators) == 0 diff --git a/types/validator_set_test.go b/types/validator_set_test.go index b2e6623d5..2f3476c74 100644 --- a/types/validator_set_test.go +++ b/types/validator_set_test.go @@ -77,6 +77,64 @@ func TestValidatorSetBasic(t *testing.T) { } +func TestValidatorSetValidateBasic(t *testing.T) { + val, _ := RandValidator(false, 1) + badVal := &Validator{} + + testCases := []struct { + vals ValidatorSet + err bool + msg string + }{ + { + vals: ValidatorSet{}, + err: true, + msg: "validator set is nil or empty", + }, + { + vals: ValidatorSet{ + Validators: []*Validator{}, + }, + err: true, + msg: "validator set is nil or empty", + }, + { + vals: ValidatorSet{ + Validators: []*Validator{val}, + }, + err: true, + msg: "proposer failed validate basic, error: nil validator", + }, + { + vals: ValidatorSet{ + Validators: []*Validator{badVal}, + }, + err: true, + msg: "invalid validator #0: validator does not have a public key", + }, + { + vals: ValidatorSet{ + Validators: []*Validator{val}, + Proposer: val, + }, + err: false, + msg: "", + }, + } + + for _, tc := range testCases { + err := tc.vals.ValidateBasic() + if tc.err { + if assert.Error(t, err) { + assert.Equal(t, tc.msg, err.Error()) + } + } else { + assert.NoError(t, err) + } + } + +} + func TestCopy(t *testing.T) { vset := randValidatorSet(10) vsetHash := vset.Hash() diff --git a/types/validator_test.go b/types/validator_test.go index edf877baf..5eb2ed7bf 100644 --- a/types/validator_test.go +++ b/types/validator_test.go @@ -3,6 +3,7 @@ package types import ( "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -36,3 +37,63 @@ func TestValidatorProtoBuf(t *testing.T) { } } } + +func TestValidatorValidateBasic(t *testing.T) { + priv := NewMockPV() + pubKey, _ := priv.GetPubKey() + testCases := []struct { + val *Validator + err bool + msg string + }{ + { + val: NewValidator(pubKey, 1), + err: false, + msg: "", + }, + { + val: nil, + err: true, + msg: "nil validator", + }, + { + val: &Validator{ + PubKey: nil, + }, + err: true, + msg: "validator does not have a public key", + }, + { + val: NewValidator(pubKey, -1), + err: true, + msg: "validator has negative voting power", + }, + { + val: &Validator{ + PubKey: pubKey, + Address: nil, + }, + err: true, + msg: "validator address is the wrong size: ", + }, + { + val: &Validator{ + PubKey: pubKey, + Address: []byte{'a'}, + }, + err: true, + msg: "validator address is the wrong size: 61", + }, + } + + for _, tc := range testCases { + err := tc.val.ValidateBasic() + if tc.err { + if assert.Error(t, err) { + assert.Equal(t, tc.msg, err.Error()) + } + } else { + assert.NoError(t, err) + } + } +}