diff --git a/internal/consensus/replayer.go b/internal/consensus/replayer.go index 5c45c5cbb..416c5a24b 100644 --- a/internal/consensus/replayer.go +++ b/internal/consensus/replayer.go @@ -320,7 +320,7 @@ func (r *BlockReplayer) execInitChain(ctx context.Context, rs *replayState, stat return nil } stateBlockHeight := state.LastBlockHeight - nextVals, err := validatorSetUpdateFromGenesis(r.genDoc, r.nodeProTxHash) + nextVals, err := validatorSetUpdateFromGenesis(r.genDoc) if err != nil { return err } @@ -382,7 +382,7 @@ func (r *BlockReplayer) publishEvents( return nil } -func validatorSetUpdateFromGenesis(genDoc *types.GenesisDoc, nodeProTxHash types.ProTxHash) (*abci.ValidatorSetUpdate, error) { +func validatorSetUpdateFromGenesis(genDoc *types.GenesisDoc) (*abci.ValidatorSetUpdate, error) { if len(genDoc.QuorumHash) != crypto.DefaultHashSize { return nil, nil } @@ -394,12 +394,11 @@ func validatorSetUpdateFromGenesis(genDoc *types.GenesisDoc, nodeProTxHash types return nil, fmt.Errorf("blockReplayer blocks error when validating validator: %s", err) } } - validatorSet := types.NewValidatorSetWithLocalNodeProTxHash( + validatorSet := types.NewValidatorSetCheckPublicKeys( validators, genDoc.ThresholdPublicKey, genDoc.QuorumType, genDoc.QuorumHash, - nodeProTxHash, ) err := validatorSet.ValidateBasic() if err != nil { diff --git a/internal/state/current_round_state.go b/internal/state/current_round_state.go index b14498d38..f16bc353d 100644 --- a/internal/state/current_round_state.go +++ b/internal/state/current_round_state.go @@ -195,7 +195,7 @@ func (candidate *CurrentRoundState) populateValsetUpdates() error { base := candidate.Base - newValSet, err := valsetUpdate(candidate.ProTxHash, update, base.Validators, candidate.NextConsensusParams.Validator) + newValSet, err := valsetUpdate(update, base.Validators, candidate.NextConsensusParams.Validator) if err != nil { return fmt.Errorf("validator set updates: %w", err) } @@ -313,7 +313,6 @@ func RoundParamsFromInitChain(resp *abci.ResponseInitChain) (RoundParams, error) // valsetUpdate processes validator set updates received from ABCI app. func valsetUpdate( - nodeProTxHash types.ProTxHash, vu *abci.ValidatorSetUpdate, currentVals *types.ValidatorSet, params types.ValidatorParams, @@ -339,8 +338,8 @@ func valsetUpdate( } } else { // if we don't have proTxHash, NewValidatorSetWithLocalNodeProTxHash behaves like NewValidatorSet - nValSet = types.NewValidatorSetWithLocalNodeProTxHash(validatorUpdates, thresholdPubKey, - currentVals.QuorumType, quorumHash, nodeProTxHash) + nValSet = types.NewValidatorSetCheckPublicKeys(validatorUpdates, thresholdPubKey, + currentVals.QuorumType, quorumHash) } } else { // validators not changed, but we might have a new quorum hash or threshold public key diff --git a/types/protobuf.go b/types/protobuf.go index 2bfa083b9..671e21321 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -164,12 +164,21 @@ func (pb2tm) ValidatorSetFromProtoUpdate( valSetUpdate *abci.ValidatorSetUpdate, ) (*ValidatorSet, error) { hasPublicKeys := true - for _, v := range valSetUpdate.ValidatorUpdates { + for i, v := range valSetUpdate.ValidatorUpdates { if v.PubKey == nil { hasPublicKeys = false break } + + pubkey, err := cryptoenc.PubKeyFromProto(*v.PubKey) + if err != nil { + return nil, fmt.Errorf("invalid pubkey of validator %d (%x) in valset update: %w", i, v.ProTxHash, err) + } + if len(pubkey.Bytes()) == 0 { + return nil, fmt.Errorf("pubkey of validator %d (%x) in valset update has zero length", i, v.ProTxHash) + } } + tmVals, pub, quorumHash, err := PB2TM.ValidatorUpdatesFromValidatorSet(valSetUpdate) if err != nil { return nil, err diff --git a/types/validator_set.go b/types/validator_set.go index 01e0cf292..eebf70c0e 100644 --- a/types/validator_set.go +++ b/types/validator_set.go @@ -100,21 +100,21 @@ func NewValidatorSet(valz []*Validator, newThresholdPublicKey crypto.PubKey, quo return vals } -// NewValidatorSetWithLocalNodeProTxHash initializes a ValidatorSet the same way as NewValidatorSet does, -// however it does allows to set the localNodeProTxHash to more easily identify if the validator set should have public -// keys. If the local node is part of the validator set the public keys must be present -func NewValidatorSetWithLocalNodeProTxHash( +// NewValidatorSetCheckPublicKeys initializes a ValidatorSet the same way as NewValidatorSet does, +// but determines if the public keys are present. +func NewValidatorSetCheckPublicKeys( valz []*Validator, newThresholdPublicKey crypto.PubKey, quorumType btcjson.LLMQType, quorumHash crypto.QuorumHash, - localNodeProTxHash crypto.ProTxHash, ) *ValidatorSet { - vals := NewValidatorSet(valz, newThresholdPublicKey, quorumType, quorumHash, false) - if vals.HasProTxHash(localNodeProTxHash) { - vals.HasPublicKeys = true + hasPublicKeys := true + for _, val := range valz { + if val.PubKey == nil || len(val.PubKey.Bytes()) == 0 { + hasPublicKeys = false + } } - return vals + return NewValidatorSet(valz, newThresholdPublicKey, quorumType, quorumHash, hasPublicKeys) } // NewEmptyValidatorSet initializes a ValidatorSet with no validators @@ -199,6 +199,9 @@ func (vals *ValidatorSet) ThresholdPublicKeyValid() error { return errors.New("threshold public key is wrong size") } if len(vals.Validators) == 1 && vals.HasPublicKeys { + if vals.Validators[0].PubKey == nil { + return errors.New("validator public key is not set") + } if !vals.Validators[0].PubKey.Equals(vals.ThresholdPublicKey) { return errors.New("incorrect threshold public key") } diff --git a/types/vote.go b/types/vote.go index 82c6f1186..ea844a1a4 100644 --- a/types/vote.go +++ b/types/vote.go @@ -46,6 +46,7 @@ var ( ErrVoteExtensionTypeWrongForRequestID = errors.New("provided vote extension type does not support sign request ID") ErrVoteInvalidValidatorProTxHash = errors.New("invalid validator pro_tx_hash") ErrVoteInvalidValidatorPubKeySize = errors.New("invalid validator public key size") + ErrVoteMissingValidatorPubKey = errors.New("missing validator public key") ErrVoteInvalidBlockSignature = errors.New("invalid block signature") ErrVoteInvalidStateSignature = errors.New("invalid state signature") ErrVoteStateSignatureShouldBeNil = errors.New("state signature when voting for nil block") @@ -197,6 +198,11 @@ func (vote *Vote) verifyBasic(proTxHash ProTxHash, pubKey crypto.PubKey) error { if !bytes.Equal(proTxHash, vote.ValidatorProTxHash) { return ErrVoteInvalidValidatorProTxHash } + + if pubKey == nil { + return ErrVoteMissingValidatorPubKey + } + if len(pubKey.Bytes()) != bls12381.PubKeySize { return ErrVoteInvalidValidatorPubKeySize }