Skip to content

Commit

Permalink
update ICS misbehaviour test
Browse files Browse the repository at this point in the history
  • Loading branch information
sainoe committed Jul 11, 2023
1 parent 4357efa commit 2be79d7
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 93 deletions.
3 changes: 1 addition & 2 deletions proto/interchain_security/ccv/provider/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import "google/api/annotations.proto";
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/any.proto";
import "ibc/lightclients/tendermint/v1/tendermint.proto";

// Msg defines the Msg service.
service Msg {
Expand Down Expand Up @@ -55,7 +54,7 @@ message MsgSubmitConsumerMisbehaviour {
string submitter = 1;
// The Misbehaviour of the consumer chain wrapping
// two conflicting IBC headers
ibc.lightclients.tendermint.v1.Misbehaviour misbehaviour = 2;
google.protobuf.Any misbehaviour = 2;
}

message MsgSubmitConsumerMisbehaviourResponse {}
2 changes: 0 additions & 2 deletions tests/e2e/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -840,8 +840,6 @@ func (tr TestRun) addChainToHermes(
}

saveMnemonicCommand := fmt.Sprintf(`echo '%s' > %s`, mnemonic, "/root/.hermes/mnemonic.txt")
fmt.Println("Add to hermes", action.validator)
fmt.Println(mnemonic)
//#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments.
bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, "bash", "-c",
saveMnemonicCommand,
Expand Down
133 changes: 99 additions & 34 deletions tests/integration/misbehaviour.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,123 @@ import (
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/interchain-security/v2/x/ccv/provider/types"

ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"
)

// TestHandleConsumerMisbehaviour verifies first that ICS misbehaviour is handled
// only if its conlflicting headers are valid. Then, it checks
// that validators who signed the incorrect header are jailed and tombstoned.
func (s *CCVTestSuite) TestHandleConsumerMisbehaviour() {
s.SetupCCVChannel(s.path)
// required to have the consumer client revision height greater than 0
s.SendEmptyVSCPacket()

// create signing info for all validators
for _, v := range s.providerChain.Vals.Validators {
s.setDefaultValSigningInfo(*v)
}

altTime := s.providerCtx().BlockTime().Add(time.Minute)
// create a new header timestamp
headerTs := s.providerCtx().BlockTime().Add(time.Minute)

// get trusted validators and height
clientHeight := s.consumerChain.LastHeader.TrustedHeight
clientTMValset := tmtypes.NewValidatorSet(s.consumerChain.Vals.Validators)
clientSigners := s.consumerChain.Signers

// create an alternative validator set using more than 1/3 of the trusted validator set
altValset := tmtypes.NewValidatorSet(s.consumerChain.Vals.Validators[0:2])
altSigners := make(map[string]tmtypes.PrivValidator, 1)
altSigners[clientTMValset.Validators[0].Address.String()] = clientSigners[clientTMValset.Validators[0].Address.String()]
altSigners[clientTMValset.Validators[1].Address.String()] = clientSigners[clientTMValset.Validators[1].Address.String()]

misb := &ibctmtypes.Misbehaviour{
ClientId: s.path.EndpointA.ClientID,
Header1: s.consumerChain.CreateTMClientHeader(
s.consumerChain.ChainID,
int64(clientHeight.RevisionHeight+1),
clientHeight,
altTime,
clientTMValset,
clientTMValset,
clientTMValset,
clientSigners,
),
Header2: s.consumerChain.CreateTMClientHeader(
s.consumerChain.ChainID,
int64(clientHeight.RevisionHeight+1),
clientHeight,
altTime,
altValset,
altValset,
clientTMValset,
altSigners,
),
testCases := []struct {
name string
misbehaviour *ibctmtypes.Misbehaviour
expPass bool
}{
{
"invalid misbehaviour with empty header1 - shouldn't pass",
&ibctmtypes.Misbehaviour{
Header1: &ibctmtypes.Header{},
Header2: s.consumerChain.CreateTMClientHeader(
s.consumerChain.ChainID,
int64(clientHeight.RevisionHeight+1),
clientHeight,
headerTs,
altValset,
altValset,
clientTMValset,
altSigners,
),
},
false,
},
{
"valid misbehaviour - should pass",
&ibctmtypes.Misbehaviour{
ClientId: s.path.EndpointA.ClientID,
Header1: s.consumerChain.CreateTMClientHeader(
s.consumerChain.ChainID,
int64(clientHeight.RevisionHeight+1),
clientHeight,
headerTs,
clientTMValset,
clientTMValset,
clientTMValset,
clientSigners,
),
// the resulting Header2 will have a different BlockID
// than Header1 since doesn't share the same valset and signers
Header2: s.consumerChain.CreateTMClientHeader(
s.consumerChain.ChainID,
int64(clientHeight.RevisionHeight+1),
clientHeight,
headerTs,
altValset,
altValset,
clientTMValset,
altSigners,
),
},
true,
},
}

err := s.providerApp.GetProviderKeeper().HandleConsumerMisbehaviour(s.providerCtx(), *misb)
s.NoError(err)

for _, v := range altValset.Validators {
consuAddr := sdk.ConsAddress(v.Address.Bytes())
provAddr := s.providerApp.GetProviderKeeper().GetProviderAddrFromConsumerAddr(s.providerCtx(), s.consumerChain.ChainID, types.NewConsumerConsAddress(consuAddr))
val, ok := s.providerApp.GetTestStakingKeeper().GetValidatorByConsAddr(s.providerCtx(), provAddr.Address)
s.Require().True(ok)
s.Require().True(val.Jailed)
s.Require().True(s.providerApp.GetTestSlashingKeeper().IsTombstoned(s.providerCtx(), provAddr.Address))
for _, tc := range testCases {
s.Run(tc.name, func() {
err := s.providerApp.GetProviderKeeper().HandleConsumerMisbehaviour(s.providerCtx(), tc.misbehaviour)
if tc.expPass {
s.NoError(err)
// Check that only the validators of the alternate validator set
// , i.e. altValset, are jailed and tombstoned on the provider
for _, consuVal := range clientTMValset.Validators {
provVal := s.getProviderValFromConsumerVal(*consuVal)
provConsAddr, err := provVal.GetConsAddr()
s.Require().NoError(err)
if _, ok := altSigners[consuVal.Address.String()]; ok {
s.Require().True(provVal.Jailed)
s.Require().True(s.providerApp.GetTestSlashingKeeper().IsTombstoned(s.providerCtx(), provConsAddr))
} else {
s.Require().False(provVal.Jailed)
s.Require().False(s.providerApp.GetTestSlashingKeeper().IsTombstoned(s.providerCtx(), provConsAddr))
}
}
} else {
// Check that no validators are jailed or tombstoned on the provider
for _, consuVal := range clientTMValset.Validators {
s.Error(err)
provVal := s.getProviderValFromConsumerVal(*consuVal)
s.Require().False(provVal.Jailed)
provConsAddr, err := provVal.GetConsAddr()
s.Require().NoError(err)
s.Require().False(s.providerApp.GetTestSlashingKeeper().IsTombstoned(s.providerCtx(), provConsAddr))
}
}
})
}
}

Expand Down Expand Up @@ -234,3 +291,11 @@ func (s *CCVTestSuite) TestConstructLightClientEvidence() {
})
}
}

func (s *CCVTestSuite) getProviderValFromConsumerVal(valAddr tmtypes.Validator) stakingtypes.Validator {
consuAddr := types.NewConsumerConsAddress(sdk.ConsAddress(valAddr.Address.Bytes()))
provAddr := s.providerApp.GetProviderKeeper().GetProviderAddrFromConsumerAddr(s.providerCtx(), s.consumerChain.ChainID, consuAddr)
val, ok := s.providerApp.GetTestStakingKeeper().GetValidatorByConsAddr(s.providerCtx(), provAddr.Address)
s.Require().True(ok)
return val
}
8 changes: 4 additions & 4 deletions x/ccv/provider/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/cosmos/cosmos-sdk/version"

sdk "github.com/cosmos/cosmos-sdk/types"
ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types"
"github.com/cosmos/ibc-go/v4/modules/core/exported"
"github.com/cosmos/interchain-security/v2/x/ccv/provider/types"
)

Expand Down Expand Up @@ -117,12 +117,12 @@ func NewSubmitConsumerMisbehaviourCmd() *cobra.Command {
WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)

submitter := clientCtx.GetFromAddress()
var misbehavior ibctmtypes.Misbehaviour
if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(args[1]), &misbehavior); err != nil {
var misbehaviour exported.Misbehaviour
if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(args[1]), misbehaviour); err != nil {
return err
}

msg, err := types.NewMsgSubmitConsumerMisbehaviour(submitter, &misbehavior)
msg, err := types.NewMsgSubmitConsumerMisbehaviour(submitter, misbehaviour)
if err != nil {
return err
}
Expand Down
14 changes: 10 additions & 4 deletions x/ccv/provider/keeper/misbehaviour.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,33 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
"github.com/cosmos/ibc-go/v4/modules/core/exported"
ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"
)

// HandleConsumerMisbehaviour checks whether the given IBC misbehaviour is valid and, if they are, the misbehaving
// CheckConsumerMisbehaviour check that the given IBC misbehaviour headers forms a valid light client attack evidence.
// proceed to the jailing and tombstoning of the bzyantine validators.
func (k Keeper) HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour) error {
func (k Keeper) HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour exported.Misbehaviour) error {
logger := ctx.Logger()

if err := k.clientKeeper.CheckMisbehaviourAndUpdateState(ctx, &misbehaviour); err != nil {
// Check that the validity of the misbehaviour
if err := k.clientKeeper.CheckMisbehaviourAndUpdateState(ctx, misbehaviour); err != nil {
logger.Info("Misbehaviour rejected", err.Error())

return err
}

// Assign the Tendermint client misbehaviour concrete type
tmMisbehaviour := misbehaviour.(*ibctmtypes.Misbehaviour)

// Since the misbehaviour packet was received within the trusting period
// w.r.t to the last trusted consensus it entails that the infraction age
// isn't too old. see ibc-go/modules/light-clients/07-tendermint/types/misbehaviour_handle.go

// construct a ligth client attack evidence
evidence, err := k.ConstructLightClientEvidence(ctx, misbehaviour)
evidence, err := k.ConstructLightClientEvidence(ctx, *tmMisbehaviour)
if err != nil {
return err
}
Expand All @@ -39,7 +45,7 @@ func (k Keeper) HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmty
for _, v := range evidence.ByzantineValidators {
// convert consumer consensus address
consuAddr := sdk.ConsAddress(v.Address.Bytes())
provAddr := k.GetProviderAddrFromConsumerAddr(ctx, misbehaviour.Header1.Header.ChainID, types.NewConsumerConsAddress(consuAddr))
provAddr := k.GetProviderAddrFromConsumerAddr(ctx, tmMisbehaviour.Header1.Header.ChainID, types.NewConsumerConsAddress(consuAddr))
k.stakingKeeper.ValidatorByConsAddr(ctx, consuAddr)
val, ok := k.stakingKeeper.GetValidatorByConsAddr(ctx, provAddr.Address)

Expand Down
9 changes: 8 additions & 1 deletion x/ccv/provider/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"
"github.com/cosmos/interchain-security/v2/x/ccv/provider/types"
ccvtypes "github.com/cosmos/interchain-security/v2/x/ccv/types"
tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto"
Expand Down Expand Up @@ -129,7 +130,13 @@ func (k msgServer) RegisterConsumerRewardDenom(goCtx context.Context, msg *types

func (k msgServer) SubmitConsumerMisbehaviour(goCtx context.Context, msg *types.MsgSubmitConsumerMisbehaviour) (*types.MsgSubmitConsumerMisbehaviourResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
if err := k.Keeper.HandleConsumerMisbehaviour(ctx, *msg.Misbehaviour); err != nil {

misbehaviour, err := clienttypes.UnpackMisbehaviour(msg.Misbehaviour)
if err != nil {
return nil, err
}

if err := k.Keeper.HandleConsumerMisbehaviour(ctx, misbehaviour); err != nil {
return &types.MsgSubmitConsumerMisbehaviourResponse{}, err
}

Expand Down
5 changes: 5 additions & 0 deletions x/ccv/provider/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/ibc-go/v4/modules/core/exported"
)

// RegisterLegacyAminoCodec registers the necessary x/ibc transfer interfaces and concrete types
Expand Down Expand Up @@ -40,6 +41,10 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
(*sdk.Msg)(nil),
&MsgSubmitConsumerMisbehaviour{},
)
registry.RegisterInterface(
"ibc.core.client.v1.Misbehaviour",
(*exported.Misbehaviour)(nil),
)

msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}
Expand Down
19 changes: 14 additions & 5 deletions x/ccv/provider/types/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types"
ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"
"github.com/cosmos/ibc-go/v4/modules/core/exported"
)

// provider message types
Expand Down Expand Up @@ -147,8 +147,13 @@ func (msg MsgRegisterConsumerRewardDenom) ValidateBasic() error {
return nil
}

func NewMsgSubmitConsumerMisbehaviour(submitter sdk.AccAddress, m *ibctmtypes.Misbehaviour) (*MsgSubmitConsumerMisbehaviour, error) {
return &MsgSubmitConsumerMisbehaviour{Submitter: submitter.String(), Misbehaviour: m}, nil
func NewMsgSubmitConsumerMisbehaviour(submitter sdk.AccAddress, misbehaviour exported.Misbehaviour) (*MsgSubmitConsumerMisbehaviour, error) {
anyMisbehaviour, err := ibcclienttypes.PackMisbehaviour(misbehaviour)
if err != nil {
return nil, err
}

return &MsgSubmitConsumerMisbehaviour{Submitter: submitter.String(), Misbehaviour: anyMisbehaviour}, nil
}

// Route implements the sdk.Msg interface.
Expand All @@ -164,7 +169,11 @@ func (msg MsgSubmitConsumerMisbehaviour) ValidateBasic() error {
if msg.Submitter == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Submitter)
}
if err := msg.Misbehaviour.ValidateBasic(); err != nil {
misbehaviour, err := ibcclienttypes.UnpackMisbehaviour(msg.Misbehaviour)
if err != nil {
return err
}
if err := misbehaviour.ValidateBasic(); err != nil {
return err
}
return nil
Expand Down
Loading

0 comments on commit 2be79d7

Please sign in to comment.