Skip to content

Commit

Permalink
verify dv evidence using malicious validator pubkey in infraction blo…
Browse files Browse the repository at this point in the history
…ck header
  • Loading branch information
sainoe committed Sep 5, 2023
1 parent 2501e83 commit 20b0e35
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 46 deletions.
29 changes: 28 additions & 1 deletion tests/integration/double_vote.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package integration

import (
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
testutil "github.com/cosmos/interchain-security/v2/testutil/crypto"
"github.com/cosmos/interchain-security/v2/x/ccv/provider/types"
"github.com/tendermint/tendermint/crypto"
tmtypes "github.com/tendermint/tendermint/types"
)

Expand Down Expand Up @@ -74,10 +76,13 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() {
s.consumerChain.ChainID,
)

provSigner.GetPubKey()

testCases := []struct {
name string
ev *tmtypes.DuplicateVoteEvidence
chainID string
pubkey crypto.PubKey
expPass bool
}{
{
Expand All @@ -90,6 +95,20 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() {
Timestamp: s.consumerCtx().BlockTime(),
},
"chainID",
consuVal.PubKey,
false,
},
{
"wrong public key - shouldn't pass",
&tmtypes.DuplicateVoteEvidence{
VoteA: consuVote,
VoteB: consuVote,
ValidatorPower: consuVal.VotingPower,
TotalVotingPower: consuVal.VotingPower,
Timestamp: s.consumerCtx().BlockTime(),
},
s.consumerChain.ChainID,
provVal.PubKey,
false,
},
{
Expand All @@ -103,6 +122,7 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() {
Timestamp: s.consumerCtx().BlockTime(),
},
s.consumerChain.ChainID,
consuVal.PubKey,
false,
},
{
Expand All @@ -119,6 +139,7 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() {
Timestamp: s.consumerCtx().BlockTime(),
},
s.consumerChain.ChainID,
consuVal.PubKey,
true,
},
{
Expand All @@ -132,6 +153,7 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() {
Timestamp: s.consumerCtx().BlockTime(),
},
s.consumerChain.ChainID,
provVal.PubKey,
true,
},
}
Expand All @@ -144,17 +166,22 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() {
// reset context for each run
provCtx := s.providerCtx()

// if the evidence was built using the validator provider address and key,
// if the evidence was built using the validator provider address andkey,
// we remove the consumer key assigned to the validator otherwise
// HandleConsumerDoubleVoting uses the consumer key to verify the signature
if tc.ev.VoteA.ValidatorAddress.String() != consuVal.Address.String() {
s.providerApp.GetProviderKeeper().DeleteKeyAssignments(provCtx, s.consumerChain.ChainID)
}

// convert validator public key
pk, err := cryptocodec.FromTmPubKeyInterface(tc.pubkey)
s.Require().NoError(err)

err = s.providerApp.GetProviderKeeper().HandleConsumerDoubleVoting(
provCtx,
tc.ev,
tc.chainID,
pk,
)

if tc.expPass {
Expand Down
58 changes: 14 additions & 44 deletions x/ccv/provider/keeper/double_vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"fmt"

cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -14,27 +13,27 @@ import (
tmtypes "github.com/tendermint/tendermint/types"
)

// HandleConsumerDoubleVoting verifies a double voting evidence for a given a consumer chain and,
// if successful, executes the jailing of the malicious validator.
func (k Keeper) HandleConsumerDoubleVoting(ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string) error {
// HandleConsumerDoubleVoting verifies a double voting evidence for a given a consumer chain ID
// and a public key, if successful, executes the jailing of the malicious validator.
func (k Keeper) HandleConsumerDoubleVoting(
ctx sdk.Context,
evidence *tmtypes.DuplicateVoteEvidence,
chainID string,
pubkey cryptotypes.PubKey,
) error {

Check failure on line 24 in x/ccv/provider/keeper/double_vote.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed with `-extra` (gofumpt)

Check failure on line 24 in x/ccv/provider/keeper/double_vote.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed with `-extra` (gofumpt)
// verifies the double voting evidence using the consumer chain public key
if err := k.VerifyDoubleVotingEvidence(ctx, *evidence, chainID, pubkey); err != nil {
return err
}

// get the validator's consensus address on the provider
providerAddr := k.GetProviderAddrFromConsumerAddr(
ctx,
chainID,
types.NewConsumerConsAddress(sdk.ConsAddress(evidence.VoteA.ValidatorAddress.Bytes())),
)

// get validator pubkey used on the consumer chain
pubkey, err := k.getValidatorPubkeyOnConsumer(ctx, chainID, providerAddr)
if err != nil {
return err
}

// verifies the double voting evidence using the consumer chain public key
if err := k.VerifyDoubleVotingEvidence(ctx, *evidence, chainID, pubkey); err != nil {
return err
}

// execute the jailing
k.JailValidator(ctx, providerAddr)

Expand Down Expand Up @@ -107,32 +106,3 @@ func (k Keeper) VerifyDoubleVotingEvidence(

return nil
}

// getValidatorPubkeyOnConsumer returns the public key a validator used on a given consumer chain.
// Note that it can either be an assigned public key or the same public key the validator uses
// on the provider chain.
func (k Keeper) getValidatorPubkeyOnConsumer(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) (pubkey cryptotypes.PubKey, err error) {
tmPK, ok := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)
if ok {
pubkey, err = cryptocodec.FromTmProtoPublicKey(tmPK)
if err != nil {
return
}
} else {
val, ok := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.ToSdkConsAddr())
if !ok {
err = fmt.Errorf("cannot find validator %s", providerAddr.String())
return
}
pubkey, err = val.ConsPubKey()
if err != nil {
return
}
}

return
}
29 changes: 28 additions & 1 deletion x/ccv/provider/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"encoding/base64"

cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
Expand Down Expand Up @@ -156,7 +158,32 @@ func (k msgServer) SubmitConsumerDoubleVoting(goCtx context.Context, msg *types.
return nil, err
}

if err := k.Keeper.HandleConsumerDoubleVoting(ctx, evidence, msg.InfractionBlockHeader.Header.ChainID); err != nil {
// parse the validator set of the infraction block header in order
// to find the public key of the validator who double voted

// get validator set
valset, err := tmtypes.ValidatorSetFromProto(msg.InfractionBlockHeader.ValidatorSet)
if err != nil {
return nil, err
}

// look for the malicious validator in the validator set
_, validator := valset.GetByAddress(evidence.VoteA.ValidatorAddress)
if validator == nil {
return nil, errorsmod.Wrapf(
ccvtypes.ErrInvalidEvidence,
"misbehaving validator %s cannot be found in the infraction block header validator set",
evidence.VoteA.ValidatorAddress)
}

pubkey, err := cryptocodec.FromTmPubKeyInterface(validator.PubKey)
if err != nil {
return nil, err
}

// handle the the double voting evidence using the the chain ID of the infraction block header
// and the malicious validator's public key
if err := k.Keeper.HandleConsumerDoubleVoting(ctx, evidence, msg.InfractionBlockHeader.Header.ChainID, pubkey); err != nil {
return &types.MsgSubmitConsumerDoubleVotingResponse{}, err
}

Expand Down

0 comments on commit 20b0e35

Please sign in to comment.