ibc: modular client messages (#7160)
* ibc: modular client messages * more updates * remove client messages * fixes * fix tests * lint * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * codec.go tests * cleanup exported * MsgCreateClient test * msg tests * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix tests * proto files update * errors * address comments * spec changes * add sanity check test cases * add additional sanity check * fix expPass * fix build and remove unnecessary test since validatebasic is checked in the msg Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya Sripal <adityasripal@gmail.com> Co-authored-by: Colin Axner <colinaxner@berkeley.edu>
This commit is contained in:
parent
1c9158b746
commit
0fffaf589b
@ -6,30 +6,75 @@ option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types";
|
||||
import "gogoproto/gogo.proto";
|
||||
import "google/protobuf/any.proto";
|
||||
|
||||
// IdentifiedClientState defines a client state with additional client identifier field.
|
||||
// IdentifiedClientState defines a client state with additional client
|
||||
// identifier field.
|
||||
message IdentifiedClientState {
|
||||
// client identifier
|
||||
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
|
||||
// client state
|
||||
google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""];
|
||||
google.protobuf.Any client_state = 2
|
||||
[(gogoproto.moretags) = "yaml:\"client_state\""];
|
||||
}
|
||||
|
||||
// ClientConsensusStates defines all the stored consensus states for a given client.
|
||||
// ClientConsensusStates defines all the stored consensus states for a given
|
||||
// client.
|
||||
message ClientConsensusStates {
|
||||
// client identifier
|
||||
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
|
||||
// consensus states associated with the client
|
||||
repeated google.protobuf.Any consensus_states = 2 [(gogoproto.moretags) = "yaml:\"consensus_states\""];
|
||||
repeated google.protobuf.Any consensus_states = 2
|
||||
[(gogoproto.moretags) = "yaml:\"consensus_states\""];
|
||||
}
|
||||
|
||||
// MsgCreateClient defines a message to create an IBC client
|
||||
message MsgCreateClient {
|
||||
// client unique identifier
|
||||
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
|
||||
// light client state
|
||||
google.protobuf.Any client_state = 2
|
||||
[(gogoproto.moretags) = "yaml:\"client_state\""];
|
||||
// consensus state associated with the client that corresponds to a given
|
||||
// height.
|
||||
google.protobuf.Any consensus_state = 3
|
||||
[(gogoproto.moretags) = "yaml:\"consensus_state\""];
|
||||
// signer address
|
||||
bytes signer = 4
|
||||
[(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
|
||||
}
|
||||
|
||||
// MsgUpdateClient defines an sdk.Msg to update a IBC client state using
|
||||
// the given header.
|
||||
message MsgUpdateClient {
|
||||
// client unique identifier
|
||||
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
|
||||
// header to update the light client
|
||||
google.protobuf.Any header = 2;
|
||||
// signer address
|
||||
bytes signer = 3
|
||||
[(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
|
||||
}
|
||||
|
||||
// MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for
|
||||
// light client misbehaviour.
|
||||
message MsgSubmitMisbehaviour {
|
||||
// client unique identifier
|
||||
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
|
||||
// misbehaviour used for freezing the light client
|
||||
google.protobuf.Any misbehaviour = 2;
|
||||
// signer address
|
||||
bytes signer = 3
|
||||
[(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
|
||||
}
|
||||
|
||||
// Height is a monotonically increasing data type
|
||||
// that can be compared against another Height for the purposes of updating and freezing clients
|
||||
// that can be compared against another Height for the purposes of updating and
|
||||
// freezing clients
|
||||
//
|
||||
// Normally the EpochHeight is incremented at each height while keeping epoch number the same
|
||||
// However some consensus algorithms may choose to reset the height in certain conditions
|
||||
// e.g. hard forks, state-machine breaking changes
|
||||
// In these cases, the epoch number is incremented so that height continues to be monitonically increasing
|
||||
// even as the EpochHeight gets reset
|
||||
// Normally the EpochHeight is incremented at each height while keeping epoch
|
||||
// number the same However some consensus algorithms may choose to reset the
|
||||
// height in certain conditions e.g. hard forks, state-machine breaking changes
|
||||
// In these cases, the epoch number is incremented so that height continues to
|
||||
// be monitonically increasing even as the EpochHeight gets reset
|
||||
message Height {
|
||||
option (gogoproto.goproto_stringer) = false;
|
||||
|
||||
|
||||
@ -117,6 +117,12 @@ var (
|
||||
// the signer info doesn't match the account's actual sequence number.
|
||||
ErrWrongSequence = Register(RootCodespace, 32, "incorrect account sequence")
|
||||
|
||||
// ErrPackAny defines an error when packing a protobuf message to Any fails.
|
||||
ErrPackAny = Register(RootCodespace, 33, "failed packing protobuf message to Any")
|
||||
|
||||
// ErrUnpackAny defines an error when unpacking a protobuf message from Any fails.
|
||||
ErrUnpackAny = Register(RootCodespace, 34, "failed unpacking protobuf message from Any")
|
||||
|
||||
// ErrPanic is only set when we recover from a panic, so we know to
|
||||
// redact potentially sensitive system info
|
||||
ErrPanic = Register(UndefinedCodespace, 111222, "panic")
|
||||
|
||||
@ -132,6 +132,9 @@ type ConsensusState interface {
|
||||
ValidateBasic() error
|
||||
}
|
||||
|
||||
// TypeClientMisbehaviour is the shared evidence misbehaviour type
|
||||
const TypeClientMisbehaviour string = "client_misbehaviour"
|
||||
|
||||
// Misbehaviour defines counterparty misbehaviour for a specific consensus type
|
||||
type Misbehaviour interface {
|
||||
ClientType() ClientType
|
||||
@ -147,39 +150,7 @@ type Misbehaviour interface {
|
||||
type Header interface {
|
||||
ClientType() ClientType
|
||||
GetHeight() uint64
|
||||
}
|
||||
|
||||
// message and evidence types for the IBC client
|
||||
const (
|
||||
TypeMsgCreateClient string = "create_client"
|
||||
TypeMsgUpdateClient string = "update_client"
|
||||
TypeMsgSubmitClientMisbehaviour string = "submit_client_misbehaviour"
|
||||
TypeEvidenceClientMisbehaviour string = "client_misbehaviour"
|
||||
)
|
||||
|
||||
// MsgCreateClient defines the msg interface that the
|
||||
// CreateClient Handler expects
|
||||
type MsgCreateClient interface {
|
||||
sdk.Msg
|
||||
GetClientID() string
|
||||
GetClientType() string
|
||||
GetConsensusState() ConsensusState
|
||||
InitializeClientState() ClientState
|
||||
}
|
||||
|
||||
// MsgUpdateClient defines the msg interface that the
|
||||
// UpdateClient Handler expects
|
||||
type MsgUpdateClient interface {
|
||||
sdk.Msg
|
||||
GetClientID() string
|
||||
GetHeader() Header
|
||||
}
|
||||
|
||||
// MsgSubmitMisbehaviour defines the msg interface that the
|
||||
// SubmitMisbehaviour Handler expects
|
||||
type MsgSubmitMisbehaviour interface {
|
||||
sdk.Msg
|
||||
GetMisbehaviour() Misbehaviour
|
||||
ValidateBasic() error
|
||||
}
|
||||
|
||||
// Height is a wrapper interface over clienttypes.Height
|
||||
@ -212,6 +183,8 @@ const (
|
||||
|
||||
func (ct ClientType) String() string {
|
||||
switch ct {
|
||||
case SoloMachine:
|
||||
return ClientTypeSoloMachine
|
||||
case Tendermint:
|
||||
return ClientTypeTendermint
|
||||
case Localhost:
|
||||
@ -247,6 +220,8 @@ func (ct *ClientType) UnmarshalJSON(data []byte) error {
|
||||
// type. It returns 0 if the type is not found/registered.
|
||||
func ClientTypeFromString(clientType string) ClientType {
|
||||
switch clientType {
|
||||
case ClientTypeSoloMachine:
|
||||
return SoloMachine
|
||||
case ClientTypeTendermint:
|
||||
return Tendermint
|
||||
case ClientTypeLocalHost:
|
||||
|
||||
@ -12,7 +12,9 @@ func TestClientTypeString(t *testing.T) {
|
||||
name string
|
||||
clientType ClientType
|
||||
}{
|
||||
{"solomachine client", ClientTypeSoloMachine, SoloMachine},
|
||||
{"tendermint client", ClientTypeTendermint, Tendermint},
|
||||
{"localhost client", ClientTypeLocalHost, Localhost},
|
||||
{"empty type", "", 0},
|
||||
}
|
||||
|
||||
@ -30,7 +32,9 @@ func TestClientTypeMarshalJSON(t *testing.T) {
|
||||
clientType ClientType
|
||||
expectPass bool
|
||||
}{
|
||||
{"tendermint client should have passed", ClientTypeTendermint, Tendermint, true},
|
||||
{"solomachine client", ClientTypeSoloMachine, SoloMachine, true},
|
||||
{"tendermint client", ClientTypeTendermint, Tendermint, true},
|
||||
{"localhost client", ClientTypeLocalHost, Localhost, true},
|
||||
{"empty type should have failed", "", 0, false},
|
||||
}
|
||||
|
||||
|
||||
@ -5,37 +5,23 @@ import (
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
||||
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
|
||||
)
|
||||
|
||||
// HandleMsgCreateClient defines the sdk.Handler for MsgCreateClient
|
||||
func HandleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg exported.MsgCreateClient) (*sdk.Result, error) {
|
||||
var (
|
||||
consensusHeight uint64
|
||||
clientState exported.ClientState
|
||||
)
|
||||
|
||||
switch msg.(type) {
|
||||
// localhost is a special case that must initialize client state
|
||||
// from context and not from msg
|
||||
case *localhosttypes.MsgCreateClient:
|
||||
selfHeight := types.NewHeight(0, uint64(ctx.BlockHeight()))
|
||||
clientState = localhosttypes.NewClientState(ctx.ChainID(), selfHeight)
|
||||
// Localhost consensus height is chain's blockheight
|
||||
consensusHeight = uint64(ctx.BlockHeight())
|
||||
default:
|
||||
clientState = msg.InitializeClientState()
|
||||
if consState := msg.GetConsensusState(); consState != nil {
|
||||
consensusHeight = consState.GetHeight()
|
||||
}
|
||||
func HandleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg *types.MsgCreateClient) (*sdk.Result, error) {
|
||||
clientState, err := types.UnpackClientState(msg.ClientState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err := k.CreateClient(
|
||||
ctx, msg.GetClientID(), clientState, msg.GetConsensusState(),
|
||||
)
|
||||
consensusState, err := types.UnpackConsensusState(msg.ConsensusState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = k.CreateClient(ctx, msg.ClientId, clientState, consensusState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -43,9 +29,9 @@ func HandleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg exported.MsgCre
|
||||
ctx.EventManager().EmitEvents(sdk.Events{
|
||||
sdk.NewEvent(
|
||||
types.EventTypeCreateClient,
|
||||
sdk.NewAttribute(types.AttributeKeyClientID, msg.GetClientID()),
|
||||
sdk.NewAttribute(types.AttributeKeyClientType, msg.GetClientType()),
|
||||
sdk.NewAttribute(types.AttributeKeyConsensusHeight, fmt.Sprintf("%d", consensusHeight)),
|
||||
sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientId),
|
||||
sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType().String()),
|
||||
sdk.NewAttribute(types.AttributeKeyConsensusHeight, fmt.Sprintf("%d", consensusState.GetHeight())),
|
||||
),
|
||||
sdk.NewEvent(
|
||||
sdk.EventTypeMessage,
|
||||
@ -59,8 +45,13 @@ func HandleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg exported.MsgCre
|
||||
}
|
||||
|
||||
// HandleMsgUpdateClient defines the sdk.Handler for MsgUpdateClient
|
||||
func HandleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg exported.MsgUpdateClient) (*sdk.Result, error) {
|
||||
_, err := k.UpdateClient(ctx, msg.GetClientID(), msg.GetHeader())
|
||||
func HandleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg *types.MsgUpdateClient) (*sdk.Result, error) {
|
||||
header, err := types.UnpackHeader(msg.Header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = k.UpdateClient(ctx, msg.ClientId, header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -79,13 +70,9 @@ func HandleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg exported.MsgUpd
|
||||
|
||||
// HandleMsgSubmitMisbehaviour defines the Evidence module handler for submitting a
|
||||
// light client misbehaviour.
|
||||
func HandleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg exported.MsgSubmitMisbehaviour) (*sdk.Result, error) {
|
||||
misbehaviour := msg.GetMisbehaviour()
|
||||
if misbehaviour == nil {
|
||||
return nil, sdkerrors.Wrapf(types.ErrInvalidMisbehaviour, "misbehaviour is nil")
|
||||
}
|
||||
|
||||
if err := misbehaviour.ValidateBasic(); err != nil {
|
||||
func HandleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg *types.MsgSubmitMisbehaviour) (*sdk.Result, error) {
|
||||
misbehaviour, err := types.UnpackMisbehaviour(msg.Misbehaviour)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -96,7 +83,7 @@ func HandleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg exported.
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
types.EventTypeSubmitMisbehaviour,
|
||||
sdk.NewAttribute(types.AttributeKeyClientID, misbehaviour.GetClientID()),
|
||||
sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientId),
|
||||
sdk.NewAttribute(types.AttributeKeyClientType, misbehaviour.ClientType().String()),
|
||||
sdk.NewAttribute(types.AttributeKeyConsensusHeight, fmt.Sprintf("%d", misbehaviour.GetHeight())),
|
||||
),
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
package client_test
|
||||
|
||||
import (
|
||||
client "github.com/cosmos/cosmos-sdk/x/ibc/02-client"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
|
||||
)
|
||||
|
||||
func (suite *ClientTestSuite) TestHandleCreateClientLocalHost() {
|
||||
cases := []struct {
|
||||
name string
|
||||
clientID string
|
||||
msg exported.MsgCreateClient
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"tendermint client",
|
||||
"gaiamainnet",
|
||||
suite.chainA.ConstructMsgCreateClient(suite.chainB, "gaiamainnet"),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"client already exists",
|
||||
exported.ClientTypeLocalHost,
|
||||
&localhosttypes.MsgCreateClient{suite.chainA.SenderAccount.GetAddress()},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
_, err := client.HandleMsgCreateClient(
|
||||
suite.chainA.GetContext(),
|
||||
suite.chainA.App.IBCKeeper.ClientKeeper,
|
||||
tc.msg,
|
||||
)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err, "expected test case %s to pass, got error %v", tc.name, err)
|
||||
|
||||
clientState, ok := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), tc.clientID)
|
||||
suite.Require().True(ok, "could not retrieve clientState")
|
||||
suite.Require().NotNil(clientState, "clientstate is nil")
|
||||
} else {
|
||||
suite.Require().Error(err, "invalid test case %s passed", tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -102,12 +102,8 @@ func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, misbehaviour ex
|
||||
if !found {
|
||||
return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot check misbehaviour for client with ID %s", misbehaviour.GetClientID())
|
||||
}
|
||||
if err := misbehaviour.ValidateBasic(); err != nil {
|
||||
return sdkerrors.Wrap(err, "IBC misbehaviour failed validate basic")
|
||||
}
|
||||
|
||||
clientState, err := clientState.CheckMisbehaviourAndUpdateState(ctx, k.cdc, k.ClientStore(ctx, misbehaviour.GetClientID()), misbehaviour)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -346,23 +346,6 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"misbehaviour fails validatebasic",
|
||||
&ibctmtypes.Misbehaviour{
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, height+1, height, altTime, bothValSet, bothValSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, height, height, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: testChainID,
|
||||
ClientId: testClientID,
|
||||
},
|
||||
func() error {
|
||||
suite.consensusState.NextValidatorsHash = bothValsHash
|
||||
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs())
|
||||
_, err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
|
||||
|
||||
return err
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"trusted ConsensusState1 not found",
|
||||
&ibctmtypes.Misbehaviour{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,12 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
)
|
||||
|
||||
@ -24,6 +24,16 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
||||
"cosmos_sdk.ibc.v1.client.Header",
|
||||
(*exported.Header)(nil),
|
||||
)
|
||||
registry.RegisterInterface(
|
||||
"cosmos_sdk.ibc.v1.client.Misbehaviour",
|
||||
(*exported.Misbehaviour)(nil),
|
||||
)
|
||||
registry.RegisterImplementations(
|
||||
(*sdk.Msg)(nil),
|
||||
&MsgCreateClient{},
|
||||
&MsgUpdateClient{},
|
||||
&MsgSubmitMisbehaviour{},
|
||||
)
|
||||
}
|
||||
|
||||
var (
|
||||
@ -41,33 +51,27 @@ var (
|
||||
func PackClientState(clientState exported.ClientState) (*codectypes.Any, error) {
|
||||
msg, ok := clientState.(proto.Message)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot proto marshal %T", clientState)
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", clientState)
|
||||
}
|
||||
|
||||
anyClientState, err := codectypes.NewAnyWithValue(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error())
|
||||
}
|
||||
|
||||
return anyClientState, nil
|
||||
}
|
||||
|
||||
// MustPackClientState calls PackClientState and panics on error.
|
||||
func MustPackClientState(clientState exported.ClientState) *codectypes.Any {
|
||||
anyClientState, err := PackClientState(clientState)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return anyClientState
|
||||
}
|
||||
|
||||
// UnpackClientState unpacks an Any into a ClientState. It returns an error if the
|
||||
// client state can't be unpacked into a ClientState.
|
||||
func UnpackClientState(any *codectypes.Any) (exported.ClientState, error) {
|
||||
if any == nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil")
|
||||
}
|
||||
|
||||
clientState, ok := any.GetCachedValue().(exported.ClientState)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot unpack Any into ClientState %T", any)
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into ClientState %T", any)
|
||||
}
|
||||
|
||||
return clientState, nil
|
||||
@ -79,12 +83,12 @@ func UnpackClientState(any *codectypes.Any) (exported.ClientState, error) {
|
||||
func PackConsensusState(consensusState exported.ConsensusState) (*codectypes.Any, error) {
|
||||
msg, ok := consensusState.(proto.Message)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot proto marshal %T", consensusState)
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", consensusState)
|
||||
}
|
||||
|
||||
anyConsensusState, err := codectypes.NewAnyWithValue(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error())
|
||||
}
|
||||
|
||||
return anyConsensusState, nil
|
||||
@ -103,10 +107,78 @@ func MustPackConsensusState(consensusState exported.ConsensusState) *codectypes.
|
||||
// UnpackConsensusState unpacks an Any into a ConsensusState. It returns an error if the
|
||||
// consensus state can't be unpacked into a ConsensusState.
|
||||
func UnpackConsensusState(any *codectypes.Any) (exported.ConsensusState, error) {
|
||||
if any == nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil")
|
||||
}
|
||||
|
||||
consensusState, ok := any.GetCachedValue().(exported.ConsensusState)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot unpack Any into ConsensusState %T", any)
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into ConsensusState %T", any)
|
||||
}
|
||||
|
||||
return consensusState, nil
|
||||
}
|
||||
|
||||
// PackHeader constructs a new Any packed with the given header value. It returns
|
||||
// an error if the header can't be casted to a protobuf message or if the concrete
|
||||
// implemention is not registered to the protobuf codec.
|
||||
func PackHeader(header exported.Header) (*codectypes.Any, error) {
|
||||
msg, ok := header.(proto.Message)
|
||||
if !ok {
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", header)
|
||||
}
|
||||
|
||||
anyHeader, err := codectypes.NewAnyWithValue(msg)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error())
|
||||
}
|
||||
|
||||
return anyHeader, nil
|
||||
}
|
||||
|
||||
// UnpackHeader unpacks an Any into a Header. It returns an error if the
|
||||
// consensus state can't be unpacked into a Header.
|
||||
func UnpackHeader(any *codectypes.Any) (exported.Header, error) {
|
||||
if any == nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil")
|
||||
}
|
||||
|
||||
header, ok := any.GetCachedValue().(exported.Header)
|
||||
if !ok {
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into Header %T", any)
|
||||
}
|
||||
|
||||
return header, nil
|
||||
}
|
||||
|
||||
// PackMisbehaviour constructs a new Any packed with the given misbehaviour value. It returns
|
||||
// an error if the misbehaviour can't be casted to a protobuf message or if the concrete
|
||||
// implemention is not registered to the protobuf codec.
|
||||
func PackMisbehaviour(misbehaviour exported.Misbehaviour) (*codectypes.Any, error) {
|
||||
msg, ok := misbehaviour.(proto.Message)
|
||||
if !ok {
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", misbehaviour)
|
||||
}
|
||||
|
||||
anyMisbhaviour, err := codectypes.NewAnyWithValue(msg)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error())
|
||||
}
|
||||
|
||||
return anyMisbhaviour, nil
|
||||
}
|
||||
|
||||
// UnpackMisbehaviour unpacks an Any into a Misbehaviour. It returns an error if the
|
||||
// Any can't be unpacked into a Misbehaviour.
|
||||
func UnpackMisbehaviour(any *codectypes.Any) (exported.Misbehaviour, error) {
|
||||
if any == nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil")
|
||||
}
|
||||
|
||||
misbehaviour, ok := any.GetCachedValue().(exported.Misbehaviour)
|
||||
if !ok {
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into Misbehaviour %T", any)
|
||||
}
|
||||
|
||||
return misbehaviour, nil
|
||||
}
|
||||
|
||||
@ -2,41 +2,218 @@ package types_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
||||
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
|
||||
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type caseAny struct {
|
||||
name string
|
||||
any *codectypes.Any
|
||||
expPass bool
|
||||
}
|
||||
|
||||
func TestPackClientState(t *testing.T) {
|
||||
clientState := localhosttypes.NewClientState(chainID, clientHeight)
|
||||
testCases := []struct {
|
||||
name string
|
||||
clientState exported.ClientState
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"solo machine client",
|
||||
ibctesting.NewSolomachine(t, "solomachine").ClientState(),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"tendermint client",
|
||||
ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs()),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"localhost client",
|
||||
localhosttypes.NewClientState(chainID, clientHeight),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"nil",
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
clientAny, err := types.PackClientState(clientState)
|
||||
require.NoError(t, err, "pack clientstate should not return error")
|
||||
testCasesAny := []caseAny{}
|
||||
|
||||
cs, err := types.UnpackClientState(clientAny)
|
||||
require.NoError(t, err, "unpack clientstate should not return error")
|
||||
for _, tc := range testCases {
|
||||
clientAny, err := types.PackClientState(tc.clientState)
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.name)
|
||||
} else {
|
||||
require.Error(t, err, tc.name)
|
||||
}
|
||||
|
||||
require.Equal(t, clientState, cs, "client states are not equal after packing and unpacking")
|
||||
testCasesAny = append(testCasesAny, caseAny{tc.name, clientAny, tc.expPass})
|
||||
}
|
||||
|
||||
_, err = types.PackClientState(nil)
|
||||
require.Error(t, err, "did not error after packing nil")
|
||||
for i, tc := range testCasesAny {
|
||||
cs, err := types.UnpackClientState(tc.any)
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.name)
|
||||
require.Equal(t, testCases[i].clientState, cs, tc.name)
|
||||
} else {
|
||||
require.Error(t, err, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackConsensusState(t *testing.T) {
|
||||
consensusState := ibctmtypes.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("root")), clientHeight, []byte("nextvalshash"))
|
||||
chain := ibctesting.NewTestChain(t, "cosmoshub")
|
||||
|
||||
consensusAny, err := types.PackConsensusState(consensusState)
|
||||
require.NoError(t, err, "pack consensusstate should not return error")
|
||||
testCases := []struct {
|
||||
name string
|
||||
consensusState exported.ConsensusState
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"solo machine consensus",
|
||||
ibctesting.NewSolomachine(t, "solomachine").ConsensusState(),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"tendermint consensus",
|
||||
chain.LastHeader.ConsensusState(),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"nil",
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
cs, err := types.UnpackConsensusState(consensusAny)
|
||||
require.NoError(t, err, "unpack consensusstate should not return error")
|
||||
testCasesAny := []caseAny{}
|
||||
|
||||
require.Equal(t, consensusState, cs, "consensus states are not equal after packing and unpacking")
|
||||
for _, tc := range testCases {
|
||||
clientAny, err := types.PackConsensusState(tc.consensusState)
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.name)
|
||||
} else {
|
||||
require.Error(t, err, tc.name)
|
||||
}
|
||||
testCasesAny = append(testCasesAny, caseAny{tc.name, clientAny, tc.expPass})
|
||||
}
|
||||
|
||||
_, err = types.PackConsensusState(nil)
|
||||
require.Error(t, err, "did not error after packing nil")
|
||||
for i, tc := range testCasesAny {
|
||||
cs, err := types.UnpackConsensusState(tc.any)
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.name)
|
||||
require.Equal(t, testCases[i].consensusState, cs, tc.name)
|
||||
} else {
|
||||
require.Error(t, err, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackHeader(t *testing.T) {
|
||||
chain := ibctesting.NewTestChain(t, "cosmoshub")
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
header exported.Header
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"solo machine header",
|
||||
ibctesting.NewSolomachine(t, "solomachine").CreateHeader(),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"tendermint header",
|
||||
chain.LastHeader,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"nil",
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
testCasesAny := []caseAny{}
|
||||
|
||||
for _, tc := range testCases {
|
||||
clientAny, err := types.PackHeader(tc.header)
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.name)
|
||||
} else {
|
||||
require.Error(t, err, tc.name)
|
||||
}
|
||||
|
||||
testCasesAny = append(testCasesAny, caseAny{tc.name, clientAny, tc.expPass})
|
||||
}
|
||||
|
||||
for i, tc := range testCasesAny {
|
||||
cs, err := types.UnpackHeader(tc.any)
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.name)
|
||||
require.Equal(t, testCases[i].header, cs, tc.name)
|
||||
} else {
|
||||
require.Error(t, err, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackMisbehaviour(t *testing.T) {
|
||||
chain := ibctesting.NewTestChain(t, "cosmoshub")
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
misbehaviour exported.Misbehaviour
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"solo machine misbehaviour",
|
||||
ibctesting.NewSolomachine(t, "solomachine").CreateMisbehaviour(),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"tendermint misbehaviour",
|
||||
ibctmtypes.NewMisbehaviour("tendermint", chain.ChainID, chain.LastHeader, chain.LastHeader),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"nil",
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
testCasesAny := []caseAny{}
|
||||
|
||||
for _, tc := range testCases {
|
||||
clientAny, err := types.PackMisbehaviour(tc.misbehaviour)
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.name)
|
||||
} else {
|
||||
require.Error(t, err, tc.name)
|
||||
}
|
||||
|
||||
testCasesAny = append(testCasesAny, caseAny{tc.name, clientAny, tc.expPass})
|
||||
}
|
||||
|
||||
for i, tc := range testCasesAny {
|
||||
cs, err := types.UnpackMisbehaviour(tc.any)
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, tc.name)
|
||||
require.Equal(t, testCases[i].misbehaviour, cs, tc.name)
|
||||
} else {
|
||||
require.Error(t, err, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
197
x/ibc/02-client/types/msgs.go
Normal file
197
x/ibc/02-client/types/msgs.go
Normal file
@ -0,0 +1,197 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
||||
)
|
||||
|
||||
// message types for the IBC client
|
||||
const (
|
||||
TypeMsgCreateClient string = "create_client"
|
||||
TypeMsgUpdateClient string = "update_client"
|
||||
TypeMsgSubmitMisbehaviour string = "submit_misbehaviour"
|
||||
)
|
||||
|
||||
var (
|
||||
_ sdk.Msg = &MsgCreateClient{}
|
||||
_ sdk.Msg = &MsgUpdateClient{}
|
||||
_ sdk.Msg = &MsgSubmitMisbehaviour{}
|
||||
)
|
||||
|
||||
// NewMsgCreateClient creates a new MsgCreateClient instance
|
||||
func NewMsgCreateClient(
|
||||
id string, clientState exported.ClientState, consensusState exported.ConsensusState, signer sdk.AccAddress,
|
||||
) (*MsgCreateClient, error) {
|
||||
|
||||
anyClientState, err := PackClientState(clientState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
anyConsensusState, err := PackConsensusState(consensusState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &MsgCreateClient{
|
||||
ClientId: id,
|
||||
ClientState: anyClientState,
|
||||
ConsensusState: anyConsensusState,
|
||||
Signer: signer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Route implements sdk.Msg
|
||||
func (msg MsgCreateClient) Route() string {
|
||||
return host.RouterKey
|
||||
}
|
||||
|
||||
// Type implements sdk.Msg
|
||||
func (msg MsgCreateClient) Type() string {
|
||||
return TypeMsgCreateClient
|
||||
}
|
||||
|
||||
// ValidateBasic implements sdk.Msg
|
||||
func (msg MsgCreateClient) ValidateBasic() error {
|
||||
if msg.Signer.Empty() {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "signer address cannot be empty")
|
||||
}
|
||||
clientState, err := UnpackClientState(msg.ClientState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := clientState.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if clientState.ClientType() == exported.Localhost || msg.ClientId == exported.ClientTypeLocalHost {
|
||||
return sdkerrors.Wrap(ErrInvalidClient, "localhost client can only be created on chain initialization")
|
||||
}
|
||||
consensusState, err := UnpackConsensusState(msg.ConsensusState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := consensusState.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
return host.ClientIdentifierValidator(msg.ClientId)
|
||||
}
|
||||
|
||||
// GetSignBytes implements sdk.Msg
|
||||
func (msg MsgCreateClient) GetSignBytes() []byte {
|
||||
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg))
|
||||
}
|
||||
|
||||
// GetSigners implements sdk.Msg
|
||||
func (msg MsgCreateClient) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.Signer}
|
||||
}
|
||||
|
||||
// NewMsgUpdateClient creates a new MsgUpdateClient instance
|
||||
func NewMsgUpdateClient(id string, header exported.Header, signer sdk.AccAddress) (*MsgUpdateClient, error) {
|
||||
anyHeader, err := PackHeader(header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &MsgUpdateClient{
|
||||
ClientId: id,
|
||||
Header: anyHeader,
|
||||
Signer: signer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Route implements sdk.Msg
|
||||
func (msg MsgUpdateClient) Route() string {
|
||||
return host.RouterKey
|
||||
}
|
||||
|
||||
// Type implements sdk.Msg
|
||||
func (msg MsgUpdateClient) Type() string {
|
||||
return TypeMsgUpdateClient
|
||||
}
|
||||
|
||||
// ValidateBasic implements sdk.Msg
|
||||
func (msg MsgUpdateClient) ValidateBasic() error {
|
||||
if msg.Signer.Empty() {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "signer address cannot be empty")
|
||||
}
|
||||
header, err := UnpackHeader(msg.Header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := header.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
if msg.ClientId == exported.ClientTypeLocalHost {
|
||||
return sdkerrors.Wrap(ErrInvalidClient, "localhost client is only updated on ABCI BeginBlock")
|
||||
}
|
||||
return host.ClientIdentifierValidator(msg.ClientId)
|
||||
}
|
||||
|
||||
// GetSignBytes implements sdk.Msg
|
||||
func (msg MsgUpdateClient) GetSignBytes() []byte {
|
||||
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg))
|
||||
}
|
||||
|
||||
// GetSigners implements sdk.Msg
|
||||
func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.Signer}
|
||||
}
|
||||
|
||||
// NewMsgSubmitMisbehaviour creates a new MsgSubmitMisbehaviour instance.
|
||||
func NewMsgSubmitMisbehaviour(clientID string, misbehaviour exported.Misbehaviour, signer sdk.AccAddress) (*MsgSubmitMisbehaviour, error) {
|
||||
anyMisbehaviour, err := PackMisbehaviour(misbehaviour)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &MsgSubmitMisbehaviour{
|
||||
ClientId: clientID,
|
||||
Misbehaviour: anyMisbehaviour,
|
||||
Signer: signer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Route returns the MsgSubmitClientMisbehaviour's route.
|
||||
func (msg MsgSubmitMisbehaviour) Route() string { return host.RouterKey }
|
||||
|
||||
// Type returns the MsgSubmitMisbehaviour's type.
|
||||
func (msg MsgSubmitMisbehaviour) Type() string {
|
||||
return TypeMsgSubmitMisbehaviour
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic (non-state-dependant) validation on a MsgSubmitMisbehaviour.
|
||||
func (msg MsgSubmitMisbehaviour) ValidateBasic() error {
|
||||
if msg.Signer.Empty() {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "signer address cannot be empty")
|
||||
}
|
||||
misbehaviour, err := UnpackMisbehaviour(msg.Misbehaviour)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := misbehaviour.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
if misbehaviour.GetClientID() != msg.ClientId {
|
||||
return sdkerrors.Wrapf(
|
||||
ErrInvalidMisbehaviour,
|
||||
"misbehaviour client-id doesn't match client-id from message (%s ≠ %s)",
|
||||
misbehaviour.GetClientID(), msg.ClientId,
|
||||
)
|
||||
}
|
||||
|
||||
return host.ClientIdentifierValidator(msg.ClientId)
|
||||
}
|
||||
|
||||
// GetSignBytes returns the raw bytes a signer is expected to sign when submitting
|
||||
// a MsgSubmitMisbehaviour message.
|
||||
func (msg MsgSubmitMisbehaviour) GetSignBytes() []byte {
|
||||
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg))
|
||||
}
|
||||
|
||||
// GetSigners returns the single expected signer for a MsgSubmitMisbehaviour.
|
||||
func (msg MsgSubmitMisbehaviour) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.Signer}
|
||||
}
|
||||
316
x/ibc/02-client/types/msgs_test.go
Normal file
316
x/ibc/02-client/types/msgs_test.go
Normal file
@ -0,0 +1,316 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
||||
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
|
||||
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||
solomachinetypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine/types"
|
||||
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
|
||||
)
|
||||
|
||||
type TypesTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
chain *ibctesting.TestChain
|
||||
}
|
||||
|
||||
func (suite *TypesTestSuite) SetupTest() {
|
||||
coordinator := ibctesting.NewCoordinator(suite.T(), 1)
|
||||
suite.chain = coordinator.GetChain(ibctesting.GetChainID(0))
|
||||
}
|
||||
|
||||
func TestTypesTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(TypesTestSuite))
|
||||
}
|
||||
|
||||
func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() {
|
||||
var (
|
||||
msg = &types.MsgCreateClient{}
|
||||
err error
|
||||
)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
malleate func()
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"invalid client-id",
|
||||
func() {
|
||||
msg.ClientId = ""
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid - tendermint client",
|
||||
func() {
|
||||
tendermintClient := ibctmtypes.NewClientState(suite.chain.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs())
|
||||
msg, err = types.NewMsgCreateClient("tendermint", tendermintClient, suite.chain.CreateTMClientHeader().ConsensusState(), suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid tendermint client",
|
||||
func() {
|
||||
msg, err = types.NewMsgCreateClient("tendermint", &ibctmtypes.ClientState{}, suite.chain.CreateTMClientHeader().ConsensusState(), suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"failed to unpack client",
|
||||
func() {
|
||||
msg.ClientState = nil
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"failed to unpack consensus state",
|
||||
func() {
|
||||
tendermintClient := ibctmtypes.NewClientState(suite.chain.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs())
|
||||
msg, err = types.NewMsgCreateClient("tendermint", tendermintClient, suite.chain.CreateTMClientHeader().ConsensusState(), suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
msg.ConsensusState = nil
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid signer",
|
||||
func() {
|
||||
msg.Signer = nil
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid - solomachine client",
|
||||
func() {
|
||||
soloMachine := ibctesting.NewSolomachine(suite.T(), "solomachine")
|
||||
msg, err = types.NewMsgCreateClient(soloMachine.ClientID, soloMachine.ClientState(), soloMachine.ConsensusState(), suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid solomachine client",
|
||||
func() {
|
||||
soloMachine := ibctesting.NewSolomachine(suite.T(), "solomachine")
|
||||
msg, err = types.NewMsgCreateClient(soloMachine.ClientID, &solomachinetypes.ClientState{}, soloMachine.ConsensusState(), suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid solomachine consensus state",
|
||||
func() {
|
||||
soloMachine := ibctesting.NewSolomachine(suite.T(), "solomachine")
|
||||
msg, err = types.NewMsgCreateClient(soloMachine.ClientID, soloMachine.ClientState(), &solomachinetypes.ConsensusState{}, suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"unsupported - localhost client",
|
||||
func() {
|
||||
localhostClient := localhosttypes.NewClientState(suite.chain.ChainID, types.NewHeight(0, uint64(suite.chain.LastHeader.Header.Height)))
|
||||
msg, err = types.NewMsgCreateClient("localhost", localhostClient, suite.chain.LastHeader.ConsensusState(), suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc.malleate()
|
||||
err = msg.ValidateBasic()
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err, tc.name)
|
||||
} else {
|
||||
suite.Require().Error(err, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TypesTestSuite) TestMsgUpdateClient_ValidateBasic() {
|
||||
var (
|
||||
msg = &types.MsgUpdateClient{}
|
||||
err error
|
||||
)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
malleate func()
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"invalid client-id",
|
||||
func() {
|
||||
msg.ClientId = ""
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid - tendermint header",
|
||||
func() {
|
||||
msg, err = types.NewMsgUpdateClient("tendermint", suite.chain.CreateTMClientHeader(), suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid tendermint header",
|
||||
func() {
|
||||
msg, err = types.NewMsgUpdateClient("tendermint", &ibctmtypes.Header{}, suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"failed to unpack header",
|
||||
func() {
|
||||
msg.Header = nil
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid signer",
|
||||
func() {
|
||||
msg.Signer = nil
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid - solomachine header",
|
||||
func() {
|
||||
soloMachine := ibctesting.NewSolomachine(suite.T(), "solomachine")
|
||||
msg, err = types.NewMsgUpdateClient(soloMachine.ClientID, soloMachine.CreateHeader(), suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid solomachine header",
|
||||
func() {
|
||||
msg, err = types.NewMsgUpdateClient("solomachine", &solomachinetypes.Header{}, suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"unsupported - localhost",
|
||||
func() {
|
||||
msg, err = types.NewMsgUpdateClient(exported.ClientTypeLocalHost, suite.chain.CreateTMClientHeader(), suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc.malleate()
|
||||
err = msg.ValidateBasic()
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err, tc.name)
|
||||
} else {
|
||||
suite.Require().Error(err, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TypesTestSuite) TestMsgSubmitMisbehaviour_ValidateBasic() {
|
||||
var (
|
||||
msg = &types.MsgSubmitMisbehaviour{}
|
||||
err error
|
||||
)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
malleate func()
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"invalid client-id",
|
||||
func() {
|
||||
msg.ClientId = ""
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid - tendermint misbehaviour",
|
||||
func() {
|
||||
header1 := ibctmtypes.CreateTestHeader(suite.chain.ChainID, suite.chain.CurrentHeader.Height, suite.chain.CurrentHeader.Height-1, suite.chain.CurrentHeader.Time, suite.chain.Vals, suite.chain.Vals, suite.chain.Signers)
|
||||
header2 := ibctmtypes.CreateTestHeader(suite.chain.ChainID, suite.chain.CurrentHeader.Height, suite.chain.CurrentHeader.Height-1, suite.chain.CurrentHeader.Time.Add(time.Minute), suite.chain.Vals, suite.chain.Vals, suite.chain.Signers)
|
||||
|
||||
misbehaviour := ibctmtypes.NewMisbehaviour("tendermint", suite.chain.ChainID, header1, header2)
|
||||
msg, err = types.NewMsgSubmitMisbehaviour("tendermint", misbehaviour, suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid tendermint misbehaviour",
|
||||
func() {
|
||||
msg, err = types.NewMsgSubmitMisbehaviour("tendermint", &ibctmtypes.Misbehaviour{}, suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"failed to unpack misbehaviourt",
|
||||
func() {
|
||||
msg.Misbehaviour = nil
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid signer",
|
||||
func() {
|
||||
msg.Signer = nil
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid - solomachine misbehaviour",
|
||||
func() {
|
||||
soloMachine := ibctesting.NewSolomachine(suite.T(), "solomachine")
|
||||
msg, err = types.NewMsgSubmitMisbehaviour(soloMachine.ClientID, soloMachine.CreateMisbehaviour(), suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid solomachine misbehaviour",
|
||||
func() {
|
||||
msg, err = types.NewMsgSubmitMisbehaviour("solomachine", &solomachinetypes.Misbehaviour{}, suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"client-id mismatch",
|
||||
func() {
|
||||
soloMachineMisbehaviour := ibctesting.NewSolomachine(suite.T(), "solomachine").CreateMisbehaviour()
|
||||
msg, err = types.NewMsgSubmitMisbehaviour("external", soloMachineMisbehaviour, suite.chain.SenderAccount.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc.malleate()
|
||||
err = msg.ValidateBasic()
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err, tc.name)
|
||||
} else {
|
||||
suite.Require().Error(err, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||
)
|
||||
@ -110,10 +111,24 @@ func NewCreateClientCmd() *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
msg := types.NewMsgCreateClient(
|
||||
clientID, header, trustLevel, trustingPeriod, ubdPeriod, maxClockDrift, specs, clientCtx.GetFromAddress(),
|
||||
// validate header
|
||||
if err := header.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientState := types.NewClientState(
|
||||
header.GetHeader().GetChainID(), trustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(0, header.GetHeight()), specs,
|
||||
)
|
||||
|
||||
consensusState := header.ConsensusState()
|
||||
|
||||
msg, err := clienttypes.NewMsgCreateClient(
|
||||
clientID, clientState, consensusState, clientCtx.GetFromAddress(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -164,7 +179,11 @@ func NewUpdateClientCmd() *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
msg := types.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress())
|
||||
msg, err := clienttypes.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -212,7 +231,11 @@ func NewSubmitMisbehaviourCmd() *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
msg := types.NewMsgSubmitClientMisbehaviour(m, clientCtx.GetFromAddress())
|
||||
msg, err := clienttypes.NewMsgSubmitMisbehaviour(m.ClientId, m, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -21,6 +21,10 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
||||
(*clientexported.Misbehaviour)(nil),
|
||||
&Misbehaviour{},
|
||||
)
|
||||
registry.RegisterImplementations(
|
||||
(*clientexported.Misbehaviour)(nil),
|
||||
&Misbehaviour{},
|
||||
)
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@ -55,7 +55,7 @@ func (h Header) GetTime() time.Time {
|
||||
// that validatorsets are not nil.
|
||||
// NOTE: TrustedHeight and TrustedValidators may be empty when creating client
|
||||
// with MsgCreateClient
|
||||
func (h Header) ValidateBasic(chainID string) error {
|
||||
func (h Header) ValidateBasic() error {
|
||||
if h.SignedHeader == nil {
|
||||
return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "tendermint signed header cannot be nil")
|
||||
}
|
||||
@ -66,7 +66,7 @@ func (h Header) ValidateBasic(chainID string) error {
|
||||
if err != nil {
|
||||
return sdkerrors.Wrap(err, "header is not a tendermint header")
|
||||
}
|
||||
if err := tmSignedHeader.ValidateBasic(chainID); err != nil {
|
||||
if err := tmSignedHeader.ValidateBasic(h.Header.GetChainID()); err != nil {
|
||||
return sdkerrors.Wrap(err, "header failed basic validation")
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,8 @@ package types_test
|
||||
import (
|
||||
"time"
|
||||
|
||||
tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto"
|
||||
|
||||
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||
@ -26,8 +28,7 @@ func (suite *TendermintTestSuite) TestGetTime() {
|
||||
|
||||
func (suite *TendermintTestSuite) TestHeaderValidateBasic() {
|
||||
var (
|
||||
header *types.Header
|
||||
chainID string
|
||||
header *types.Header
|
||||
)
|
||||
testCases := []struct {
|
||||
name string
|
||||
@ -41,9 +42,12 @@ func (suite *TendermintTestSuite) TestHeaderValidateBasic() {
|
||||
{"signed header is nil", func() {
|
||||
header.SignedHeader = nil
|
||||
}, false},
|
||||
{"SignedHeaderFromProto failed", func() {
|
||||
header.SignedHeader.Commit.Height = -1
|
||||
}, false},
|
||||
{"signed header failed tendermint ValidateBasic", func() {
|
||||
header = suite.chainA.LastHeader
|
||||
chainID = "chainid"
|
||||
header.SignedHeader.Commit = nil
|
||||
}, false},
|
||||
{"trusted height is greater than header height", func() {
|
||||
header.TrustedHeight = clienttypes.NewHeight(0, header.GetHeight()+1)
|
||||
@ -51,6 +55,9 @@ func (suite *TendermintTestSuite) TestHeaderValidateBasic() {
|
||||
{"validator set nil", func() {
|
||||
header.ValidatorSet = nil
|
||||
}, false},
|
||||
{"ValidatorSetFromProto failed", func() {
|
||||
header.ValidatorSet.Validators[0].PubKey = tmprotocrypto.PublicKey{}
|
||||
}, false},
|
||||
{"header validator hash does not equal hash of validator set", func() {
|
||||
// use chainB's randomly generated validator set
|
||||
header.ValidatorSet = suite.chainB.LastHeader.ValidatorSet
|
||||
@ -65,12 +72,11 @@ func (suite *TendermintTestSuite) TestHeaderValidateBasic() {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest()
|
||||
|
||||
chainID = suite.chainA.ChainID // must be explicitly changed in malleate
|
||||
header = suite.chainA.LastHeader // must be explicitly changed in malleate
|
||||
|
||||
tc.malleate()
|
||||
|
||||
err := header.ValidateBasic(chainID)
|
||||
err := header.ValidateBasic()
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
|
||||
@ -91,13 +91,13 @@ func (misbehaviour Misbehaviour) ValidateBasic() error {
|
||||
}
|
||||
|
||||
// ValidateBasic on both validators
|
||||
if err := misbehaviour.Header1.ValidateBasic(misbehaviour.ChainId); err != nil {
|
||||
if err := misbehaviour.Header1.ValidateBasic(); err != nil {
|
||||
return sdkerrors.Wrap(
|
||||
clienttypes.ErrInvalidMisbehaviour,
|
||||
sdkerrors.Wrap(err, "header 1 failed validation").Error(),
|
||||
)
|
||||
}
|
||||
if err := misbehaviour.Header2.ValidateBasic(misbehaviour.ChainId); err != nil {
|
||||
if err := misbehaviour.Header2.ValidateBasic(); err != nil {
|
||||
return sdkerrors.Wrap(
|
||||
clienttypes.ErrInvalidMisbehaviour,
|
||||
sdkerrors.Wrap(err, "header 2 failed validation").Error(),
|
||||
@ -119,7 +119,7 @@ func (misbehaviour Misbehaviour) ValidateBasic() error {
|
||||
|
||||
// Ensure that Commit Hashes are different
|
||||
if blockID1.Equals(*blockID2) {
|
||||
return sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "headers blockIDs are not equal")
|
||||
return sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "headers blockIDs are equal")
|
||||
}
|
||||
if err := ValidCommit(misbehaviour.ChainId, misbehaviour.Header1.Commit, misbehaviour.Header1.ValidatorSet); err != nil {
|
||||
return err
|
||||
|
||||
@ -75,6 +75,20 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
||||
suite.now,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid misbehavior misbehaviour from different chain",
|
||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, bothValsHash),
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, bothValsHash),
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader("ethermint", int64(height.EpochHeight), int64(height.EpochHeight), suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader("ethermint", int64(height.EpochHeight), int64(height.EpochHeight), suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: "ethermint",
|
||||
ClientId: chainID,
|
||||
},
|
||||
suite.now,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid misbehavior misbehaviour with different trusted heights",
|
||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()),
|
||||
|
||||
@ -166,6 +166,17 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
||||
func(misbehaviour *types.Misbehaviour) error { return nil },
|
||||
false,
|
||||
},
|
||||
{
|
||||
"wrong chainID in misbehaviour",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader(chainID, int64(height.EpochHeight), int64(height.EpochHeight-1), suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers),
|
||||
ChainId: "ethermint",
|
||||
ClientId: clientID,
|
||||
},
|
||||
func(misbehaviour *types.Misbehaviour) error { return nil },
|
||||
false,
|
||||
},
|
||||
{
|
||||
"mismatched heights",
|
||||
&types.Misbehaviour{
|
||||
|
||||
@ -1,231 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
ics23 "github.com/confio/ics23/go"
|
||||
"github.com/tendermint/tendermint/light"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
|
||||
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
||||
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
||||
)
|
||||
|
||||
var (
|
||||
_ clientexported.MsgCreateClient = (*MsgCreateClient)(nil)
|
||||
_ clientexported.MsgUpdateClient = (*MsgUpdateClient)(nil)
|
||||
_ clientexported.MsgSubmitMisbehaviour = (*MsgSubmitClientMisbehaviour)(nil)
|
||||
)
|
||||
|
||||
// NewMsgCreateClient creates a new MsgCreateClient instance
|
||||
func NewMsgCreateClient(
|
||||
id string, header *Header, trustLevel Fraction,
|
||||
trustingPeriod, unbondingPeriod, maxClockDrift time.Duration,
|
||||
specs []*ics23.ProofSpec, signer sdk.AccAddress,
|
||||
) *MsgCreateClient {
|
||||
|
||||
return &MsgCreateClient{
|
||||
ClientId: id,
|
||||
Header: header,
|
||||
TrustLevel: trustLevel,
|
||||
TrustingPeriod: trustingPeriod,
|
||||
UnbondingPeriod: unbondingPeriod,
|
||||
MaxClockDrift: maxClockDrift,
|
||||
ProofSpecs: specs,
|
||||
Signer: signer,
|
||||
}
|
||||
}
|
||||
|
||||
// Route implements sdk.Msg
|
||||
func (msg MsgCreateClient) Route() string {
|
||||
return host.RouterKey
|
||||
}
|
||||
|
||||
// Type implements sdk.Msg
|
||||
func (msg MsgCreateClient) Type() string {
|
||||
return clientexported.TypeMsgCreateClient
|
||||
}
|
||||
|
||||
// ValidateBasic implements sdk.Msg
|
||||
func (msg MsgCreateClient) ValidateBasic() error {
|
||||
if msg.TrustingPeriod == 0 {
|
||||
return sdkerrors.Wrap(ErrInvalidTrustingPeriod, "duration cannot be 0")
|
||||
}
|
||||
if err := light.ValidateTrustLevel(msg.TrustLevel.ToTendermint()); err != nil {
|
||||
return sdkerrors.Wrap(err, "invalid trust level for tendermint light client")
|
||||
}
|
||||
if msg.UnbondingPeriod == 0 {
|
||||
return sdkerrors.Wrap(ErrInvalidUnbondingPeriod, "duration cannot be 0")
|
||||
}
|
||||
if msg.Signer.Empty() {
|
||||
return sdkerrors.ErrInvalidAddress
|
||||
}
|
||||
|
||||
if msg.Header == nil || msg.Header.SignedHeader == nil || msg.Header.SignedHeader.Header == nil {
|
||||
return sdkerrors.Wrap(ErrInvalidHeader, "header cannot be nil")
|
||||
}
|
||||
// ValidateBasic of provided header with self-attested chain-id
|
||||
if err := msg.Header.ValidateBasic(msg.Header.Header.GetChainID()); err != nil {
|
||||
return sdkerrors.Wrapf(ErrInvalidHeader, "header failed validatebasic with its own chain-id: %v", err)
|
||||
}
|
||||
if msg.TrustingPeriod >= msg.UnbondingPeriod {
|
||||
return sdkerrors.Wrapf(
|
||||
ErrInvalidTrustingPeriod,
|
||||
"trusting period (%s) should be < unbonding period (%s)", msg.TrustingPeriod, msg.UnbondingPeriod,
|
||||
)
|
||||
}
|
||||
// Validate ProofSpecs
|
||||
if msg.ProofSpecs == nil {
|
||||
return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof specs cannot be nil")
|
||||
}
|
||||
for _, spec := range msg.ProofSpecs {
|
||||
if spec == nil {
|
||||
return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof spec cannot be nil")
|
||||
}
|
||||
}
|
||||
return host.ClientIdentifierValidator(msg.ClientId)
|
||||
}
|
||||
|
||||
// GetSignBytes implements sdk.Msg
|
||||
func (msg MsgCreateClient) GetSignBytes() []byte {
|
||||
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg))
|
||||
}
|
||||
|
||||
// GetSigners implements sdk.Msg
|
||||
func (msg MsgCreateClient) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.Signer}
|
||||
}
|
||||
|
||||
// GetClientID implements clientexported.MsgCreateClient
|
||||
func (msg MsgCreateClient) GetClientID() string {
|
||||
return msg.ClientId
|
||||
}
|
||||
|
||||
// GetClientType implements clientexported.MsgCreateClient
|
||||
func (msg MsgCreateClient) GetClientType() string {
|
||||
return clientexported.ClientTypeTendermint
|
||||
}
|
||||
|
||||
// GetConsensusState implements clientexported.MsgCreateClient
|
||||
func (msg MsgCreateClient) GetConsensusState() clientexported.ConsensusState {
|
||||
// Construct initial consensus state from provided Header
|
||||
root := commitmenttypes.NewMerkleRoot(msg.Header.Header.GetAppHash())
|
||||
// NOTE: Using 0 for epoch number for now
|
||||
// TODO: Use clienttypes.Height in Header once Header.GetHeight returns *clienttypes.Height
|
||||
return &ConsensusState{
|
||||
Timestamp: msg.Header.GetTime(),
|
||||
Root: root,
|
||||
Height: clienttypes.NewHeight(0, msg.Header.GetHeight()),
|
||||
NextValidatorsHash: msg.Header.Header.NextValidatorsHash,
|
||||
}
|
||||
}
|
||||
|
||||
// InitializeFromMsg creates a tendermint client state from a CreateClientMsg
|
||||
func (msg MsgCreateClient) InitializeClientState() clientexported.ClientState {
|
||||
return NewClientState(msg.Header.Header.GetChainID(), msg.TrustLevel,
|
||||
msg.TrustingPeriod, msg.UnbondingPeriod, msg.MaxClockDrift,
|
||||
clienttypes.NewHeight(0, msg.Header.GetHeight()), msg.ProofSpecs,
|
||||
)
|
||||
}
|
||||
|
||||
// NewMsgUpdateClient creates a new MsgUpdateClient instance
|
||||
func NewMsgUpdateClient(id string, header *Header, signer sdk.AccAddress) *MsgUpdateClient {
|
||||
return &MsgUpdateClient{
|
||||
ClientId: id,
|
||||
Header: header,
|
||||
Signer: signer,
|
||||
}
|
||||
}
|
||||
|
||||
// Route implements sdk.Msg
|
||||
func (msg MsgUpdateClient) Route() string {
|
||||
return host.RouterKey
|
||||
}
|
||||
|
||||
// Type implements sdk.Msg
|
||||
func (msg MsgUpdateClient) Type() string {
|
||||
return clientexported.TypeMsgUpdateClient
|
||||
}
|
||||
|
||||
// ValidateBasic implements sdk.Msg
|
||||
func (msg MsgUpdateClient) ValidateBasic() error {
|
||||
if msg.Signer.Empty() {
|
||||
return sdkerrors.ErrInvalidAddress
|
||||
}
|
||||
if msg.Header == nil || msg.Header.SignedHeader == nil || msg.Header.Header == nil {
|
||||
return sdkerrors.Wrap(ErrInvalidHeader, "header cannot be nil")
|
||||
}
|
||||
// ValidateBasic of provided header with self-attested chain-id
|
||||
if err := msg.Header.ValidateBasic(msg.Header.Header.GetChainID()); err != nil {
|
||||
return err
|
||||
}
|
||||
return host.ClientIdentifierValidator(msg.ClientId)
|
||||
}
|
||||
|
||||
// GetSignBytes implements sdk.Msg
|
||||
func (msg MsgUpdateClient) GetSignBytes() []byte {
|
||||
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg))
|
||||
}
|
||||
|
||||
// GetSigners implements sdk.Msg
|
||||
func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.Signer}
|
||||
}
|
||||
|
||||
// GetClientID implements clientexported.MsgUpdateClient
|
||||
func (msg MsgUpdateClient) GetClientID() string {
|
||||
return msg.ClientId
|
||||
}
|
||||
|
||||
// GetHeader implements clientexported.MsgUpdateClient
|
||||
func (msg MsgUpdateClient) GetHeader() clientexported.Header {
|
||||
return msg.Header
|
||||
}
|
||||
|
||||
// NewMsgSubmitClientMisbehaviour creates a new MsgSubmitClientMisbehaviour
|
||||
// instance.
|
||||
func NewMsgSubmitClientMisbehaviour(m *Misbehaviour, s sdk.AccAddress) *MsgSubmitClientMisbehaviour {
|
||||
return &MsgSubmitClientMisbehaviour{Misbehaviour: m, Signer: s}
|
||||
}
|
||||
|
||||
// Route returns the MsgSubmitClientMisbehaviour's route.
|
||||
func (msg MsgSubmitClientMisbehaviour) Route() string { return host.RouterKey }
|
||||
|
||||
// Type returns the MsgSubmitClientMisbehaviour's type.
|
||||
func (msg MsgSubmitClientMisbehaviour) Type() string {
|
||||
return clientexported.TypeMsgSubmitClientMisbehaviour
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic (non-state-dependant) validation on a MsgSubmitClientMisbehaviour.
|
||||
func (msg MsgSubmitClientMisbehaviour) ValidateBasic() error {
|
||||
if msg.Misbehaviour == nil {
|
||||
return sdkerrors.Wrap(evidencetypes.ErrInvalidEvidence, "missing evidence")
|
||||
}
|
||||
if err := msg.Misbehaviour.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
if msg.Signer.Empty() {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSignBytes returns the raw bytes a signer is expected to sign when submitting
|
||||
// a MsgSubmitClientMisbehaviour message.
|
||||
func (msg MsgSubmitClientMisbehaviour) GetSignBytes() []byte {
|
||||
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg))
|
||||
}
|
||||
|
||||
// GetSigners returns the single expected signer for a MsgSubmitClientMisbehaviour.
|
||||
func (msg MsgSubmitClientMisbehaviour) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.Signer}
|
||||
}
|
||||
|
||||
func (msg MsgSubmitClientMisbehaviour) GetMisbehaviour() clientexported.Misbehaviour {
|
||||
return msg.Misbehaviour
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
ics23 "github.com/confio/ics23/go"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
types "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
)
|
||||
|
||||
func (suite *TendermintTestSuite) TestMsgCreateClientValidateBasic() {
|
||||
privKey := secp256k1.GenPrivKey()
|
||||
signer := sdk.AccAddress(privKey.PubKey().Address())
|
||||
invalidHeader := types.CreateTestHeader(suite.header.Header.GetChainID(), int64(height.EpochHeight), 0, suite.now, suite.valSet, nil, []tmtypes.PrivValidator{suite.privVal})
|
||||
invalidHeader.ValidatorSet = nil
|
||||
|
||||
cases := []struct {
|
||||
msg *types.MsgCreateClient
|
||||
expPass bool
|
||||
errMsg string
|
||||
}{
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), true, "success msg should pass"},
|
||||
{types.NewMsgCreateClient("(BADCHAIN)", suite.header, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "invalid client id passed"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "invalid trust level"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "zero trusting period passed"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "zero unbonding period passed"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), nil), false, "Empty address passed"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, &types.Header{}, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "empty header"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, nil, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "nil header"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, &types.Header{SignedHeader: nil}, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "nil header"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, &types.Header{SignedHeader: &tmproto.SignedHeader{Header: nil}}, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "nil header"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, invalidHeader, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "invalid header"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, []*ics23.ProofSpec{nil}, signer), false, "invalid proof specs"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, nil, signer), false, "nil proof specs"},
|
||||
{types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "trusting period not less than unbonding period"},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
err := tc.msg.ValidateBasic()
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err, "Msg %d failed: %v", i, tc.errMsg)
|
||||
} else {
|
||||
suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TendermintTestSuite) TestMsgUpdateClient() {
|
||||
privKey := secp256k1.GenPrivKey()
|
||||
signer := sdk.AccAddress(privKey.PubKey().Address())
|
||||
|
||||
cases := []struct {
|
||||
msg *types.MsgUpdateClient
|
||||
expPass bool
|
||||
errMsg string
|
||||
}{
|
||||
{types.NewMsgUpdateClient(exported.ClientTypeTendermint, suite.header, signer), true, "success msg should pass"},
|
||||
{types.NewMsgUpdateClient("(badClient)", &types.Header{}, signer), false, "invalid client id passed"},
|
||||
{types.NewMsgUpdateClient(exported.ClientTypeTendermint, suite.header, nil), false, "Empty address passed"},
|
||||
{types.NewMsgUpdateClient(exported.ClientTypeTendermint, &types.Header{}, nil), false, "empty Header"},
|
||||
{types.NewMsgUpdateClient(exported.ClientTypeTendermint, nil, nil), false, "nil header"},
|
||||
{types.NewMsgUpdateClient(exported.ClientTypeTendermint, &types.Header{SignedHeader: nil}, nil), false, "nil signed header"},
|
||||
{types.NewMsgUpdateClient(exported.ClientTypeTendermint, &types.Header{SignedHeader: &tmproto.SignedHeader{Header: nil}}, nil), false, "nil tendermint header"},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
err := tc.msg.ValidateBasic()
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err, "Msg %d failed: %v", i, err)
|
||||
} else {
|
||||
suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,6 +87,16 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
||||
},
|
||||
expPass: true,
|
||||
},
|
||||
{
|
||||
name: "unsuccessful update with incorrect header chain-id",
|
||||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs())
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), height, suite.valsHash)
|
||||
newHeader = types.CreateTestHeader("ethermint", int64(height.EpochHeight+1), int64(height.EpochHeight), suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "unsuccessful update with next height: update header mismatches nextValSetHash",
|
||||
setup: func() {
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
|
||||
)
|
||||
|
||||
// NewTxCmd returns a root CLI command handler for all ibc localhost transaction commands.
|
||||
func NewTxCmd() *cobra.Command {
|
||||
txCmd := &cobra.Command{
|
||||
Use: types.SubModuleName,
|
||||
Short: "Localhost client transaction subcommands",
|
||||
DisableFlagParsing: true,
|
||||
SuggestionsMinimumDistance: 2,
|
||||
}
|
||||
|
||||
txCmd.AddCommand(
|
||||
NewCreateClientCmd(),
|
||||
)
|
||||
|
||||
return txCmd
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
|
||||
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
||||
)
|
||||
|
||||
// NewCreateClientCmd defines the command to create a new IBC Loopback Client as defined
|
||||
// in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create
|
||||
func NewCreateClientCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "create new localhost client",
|
||||
Long: "create new localhost (loopback) client",
|
||||
Example: fmt.Sprintf("%s tx %s %s create --from node0 --home ../node0/<app>cli --chain-id $CID", version.AppName, host.ModuleName, types.SubModuleName),
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
clientCtx := client.GetClientContextFromCmd(cmd)
|
||||
clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := types.NewMsgCreateClient(clientCtx.GetFromAddress())
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
}
|
||||
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -1,9 +1,6 @@
|
||||
package localhost
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/client/cli"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
|
||||
)
|
||||
|
||||
@ -11,8 +8,3 @@ import (
|
||||
func Name() string {
|
||||
return types.SubModuleName
|
||||
}
|
||||
|
||||
// GetTxCmd returns the root tx command for the IBC localhost client
|
||||
func GetTxCmd() *cobra.Command {
|
||||
return cli.NewTxCmd()
|
||||
}
|
||||
|
||||
@ -3,17 +3,12 @@ package types
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
)
|
||||
|
||||
// RegisterInterfaces register the ibc interfaces submodule implementations to protobuf
|
||||
// Any.
|
||||
func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
||||
registry.RegisterImplementations(
|
||||
(*sdk.Msg)(nil),
|
||||
&MsgCreateClient{},
|
||||
)
|
||||
registry.RegisterImplementations(
|
||||
(*clientexported.ClientState)(nil),
|
||||
&ClientState{},
|
||||
|
||||
@ -1,69 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
||||
)
|
||||
|
||||
var (
|
||||
_ clientexported.MsgCreateClient = (*MsgCreateClient)(nil)
|
||||
)
|
||||
|
||||
// NewMsgCreateClient creates a new MsgCreateClient instance
|
||||
func NewMsgCreateClient(signer sdk.AccAddress) *MsgCreateClient {
|
||||
return &MsgCreateClient{
|
||||
Signer: signer,
|
||||
}
|
||||
}
|
||||
|
||||
// Route implements sdk.Msg
|
||||
func (msg MsgCreateClient) Route() string {
|
||||
return host.RouterKey
|
||||
}
|
||||
|
||||
// Type implements sdk.Msg
|
||||
func (msg MsgCreateClient) Type() string {
|
||||
return clientexported.TypeMsgCreateClient
|
||||
}
|
||||
|
||||
// ValidateBasic implements sdk.Msg
|
||||
func (msg MsgCreateClient) ValidateBasic() error {
|
||||
if msg.Signer.Empty() {
|
||||
return sdkerrors.ErrInvalidAddress
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSignBytes implements sdk.Msg
|
||||
func (msg MsgCreateClient) GetSignBytes() []byte {
|
||||
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg))
|
||||
}
|
||||
|
||||
// GetSigners implements sdk.Msg
|
||||
func (msg MsgCreateClient) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.Signer}
|
||||
}
|
||||
|
||||
// GetClientID implements clientexported.MsgCreateClient
|
||||
func (msg MsgCreateClient) GetClientID() string {
|
||||
return clientexported.ClientTypeLocalHost
|
||||
}
|
||||
|
||||
// GetClientType implements clientexported.MsgCreateClient
|
||||
func (msg MsgCreateClient) GetClientType() string {
|
||||
return clientexported.ClientTypeLocalHost
|
||||
}
|
||||
|
||||
// GetConsensusState implements clientexported.MsgCreateClient
|
||||
func (msg MsgCreateClient) GetConsensusState() clientexported.ConsensusState {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitializeClientState implements clientexported.MsgCreateClient
|
||||
// localhost is a special case that require the running chain's context to initialize
|
||||
// the client state, thus this function is a no-op
|
||||
func (msg MsgCreateClient) InitializeClientState() clientexported.ClientState {
|
||||
return nil
|
||||
}
|
||||
@ -8,8 +8,8 @@ import (
|
||||
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
|
||||
channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel"
|
||||
tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint"
|
||||
localhost "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost"
|
||||
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine"
|
||||
)
|
||||
|
||||
// GetTxCmd returns the transaction commands for this module
|
||||
@ -23,8 +23,8 @@ func GetTxCmd() *cobra.Command {
|
||||
}
|
||||
|
||||
ibcTxCmd.AddCommand(
|
||||
solomachine.GetTxCmd(),
|
||||
tendermint.GetTxCmd(),
|
||||
localhost.GetTxCmd(),
|
||||
connection.GetTxCmd(),
|
||||
channel.GetTxCmd(),
|
||||
)
|
||||
|
||||
@ -4,7 +4,7 @@ import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
client "github.com/cosmos/cosmos-sdk/x/ibc/02-client"
|
||||
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
||||
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
|
||||
connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
|
||||
channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel"
|
||||
@ -20,13 +20,13 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
|
||||
|
||||
switch msg := msg.(type) {
|
||||
// IBC client msg interface types
|
||||
case clientexported.MsgCreateClient:
|
||||
case *clienttypes.MsgCreateClient:
|
||||
return client.HandleMsgCreateClient(ctx, k.ClientKeeper, msg)
|
||||
|
||||
case clientexported.MsgUpdateClient:
|
||||
case *clienttypes.MsgUpdateClient:
|
||||
return client.HandleMsgUpdateClient(ctx, k.ClientKeeper, msg)
|
||||
|
||||
case clientexported.MsgSubmitMisbehaviour:
|
||||
case *clienttypes.MsgSubmitMisbehaviour:
|
||||
return client.HandleMsgSubmitMisbehaviour(ctx, k.ClientKeeper, msg)
|
||||
|
||||
// IBC connection msgs
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine/types"
|
||||
)
|
||||
|
||||
@ -46,7 +47,11 @@ func NewCreateClientCmd() *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
msg := types.NewMsgCreateClient(clientID, consensusState)
|
||||
clientState := types.NewClientState(consensusState)
|
||||
msg, err := clienttypes.NewMsgCreateClient(clientID, clientState, consensusState, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
@ -88,7 +93,11 @@ func NewUpdateClientCmd() *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
msg := types.NewMsgUpdateClient(clientID, header)
|
||||
msg, err := clienttypes.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -128,7 +137,11 @@ func NewSubmitMisbehaviourCmd() *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
msg := types.NewMsgSubmitClientMisbehaviour(m, clientCtx.GetFromAddress())
|
||||
msg, err := clienttypes.NewMsgSubmitMisbehaviour(m.ClientId, m, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -57,6 +57,9 @@ func (cs ClientState) GetProofSpecs() []*ics23.ProofSpec {
|
||||
|
||||
// Validate performs basic validation of the client state fields.
|
||||
func (cs ClientState) Validate() error {
|
||||
if cs.ConsensusState == nil {
|
||||
return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be nil")
|
||||
}
|
||||
return cs.ConsensusState.ValidateBasic()
|
||||
}
|
||||
|
||||
|
||||
@ -33,6 +33,11 @@ func (suite *SoloMachineTestSuite) TestClientStateValidateBasic() {
|
||||
suite.solomachine.ClientState(),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"empty ClientState",
|
||||
&types.ClientState{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"sequence is zero",
|
||||
types.NewClientState(&types.ConsensusState{0, suite.solomachine.ConsensusState().PublicKey, suite.solomachine.Time}),
|
||||
|
||||
@ -3,19 +3,12 @@ package types
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
)
|
||||
|
||||
// RegisterInterfaces register the ibc channel submodule interfaces to protobuf
|
||||
// Any.
|
||||
func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
||||
registry.RegisterImplementations(
|
||||
(*sdk.Msg)(nil),
|
||||
&MsgCreateClient{},
|
||||
&MsgUpdateClient{},
|
||||
&MsgSubmitClientMisbehaviour{},
|
||||
)
|
||||
registry.RegisterImplementations(
|
||||
(*clientexported.ClientState)(nil),
|
||||
&ClientState{},
|
||||
@ -24,6 +17,14 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
||||
(*clientexported.ConsensusState)(nil),
|
||||
&ConsensusState{},
|
||||
)
|
||||
registry.RegisterImplementations(
|
||||
(*clientexported.Header)(nil),
|
||||
&Header{},
|
||||
)
|
||||
registry.RegisterImplementations(
|
||||
(*clientexported.Misbehaviour)(nil),
|
||||
&Misbehaviour{},
|
||||
)
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@ -27,7 +27,7 @@ func (misbehaviour Misbehaviour) GetClientID() string {
|
||||
|
||||
// Type implements Evidence interface.
|
||||
func (misbehaviour Misbehaviour) Type() string {
|
||||
return clientexported.TypeEvidenceClientMisbehaviour
|
||||
return clientexported.TypeClientMisbehaviour
|
||||
}
|
||||
|
||||
// String implements Evidence interface.
|
||||
|
||||
@ -1,165 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
||||
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
||||
)
|
||||
|
||||
var (
|
||||
_ clientexported.MsgCreateClient = &MsgCreateClient{}
|
||||
_ clientexported.MsgUpdateClient = &MsgUpdateClient{}
|
||||
_ clientexported.MsgSubmitMisbehaviour = &MsgSubmitClientMisbehaviour{}
|
||||
)
|
||||
|
||||
// NewMsgCreateClient creates a new MsgCreateClient instance
|
||||
func NewMsgCreateClient(id string, consensusState *ConsensusState) *MsgCreateClient {
|
||||
return &MsgCreateClient{
|
||||
ClientId: id,
|
||||
ConsensusState: consensusState,
|
||||
}
|
||||
}
|
||||
|
||||
// Route implements sdk.Msg
|
||||
func (msg MsgCreateClient) Route() string {
|
||||
return host.RouterKey
|
||||
}
|
||||
|
||||
// Type implements sdk.Msg
|
||||
func (msg MsgCreateClient) Type() string {
|
||||
return clientexported.TypeMsgCreateClient
|
||||
}
|
||||
|
||||
// ValidateBasic implements sdk.Msg
|
||||
func (msg MsgCreateClient) ValidateBasic() error {
|
||||
if msg.ConsensusState == nil {
|
||||
return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be nil")
|
||||
}
|
||||
if err := msg.ConsensusState.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return host.ClientIdentifierValidator(msg.ClientId)
|
||||
}
|
||||
|
||||
// GetSignBytes implements sdk.Msg
|
||||
func (msg MsgCreateClient) GetSignBytes() []byte {
|
||||
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg))
|
||||
}
|
||||
|
||||
// GetSigners implements sdk.Msg
|
||||
func (msg MsgCreateClient) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{sdk.AccAddress(msg.ConsensusState.GetPubKey().Address())}
|
||||
}
|
||||
|
||||
// GetClientID implements clientexported.MsgCreateClient
|
||||
func (msg MsgCreateClient) GetClientID() string {
|
||||
return msg.ClientId
|
||||
}
|
||||
|
||||
// GetClientType implements clientexported.MsgCreateClient
|
||||
func (msg MsgCreateClient) GetClientType() string {
|
||||
return clientexported.ClientTypeSoloMachine
|
||||
}
|
||||
|
||||
// GetConsensusState implements clientexported.MsgCreateClient
|
||||
func (msg MsgCreateClient) GetConsensusState() clientexported.ConsensusState {
|
||||
return msg.ConsensusState
|
||||
}
|
||||
|
||||
// InitializeFromMsg creates a solo machine client state from a MsgCreateClient
|
||||
func (msg MsgCreateClient) InitializeClientState() clientexported.ClientState {
|
||||
return NewClientState(msg.ConsensusState)
|
||||
}
|
||||
|
||||
// NewMsgUpdateClient creates a new MsgUpdateClient instance
|
||||
func NewMsgUpdateClient(id string, header *Header) *MsgUpdateClient {
|
||||
return &MsgUpdateClient{
|
||||
ClientId: id,
|
||||
Header: header,
|
||||
}
|
||||
}
|
||||
|
||||
// Route implements sdk.Msg
|
||||
func (msg MsgUpdateClient) Route() string {
|
||||
return host.RouterKey
|
||||
}
|
||||
|
||||
// Type implements sdk.Msg
|
||||
func (msg MsgUpdateClient) Type() string {
|
||||
return clientexported.TypeMsgUpdateClient
|
||||
}
|
||||
|
||||
// ValidateBasic implements sdk.Msg
|
||||
func (msg MsgUpdateClient) ValidateBasic() error {
|
||||
if msg.Header == nil {
|
||||
return sdkerrors.Wrap(ErrInvalidHeader, "header cannot be nil")
|
||||
}
|
||||
if err := msg.Header.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
return host.ClientIdentifierValidator(msg.ClientId)
|
||||
}
|
||||
|
||||
// GetSignBytes implements sdk.Msg
|
||||
func (msg MsgUpdateClient) GetSignBytes() []byte {
|
||||
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg))
|
||||
}
|
||||
|
||||
// GetSigners implements sdk.Msg
|
||||
func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{sdk.AccAddress(msg.Header.GetPubKey().Address())}
|
||||
}
|
||||
|
||||
// GetClientID implements clientexported.MsgUpdateClient
|
||||
func (msg MsgUpdateClient) GetClientID() string {
|
||||
return msg.ClientId
|
||||
}
|
||||
|
||||
// GetHeader implements clientexported.MsgUpdateClient
|
||||
func (msg MsgUpdateClient) GetHeader() clientexported.Header {
|
||||
return msg.Header
|
||||
}
|
||||
|
||||
// NewMsgSubmitClientMisbehaviour creates a new MsgSubmitClientMisbehaviour
|
||||
// instance.
|
||||
func NewMsgSubmitClientMisbehaviour(m *Misbehaviour, s sdk.AccAddress) *MsgSubmitClientMisbehaviour {
|
||||
return &MsgSubmitClientMisbehaviour{Misbehaviour: m, Signer: s}
|
||||
}
|
||||
|
||||
// Route returns the MsgSubmitClientMisbehaviour's route.
|
||||
func (msg MsgSubmitClientMisbehaviour) Route() string { return host.RouterKey }
|
||||
|
||||
// Type returns the MsgSubmitClientMisbehaviour's type.
|
||||
func (msg MsgSubmitClientMisbehaviour) Type() string {
|
||||
return clientexported.TypeMsgSubmitClientMisbehaviour
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic (non-state-dependent) validation on a MsgSubmitClientMisbehaviour.
|
||||
func (msg MsgSubmitClientMisbehaviour) ValidateBasic() error {
|
||||
if err := msg.Misbehaviour.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
if msg.Signer.Empty() {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "signer address cannot be empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSignBytes returns the raw bytes a signer is expected to sign when submitting
|
||||
// a MsgSubmitClientMisbehaviour message.
|
||||
func (msg MsgSubmitClientMisbehaviour) GetSignBytes() []byte {
|
||||
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg))
|
||||
}
|
||||
|
||||
// GetSigners returns the single expected signer for a MsgSubmitClientMisbehaviour.
|
||||
func (msg MsgSubmitClientMisbehaviour) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.Signer}
|
||||
}
|
||||
|
||||
func (msg MsgSubmitClientMisbehaviour) GetMisbehaviour() clientexported.Misbehaviour {
|
||||
return msg.Misbehaviour
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine/types"
|
||||
)
|
||||
|
||||
func (suite *SoloMachineTestSuite) TestMsgCreateClientValidateBasic() {
|
||||
cases := []struct {
|
||||
name string
|
||||
msg *types.MsgCreateClient
|
||||
expPass bool
|
||||
}{
|
||||
{"valid msg", types.NewMsgCreateClient(suite.solomachine.ClientID, suite.solomachine.ConsensusState()), true},
|
||||
{"invalid client id", types.NewMsgCreateClient("(BADCLIENTID)", suite.solomachine.ConsensusState()), false},
|
||||
{"nil consensus state", types.NewMsgCreateClient(suite.solomachine.ClientID, nil), false},
|
||||
{"invalid consensus state with zero sequence", types.NewMsgCreateClient(suite.solomachine.ClientID, &types.ConsensusState{0, suite.solomachine.ConsensusState().PublicKey, suite.solomachine.Time}), false},
|
||||
{"invalid consensus state with zero timestamp", types.NewMsgCreateClient(suite.solomachine.ClientID, &types.ConsensusState{1, suite.solomachine.ConsensusState().PublicKey, 0}), false},
|
||||
{"invalid consensus state with nil pubkey", types.NewMsgCreateClient(suite.solomachine.ClientID, &types.ConsensusState{suite.solomachine.Sequence, nil, suite.solomachine.Time}), false},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
err := tc.msg.ValidateBasic()
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err, "Msg %d failed: %v", i, tc.name)
|
||||
} else {
|
||||
suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *SoloMachineTestSuite) TestMsgUpdateClientValidateBasic() {
|
||||
header := suite.solomachine.CreateHeader()
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
msg *types.MsgUpdateClient
|
||||
expPass bool
|
||||
}{
|
||||
{"valid msg", types.NewMsgUpdateClient(suite.solomachine.ClientID, header), true},
|
||||
{"invalid client id", types.NewMsgUpdateClient("(BADCLIENTID)", header), false},
|
||||
{"nil header", types.NewMsgUpdateClient(suite.solomachine.ClientID, nil), false},
|
||||
{"invalid header - sequence is zero", types.NewMsgUpdateClient(suite.solomachine.ClientID, &types.Header{0, header.Signature, header.NewPublicKey}), false},
|
||||
{"invalid header - signature is empty", types.NewMsgUpdateClient(suite.solomachine.ClientID, &types.Header{header.Sequence, []byte{}, header.NewPublicKey}), false},
|
||||
{"invalid header - pubkey is empty", types.NewMsgUpdateClient(suite.solomachine.ClientID, &types.Header{header.Sequence, header.Signature, nil}), false},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
err := tc.msg.ValidateBasic()
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err, "Msg %d failed: %v", i, tc.name)
|
||||
} else {
|
||||
suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -15,17 +15,17 @@ A light client is created using the `MsgCreateClient`.
|
||||
```go
|
||||
type MsgCreateClient struct {
|
||||
ClientId string
|
||||
ClientType string
|
||||
ConsensusState ConsensusState
|
||||
ClientState *types.Any // proto-packed client state
|
||||
ConsensusState *types.Any // proto-packed consensus state
|
||||
Signer sdk.AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `ClientId` is invalid (not alphanumeric or not within 10-20 characters)
|
||||
- `ClientType` is not registered
|
||||
- `ConsensusState` is empty
|
||||
- `ClientId` is invalid (see naming requirements)
|
||||
- `ClientState` is empty or invalid
|
||||
- `ConsensusState` is empty or invalid
|
||||
- `Signer` is empty
|
||||
- A light client with the provided id and type already exist
|
||||
|
||||
@ -40,7 +40,7 @@ A light client is updated with a new header using the `MsgUpdateClient`.
|
||||
```go
|
||||
type MsgUpdateClient struct {
|
||||
ClientId string
|
||||
Header Header
|
||||
Header *types.Any // proto-packed header
|
||||
Signer sdk.AccAddress
|
||||
}
|
||||
```
|
||||
@ -48,15 +48,38 @@ type MsgUpdateClient struct {
|
||||
This message is expected to fail if:
|
||||
|
||||
- `ClientId` is invalid (not alphanumeric or not within 10-20 characters)
|
||||
- `Header` is empty
|
||||
- `Header` is empty or invalid
|
||||
- `Signer` is empty
|
||||
- A Client hasn't been created for the given ID
|
||||
- A `ClientState` hasn't been created for the given ID
|
||||
- the header's client type is different from the registered one
|
||||
- the client is frozen due to misbehaviour and cannot be updated
|
||||
|
||||
The message validates the header and updates the consensus state with the new
|
||||
height, commitment root and validator sets, which are then stored.
|
||||
|
||||
### MsgSubmitMisbehaviour
|
||||
|
||||
Submit a evidence of light client misbehaviour to freeze the client state and prevent additional packets from being relayed.
|
||||
|
||||
```go
|
||||
type MsgSubmitMisbehaviour struct {
|
||||
ClientId string
|
||||
Misbehaviour *types.Any // proto-packed misbehaviour
|
||||
Signer sdk.AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `ClientId` is invalid (not alphanumeric or not within 10-20 characters)
|
||||
- `Misbehaviour` is empty or invalid
|
||||
- `Signer` is empty
|
||||
- A `ClientState` hasn't been created for the given ID
|
||||
- `Misbehaviour` check failed
|
||||
|
||||
The message validates the header and updates the consensus state with the new
|
||||
height, commitment root and validator sets, which are then stored.
|
||||
|
||||
## ICS 03 - Connection
|
||||
|
||||
### MsgConnectionOpenInit
|
||||
@ -89,26 +112,27 @@ using the `MsgConnectionOpenTry`.
|
||||
|
||||
```go
|
||||
type MsgConnectionOpenTry struct {
|
||||
ClientId string
|
||||
ConnectionId string
|
||||
ClientId string
|
||||
ConnectionId string
|
||||
ClientState *types.Any // proto-packed counterparty client
|
||||
Counterparty Counterparty
|
||||
CounterpartyVersions []string
|
||||
ProofHeight uint64
|
||||
ProofInit []byte
|
||||
Counterparty Counterparty
|
||||
CounterpartyVersions []string
|
||||
ProofHeight uint64
|
||||
ProofInit []byte
|
||||
ProofClient []byte
|
||||
ProofConsensus []byte
|
||||
ProofConsensus []byte
|
||||
ConsensusHeight uint64
|
||||
Signer sdk.AccAddress
|
||||
Signer sdk.AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `ClientId` is invalid (see naming requirements)
|
||||
- `ConnectionId` is invalid (see naming requirements)
|
||||
- `ClientState` is not a valid client of the executing chain
|
||||
- `Counterparty` is empty
|
||||
- `CounterpartyVersions` is empty
|
||||
- `CounterpartyVersions` is empty
|
||||
- `ProofHeight` is zero
|
||||
- `ProofInit` is empty
|
||||
- `ProofClient` is empty
|
||||
@ -130,19 +154,20 @@ using the `MsgConnectionOpenAck`.
|
||||
|
||||
```go
|
||||
type MsgConnectionOpenAck struct {
|
||||
ConnectionId string
|
||||
Version string
|
||||
ConnectionId string
|
||||
Version string
|
||||
ClientState *types.Any // proto-packed counterparty client
|
||||
ProofHeight uint64
|
||||
ProofTry []byte
|
||||
ProofHeight uint64
|
||||
ProofTry []byte
|
||||
ProofClient []byte
|
||||
ProofConsensus []byte
|
||||
ConsensusHeight uint64
|
||||
Signer sdk.AccAddress
|
||||
ProofConsensus []byte
|
||||
ConsensusHeight uint64
|
||||
Signer sdk.AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `ConnectionId` is invalid (see naming requirements)
|
||||
- `Version` is empty
|
||||
- `ClientState` is not a valid client of the executing chain
|
||||
@ -165,14 +190,15 @@ the `MsgConnectionOpenConfirm`.
|
||||
|
||||
```go
|
||||
type MsgConnectionOpenConfirm struct {
|
||||
ConnectionId string
|
||||
ProofAck []byte
|
||||
ProofHeight uint64
|
||||
Signer sdk.AccAddress
|
||||
ConnectionId string
|
||||
ProofAck []byte
|
||||
ProofHeight uint64
|
||||
Signer sdk.AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `ConnectionId` is invalid (see naming requirements)
|
||||
- `ProofAck` is empty
|
||||
- `ProofHeight` is zero
|
||||
@ -199,18 +225,19 @@ type MsgChannelOpenInit struct {
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `PortId` is invalid (see naming requirements)
|
||||
- `ChannelId` is invalid (see naming requirements)
|
||||
- `Channel` is empty
|
||||
- `Signer` is empty
|
||||
- A Channel End exists for the given Channel ID and Port ID
|
||||
|
||||
The message creates a channel on chain A with an INIT state for the given Channel ID
|
||||
The message creates a channel on chain A with an INIT state for the given Channel ID
|
||||
and Port ID.
|
||||
|
||||
### MsgChannelOpenTry
|
||||
|
||||
A channel handshake initialization attempt is acknowledged by a chain B using
|
||||
A channel handshake initialization attempt is acknowledged by a chain B using
|
||||
the `MsgChannelOpenTry` message.
|
||||
|
||||
```go
|
||||
@ -226,6 +253,7 @@ type MsgChannelOpenTry struct {
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `PortId` is invalid (see naming requirements)
|
||||
- `ChannelId` is invalid (see naming requirements)
|
||||
- `Channel` is empty
|
||||
@ -245,16 +273,17 @@ A channel handshake is opened by a chain A using the `MsgChannelOpenAck` message
|
||||
|
||||
```go
|
||||
type MsgChannelOpenAck struct {
|
||||
PortId string
|
||||
ChannelId string
|
||||
CounterpartyVersion string
|
||||
PortId string
|
||||
ChannelId string
|
||||
CounterpartyVersion string
|
||||
ProofTry []byte
|
||||
ProofHeight uint64
|
||||
Signer sdk.AccAddress
|
||||
Signer sdk.AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `PortId` is invalid (see naming requirements)
|
||||
- `ChannelId` is invalid (see naming requirements)
|
||||
- `CounterpartyVersion` is empty
|
||||
@ -272,15 +301,16 @@ message.
|
||||
|
||||
```go
|
||||
type MsgChannelOpenConfirm struct {
|
||||
PortId string
|
||||
ChannelId string
|
||||
PortId string
|
||||
ChannelId string
|
||||
ProofAck []byte
|
||||
ProofHeight uint64
|
||||
Signer sdk.AccAddress
|
||||
Signer sdk.AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `PortId` is invalid (see naming requirements)
|
||||
- `ChannelId` is invalid (see naming requirements)
|
||||
- `ProofAck` is empty
|
||||
@ -296,13 +326,14 @@ A channel is closed on chain A using the `MsgChannelCloseInit`.
|
||||
|
||||
```go
|
||||
type MsgChannelCloseInit struct {
|
||||
PortId string
|
||||
ChannelId string
|
||||
Signer sdk.AccAddress
|
||||
PortId string
|
||||
ChannelId string
|
||||
Signer sdk.AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `PortId` is invalid (see naming requirements)
|
||||
- `ChannelId` is invalid (see naming requirements)
|
||||
- `Signer` is empty
|
||||
@ -316,15 +347,16 @@ A channel is closed on chain B using the `MsgChannelCloseConfirm`.
|
||||
|
||||
```go
|
||||
type MsgChannelCloseConfirm struct {
|
||||
PortId string
|
||||
ChannelId string
|
||||
PortId string
|
||||
ChannelId string
|
||||
ProofInit []byte
|
||||
ProofHeight uint64
|
||||
Signer sdk.AccAddress
|
||||
ProofHeight uint64
|
||||
Signer sdk.AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `PortId` is invalid (see naming requirements)
|
||||
- `ChannelId` is invalid (see naming requirements)
|
||||
- `ProofInit` is empty
|
||||
@ -344,11 +376,12 @@ type MsgRecvPacket struct {
|
||||
Packet Packet
|
||||
Proof []byte
|
||||
ProofHeight uint64
|
||||
Signer sdk.AccAddress
|
||||
Signer sdk.AccAddress
|
||||
}
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `Proof` is empty
|
||||
- `ProofHeight` is zero
|
||||
- `Signer` is empty
|
||||
@ -363,7 +396,7 @@ A packet is timed out on chain A using the `MsgTimeout`.
|
||||
|
||||
```go
|
||||
type MsgTimeout struct {
|
||||
Packet Packet
|
||||
Packet Packet
|
||||
Proof []byte
|
||||
ProofHeight uint64
|
||||
NextSequenceRecv uint64
|
||||
@ -372,6 +405,7 @@ type MsgTimeout struct {
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `Proof` is empty
|
||||
- `ProofHeight` is zero
|
||||
- `NextSequenceRecv` is zero
|
||||
@ -388,7 +422,7 @@ the `MsgTimeoutOnClose`.
|
||||
|
||||
```go
|
||||
type MsgTimeoutOnClose struct {
|
||||
Packet Packet
|
||||
Packet Packet
|
||||
Proof []byte
|
||||
ProofClose []byte
|
||||
ProofHeight uint64
|
||||
@ -398,6 +432,7 @@ type MsgTimeoutOnClose struct {
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `Proof` is empty
|
||||
- `ProofClose` is empty
|
||||
- `ProofHeight` is zero
|
||||
@ -413,7 +448,7 @@ The message times out a packet on chain B.
|
||||
|
||||
A packet is acknowledged on chain A using the `MsgAcknowledgement`.
|
||||
|
||||
```go
|
||||
```go
|
||||
type MsgAcknowledgement struct {
|
||||
Packet Packet
|
||||
Acknowledgement []byte
|
||||
@ -424,6 +459,7 @@ type MsgAcknowledgement struct {
|
||||
```
|
||||
|
||||
This message is expected to fail if:
|
||||
|
||||
- `Proof` is empty
|
||||
- `ProofHeight` is zero
|
||||
- `Signer` is empty
|
||||
@ -432,4 +468,3 @@ This message is expected to fail if:
|
||||
- `Proof` does not prove that the counterparty received the `Packet`.
|
||||
|
||||
The message receives a packet on chain A.
|
||||
|
||||
|
||||
@ -123,8 +123,9 @@ func NewTestChain(t *testing.T, chainID string) *TestChain {
|
||||
|
||||
// create current header and call begin block
|
||||
header := tmproto.Header{
|
||||
Height: 1,
|
||||
Time: globalStartTime,
|
||||
ChainID: chainID,
|
||||
Height: 1,
|
||||
Time: globalStartTime,
|
||||
}
|
||||
|
||||
txConfig := simapp.MakeEncodingConfig().TxConfig
|
||||
@ -367,19 +368,40 @@ func (chain *TestChain) GetFirstTestConnection(clientID, counterpartyClientID st
|
||||
return chain.ConstructNextTestConnection(clientID, counterpartyClientID)
|
||||
}
|
||||
|
||||
func (chain *TestChain) ConstructMsgCreateClient(counterparty *TestChain, clientID string) clientexported.MsgCreateClient {
|
||||
return ibctmtypes.NewMsgCreateClient(
|
||||
clientID, counterparty.LastHeader,
|
||||
DefaultTrustLevel, TrustingPeriod, UnbondingPeriod, MaxClockDrift,
|
||||
commitmenttypes.GetSDKSpecs(), chain.SenderAccount.GetAddress(),
|
||||
// ConstructMsgCreateClient constructs a message to create a new client state (tendermint or solomachine).
|
||||
func (chain *TestChain) ConstructMsgCreateClient(counterparty *TestChain, clientID string, clientType string) *clienttypes.MsgCreateClient {
|
||||
var (
|
||||
clientState clientexported.ClientState
|
||||
consensusState clientexported.ConsensusState
|
||||
)
|
||||
|
||||
switch clientType {
|
||||
case clientexported.ClientTypeTendermint:
|
||||
clientState = ibctmtypes.NewClientState(
|
||||
counterparty.ChainID, DefaultTrustLevel, TrustingPeriod, UnbondingPeriod, MaxClockDrift,
|
||||
clienttypes.NewHeight(0, counterparty.LastHeader.GetHeight()), commitmenttypes.GetSDKSpecs(),
|
||||
)
|
||||
consensusState = counterparty.LastHeader.ConsensusState()
|
||||
case clientexported.ClientTypeSoloMachine:
|
||||
solo := NewSolomachine(chain.t, clientID)
|
||||
clientState = solo.ClientState()
|
||||
consensusState = solo.ConsensusState()
|
||||
default:
|
||||
chain.t.Fatalf("unsupported client state type %s", clientType)
|
||||
}
|
||||
|
||||
msg, err := clienttypes.NewMsgCreateClient(
|
||||
clientID, clientState, consensusState, chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
require.NoError(chain.t, err)
|
||||
return msg
|
||||
}
|
||||
|
||||
// CreateTMClient will construct and execute a 07-tendermint MsgCreateClient. A counterparty
|
||||
// client will be created on the (target) chain.
|
||||
func (chain *TestChain) CreateTMClient(counterparty *TestChain, clientID string) error {
|
||||
// construct MsgCreateClient using counterparty
|
||||
msg := chain.ConstructMsgCreateClient(counterparty, clientID)
|
||||
msg := chain.ConstructMsgCreateClient(counterparty, clientID, clientexported.ClientTypeTendermint)
|
||||
return chain.sendMsgs(msg)
|
||||
}
|
||||
|
||||
@ -420,10 +442,11 @@ func (chain *TestChain) UpdateTMClient(counterparty *TestChain, clientID string)
|
||||
}
|
||||
header.TrustedValidators = trustedVals
|
||||
|
||||
msg := ibctmtypes.NewMsgUpdateClient(
|
||||
msg, err := clienttypes.NewMsgUpdateClient(
|
||||
clientID, header,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
require.NoError(chain.t, err)
|
||||
|
||||
return chain.sendMsgs(msg)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user