From 7215cd38d8c4128f4481dc28b69c3badf226c55c Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 10 May 2024 16:34:07 +0200 Subject: [PATCH 1/4] fix(types): ValidatorSetFromProtoUpdate --- types/protobuf.go | 7 +++++++ types/validator_set.go | 3 +++ types/vote.go | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/types/protobuf.go b/types/protobuf.go index 2bfa083b94..888afb1262 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -169,7 +169,14 @@ func (pb2tm) ValidatorSetFromProtoUpdate( hasPublicKeys = false break } + + pubkey, err := cryptoenc.PubKeyFromProto(*v.PubKey) + if err != nil || len(pubkey.Bytes()) == 0 { + hasPublicKeys = false + break + } } + 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 01e0cf2925..8105df3444 100644 --- a/types/validator_set.go +++ b/types/validator_set.go @@ -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 82c6f11866..ea844a1a46 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 } From 41bf3460f1e690ddb818c46696df740f365ce402 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 15 May 2024 13:08:45 +0200 Subject: [PATCH 2/4] fix(types): autodetect if valset has pubkeys --- internal/consensus/replayer.go | 3 +-- internal/state/current_round_state.go | 7 +++---- types/validator_set.go | 18 +++++++++--------- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/internal/consensus/replayer.go b/internal/consensus/replayer.go index 5c45c5cbb1..9603f99cf6 100644 --- a/internal/consensus/replayer.go +++ b/internal/consensus/replayer.go @@ -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 b14498d381..f16bc353d7 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/validator_set.go b/types/validator_set.go index 8105df3444..eebf70c0e9 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 From 4bc98b01cf834ebfbfb6ade1f147006a8a5393b9 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 15 May 2024 15:15:12 +0200 Subject: [PATCH 3/4] chore: fix linter issue --- internal/consensus/replayer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/consensus/replayer.go b/internal/consensus/replayer.go index 9603f99cf6..416c5a24b0 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 } From 0f0adc211da7737b63b6b4468d858b84e0e1004f Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 15 May 2024 17:16:49 +0200 Subject: [PATCH 4/4] fix(types): throw error on invalid pubkey in ValidatorSetFromProtoUpdate --- types/protobuf.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/types/protobuf.go b/types/protobuf.go index 888afb1262..671e21321c 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -164,16 +164,18 @@ 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 || len(pubkey.Bytes()) == 0 { - hasPublicKeys = false - break + 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) } }