Skip to content

Commit

Permalink
fix(types): abci valset update abci does not need a public key on rep…
Browse files Browse the repository at this point in the history
…lay (#786)

* fix(types): ValidatorSetFromProtoUpdate

* fix(types): autodetect if valset has pubkeys

* chore: fix linter issue

* fix(types): throw error on invalid pubkey in ValidatorSetFromProtoUpdate
  • Loading branch information
lklimek authored May 16, 2024
1 parent d978eac commit 79515d6
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 18 deletions.
7 changes: 3 additions & 4 deletions internal/consensus/replayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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 {
Expand Down
7 changes: 3 additions & 4 deletions internal/state/current_round_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
11 changes: 10 additions & 1 deletion types/protobuf.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 12 additions & 9 deletions types/validator_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
}
Expand Down
6 changes: 6 additions & 0 deletions types/vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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
}
Expand Down

0 comments on commit 79515d6

Please sign in to comment.