From f6303ddd8a7b9f42de81c99d2e4e05fd70490aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 15 Jul 2021 13:00:02 +0200 Subject: [PATCH 01/66] migrate ibc-account module to ibc-go --- go.mod | 2 + modules/apps/ibc-account/client/cli/query.go | 52 + modules/apps/ibc-account/genesis.go | 27 + modules/apps/ibc-account/keeper/account.go | 108 +++ modules/apps/ibc-account/keeper/grpc_query.go | 35 + modules/apps/ibc-account/keeper/handshake.go | 107 ++ .../apps/ibc-account/keeper/handshake_test.go | 1 + modules/apps/ibc-account/keeper/keeper.go | 157 +++ modules/apps/ibc-account/keeper/relay.go | 251 +++++ modules/apps/ibc-account/module.go | 256 +++++ modules/apps/ibc-account/spec/03_types.md | 30 + modules/apps/ibc-account/spec/04_keeper.md | 79 ++ modules/apps/ibc-account/spec/05_packets.md | 37 + modules/apps/ibc-account/spec/README.md | 21 + modules/apps/ibc-account/types/account.go | 110 +++ modules/apps/ibc-account/types/account.pb.go | 371 +++++++ modules/apps/ibc-account/types/codec.go | 24 + modules/apps/ibc-account/types/encoder.go | 3 + modules/apps/ibc-account/types/errors.go | 17 + .../ibc-account/types/expected_keepers.go | 47 + modules/apps/ibc-account/types/genesis.go | 7 + modules/apps/ibc-account/types/genesis.pb.go | 319 ++++++ modules/apps/ibc-account/types/hook.go | 30 + modules/apps/ibc-account/types/keys.go | 41 + modules/apps/ibc-account/types/packet.go | 9 + modules/apps/ibc-account/types/querier.go | 7 + modules/apps/ibc-account/types/query.pb.go | 620 ++++++++++++ modules/apps/ibc-account/types/types.pb.go | 913 ++++++++++++++++++ 28 files changed, 3681 insertions(+) create mode 100644 modules/apps/ibc-account/client/cli/query.go create mode 100644 modules/apps/ibc-account/genesis.go create mode 100644 modules/apps/ibc-account/keeper/account.go create mode 100644 modules/apps/ibc-account/keeper/grpc_query.go create mode 100644 modules/apps/ibc-account/keeper/handshake.go create mode 100644 modules/apps/ibc-account/keeper/handshake_test.go create mode 100644 modules/apps/ibc-account/keeper/keeper.go create mode 100644 modules/apps/ibc-account/keeper/relay.go create mode 100644 modules/apps/ibc-account/module.go create mode 100644 modules/apps/ibc-account/spec/03_types.md create mode 100644 modules/apps/ibc-account/spec/04_keeper.md create mode 100644 modules/apps/ibc-account/spec/05_packets.md create mode 100644 modules/apps/ibc-account/spec/README.md create mode 100644 modules/apps/ibc-account/types/account.go create mode 100644 modules/apps/ibc-account/types/account.pb.go create mode 100644 modules/apps/ibc-account/types/codec.go create mode 100644 modules/apps/ibc-account/types/encoder.go create mode 100644 modules/apps/ibc-account/types/errors.go create mode 100644 modules/apps/ibc-account/types/expected_keepers.go create mode 100644 modules/apps/ibc-account/types/genesis.go create mode 100644 modules/apps/ibc-account/types/genesis.pb.go create mode 100644 modules/apps/ibc-account/types/hook.go create mode 100644 modules/apps/ibc-account/types/keys.go create mode 100644 modules/apps/ibc-account/types/packet.go create mode 100644 modules/apps/ibc-account/types/querier.go create mode 100644 modules/apps/ibc-account/types/query.pb.go create mode 100644 modules/apps/ibc-account/types/types.pb.go diff --git a/go.mod b/go.mod index c0fc5269937..a647d655cf3 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 + github.com/regen-network/cosmos-proto v0.3.1 github.com/spf13/cast v1.3.1 github.com/spf13/cobra v1.2.1 github.com/spf13/viper v1.8.1 @@ -23,4 +24,5 @@ require ( google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c google.golang.org/grpc v1.39.0 google.golang.org/protobuf v1.27.1 + gopkg.in/yaml.v2 v2.4.0 ) diff --git a/modules/apps/ibc-account/client/cli/query.go b/modules/apps/ibc-account/client/cli/query.go new file mode 100644 index 00000000000..35f10bc04f4 --- /dev/null +++ b/modules/apps/ibc-account/client/cli/query.go @@ -0,0 +1,52 @@ +package cli + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" + + "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" +) + +func GetQueryCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the ibc account module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(GetIBCAccountCmd()) + + return cmd +} + +func GetIBCAccountCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "address [address] [connection-id]", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + address := args[0] + connectionId := args[1] + + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.IBCAccount(context.Background(), &types.QueryIBCAccountRequest{Address: address, ConnectionId: connectionId}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/modules/apps/ibc-account/genesis.go b/modules/apps/ibc-account/genesis.go new file mode 100644 index 00000000000..1bffea2b5c4 --- /dev/null +++ b/modules/apps/ibc-account/genesis.go @@ -0,0 +1,27 @@ +package ibc_account + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/modules/apps/ibc-account/keeper" + "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" +) + +func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState) { + if !keeper.IsBound(ctx, state.PortId) { + err := keeper.BindPort(ctx, state.PortId) + if err != nil { + panic(fmt.Sprintf("could not claim port capability: %v", err)) + } + } +} + +// ExportGenesis exports transfer module's portID into its geneis state +func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState { + portID := keeper.GetPort(ctx) + + return &types.GenesisState{ + PortId: portID, + } +} diff --git a/modules/apps/ibc-account/keeper/account.go b/modules/apps/ibc-account/keeper/account.go new file mode 100644 index 00000000000..e165eea4773 --- /dev/null +++ b/modules/apps/ibc-account/keeper/account.go @@ -0,0 +1,108 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/modules/core/24-host" + "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" + "github.com/tendermint/tendermint/crypto/tmhash" +) + +// The first step in registering an interchain account +// Binds a new port & calls OnChanOpenInit +func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionId, owner string) error { + portId := k.GeneratePortId(owner, connectionId) + + // Check if the port is already bound + isBound := k.IsBound(ctx, portId) + if isBound == true { + return sdkerrors.Wrap(types.ErrPortAlreadyBound, portId) + } + + portCap := k.portKeeper.BindPort(ctx, portId) + err := k.ClaimCapability(ctx, portCap, host.PortPath(portId)) + if err != nil { + return err + } + + counterParty := channeltypes.Counterparty{PortId: "ibcaccount", ChannelId: ""} + order := channeltypes.Order(2) + channelId, cap, err := k.channelKeeper.ChanOpenInit(ctx, order, []string{connectionId}, portId, portCap, counterParty, types.Version) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + channeltypes.EventTypeChannelOpenInit, + sdk.NewAttribute(channeltypes.AttributeKeyPortID, portId), + sdk.NewAttribute(channeltypes.AttributeKeyChannelID, channelId), + sdk.NewAttribute(channeltypes.AttributeCounterpartyPortID, "ibcaccount"), + sdk.NewAttribute(channeltypes.AttributeCounterpartyChannelID, ""), + sdk.NewAttribute(channeltypes.AttributeKeyConnectionID, connectionId), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, channeltypes.AttributeValueCategory), + ), + }) + + _ = k.OnChanOpenInit(ctx, channeltypes.Order(2), []string{connectionId}, portId, channelId, cap, counterParty, types.Version) + + return err +} + +// Register interchain account if it has not already been created +func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portId string) (types.IBCAccountI, error) { + address := k.GenerateAddress(portId) + account := k.accountKeeper.GetAccount(ctx, address) + + if account != nil { + return nil, sdkerrors.Wrap(types.ErrAccountAlreadyExist, account.String()) + } + + interchainAccount := types.NewIBCAccount( + authtypes.NewBaseAccountWithAddress(address), + portId, + ) + k.accountKeeper.NewAccount(ctx, interchainAccount) + k.accountKeeper.SetAccount(ctx, interchainAccount) + _ = k.SetInterchainAccountAddress(ctx, portId, interchainAccount.Address) + + return interchainAccount, nil +} + +func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portId string, address string) string { + store := ctx.KVStore(k.storeKey) + key := types.KeyOwnerAccount(portId) + store.Set(key, []byte(address)) + return address +} + +func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portId string) (string, error) { + store := ctx.KVStore(k.storeKey) + key := types.KeyOwnerAccount(portId) + if !store.Has(key) { + return "", sdkerrors.Wrap(types.ErrIBCAccountNotFound, portId) + } + + interchainAccountAddr := string(store.Get(key)) + return interchainAccountAddr, nil +} + +// Determine account's address that will be created. +func (k Keeper) GenerateAddress(identifier string) []byte { + return tmhash.SumTruncated(append([]byte(identifier))) +} + +func (k Keeper) GetIBCAccount(ctx sdk.Context, addr sdk.AccAddress) (types.IBCAccount, error) { + acc := k.accountKeeper.GetAccount(ctx, addr) + if acc == nil { + return types.IBCAccount{}, sdkerrors.Wrap(types.ErrIBCAccountNotFound, "there is no account") + } + + ibcAcc, ok := acc.(*types.IBCAccount) + if !ok { + return types.IBCAccount{}, sdkerrors.Wrap(types.ErrIBCAccountNotFound, "account is not an IBC account") + } + return *ibcAcc, nil +} diff --git a/modules/apps/ibc-account/keeper/grpc_query.go b/modules/apps/ibc-account/keeper/grpc_query.go new file mode 100644 index 00000000000..512134cd40a --- /dev/null +++ b/modules/apps/ibc-account/keeper/grpc_query.go @@ -0,0 +1,35 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" +) + +var _ types.QueryServer = Keeper{} + +// IBCAccount implements the Query/IBCAccount gRPC method +func (k Keeper) IBCAccount(ctx context.Context, req *types.QueryIBCAccountRequest) (*types.QueryIBCAccountResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + if req.Address == "" { + return nil, status.Error(codes.InvalidArgument, "address cannot be empty") + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + portId := k.GeneratePortId(req.Address, req.ConnectionId) + + address, err := k.GetInterchainAccountAddress(sdkCtx, portId) + if err != nil { + return nil, err + } + + return &types.QueryIBCAccountResponse{AccountAddress: address}, nil +} diff --git a/modules/apps/ibc-account/keeper/handshake.go b/modules/apps/ibc-account/keeper/handshake.go new file mode 100644 index 00000000000..614ed22882d --- /dev/null +++ b/modules/apps/ibc-account/keeper/handshake.go @@ -0,0 +1,107 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/modules/core/24-host" +) + +func (k Keeper) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) error { + //TODO: + // check version string + if order != channeltypes.ORDERED { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "invalid channel ordering: %s, expected %s", order.String(), channeltypes.ORDERED.String()) + } + + // Claim channel capability passed back by IBC module + if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, err.Error()) + } + + return nil +} + +// register account (if it doesn't exist) +// check if counterpary version is the same +// TODO: remove ics27-1 hardcoded +func (k Keeper) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version, + counterpartyVersion string, +) error { + if order != channeltypes.ORDERED { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "invalid channel ordering: %s, expected %s", order.String(), channeltypes.ORDERED.String()) + } + + // TODO: Check counterparty version + // if counterpartyVersion != types.Version { + // return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid counterparty version: %s, expected %s", counterpartyVersion, "ics20-1") + // } + + // Claim channel capability passed back by IBC module + if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, err.Error()) + } + + // Register interchain account if it does not already exist + _, _ = k.RegisterInterchainAccount(ctx, counterparty.PortId) + return nil +} + +func (k Keeper) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyVersion string, +) error { + k.SetActiveChannel(ctx, portID, channelID) + + return nil +} + +// Set active channel +func (k Keeper) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + + return nil +} + +// May want to use these for re-opening a channel when it is closed +//// OnChanCloseInit implements the IBCModule interface +//func (am AppModule) OnChanCloseInit( +// ctx sdk.Context, +// portID, +// channelID string, +//) error { +// // Disallow user-initiated channel closing for transfer channels +// return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") +//} + +//// OnChanCloseConfirm implements the IBCModule interface +//func (am AppModule) OnChanCloseConfirm( +// ctx sdk.Context, +// portID, +// channelID string, +//) error { +// return nil +//} diff --git a/modules/apps/ibc-account/keeper/handshake_test.go b/modules/apps/ibc-account/keeper/handshake_test.go new file mode 100644 index 00000000000..9429264902a --- /dev/null +++ b/modules/apps/ibc-account/keeper/handshake_test.go @@ -0,0 +1 @@ +package keeper_test diff --git a/modules/apps/ibc-account/keeper/keeper.go b/modules/apps/ibc-account/keeper/keeper.go new file mode 100644 index 00000000000..4958645e367 --- /dev/null +++ b/modules/apps/ibc-account/keeper/keeper.go @@ -0,0 +1,157 @@ +package keeper + +import ( + "fmt" + "strings" + + baseapp "github.com/cosmos/cosmos-sdk/baseapp" + "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" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + host "github.com/cosmos/ibc-go/modules/core/24-host" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" +) + +// Keeper defines the IBC transfer keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc codec.BinaryCodec + + hook types.IBCAccountHooks + + channelKeeper types.ChannelKeeper + portKeeper types.PortKeeper + accountKeeper types.AccountKeeper + + scopedKeeper capabilitykeeper.ScopedKeeper + + msgRouter *baseapp.MsgServiceRouter + memKey sdk.StoreKey +} + +// NewKeeper creates a new IBC account Keeper instance +func NewKeeper( + memKey sdk.StoreKey, + cdc codec.BinaryCodec, key sdk.StoreKey, + channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, + accountKeeper types.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, hook types.IBCAccountHooks, +) Keeper { + return Keeper{ + storeKey: key, + cdc: cdc, + channelKeeper: channelKeeper, + portKeeper: portKeeper, + accountKeeper: accountKeeper, + scopedKeeper: scopedKeeper, + msgRouter: msgRouter, + memKey: memKey, + hook: hook, + } +} + +func (k Keeper) SerializeCosmosTx(cdc codec.BinaryCodec, data interface{}) ([]byte, error) { + msgs := make([]sdk.Msg, 0) + switch data := data.(type) { + case sdk.Msg: + msgs = append(msgs, data) + case []sdk.Msg: + msgs = append(msgs, data...) + default: + return nil, types.ErrInvalidOutgoingData + } + + msgAnys := make([]*codectypes.Any, len(msgs)) + + for i, msg := range msgs { + var err error + msgAnys[i], err = codectypes.NewAnyWithValue(msg) + if err != nil { + return nil, err + } + } + + txBody := &types.IBCTxBody{ + Messages: msgAnys, + } + + txRaw := &types.IBCTxRaw{ + BodyBytes: cdc.MustMarshal(txBody), + } + + bz, err := cdc.Marshal(txRaw) + if err != nil { + return nil, err + } + + return bz, nil +} + +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) +} + +// IsBound checks if the interchain account module is already bound to the desired port +func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { + _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) + return ok +} + +// BindPort defines a wrapper function for the ort Keeper's function in +// order to expose it to module's InitGenesis function +func (k Keeper) BindPort(ctx sdk.Context, portID string) error { + // Set the portID into our store so we can retrieve it later + store := ctx.KVStore(k.storeKey) + store.Set([]byte(types.PortKey), []byte(portID)) + + cap := k.portKeeper.BindPort(ctx, portID) + return k.ClaimCapability(ctx, cap, host.PortPath(portID)) +} + +// GetPort returns the portID for the ibc account module. Used in ExportGenesis +func (k Keeper) GetPort(ctx sdk.Context) string { + store := ctx.KVStore(k.storeKey) + return string(store.Get([]byte(types.PortKey))) +} + +// ClaimCapability allows the transfer module that can claim a capability that IBC module +// passes to it +func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { + return k.scopedKeeper.ClaimCapability(ctx, cap, name) +} + +// Utility function for parsing the connection number from the connection-id +func getConnectionNumber(connectionId string) string { + ss := strings.Split(connectionId, "-") + return ss[len(ss)-1] +} + +func (k Keeper) GeneratePortId(owner, connectionId string) string { + ownerId := strings.TrimSpace(owner) + connectionNumber := getConnectionNumber(connectionId) + portId := types.IcaPrefix + connectionNumber + "-" + ownerId + return portId +} + +func (k Keeper) SetActiveChannel(ctx sdk.Context, portId, channelId string) error { + store := ctx.KVStore(k.storeKey) + + key := types.KeyActiveChannel(portId) + store.Set(key, []byte(channelId)) + return nil +} + +func (k Keeper) GetActiveChannel(ctx sdk.Context, portId string) (string, error) { + store := ctx.KVStore(k.storeKey) + key := types.KeyActiveChannel(portId) + if !store.Has(key) { + return "", sdkerrors.Wrap(types.ErrActiveChannelNotFound, portId) + } + + activeChannel := string(store.Get(key)) + return activeChannel, nil +} diff --git a/modules/apps/ibc-account/keeper/relay.go b/modules/apps/ibc-account/keeper/relay.go new file mode 100644 index 00000000000..09e616b0ec0 --- /dev/null +++ b/modules/apps/ibc-account/keeper/relay.go @@ -0,0 +1,251 @@ +package keeper + +import ( + "encoding/binary" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/modules/core/24-host" + "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" + "github.com/tendermint/tendermint/crypto/tmhash" +) + +func (k Keeper) TrySendTx(ctx sdk.Context, accountOwner sdk.AccAddress, connectionId string, data interface{}) ([]byte, error) { + portId := k.GeneratePortId(accountOwner.String(), connectionId) + // Check for the active channel + activeChannelId, err := k.GetActiveChannel(ctx, portId) + if err != nil { + return nil, err + } + + sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, portId, activeChannelId) + if !found { + return []byte{}, sdkerrors.Wrap(channeltypes.ErrChannelNotFound, activeChannelId) + } + + destinationPort := sourceChannelEnd.GetCounterparty().GetPortID() + destinationChannel := sourceChannelEnd.GetCounterparty().GetChannelID() + + return k.createOutgoingPacket(ctx, portId, activeChannelId, destinationPort, destinationChannel, data) +} + +func (k Keeper) createOutgoingPacket( + ctx sdk.Context, + sourcePort, + sourceChannel, + destinationPort, + destinationChannel string, + data interface{}, +) ([]byte, error) { + + if data == nil { + return []byte{}, types.ErrInvalidOutgoingData + } + + var msgs []sdk.Msg + + switch data := data.(type) { + case []sdk.Msg: + msgs = data + case sdk.Msg: + msgs = []sdk.Msg{data} + default: + return []byte{}, types.ErrInvalidOutgoingData + } + + txBytes, err := k.SerializeCosmosTx(k.cdc, msgs) + if err != nil { + return []byte{}, sdkerrors.Wrap(err, "invalid packet data or codec") + } + + channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(sourcePort, sourceChannel)) + if !ok { + return []byte{}, sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + + // get the next sequence + sequence, found := k.channelKeeper.GetNextSequenceSend(ctx, sourcePort, sourceChannel) + if !found { + return []byte{}, channeltypes.ErrSequenceSendNotFound + } + + packetData := types.IBCAccountPacketData{ + Type: types.Type_RUNTX, + Data: txBytes, + } + + // timeoutTimestamp is set to be a max number here so that we never recieve a timeout + // ics-27-1 uses ordered channels which can close upon recieving a timeout, which is an undesired effect + const timeoutTimestamp = ^uint64(0) >> 1 // Shift the unsigned bit to satisfy hermes relayer timestamp conversion + + packet := channeltypes.NewPacket( + packetData.GetBytes(), + sequence, + sourcePort, + sourceChannel, + destinationPort, + destinationChannel, + clienttypes.ZeroHeight(), + timeoutTimestamp, + ) + + return k.ComputeVirtualTxHash(packetData.Data, packet.Sequence), k.channelKeeper.SendPacket(ctx, channelCap, packet) +} + +func (k Keeper) DeserializeTx(_ sdk.Context, txBytes []byte) ([]sdk.Msg, error) { + var txRaw types.IBCTxRaw + + err := k.cdc.Unmarshal(txBytes, &txRaw) + if err != nil { + return nil, err + } + + var txBody types.IBCTxBody + + err = k.cdc.Unmarshal(txRaw.BodyBytes, &txBody) + if err != nil { + return nil, err + } + + anys := txBody.Messages + res := make([]sdk.Msg, len(anys)) + for i, any := range anys { + var msg sdk.Msg + err := k.cdc.UnpackAny(any, &msg) + if err != nil { + return nil, err + } + res[i] = msg + } + + return res, nil +} + +func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portId string) error { + seen := map[string]bool{} + var signers []sdk.AccAddress + for _, msg := range msgs { + for _, addr := range msg.GetSigners() { + if !seen[addr.String()] { + signers = append(signers, addr) + seen[addr.String()] = true + } + } + } + + interchainAccountAddr, err := k.GetInterchainAccountAddress(ctx, portId) + if err != nil { + return sdkerrors.ErrUnauthorized + } + + for _, signer := range signers { + if interchainAccountAddr != signer.String() { + return sdkerrors.ErrUnauthorized + } + } + + return nil +} + +func (k Keeper) executeTx(ctx sdk.Context, sourcePort, destPort, destChannel string, msgs []sdk.Msg) error { + err := k.AuthenticateTx(ctx, msgs, sourcePort) + if err != nil { + return err + } + + for _, msg := range msgs { + err := msg.ValidateBasic() + if err != nil { + return err + } + } + + cacheContext, writeFn := ctx.CacheContext() + for _, msg := range msgs { + _, msgErr := k.executeMsg(cacheContext, msg) + if msgErr != nil { + err = msgErr + break + } + } + + if err != nil { + return err + } + + // Write the state transitions if all handlers succeed. + writeFn() + + return nil +} + +// It tries to get the handler from router. And, if router exites, it will perform message. +func (k Keeper) executeMsg(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + handler := k.msgRouter.Handler(msg) + if handler == nil { + return nil, types.ErrInvalidRoute + } + + return handler(ctx, msg) +} + +// Compute the virtual tx hash that is used only internally. +func (k Keeper) ComputeVirtualTxHash(txBytes []byte, seq uint64) []byte { + bz := make([]byte, 8) + binary.LittleEndian.PutUint64(bz, seq) + return tmhash.SumTruncated(append(txBytes, bz...)) +} + +func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error { + var data types.IBCAccountPacketData + + if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal interchain account packet data: %s", err.Error()) + } + + switch data.Type { + case types.Type_RUNTX: + msgs, err := k.DeserializeTx(ctx, data.Data) + if err != nil { + return err + } + + err = k.executeTx(ctx, packet.SourcePort, packet.DestinationPort, packet.DestinationChannel, msgs) + if err != nil { + return err + } + + return nil + default: + return types.ErrUnknownPacketData + } +} + +func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.IBCAccountPacketData, ack channeltypes.Acknowledgement) error { + switch ack.Response.(type) { + case *channeltypes.Acknowledgement_Error: + if k.hook != nil { + k.hook.OnTxFailed(ctx, packet.SourcePort, packet.SourceChannel, k.ComputeVirtualTxHash(data.Data, packet.Sequence), data.Data) + } + return nil + case *channeltypes.Acknowledgement_Result: + if k.hook != nil { + k.hook.OnTxSucceeded(ctx, packet.SourcePort, packet.SourceChannel, k.ComputeVirtualTxHash(data.Data, packet.Sequence), data.Data) + } + return nil + default: + // the acknowledgement succeeded on the receiving chain so nothing + // needs to be executed and no error needs to be returned + return nil + } +} + +func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.IBCAccountPacketData) error { + if k.hook != nil { + k.hook.OnTxFailed(ctx, packet.SourcePort, packet.SourceChannel, k.ComputeVirtualTxHash(data.Data, packet.Sequence), data.Data) + } + + return nil +} diff --git a/modules/apps/ibc-account/module.go b/modules/apps/ibc-account/module.go new file mode 100644 index 00000000000..6c3b93ba995 --- /dev/null +++ b/modules/apps/ibc-account/module.go @@ -0,0 +1,256 @@ +package ibc_account + +import ( + "encoding/json" + "fmt" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "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/types/module" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/ibc-go/modules/apps/ibc-account/client/cli" + "github.com/cosmos/ibc-go/modules/apps/ibc-account/keeper" + "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/modules/core/exported" +) + +var ( + _ module.AppModule = AppModule{} + _ porttypes.IBCModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +type AppModuleBasic struct{} + +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec implements AppModuleBasic interface +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) +} + +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + return nil +} + +func (AppModuleBasic) RegisterRESTRoutes(ctx client.Context, rtr *mux.Router) { + // noop +} + +func (AppModuleBasic) GetTxCmd() *cobra.Command { + // noop + return nil +} + +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// RegisterInterfaces registers module concrete types into protobuf Any. +func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { + types.RegisterInterfaces(registry) +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the ibc-account module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { +} + +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper +} + +func NewAppModule(k keeper.Keeper) AppModule { + return AppModule{ + keeper: k, + } +} + +func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + // TODO +} + +func (AppModule) Route() sdk.Route { + return sdk.NewRoute(types.RouterKey, nil) +} + +func (AppModule) NewHandler() sdk.Handler { + return nil +} + +func (AppModule) QuerierRoute() string { + return types.QuerierRoute +} + +// LegacyQuerierHandler implements the AppModule interface +func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return nil +} + +// RegisterServices registers a GRPC query service to respond to the +// module-specific GRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + cdc.MustUnmarshalJSON(data, &genesisState) + + InitGenesis(ctx, am.keeper, genesisState) + return []abci.ValidatorUpdate{} +} + +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + gs := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(gs) +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// BeginBlock implements the AppModule interface +func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { + +} + +// EndBlock implements the AppModule interface +func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// Implement IBCModule callbacks +func (am AppModule) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) error { + return am.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) +} + +func (am AppModule) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version, + counterpartyVersion string, +) error { + return am.keeper.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version, counterpartyVersion) +} + +func (am AppModule) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyVersion string, +) error { + return am.keeper.OnChanOpenAck(ctx, portID, channelID, counterpartyVersion) +} + +func (am AppModule) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return am.keeper.OnChanOpenConfirm(ctx, portID, channelID) +} + +func (am AppModule) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + // Disallow user-initiated channel closing for interchain account channels + return nil +} + +func (am AppModule) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") +} + +func (am AppModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + _ sdk.AccAddress, +) ibcexported.Acknowledgement { + ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + + var data types.IBCAccountPacketData + if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + ack = channeltypes.NewErrorAcknowledgement(fmt.Sprintf("cannot unmarshal ICS-27 interchain account packet data: %s", err.Error())) + } + + // only attempt the application logic if the packet data + // was successfully decoded + if ack.Success() { + err := am.keeper.OnRecvPacket(ctx, packet) + if err != nil { + ack = channeltypes.NewErrorAcknowledgement(err.Error()) + } + } + + // NOTE: acknowledgement will be written synchronously during IBC handler execution. + return ack +} + +func (am AppModule) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + _ sdk.AccAddress, +) error { + var ack channeltypes.Acknowledgement + + if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-27 interchain account packet acknowledgment: %v", err) + } + var data types.IBCAccountPacketData + if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-27 interchain account packet data: %s", err.Error()) + } + + if err := am.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil { + return err + } + + return nil +} + +func (am AppModule) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, + _ sdk.AccAddress, +) error { + // TODO + return nil +} diff --git a/modules/apps/ibc-account/spec/03_types.md b/modules/apps/ibc-account/spec/03_types.md new file mode 100644 index 00000000000..2bb17cd4cc1 --- /dev/null +++ b/modules/apps/ibc-account/spec/03_types.md @@ -0,0 +1,30 @@ + + +# Types + +## IBCAccount + +IBCAccount implements the standard AccountI interface similar to Cosmos SDK x/auth module's BaseAccount or Module Account + +```proto +// IBCAccount defines an account to which other chains have privileges +message IBCAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + option (cosmos_proto.implements_interface) = "IBCAccountI"; + + cosmos.auth.v1beta1.BaseAccount base_account = 1 [(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"base_account\""]; + string sourcePort = 2; + string sourceChannel = 3; + string destinationPort = 4; + string destinationChannel = 5; +} +``` + +As shown above, IBCAccount embeds the BaseAccount, and is assigned an Address and AccountNumber similar to the BaseAccount. However, because IBCAccount was designed to be used through the module, and not the user, there is no need to designate a PubKey or Sequence (which is implemented in the ModuleAccount). + +Also, IBCAccount stores the information on the IBC Port and Channel that requested the creation of the account. + +One can check if a specific address is an IBCAccount as well as the actual IBCAccount type through the IBCAccountKeeper's GetIBCAccount method. If the address queried doesn't exist or is not an IBC account, an error is returned. diff --git a/modules/apps/ibc-account/spec/04_keeper.md b/modules/apps/ibc-account/spec/04_keeper.md new file mode 100644 index 00000000000..dacc25b1124 --- /dev/null +++ b/modules/apps/ibc-account/spec/04_keeper.md @@ -0,0 +1,79 @@ + +# Keeper + +## Structure + +```go + +type TxEncoder func(data interface{}) ([]byte, error) + +type Keeper struct { + ... + txEncoders map[string]types.TxEncoder + ... + router types.Router +} +``` + +The most important part of the IBC account keeper, as shown above, is the **map of txEncoders** and the **router**. Because ICS-027 specification defines that the chain can send arbitrary tx bytes to the counterparty chain, both chains must define the way that they process the caller's requests or make the tx bytes that the callee can process. + +The `TxEncoder` serializes the source chain's tx bytes from any data. And the map of `TxEncoder` has the key, such as `chain-id` and `keeper`, which the keeper uses to send packets. Therefore, it is necessary to know which source chain's transaction is being executed. + +`SerializeCosmosTx(cdc codec.BinaryCodec, registry codectypes.InterfaceRegistry)` provides a way to serialize the tx bytes from messages if the destination chain is based on the Cosmos-SDK. + +The router is used to delegate the process of handling the message to a module. When a packet which requests a set of transaction bytes to be run is passed, the router deserializes the tx bytes and passes the message to the handler. The keeper checks the result of each message, and if any message returns an error, the entire transaction is aborted, and state change rolled back. + +`TryRunTx(ctx sdk.Context, sourcePort, sourceChannel, typ string, data interface{}, timeoutHeight clienttypes.Height, timeoutTimestamp uint64)` method is used to request transactions to be run on the destination chain. This method uses the `typ` parameter from the `txEncoders map`'s key to find the right `txEncoder`. If the `txEncoder` exists, the transaction is serialized and a `RUNTX` packet is sent to the destination chain. The `TryRunTx` also returns the virtual txHash which is used in the 'Hook' section shown below. This virtual txHash is not related to the actual on-chain transaction, but only 'virtually' created so transactions requested by the Hook can be identified. + +### IBC Packets + +```go + +enum Type { + REGISTER = 0; + RUNTX = 1; +} + +message IBCAccountPacketData { + Type type = 1; + bytes data = 2; +} + +message IBCAccountPacketAcknowledgement { + Type type = 1; + string chainID = 2; + uint32 code = 3; + string error = 4; +} +``` + +The example above shows the IBC packets that are used in ICS-027. `Type` indicates what action the packet is performing. When a `REGISTER` packet type is delivered, the counterparty chain will create an account with the address using the hash of {destPort}/{destChannel}/{packet.data}, assuming a duplicate prior account doesn't exist. + +If the account is created successfully, it returns an acknowledgement packet to the origin chain with type `REGISTER` and code `0`. If there's an error, it returns the acknowledgement packet with type `REGISTER` and the code of the resulting error. + +When a `RUNTX` type packet is delivered, the counterparty chain will deserialize the tx bytes (packet's data field) in a predefined way. + +In this implementation of ICS27 for the Cosmos-SDK, it deserializes the tx bytes into slices of messages and gets the handler from the router and executes and checks the result like described above. + +If the all messages are successful, it returns the acknowledgment packet to the chain with type `RUNTX` and code `0`. If there's an error, it returns the acknowledgement packet with type `RUNTX` and the code and error of the first failed message. + +### Hook + +```go + +type IBCAccountHooks interface { + OnAccountCreated(ctx sdk.Context, sourcePort, sourceChannel string, address sdk.AccAddress) + OnTxSucceeded(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) + OnTxFailed(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) +} +``` + +The example above shows the hook for helping developer using the IBC account keeper. + +The hook lets the developer know whether the IBC account has been successfully created on the counterparty chain. + +After sending the packet with an `IBCAccountPacketData` with the type `REGISTER`, if the acknowledgement packet with the type `REGISTER` and code `0` is delivered, `OnAccountCreated` is executed with the counterparty chain's chain-id and address. + +After sending the packet with an `IBCAccountPacketData` with the type `RUNTX`, if the acknowledgement packet with the type `RUNTX` and code `0` is delivered, `OnTxSucceeded` is executed with the counterparty chain's chain-id, virtual tx hash and requested data that is not serialized. Virtual tx hash is used only for internal logic to distinguish the requested tx and it is computed by hashing the tx bytes and sequence of packet. Otherwise, `OnTxFailed` will be executed. diff --git a/modules/apps/ibc-account/spec/05_packets.md b/modules/apps/ibc-account/spec/05_packets.md new file mode 100644 index 00000000000..d6fdd72b006 --- /dev/null +++ b/modules/apps/ibc-account/spec/05_packets.md @@ -0,0 +1,37 @@ + + +# Packets + +```proto +message IBCTxRaw { + bytes body_bytes = 1; +} + +message IBCTxBody { + repeated google.protobuf.Any messages = 1; +} + +enum Type { + REGISTER = 0; + RUNTX = 1; +} + +message IBCAccountPacketData { + Type type = 1; + bytes data = 2; +} + +message IBCAccountPacketAcknowledgement { + Type type = 1; + string chainID = 2; + uint32 code = 3; + bytes data = 4; + string error = 5; +} +``` + +- `IBCAccountPacketAcknowledgement` returns the result of the packet request back to the chain that sent the packet. +- `IBCAccountPacketData` is sent when the counterparty chain registers a IBCAccount or wants to execute a specific tx through the IBC Account. +- `IBCAccountPacketData` type field displays the behavior requested by the packet. If the type is `REGISTER`, this means request to register a new IBCAccount. In this case, the destination chain can set the IBCAccount's address, but typically it is recommended to refer to the data field to create the address in a deterministic way. If the IBCAccount has been successfully registered, an `IBCAccountPacketAcknowledgment` is returned to the requesting chain with the `Code` field set to `0`. If there was an error, an `IBCAccountPacketAcknowledgment` is returned to the requesting chain with the `Code` field including the error message. diff --git a/modules/apps/ibc-account/spec/README.md b/modules/apps/ibc-account/spec/README.md new file mode 100644 index 00000000000..88b4a45e658 --- /dev/null +++ b/modules/apps/ibc-account/spec/README.md @@ -0,0 +1,21 @@ + + +# IBC Account + +## Abstract + +This document specifies the IBC account module for the Cosmos SDK. + +The IBCAccount module manages the creation of IBC Accounts and ICS20 packet handling for the IBC accounts. This module is built based on the [ICS27 specification](https://github.com/cosmos/ics/tree/master/spec/ics-027-interchain-accounts). IBC Accounts allow a remote, IBC-connected **source blockchain** to request an arbitrary transaction to be executed on the **destination blockchain**(the chain which hosts the IBC account) via the IBC account. It should be noted that an IBC account has similar properties to a user account, and are bound to the same restrictions (unbonding periods, redelegation rules, etc). + +The current implementation allows the same IBCAccount module on the destination chain to run any of the domiciling blockchain's native transactions that a user account is able to request(i.e. same module can handle 'send', 'stake', 'vote', etc), but the controlling chain/source chain must implement its own logic for controlling the IBC account from its own IBCAccount logic. + +## Contents +1. **[Types](03_types.md)** +2. **[Keeper](04_keeper.md)** +3. **[Packets](05_packets.md)** diff --git a/modules/apps/ibc-account/types/account.go b/modules/apps/ibc-account/types/account.go new file mode 100644 index 00000000000..eaf8f65e590 --- /dev/null +++ b/modules/apps/ibc-account/types/account.go @@ -0,0 +1,110 @@ +package types + +import ( + "encoding/json" + "fmt" + + yaml "gopkg.in/yaml.v2" + + crypto "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +const ( + IcaPrefix string = "ics27-1-" +) + +type IBCAccountI interface { + authtypes.AccountI +} + +var ( + _ authtypes.GenesisAccount = (*IBCAccount)(nil) + _ IBCAccountI = (*IBCAccount)(nil) +) + +func NewIBCAccount(ba *authtypes.BaseAccount, accountOwner string) *IBCAccount { + return &IBCAccount{ + BaseAccount: ba, + AccountOwner: accountOwner, + } +} + +// SetPubKey - Implements AccountI +func (IBCAccount) SetPubKey(pubKey crypto.PubKey) error { + return fmt.Errorf("not supported for ibc accounts") +} + +// SetSequence - Implements AccountI +func (IBCAccount) SetSequence(seq uint64) error { + return fmt.Errorf("not supported for ibc accounts") +} + +func (ia IBCAccount) Validate() error { + return ia.BaseAccount.Validate() +} + +type ibcAccountPretty struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + PubKey string `json:"public_key" yaml:"public_key"` + AccountNumber uint64 `json:"account_number" yaml:"account_number"` + Sequence uint64 `json:"sequence" yaml:"sequence"` + AccountOwner string `json:"address" yaml:"account_owner"` +} + +func (ia IBCAccount) String() string { + out, _ := ia.MarshalYAML() + return out.(string) +} + +// MarshalYAML returns the YAML representation of a IBCAccount. +func (ia IBCAccount) MarshalYAML() (interface{}, error) { + accAddr, err := sdk.AccAddressFromBech32(ia.Address) + if err != nil { + return nil, err + } + + bs, err := yaml.Marshal(ibcAccountPretty{ + Address: accAddr, + PubKey: "", + AccountNumber: ia.AccountNumber, + Sequence: ia.Sequence, + AccountOwner: ia.AccountOwner, + }) + + if err != nil { + return nil, err + } + + return string(bs), nil +} + +// MarshalJSON returns the JSON representation of a IBCAccount. +func (ia IBCAccount) MarshalJSON() ([]byte, error) { + accAddr, err := sdk.AccAddressFromBech32(ia.Address) + if err != nil { + return nil, err + } + + return json.Marshal(ibcAccountPretty{ + Address: accAddr, + PubKey: "", + AccountNumber: ia.AccountNumber, + Sequence: ia.Sequence, + AccountOwner: ia.AccountOwner, + }) +} + +// UnmarshalJSON unmarshals raw JSON bytes into a ModuleAccount. +func (ia *IBCAccount) UnmarshalJSON(bz []byte) error { + var alias ibcAccountPretty + if err := json.Unmarshal(bz, &alias); err != nil { + return err + } + + ia.BaseAccount = authtypes.NewBaseAccount(alias.Address, nil, alias.AccountNumber, alias.Sequence) + ia.AccountOwner = alias.AccountOwner + + return nil +} diff --git a/modules/apps/ibc-account/types/account.pb.go b/modules/apps/ibc-account/types/account.pb.go new file mode 100644 index 00000000000..85774b081af --- /dev/null +++ b/modules/apps/ibc-account/types/account.pb.go @@ -0,0 +1,371 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/account/account.proto + +package types + +import ( + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/x/auth/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + _ "github.com/regen-network/cosmos-proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// IBCAccount defines an account to which other chains have privileges +type IBCAccount struct { + *types.BaseAccount `protobuf:"bytes,1,opt,name=base_account,json=baseAccount,proto3,embedded=base_account" json:"base_account,omitempty" yaml:"base_account"` + AccountOwner string `protobuf:"bytes,2,opt,name=accountOwner,proto3" json:"accountOwner,omitempty"` +} + +func (m *IBCAccount) Reset() { *m = IBCAccount{} } +func (*IBCAccount) ProtoMessage() {} +func (*IBCAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_be5ed7ee65e0e021, []int{0} +} +func (m *IBCAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IBCAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IBCAccount.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *IBCAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_IBCAccount.Merge(m, src) +} +func (m *IBCAccount) XXX_Size() int { + return m.Size() +} +func (m *IBCAccount) XXX_DiscardUnknown() { + xxx_messageInfo_IBCAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_IBCAccount proto.InternalMessageInfo + +func init() { + proto.RegisterType((*IBCAccount)(nil), "ibc.account.IBCAccount") +} + +func init() { proto.RegisterFile("ibc/account/account.proto", fileDescriptor_be5ed7ee65e0e021) } + +var fileDescriptor_be5ed7ee65e0e021 = []byte{ + // 283 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0x4c, 0x4a, 0xd6, + 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0x81, 0xd1, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, + 0xdc, 0x99, 0x49, 0xc9, 0x7a, 0x50, 0x21, 0x29, 0xc9, 0xe4, 0xfc, 0xe2, 0xdc, 0xfc, 0xe2, 0x78, + 0xb0, 0x94, 0x3e, 0x84, 0x03, 0x51, 0x27, 0x25, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, 0x11, 0x07, 0xb1, + 0xa0, 0xa2, 0x72, 0x10, 0x35, 0xfa, 0x89, 0xa5, 0x25, 0x19, 0xfa, 0x65, 0x86, 0x49, 0xa9, 0x25, + 0x89, 0x86, 0x60, 0x0e, 0x44, 0x5e, 0x69, 0x35, 0x23, 0x17, 0x97, 0xa7, 0x93, 0xb3, 0x23, 0xc4, + 0x7c, 0xa1, 0x04, 0x2e, 0x9e, 0xa4, 0xc4, 0xe2, 0xd4, 0x78, 0xa8, 0x7d, 0x12, 0x8c, 0x0a, 0x8c, + 0x1a, 0xdc, 0x46, 0x0a, 0x7a, 0x50, 0x9b, 0xc0, 0x1a, 0xa1, 0xa6, 0xe8, 0x39, 0x25, 0x16, 0xa7, + 0x42, 0xf5, 0x39, 0x49, 0x5f, 0xb8, 0x27, 0xcf, 0xf8, 0xe9, 0x9e, 0xbc, 0x70, 0x65, 0x62, 0x6e, + 0x8e, 0x95, 0x12, 0xb2, 0x19, 0x4a, 0x41, 0xdc, 0x49, 0x08, 0x95, 0x42, 0x4a, 0x5c, 0x3c, 0x50, + 0x09, 0xff, 0xf2, 0xbc, 0xd4, 0x22, 0x09, 0x26, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x14, 0x31, 0x2b, + 0xf1, 0x8e, 0x05, 0xf2, 0x0c, 0x33, 0x16, 0xc8, 0x33, 0x5c, 0xda, 0xa2, 0xcb, 0x8d, 0x70, 0x9d, + 0xa7, 0x53, 0xf0, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, + 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x59, 0xa6, 0x67, + 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0x42, 0x83, 0x45, 0x3f, 0x33, 0xaf, 0x24, 0xb5, + 0x28, 0x39, 0x23, 0x31, 0x33, 0x4f, 0x17, 0x6a, 0x7a, 0xb1, 0x7e, 0x85, 0x7e, 0x66, 0x52, 0x32, + 0x8c, 0xab, 0x5f, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0x0e, 0x09, 0x63, 0x40, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x32, 0x59, 0x01, 0x7a, 0x84, 0x01, 0x00, 0x00, +} + +func (m *IBCAccount) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *IBCAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IBCAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AccountOwner) > 0 { + i -= len(m.AccountOwner) + copy(dAtA[i:], m.AccountOwner) + i = encodeVarintAccount(dAtA, i, uint64(len(m.AccountOwner))) + i-- + dAtA[i] = 0x12 + } + if m.BaseAccount != nil { + { + size, err := m.BaseAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAccount(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintAccount(dAtA []byte, offset int, v uint64) int { + offset -= sovAccount(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *IBCAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BaseAccount != nil { + l = m.BaseAccount.Size() + n += 1 + l + sovAccount(uint64(l)) + } + l = len(m.AccountOwner) + if l > 0 { + n += 1 + l + sovAccount(uint64(l)) + } + return n +} + +func sovAccount(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAccount(x uint64) (n int) { + return sovAccount(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *IBCAccount) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAccount + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: IBCAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IBCAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAccount + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAccount + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAccount + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BaseAccount == nil { + m.BaseAccount = &types.BaseAccount{} + } + if err := m.BaseAccount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AccountOwner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAccount + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAccount + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAccount + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AccountOwner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAccount(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAccount + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAccount(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAccount + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAccount + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAccount + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthAccount + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAccount + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAccount + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAccount = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAccount = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAccount = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/ibc-account/types/codec.go b/modules/apps/ibc-account/types/codec.go new file mode 100644 index 00000000000..e00ea354452 --- /dev/null +++ b/modules/apps/ibc-account/types/codec.go @@ -0,0 +1,24 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// RegisterLegacyAminoCodec registers the account interfaces and concrete types on the +// provided LegacyAmino codec. These types are used for Amino JSON serialization +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterInterface((*IBCAccountI)(nil), nil) + cdc.RegisterConcrete(&IBCAccount{}, "ibc-account/IBCAccount", nil) +} + +// RegisterInterface associates protoName with AccountI interface +// and creates a registry of it's concrete implementations +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations((*authtypes.AccountI)(nil), &IBCAccount{}) +} + +var ( + ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) +) diff --git a/modules/apps/ibc-account/types/encoder.go b/modules/apps/ibc-account/types/encoder.go new file mode 100644 index 00000000000..f3e325e1912 --- /dev/null +++ b/modules/apps/ibc-account/types/encoder.go @@ -0,0 +1,3 @@ +package types + +type TxEncoder func(data interface{}) ([]byte, error) diff --git a/modules/apps/ibc-account/types/errors.go b/modules/apps/ibc-account/types/errors.go new file mode 100644 index 00000000000..8854c1df4e7 --- /dev/null +++ b/modules/apps/ibc-account/types/errors.go @@ -0,0 +1,17 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +var ( + ErrUnknownPacketData = sdkerrors.Register(ModuleName, 1, "Unknown packet data") + ErrAccountAlreadyExist = sdkerrors.Register(ModuleName, 2, "Account already exist") + ErrPortAlreadyBound = sdkerrors.Register(ModuleName, 3, "Port is already bound for address") + ErrUnsupportedChain = sdkerrors.Register(ModuleName, 4, "Unsupported chain") + ErrInvalidOutgoingData = sdkerrors.Register(ModuleName, 5, "Invalid outgoing data") + ErrInvalidRoute = sdkerrors.Register(ModuleName, 6, "Invalid route") + ErrIBCAccountNotFound = sdkerrors.Register(ModuleName, 7, "Ibc account not found") + ErrIBCAccountAlreadySet = sdkerrors.Register(ModuleName, 8, "Interchain Account is already set") + ErrActiveChannelNotFound = sdkerrors.Register(ModuleName, 9, "No active channel for this owner") +) diff --git a/modules/apps/ibc-account/types/expected_keepers.go b/modules/apps/ibc-account/types/expected_keepers.go new file mode 100644 index 00000000000..448a0b3fcaa --- /dev/null +++ b/modules/apps/ibc-account/types/expected_keepers.go @@ -0,0 +1,47 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/modules/core/exported" +) + +type Router interface { + Route(ctx sdk.Context, path string) sdk.Handler +} + +// AccountKeeper defines the contract required for account APIs. +type AccountKeeper interface { + SetAccount(ctx sdk.Context, acc authtypes.AccountI) + GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI + NewAccount(ctx sdk.Context, acc authtypes.AccountI) authtypes.AccountI + NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI +} + +// ChannelKeeper defines the expected IBC channel keeper +type ChannelKeeper interface { + GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) + GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) + SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error + ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error + ChanOpenInit(ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, portCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string) (string, *capabilitytypes.Capability, error) +} + +// ClientKeeper defines the expected IBC client keeper +type ClientKeeper interface { + GetClientState(ctx sdk.Context, clientID string) (ibcexported.ClientState, bool) +} + +// ConnectionKeeper defines the expected IBC connection keeper +type ConnectionKeeper interface { + GetConnection(ctx sdk.Context, connectionID string) (connection connectiontypes.ConnectionEnd, found bool) +} + +// PortKeeper defines the expected IBC port keeper +type PortKeeper interface { + BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability + LookupModuleByPort(ctx sdk.Context, portID string) (string, *capabilitytypes.Capability, error) +} diff --git a/modules/apps/ibc-account/types/genesis.go b/modules/apps/ibc-account/types/genesis.go new file mode 100644 index 00000000000..e3a9bab7949 --- /dev/null +++ b/modules/apps/ibc-account/types/genesis.go @@ -0,0 +1,7 @@ +package types + +func DefaultGenesis() *GenesisState { + return &GenesisState{ + PortId: PortID, + } +} diff --git a/modules/apps/ibc-account/types/genesis.pb.go b/modules/apps/ibc-account/types/genesis.pb.go new file mode 100644 index 00000000000..fddc8377b68 --- /dev/null +++ b/modules/apps/ibc-account/types/genesis.pb.go @@ -0,0 +1,319 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/account/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the ibc-account genesis state +type GenesisState struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_c5549b69e3eeb3e4, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetPortId() string { + if m != nil { + return m.PortId + } + return "" +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "ibc.account.GenesisState") +} + +func init() { proto.RegisterFile("ibc/account/genesis.proto", fileDescriptor_c5549b69e3eeb3e4) } + +var fileDescriptor_c5549b69e3eeb3e4 = []byte{ + // 202 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0x4c, 0x4a, 0xd6, + 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0xd1, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xce, 0x4c, 0x4a, 0xd6, 0x83, 0x4a, 0x49, 0x89, 0xa4, + 0xe7, 0xa7, 0xe7, 0x83, 0xc5, 0xf5, 0x41, 0x2c, 0x88, 0x12, 0x25, 0x6b, 0x2e, 0x1e, 0x77, 0x88, + 0x9e, 0xe0, 0x92, 0xc4, 0x92, 0x54, 0x21, 0x6d, 0x2e, 0xf6, 0x82, 0xfc, 0xa2, 0x92, 0xf8, 0xcc, + 0x14, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0xa1, 0x4f, 0xf7, 0xe4, 0xf9, 0x2a, 0x13, 0x73, + 0x73, 0xac, 0x94, 0xa0, 0x12, 0x4a, 0x41, 0x6c, 0x20, 0x96, 0x67, 0x8a, 0x53, 0xf0, 0x89, 0x47, + 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, + 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x59, 0xa6, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, + 0x25, 0xe7, 0xe7, 0xea, 0x27, 0xe7, 0x17, 0xe7, 0xe6, 0x17, 0xeb, 0x67, 0xe6, 0x95, 0xa4, 0x16, + 0x25, 0x67, 0x24, 0x66, 0xe6, 0xe9, 0x42, 0x9d, 0x54, 0xac, 0x5f, 0xa1, 0x9f, 0x99, 0x94, 0x0c, + 0xe3, 0xea, 0x97, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x1d, 0x66, 0x0c, 0x08, 0x00, 0x00, + 0xff, 0xff, 0x01, 0x11, 0x9a, 0xe3, 0xd8, 0x00, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/ibc-account/types/hook.go b/modules/apps/ibc-account/types/hook.go new file mode 100644 index 00000000000..0218cc815cb --- /dev/null +++ b/modules/apps/ibc-account/types/hook.go @@ -0,0 +1,30 @@ +package types + +import sdk "github.com/cosmos/cosmos-sdk/types" + +type IBCAccountHooks interface { + OnTxSucceeded(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) + OnTxFailed(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) +} + +type MultiIBCAccountHooks []IBCAccountHooks + +var ( + _ IBCAccountHooks = MultiIBCAccountHooks{} +) + +func NewMultiIBCAccountHooks(hooks ...IBCAccountHooks) MultiIBCAccountHooks { + return hooks +} + +func (h MultiIBCAccountHooks) OnTxSucceeded(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) { + for i := range h { + h[i].OnTxSucceeded(ctx, sourcePort, sourceChannel, txHash, txBytes) + } +} + +func (h MultiIBCAccountHooks) OnTxFailed(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) { + for i := range h { + h[i].OnTxFailed(ctx, sourcePort, sourceChannel, txHash, txBytes) + } +} diff --git a/modules/apps/ibc-account/types/keys.go b/modules/apps/ibc-account/types/keys.go new file mode 100644 index 00000000000..321bfcee458 --- /dev/null +++ b/modules/apps/ibc-account/types/keys.go @@ -0,0 +1,41 @@ +package types + +import "fmt" + +const ( + // ModuleName defines the IBC transfer name + ModuleName = "interchainaccounts" + + // Version defines the current version the IBC tranfer + // module supports + Version = "ics27-1" + + PortID = "ibcaccount" + + StoreKey = ModuleName + RouterKey = ModuleName + + // Key to store portID in our store + PortKey = "portID" + + QuerierRoute = ModuleName + + // MemStoreKey defines the in-memory store key + MemStoreKey = "mem_capability" +) + +func KeyActiveChannel(portId string) []byte { + return []byte(fmt.Sprintf("activeChannel/%s", portId)) +} + +func KeyOwnerAccount(portId string) []byte { + return []byte(fmt.Sprintf("owner/%s", portId)) +} + +var ( + KeyPrefixRegisteredAccount = []byte("register") +) + +func GetIdentifier(portID, channelID string) string { + return fmt.Sprintf("%s/%s/", portID, channelID) +} diff --git a/modules/apps/ibc-account/types/packet.go b/modules/apps/ibc-account/types/packet.go new file mode 100644 index 00000000000..9863fca3914 --- /dev/null +++ b/modules/apps/ibc-account/types/packet.go @@ -0,0 +1,9 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (packet IBCAccountPacketData) GetBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&packet)) +} diff --git a/modules/apps/ibc-account/types/querier.go b/modules/apps/ibc-account/types/querier.go new file mode 100644 index 00000000000..34faaba304b --- /dev/null +++ b/modules/apps/ibc-account/types/querier.go @@ -0,0 +1,7 @@ +package types + +// query endpoints supported by the auth Querier +const ( + QueryIBCAccount = "ibcaccount" + QueryIBCAccountFromData = "ibcaccount-from-data" +) diff --git a/modules/apps/ibc-account/types/query.pb.go b/modules/apps/ibc-account/types/query.pb.go new file mode 100644 index 00000000000..eb7b28b6b77 --- /dev/null +++ b/modules/apps/ibc-account/types/query.pb.go @@ -0,0 +1,620 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/account/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type QueryIBCAccountRequest struct { + // address is the address to query. + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` +} + +func (m *QueryIBCAccountRequest) Reset() { *m = QueryIBCAccountRequest{} } +func (m *QueryIBCAccountRequest) String() string { return proto.CompactTextString(m) } +func (*QueryIBCAccountRequest) ProtoMessage() {} +func (*QueryIBCAccountRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_5738b2fac406b004, []int{0} +} +func (m *QueryIBCAccountRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIBCAccountRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIBCAccountRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryIBCAccountRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIBCAccountRequest.Merge(m, src) +} +func (m *QueryIBCAccountRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryIBCAccountRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIBCAccountRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIBCAccountRequest proto.InternalMessageInfo + +type QueryIBCAccountResponse struct { + // account defines the account of the corresponding address. + AccountAddress string `protobuf:"bytes,1,opt,name=account_address,json=accountAddress,proto3" json:"account_address,omitempty"` +} + +func (m *QueryIBCAccountResponse) Reset() { *m = QueryIBCAccountResponse{} } +func (m *QueryIBCAccountResponse) String() string { return proto.CompactTextString(m) } +func (*QueryIBCAccountResponse) ProtoMessage() {} +func (*QueryIBCAccountResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_5738b2fac406b004, []int{1} +} +func (m *QueryIBCAccountResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIBCAccountResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIBCAccountResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryIBCAccountResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIBCAccountResponse.Merge(m, src) +} +func (m *QueryIBCAccountResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryIBCAccountResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIBCAccountResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIBCAccountResponse proto.InternalMessageInfo + +func (m *QueryIBCAccountResponse) GetAccountAddress() string { + if m != nil { + return m.AccountAddress + } + return "" +} + +func init() { + proto.RegisterType((*QueryIBCAccountRequest)(nil), "ibc.account.QueryIBCAccountRequest") + proto.RegisterType((*QueryIBCAccountResponse)(nil), "ibc.account.QueryIBCAccountResponse") +} + +func init() { proto.RegisterFile("ibc/account/query.proto", fileDescriptor_5738b2fac406b004) } + +var fileDescriptor_5738b2fac406b004 = []byte{ + // 312 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xcf, 0x4a, 0x03, 0x31, + 0x10, 0xc6, 0xb3, 0x82, 0xff, 0xe2, 0x3f, 0x08, 0x62, 0x6b, 0x91, 0x54, 0x5a, 0x41, 0x2f, 0x6e, + 0x40, 0x4f, 0x7a, 0x6b, 0x3d, 0xf5, 0x68, 0x3d, 0xe9, 0xa5, 0x24, 0xd9, 0xb0, 0x0d, 0xd8, 0xcc, + 0x76, 0x93, 0x05, 0xfb, 0x06, 0x1e, 0x7d, 0x84, 0x3e, 0x8e, 0xc7, 0x1e, 0x3d, 0x4a, 0xf7, 0xe2, + 0x63, 0xc8, 0xee, 0xa6, 0xb4, 0xa2, 0x78, 0x4a, 0xe6, 0xfb, 0x0d, 0xdf, 0x37, 0x33, 0xb8, 0xa6, + 0x85, 0x64, 0x5c, 0x4a, 0xc8, 0x8c, 0x63, 0xe3, 0x4c, 0xa5, 0x93, 0x30, 0x49, 0xc1, 0x01, 0xd9, + 0xd1, 0x42, 0x86, 0x1e, 0x34, 0x0e, 0x63, 0x88, 0xa1, 0xd4, 0x59, 0xf1, 0xab, 0x5a, 0x1a, 0x27, + 0x31, 0x40, 0xfc, 0xac, 0x18, 0x4f, 0x34, 0xe3, 0xc6, 0x80, 0xe3, 0x4e, 0x83, 0xb1, 0x9e, 0x1e, + 0xaf, 0x3a, 0xfb, 0xb7, 0x42, 0x2d, 0x8e, 0x8f, 0xee, 0x8b, 0xa8, 0x5e, 0xf7, 0xae, 0x53, 0x81, + 0xbe, 0x1a, 0x67, 0xca, 0x3a, 0x52, 0xc7, 0x9b, 0x3c, 0x8a, 0x52, 0x65, 0x6d, 0x3d, 0x38, 0x0d, + 0x2e, 0xb6, 0xfb, 0x8b, 0x92, 0xb4, 0xf1, 0x9e, 0x04, 0x63, 0x94, 0x2c, 0x32, 0x06, 0x3a, 0xaa, + 0xaf, 0x95, 0x7c, 0x77, 0x29, 0xf6, 0xa2, 0xdb, 0xad, 0xd7, 0x69, 0x13, 0x7d, 0x4d, 0x9b, 0xa8, + 0xd5, 0xc5, 0xb5, 0x5f, 0x11, 0x36, 0x01, 0x63, 0x15, 0x39, 0xc7, 0x07, 0x7e, 0x9c, 0xc1, 0xcf, + 0xac, 0x7d, 0x2f, 0x77, 0x2a, 0xf5, 0x4a, 0xe0, 0xf5, 0xd2, 0x83, 0x3c, 0x62, 0xbc, 0xf4, 0x21, + 0xed, 0x70, 0xe5, 0x34, 0xe1, 0xdf, 0x8b, 0x34, 0xce, 0xfe, 0x6f, 0xaa, 0x46, 0x69, 0xa1, 0xee, + 0xc3, 0xfb, 0x9c, 0x06, 0xb3, 0x39, 0x0d, 0x3e, 0xe7, 0x34, 0x78, 0xcb, 0x29, 0x9a, 0xe5, 0x14, + 0x7d, 0xe4, 0x14, 0x3d, 0xdd, 0xc4, 0xda, 0x0d, 0x33, 0x11, 0x4a, 0x18, 0x31, 0x09, 0x76, 0x04, + 0x96, 0x69, 0xe3, 0x54, 0x2a, 0x87, 0x5c, 0x9b, 0x4b, 0xef, 0x6c, 0xd9, 0x0b, 0xd3, 0x42, 0x2e, + 0x4a, 0xe6, 0x26, 0x89, 0xb2, 0x62, 0xa3, 0x3c, 0xf3, 0xf5, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x90, 0xc3, 0xe9, 0x06, 0xdd, 0x01, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + IBCAccount(ctx context.Context, in *QueryIBCAccountRequest, opts ...grpc.CallOption) (*QueryIBCAccountResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) IBCAccount(ctx context.Context, in *QueryIBCAccountRequest, opts ...grpc.CallOption) (*QueryIBCAccountResponse, error) { + out := new(QueryIBCAccountResponse) + err := c.cc.Invoke(ctx, "/ibc.account.Query/IBCAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + IBCAccount(context.Context, *QueryIBCAccountRequest) (*QueryIBCAccountResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) IBCAccount(ctx context.Context, req *QueryIBCAccountRequest) (*QueryIBCAccountResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method IBCAccount not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_IBCAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryIBCAccountRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).IBCAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.account.Query/IBCAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).IBCAccount(ctx, req.(*QueryIBCAccountRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ibc.account.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "IBCAccount", + Handler: _Query_IBCAccount_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ibc/account/query.proto", +} + +func (m *QueryIBCAccountRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryIBCAccountRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIBCAccountRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ConnectionId) > 0 { + i -= len(m.ConnectionId) + copy(dAtA[i:], m.ConnectionId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ConnectionId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryIBCAccountResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryIBCAccountResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIBCAccountResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AccountAddress) > 0 { + i -= len(m.AccountAddress) + copy(dAtA[i:], m.AccountAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.AccountAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryIBCAccountRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ConnectionId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryIBCAccountResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.AccountAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryIBCAccountRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryIBCAccountRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIBCAccountRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnectionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryIBCAccountResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryIBCAccountResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIBCAccountResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AccountAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AccountAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/ibc-account/types/types.pb.go b/modules/apps/ibc-account/types/types.pb.go new file mode 100644 index 00000000000..d2eaf2455d8 --- /dev/null +++ b/modules/apps/ibc-account/types/types.pb.go @@ -0,0 +1,913 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/account/types.proto + +package types + +import ( + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/codec/types" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Type int32 + +const ( + Type_REGISTER Type = 0 + Type_RUNTX Type = 1 +) + +var Type_name = map[int32]string{ + 0: "REGISTER", + 1: "RUNTX", +} + +var Type_value = map[string]int32{ + "REGISTER": 0, + "RUNTX": 1, +} + +func (x Type) String() string { + return proto.EnumName(Type_name, int32(x)) +} + +func (Type) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_0902a1528b05ff0d, []int{0} +} + +type IBCTxRaw struct { + BodyBytes []byte `protobuf:"bytes,1,opt,name=body_bytes,json=bodyBytes,proto3" json:"body_bytes,omitempty"` +} + +func (m *IBCTxRaw) Reset() { *m = IBCTxRaw{} } +func (m *IBCTxRaw) String() string { return proto.CompactTextString(m) } +func (*IBCTxRaw) ProtoMessage() {} +func (*IBCTxRaw) Descriptor() ([]byte, []int) { + return fileDescriptor_0902a1528b05ff0d, []int{0} +} +func (m *IBCTxRaw) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IBCTxRaw) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IBCTxRaw.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *IBCTxRaw) XXX_Merge(src proto.Message) { + xxx_messageInfo_IBCTxRaw.Merge(m, src) +} +func (m *IBCTxRaw) XXX_Size() int { + return m.Size() +} +func (m *IBCTxRaw) XXX_DiscardUnknown() { + xxx_messageInfo_IBCTxRaw.DiscardUnknown(m) +} + +var xxx_messageInfo_IBCTxRaw proto.InternalMessageInfo + +func (m *IBCTxRaw) GetBodyBytes() []byte { + if m != nil { + return m.BodyBytes + } + return nil +} + +type IBCTxBody struct { + Messages []*types.Any `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` +} + +func (m *IBCTxBody) Reset() { *m = IBCTxBody{} } +func (m *IBCTxBody) String() string { return proto.CompactTextString(m) } +func (*IBCTxBody) ProtoMessage() {} +func (*IBCTxBody) Descriptor() ([]byte, []int) { + return fileDescriptor_0902a1528b05ff0d, []int{1} +} +func (m *IBCTxBody) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IBCTxBody) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IBCTxBody.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *IBCTxBody) XXX_Merge(src proto.Message) { + xxx_messageInfo_IBCTxBody.Merge(m, src) +} +func (m *IBCTxBody) XXX_Size() int { + return m.Size() +} +func (m *IBCTxBody) XXX_DiscardUnknown() { + xxx_messageInfo_IBCTxBody.DiscardUnknown(m) +} + +var xxx_messageInfo_IBCTxBody proto.InternalMessageInfo + +func (m *IBCTxBody) GetMessages() []*types.Any { + if m != nil { + return m.Messages + } + return nil +} + +type IBCAccountPacketData struct { + Type Type `protobuf:"varint,1,opt,name=type,proto3,enum=ibc.account.Type" json:"type,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *IBCAccountPacketData) Reset() { *m = IBCAccountPacketData{} } +func (m *IBCAccountPacketData) String() string { return proto.CompactTextString(m) } +func (*IBCAccountPacketData) ProtoMessage() {} +func (*IBCAccountPacketData) Descriptor() ([]byte, []int) { + return fileDescriptor_0902a1528b05ff0d, []int{2} +} +func (m *IBCAccountPacketData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IBCAccountPacketData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IBCAccountPacketData.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *IBCAccountPacketData) XXX_Merge(src proto.Message) { + xxx_messageInfo_IBCAccountPacketData.Merge(m, src) +} +func (m *IBCAccountPacketData) XXX_Size() int { + return m.Size() +} +func (m *IBCAccountPacketData) XXX_DiscardUnknown() { + xxx_messageInfo_IBCAccountPacketData.DiscardUnknown(m) +} + +var xxx_messageInfo_IBCAccountPacketData proto.InternalMessageInfo + +func (m *IBCAccountPacketData) GetType() Type { + if m != nil { + return m.Type + } + return Type_REGISTER +} + +func (m *IBCAccountPacketData) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +type AccountAddress struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` +} + +func (m *AccountAddress) Reset() { *m = AccountAddress{} } +func (m *AccountAddress) String() string { return proto.CompactTextString(m) } +func (*AccountAddress) ProtoMessage() {} +func (*AccountAddress) Descriptor() ([]byte, []int) { + return fileDescriptor_0902a1528b05ff0d, []int{3} +} +func (m *AccountAddress) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccountAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccountAddress.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AccountAddress) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccountAddress.Merge(m, src) +} +func (m *AccountAddress) XXX_Size() int { + return m.Size() +} +func (m *AccountAddress) XXX_DiscardUnknown() { + xxx_messageInfo_AccountAddress.DiscardUnknown(m) +} + +var xxx_messageInfo_AccountAddress proto.InternalMessageInfo + +func (m *AccountAddress) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func init() { + proto.RegisterEnum("ibc.account.Type", Type_name, Type_value) + proto.RegisterType((*IBCTxRaw)(nil), "ibc.account.IBCTxRaw") + proto.RegisterType((*IBCTxBody)(nil), "ibc.account.IBCTxBody") + proto.RegisterType((*IBCAccountPacketData)(nil), "ibc.account.IBCAccountPacketData") + proto.RegisterType((*AccountAddress)(nil), "ibc.account.AccountAddress") +} + +func init() { proto.RegisterFile("ibc/account/types.proto", fileDescriptor_0902a1528b05ff0d) } + +var fileDescriptor_0902a1528b05ff0d = []byte{ + // 340 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x91, 0xc1, 0x4a, 0x2b, 0x31, + 0x18, 0x85, 0x67, 0xee, 0xed, 0xbd, 0xb7, 0x93, 0x96, 0xd2, 0x1b, 0x0a, 0x56, 0xc1, 0x51, 0x06, + 0x84, 0x5a, 0x68, 0x22, 0x75, 0xe5, 0xc2, 0x45, 0xa7, 0x16, 0xe9, 0x46, 0x34, 0x1d, 0x41, 0xdc, + 0x48, 0x92, 0x89, 0xd3, 0x41, 0x3b, 0x29, 0x4d, 0x8a, 0xcd, 0x5b, 0xf8, 0x58, 0x2e, 0xbb, 0x74, + 0x29, 0xed, 0x8b, 0xc8, 0x64, 0x5a, 0xd1, 0xdd, 0x9f, 0xff, 0x1c, 0xce, 0xf9, 0xc8, 0x0f, 0x76, + 0x52, 0xc6, 0x31, 0xe5, 0x5c, 0xce, 0x33, 0x8d, 0xb5, 0x99, 0x0a, 0x85, 0xa6, 0x33, 0xa9, 0x25, + 0xac, 0xa4, 0x8c, 0xa3, 0x8d, 0xb0, 0xb7, 0x9b, 0x48, 0x99, 0x3c, 0x0b, 0x6c, 0x25, 0x36, 0x7f, + 0xc4, 0x34, 0x33, 0x85, 0x2f, 0x38, 0x06, 0xe5, 0x61, 0xd8, 0x8f, 0x16, 0x84, 0xbe, 0xc0, 0x7d, + 0x00, 0x98, 0x8c, 0xcd, 0x03, 0x33, 0x5a, 0xa8, 0xa6, 0x7b, 0xe8, 0xb6, 0xaa, 0xc4, 0xcb, 0x37, + 0x61, 0xbe, 0x08, 0xce, 0x81, 0x67, 0xad, 0xa1, 0x8c, 0x0d, 0x3c, 0x01, 0xe5, 0x89, 0x50, 0x8a, + 0x26, 0xd6, 0xf9, 0xbb, 0x55, 0xe9, 0x36, 0x50, 0xd1, 0x82, 0xb6, 0x2d, 0xa8, 0x97, 0x19, 0xf2, + 0xe5, 0x0a, 0x6e, 0x40, 0x63, 0x18, 0xf6, 0x7b, 0x05, 0xd2, 0x35, 0xe5, 0x4f, 0x42, 0x5f, 0x50, + 0x4d, 0xe1, 0x11, 0x28, 0xe5, 0xe0, 0xb6, 0xaf, 0xd6, 0xfd, 0x8f, 0xbe, 0x81, 0xa3, 0xc8, 0x4c, + 0x05, 0xb1, 0x32, 0x84, 0xa0, 0x14, 0x53, 0x4d, 0x9b, 0xbf, 0x2c, 0x96, 0x9d, 0x83, 0x36, 0xa8, + 0x6d, 0xf2, 0x7a, 0x71, 0x3c, 0x13, 0x4a, 0xc1, 0x26, 0xf8, 0x47, 0x8b, 0xd1, 0xe6, 0x79, 0x64, + 0xfb, 0x6c, 0x1f, 0x80, 0x52, 0x9e, 0x06, 0xab, 0xa0, 0x4c, 0x06, 0x97, 0xc3, 0x51, 0x34, 0x20, + 0x75, 0x07, 0x7a, 0xe0, 0x0f, 0xb9, 0xbd, 0x8a, 0xee, 0xea, 0x6e, 0x38, 0x7a, 0x5b, 0xf9, 0xee, + 0x72, 0xe5, 0xbb, 0x1f, 0x2b, 0xdf, 0x7d, 0x5d, 0xfb, 0xce, 0x72, 0xed, 0x3b, 0xef, 0x6b, 0xdf, + 0xb9, 0x3f, 0x4b, 0x52, 0x3d, 0x9e, 0x33, 0xc4, 0xe5, 0x04, 0x73, 0xa9, 0x26, 0x52, 0xe1, 0x34, + 0xd3, 0x62, 0xc6, 0xc7, 0x34, 0xcd, 0x3a, 0x1b, 0x56, 0x85, 0x17, 0x38, 0x65, 0xbc, 0xf3, 0xe3, + 0x18, 0xec, 0xaf, 0xfd, 0x8c, 0xd3, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x92, 0xef, 0xa7, 0x30, + 0xa8, 0x01, 0x00, 0x00, +} + +func (m *IBCTxRaw) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *IBCTxRaw) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IBCTxRaw) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.BodyBytes) > 0 { + i -= len(m.BodyBytes) + copy(dAtA[i:], m.BodyBytes) + i = encodeVarintTypes(dAtA, i, uint64(len(m.BodyBytes))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *IBCTxBody) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *IBCTxBody) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IBCTxBody) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Messages) > 0 { + for iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Messages[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *IBCAccountPacketData) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *IBCAccountPacketData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IBCAccountPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x12 + } + if m.Type != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *AccountAddress) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AccountAddress) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccountAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *IBCTxRaw) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.BodyBytes) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *IBCTxBody) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Messages) > 0 { + for _, e := range m.Messages { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *IBCAccountPacketData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Type != 0 { + n += 1 + sovTypes(uint64(m.Type)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *AccountAddress) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *IBCTxRaw) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: IBCTxRaw: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IBCTxRaw: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BodyBytes", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BodyBytes = append(m.BodyBytes[:0], dAtA[iNdEx:postIndex]...) + if m.BodyBytes == nil { + m.BodyBytes = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *IBCTxBody) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: IBCTxBody: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IBCTxBody: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Messages", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Messages = append(m.Messages, &types.Any{}) + if err := m.Messages[len(m.Messages)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *IBCAccountPacketData) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: IBCAccountPacketData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IBCAccountPacketData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= Type(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AccountAddress) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AccountAddress: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccountAddress: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) From c27653a9420d58eaf0bee11beef1868ce2642419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 15 Jul 2021 13:04:39 +0200 Subject: [PATCH 02/66] Add @seantking to CODEOWNERS for interchain accounts module --- .github/CODEOWNERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2e5239c6889..3ea5f422078 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,7 @@ # CODEOWNERS: https://help.github.com/articles/about-codeowners/ * @colin-axner @fedekunze @AdityaSripal + +# CODEOWNERS for interchain-accounts module + +*/modules/apps/ibc-account @seantking @colin-axner @AdityaSripal From 0148576f42843e2a1c28e8dbc83cc0588e95f99c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 21 Jul 2021 16:45:34 +0200 Subject: [PATCH 03/66] rename ibc-account -> interchain-accounts (#280) * rename ibc-account -> interchain-accounts * fix codeowner file --- .github/CODEOWNERS | 2 +- .../client/cli/query.go | 6 +++--- .../genesis.go | 4 ++-- .../keeper/account.go | 2 +- .../keeper/grpc_query.go | 2 +- .../keeper/handshake.go | 0 .../keeper/handshake_test.go | 0 .../keeper/keeper.go | 6 +++--- .../keeper/relay.go | 2 +- .../module.go | 8 +++---- .../spec/03_types.md | 0 .../spec/04_keeper.md | 0 .../spec/05_packets.md | 0 .../27-interchain-accounts/spec/README.md | 21 +++++++++++++++++++ .../types/account.go | 4 ++-- .../types/account.pb.go | 0 .../types/codec.go | 2 +- .../types/encoder.go | 0 .../types/errors.go | 0 .../types/expected_keepers.go | 0 .../types/genesis.go | 0 .../types/genesis.pb.go | 0 .../types/hook.go | 0 .../types/keys.go | 0 .../types/packet.go | 0 .../types/querier.go | 0 .../types/query.pb.go | 0 .../types/types.pb.go | 0 modules/apps/ibc-account/spec/README.md | 21 ------------------- 29 files changed, 40 insertions(+), 40 deletions(-) rename modules/apps/{ibc-account => 27-interchain-accounts}/client/cli/query.go (82%) rename modules/apps/{ibc-account => 27-interchain-accounts}/genesis.go (80%) rename modules/apps/{ibc-account => 27-interchain-accounts}/keeper/account.go (98%) rename modules/apps/{ibc-account => 27-interchain-accounts}/keeper/grpc_query.go (92%) rename modules/apps/{ibc-account => 27-interchain-accounts}/keeper/handshake.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/keeper/handshake_test.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/keeper/keeper.go (95%) rename modules/apps/{ibc-account => 27-interchain-accounts}/keeper/relay.go (98%) rename modules/apps/{ibc-account => 27-interchain-accounts}/module.go (96%) rename modules/apps/{ibc-account => 27-interchain-accounts}/spec/03_types.md (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/spec/04_keeper.md (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/spec/05_packets.md (100%) create mode 100644 modules/apps/27-interchain-accounts/spec/README.md rename modules/apps/{ibc-account => 27-interchain-accounts}/types/account.go (95%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/account.pb.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/codec.go (90%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/encoder.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/errors.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/expected_keepers.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/genesis.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/genesis.pb.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/hook.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/keys.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/packet.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/querier.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/query.pb.go (100%) rename modules/apps/{ibc-account => 27-interchain-accounts}/types/types.pb.go (100%) delete mode 100644 modules/apps/ibc-account/spec/README.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3ea5f422078..cdb6284df09 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,4 +4,4 @@ # CODEOWNERS for interchain-accounts module -*/modules/apps/ibc-account @seantking @colin-axner @AdityaSripal +*/modules/apps/27-interchain-accounts @seantking @colin-axner @AdityaSripal diff --git a/modules/apps/ibc-account/client/cli/query.go b/modules/apps/27-interchain-accounts/client/cli/query.go similarity index 82% rename from modules/apps/ibc-account/client/cli/query.go rename to modules/apps/27-interchain-accounts/client/cli/query.go index 35f10bc04f4..73f4389fa58 100644 --- a/modules/apps/ibc-account/client/cli/query.go +++ b/modules/apps/27-interchain-accounts/client/cli/query.go @@ -7,13 +7,13 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" ) func GetQueryCmd() *cobra.Command { cmd := &cobra.Command{ - Use: types.ModuleName, - Short: "Querying commands for the ibc account module", + Use: "interchain-accounts", + Short: "Querying commands for the interchain accounts module", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, diff --git a/modules/apps/ibc-account/genesis.go b/modules/apps/27-interchain-accounts/genesis.go similarity index 80% rename from modules/apps/ibc-account/genesis.go rename to modules/apps/27-interchain-accounts/genesis.go index 1bffea2b5c4..5a9569b54e6 100644 --- a/modules/apps/ibc-account/genesis.go +++ b/modules/apps/27-interchain-accounts/genesis.go @@ -4,8 +4,8 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/modules/apps/ibc-account/keeper" - "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/keeper" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" ) func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState) { diff --git a/modules/apps/ibc-account/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go similarity index 98% rename from modules/apps/ibc-account/keeper/account.go rename to modules/apps/27-interchain-accounts/keeper/account.go index e165eea4773..714b2258125 100644 --- a/modules/apps/ibc-account/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -6,7 +6,7 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/modules/core/24-host" - "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" "github.com/tendermint/tendermint/crypto/tmhash" ) diff --git a/modules/apps/ibc-account/keeper/grpc_query.go b/modules/apps/27-interchain-accounts/keeper/grpc_query.go similarity index 92% rename from modules/apps/ibc-account/keeper/grpc_query.go rename to modules/apps/27-interchain-accounts/keeper/grpc_query.go index 512134cd40a..7f54be0f80a 100644 --- a/modules/apps/ibc-account/keeper/grpc_query.go +++ b/modules/apps/27-interchain-accounts/keeper/grpc_query.go @@ -8,7 +8,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" ) var _ types.QueryServer = Keeper{} diff --git a/modules/apps/ibc-account/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go similarity index 100% rename from modules/apps/ibc-account/keeper/handshake.go rename to modules/apps/27-interchain-accounts/keeper/handshake.go diff --git a/modules/apps/ibc-account/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go similarity index 100% rename from modules/apps/ibc-account/keeper/handshake_test.go rename to modules/apps/27-interchain-accounts/keeper/handshake_test.go diff --git a/modules/apps/ibc-account/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go similarity index 95% rename from modules/apps/ibc-account/keeper/keeper.go rename to modules/apps/27-interchain-accounts/keeper/keeper.go index 4958645e367..39751e48ab1 100644 --- a/modules/apps/ibc-account/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -14,7 +14,7 @@ import ( host "github.com/cosmos/ibc-go/modules/core/24-host" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" ) // Keeper defines the IBC transfer keeper @@ -34,7 +34,7 @@ type Keeper struct { memKey sdk.StoreKey } -// NewKeeper creates a new IBC account Keeper instance +// NewKeeper creates a new interchain account Keeper instance func NewKeeper( memKey sdk.StoreKey, cdc codec.BinaryCodec, key sdk.StoreKey, @@ -112,7 +112,7 @@ func (k Keeper) BindPort(ctx sdk.Context, portID string) error { return k.ClaimCapability(ctx, cap, host.PortPath(portID)) } -// GetPort returns the portID for the ibc account module. Used in ExportGenesis +// GetPort returns the portID for the interchain accounts module. Used in ExportGenesis func (k Keeper) GetPort(ctx sdk.Context) string { store := ctx.KVStore(k.storeKey) return string(store.Get([]byte(types.PortKey))) diff --git a/modules/apps/ibc-account/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go similarity index 98% rename from modules/apps/ibc-account/keeper/relay.go rename to modules/apps/27-interchain-accounts/keeper/relay.go index 09e616b0ec0..d434fcfac9e 100644 --- a/modules/apps/ibc-account/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -8,7 +8,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/modules/core/24-host" - "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" "github.com/tendermint/tendermint/crypto/tmhash" ) diff --git a/modules/apps/ibc-account/module.go b/modules/apps/27-interchain-accounts/module.go similarity index 96% rename from modules/apps/ibc-account/module.go rename to modules/apps/27-interchain-accounts/module.go index 6c3b93ba995..9ba760952c8 100644 --- a/modules/apps/ibc-account/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -17,9 +17,9 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/runtime" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/ibc-go/modules/apps/ibc-account/client/cli" - "github.com/cosmos/ibc-go/modules/apps/ibc-account/keeper" - "github.com/cosmos/ibc-go/modules/apps/ibc-account/types" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/client/cli" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/keeper" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types" ibcexported "github.com/cosmos/ibc-go/modules/core/exported" @@ -68,7 +68,7 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) types.RegisterInterfaces(registry) } -// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the ibc-account module. +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the interchain accounts module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { } diff --git a/modules/apps/ibc-account/spec/03_types.md b/modules/apps/27-interchain-accounts/spec/03_types.md similarity index 100% rename from modules/apps/ibc-account/spec/03_types.md rename to modules/apps/27-interchain-accounts/spec/03_types.md diff --git a/modules/apps/ibc-account/spec/04_keeper.md b/modules/apps/27-interchain-accounts/spec/04_keeper.md similarity index 100% rename from modules/apps/ibc-account/spec/04_keeper.md rename to modules/apps/27-interchain-accounts/spec/04_keeper.md diff --git a/modules/apps/ibc-account/spec/05_packets.md b/modules/apps/27-interchain-accounts/spec/05_packets.md similarity index 100% rename from modules/apps/ibc-account/spec/05_packets.md rename to modules/apps/27-interchain-accounts/spec/05_packets.md diff --git a/modules/apps/27-interchain-accounts/spec/README.md b/modules/apps/27-interchain-accounts/spec/README.md new file mode 100644 index 00000000000..abd08ea7d40 --- /dev/null +++ b/modules/apps/27-interchain-accounts/spec/README.md @@ -0,0 +1,21 @@ + + +# Interchain Account + +## Abstract + +This document specifies the ICS 27 Interchain Account module for the Cosmos SDK. + +The Interchain Accounts module manages the creation of Interchain Accounts. This module is built based on the [ICS27 specification](https://github.com/cosmos/ibc/tree/master/spec/app/ics-027-interchain-accounts). Interchain Accounts allow a remote, IBC-connected **controller blockchain** to request an arbitrary transaction to be executed on the **host blockchain**(the chain which hosts the IBC account) via the interchain account. It should be noted that an interchain account has similar properties to a user account, and are bound to the same restrictions (unbonding periods, redelegation rules, etc). + +The current implementation allows the same interchain account module on the destination chain to run any of the domiciling blockchain's native transactions that a user account is able to request(i.e. same module can handle 'send', 'stake', 'vote', etc), but the controlling chain/source chain must implement its own logic for controlling the interchain account. + +## Contents +1. **[Types](03_types.md)** +2. **[Keeper](04_keeper.md)** +3. **[Packets](05_packets.md)** diff --git a/modules/apps/ibc-account/types/account.go b/modules/apps/27-interchain-accounts/types/account.go similarity index 95% rename from modules/apps/ibc-account/types/account.go rename to modules/apps/27-interchain-accounts/types/account.go index eaf8f65e590..eed5f4c46e8 100644 --- a/modules/apps/ibc-account/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -33,12 +33,12 @@ func NewIBCAccount(ba *authtypes.BaseAccount, accountOwner string) *IBCAccount { // SetPubKey - Implements AccountI func (IBCAccount) SetPubKey(pubKey crypto.PubKey) error { - return fmt.Errorf("not supported for ibc accounts") + return fmt.Errorf("not supported for interchain accounts") } // SetSequence - Implements AccountI func (IBCAccount) SetSequence(seq uint64) error { - return fmt.Errorf("not supported for ibc accounts") + return fmt.Errorf("not supported for interchain accounts") } func (ia IBCAccount) Validate() error { diff --git a/modules/apps/ibc-account/types/account.pb.go b/modules/apps/27-interchain-accounts/types/account.pb.go similarity index 100% rename from modules/apps/ibc-account/types/account.pb.go rename to modules/apps/27-interchain-accounts/types/account.pb.go diff --git a/modules/apps/ibc-account/types/codec.go b/modules/apps/27-interchain-accounts/types/codec.go similarity index 90% rename from modules/apps/ibc-account/types/codec.go rename to modules/apps/27-interchain-accounts/types/codec.go index e00ea354452..72b907dae61 100644 --- a/modules/apps/ibc-account/types/codec.go +++ b/modules/apps/27-interchain-accounts/types/codec.go @@ -10,7 +10,7 @@ import ( // provided LegacyAmino codec. These types are used for Amino JSON serialization func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterInterface((*IBCAccountI)(nil), nil) - cdc.RegisterConcrete(&IBCAccount{}, "ibc-account/IBCAccount", nil) + cdc.RegisterConcrete(&IBCAccount{}, "27-interchain-accounts/IBCAccount", nil) } // RegisterInterface associates protoName with AccountI interface diff --git a/modules/apps/ibc-account/types/encoder.go b/modules/apps/27-interchain-accounts/types/encoder.go similarity index 100% rename from modules/apps/ibc-account/types/encoder.go rename to modules/apps/27-interchain-accounts/types/encoder.go diff --git a/modules/apps/ibc-account/types/errors.go b/modules/apps/27-interchain-accounts/types/errors.go similarity index 100% rename from modules/apps/ibc-account/types/errors.go rename to modules/apps/27-interchain-accounts/types/errors.go diff --git a/modules/apps/ibc-account/types/expected_keepers.go b/modules/apps/27-interchain-accounts/types/expected_keepers.go similarity index 100% rename from modules/apps/ibc-account/types/expected_keepers.go rename to modules/apps/27-interchain-accounts/types/expected_keepers.go diff --git a/modules/apps/ibc-account/types/genesis.go b/modules/apps/27-interchain-accounts/types/genesis.go similarity index 100% rename from modules/apps/ibc-account/types/genesis.go rename to modules/apps/27-interchain-accounts/types/genesis.go diff --git a/modules/apps/ibc-account/types/genesis.pb.go b/modules/apps/27-interchain-accounts/types/genesis.pb.go similarity index 100% rename from modules/apps/ibc-account/types/genesis.pb.go rename to modules/apps/27-interchain-accounts/types/genesis.pb.go diff --git a/modules/apps/ibc-account/types/hook.go b/modules/apps/27-interchain-accounts/types/hook.go similarity index 100% rename from modules/apps/ibc-account/types/hook.go rename to modules/apps/27-interchain-accounts/types/hook.go diff --git a/modules/apps/ibc-account/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go similarity index 100% rename from modules/apps/ibc-account/types/keys.go rename to modules/apps/27-interchain-accounts/types/keys.go diff --git a/modules/apps/ibc-account/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go similarity index 100% rename from modules/apps/ibc-account/types/packet.go rename to modules/apps/27-interchain-accounts/types/packet.go diff --git a/modules/apps/ibc-account/types/querier.go b/modules/apps/27-interchain-accounts/types/querier.go similarity index 100% rename from modules/apps/ibc-account/types/querier.go rename to modules/apps/27-interchain-accounts/types/querier.go diff --git a/modules/apps/ibc-account/types/query.pb.go b/modules/apps/27-interchain-accounts/types/query.pb.go similarity index 100% rename from modules/apps/ibc-account/types/query.pb.go rename to modules/apps/27-interchain-accounts/types/query.pb.go diff --git a/modules/apps/ibc-account/types/types.pb.go b/modules/apps/27-interchain-accounts/types/types.pb.go similarity index 100% rename from modules/apps/ibc-account/types/types.pb.go rename to modules/apps/27-interchain-accounts/types/types.pb.go diff --git a/modules/apps/ibc-account/spec/README.md b/modules/apps/ibc-account/spec/README.md deleted file mode 100644 index 88b4a45e658..00000000000 --- a/modules/apps/ibc-account/spec/README.md +++ /dev/null @@ -1,21 +0,0 @@ - - -# IBC Account - -## Abstract - -This document specifies the IBC account module for the Cosmos SDK. - -The IBCAccount module manages the creation of IBC Accounts and ICS20 packet handling for the IBC accounts. This module is built based on the [ICS27 specification](https://github.com/cosmos/ics/tree/master/spec/ics-027-interchain-accounts). IBC Accounts allow a remote, IBC-connected **source blockchain** to request an arbitrary transaction to be executed on the **destination blockchain**(the chain which hosts the IBC account) via the IBC account. It should be noted that an IBC account has similar properties to a user account, and are bound to the same restrictions (unbonding periods, redelegation rules, etc). - -The current implementation allows the same IBCAccount module on the destination chain to run any of the domiciling blockchain's native transactions that a user account is able to request(i.e. same module can handle 'send', 'stake', 'vote', etc), but the controlling chain/source chain must implement its own logic for controlling the IBC account from its own IBCAccount logic. - -## Contents -1. **[Types](03_types.md)** -2. **[Keeper](04_keeper.md)** -3. **[Packets](05_packets.md)** From b870be4cd8406b8b327d58424d591484ee75fab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 22 Jul 2021 12:06:35 +0200 Subject: [PATCH 04/66] Integrate ICA into testing package, add simple keeper tests (#282) * add ica to simapp * add simple keeper tests --- .../27-interchain-accounts/keeper/keeper.go | 2 +- .../keeper/keeper_test.go | 50 +++++++++++++++++++ .../apps/27-interchain-accounts/types/keys.go | 2 +- testing/simapp/app.go | 29 ++++++++++- 4 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/keeper/keeper_test.go diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index 39751e48ab1..1dd0cd99110 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -101,7 +101,7 @@ func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { return ok } -// BindPort defines a wrapper function for the ort Keeper's function in +// BindPort defines a wrapper function for the port Keeper's BindPort function in // order to expose it to module's InitGenesis function func (k Keeper) BindPort(ctx sdk.Context, portID string) error { // Set the portID into our store so we can retrieve it later diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go new file mode 100644 index 00000000000..0e53d0d9b5f --- /dev/null +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -0,0 +1,50 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/testing" +) + +type KeeperTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + // testing chains used for convenience and readability + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain + chainC *ibctesting.TestChain +} + +func (suite *KeeperTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2)) +} + +func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { + path := ibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig.PortID = types.PortID + path.EndpointB.ChannelConfig.PortID = types.PortID + + return path +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func (suite *KeeperTestSuite) TestIsBound() { + isBound := suite.chainA.GetSimApp().ICAKeeper.IsBound(suite.chainA.GetContext(), types.PortID) + suite.Require().True(isBound) +} + +func (suite *KeeperTestSuite) TestGetPort() { + port := suite.chainA.GetSimApp().ICAKeeper.GetPort(suite.chainA.GetContext()) + suite.Require().Equal(types.PortID, port) +} diff --git a/modules/apps/27-interchain-accounts/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go index 321bfcee458..ab9aac7bbe2 100644 --- a/modules/apps/27-interchain-accounts/types/keys.go +++ b/modules/apps/27-interchain-accounts/types/keys.go @@ -10,7 +10,7 @@ const ( // module supports Version = "ics27-1" - PortID = "ibcaccount" + PortID = "interchain-account" StoreKey = ModuleName RouterKey = ModuleName diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 817996c4c4c..96a891db2e2 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -81,6 +81,9 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + ica "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts" + icakeeper "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/keeper" + icatypes "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" transfer "github.com/cosmos/ibc-go/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/modules/apps/transfer/types" @@ -131,6 +134,7 @@ var ( evidence.AppModuleBasic{}, transfer.AppModuleBasic{}, ibcmock.AppModuleBasic{}, + ica.AppModuleBasic{}, authzmodule.AppModuleBasic{}, vesting.AppModuleBasic{}, ) @@ -182,6 +186,7 @@ type SimApp struct { ParamsKeeper paramskeeper.Keeper AuthzKeeper authzkeeper.Keeper IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + ICAKeeper icakeeper.Keeper EvidenceKeeper evidencekeeper.Keeper TransferKeeper ibctransferkeeper.Keeper FeeGrantKeeper feegrantkeeper.Keeper @@ -189,6 +194,7 @@ type SimApp struct { // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper ScopedTransferKeeper capabilitykeeper.ScopedKeeper + ScopedICAKeeper capabilitykeeper.ScopedKeeper ScopedIBCMockKeeper capabilitykeeper.ScopedKeeper // the module manager @@ -230,7 +236,7 @@ func NewSimApp( authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, - evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, + evidencetypes.StoreKey, ibctransfertypes.StoreKey, icatypes.StoreKey, capabilitytypes.StoreKey, authzkeeper.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) @@ -256,6 +262,8 @@ func NewSimApp( app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) + scopedICAKeeper := app.CapabilityKeeper.ScopeToModule(icatypes.ModuleName) + // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // note replicate if you do not need to test core IBC or light clients. scopedIBCMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName) @@ -321,6 +329,13 @@ func NewSimApp( ) transferModule := transfer.NewAppModule(app.TransferKeeper) + app.ICAKeeper = icakeeper.NewKeeper( + keys[icatypes.MemStoreKey], appCodec, keys[icatypes.StoreKey], + app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, + app.AccountKeeper, scopedICAKeeper, app.MsgServiceRouter(), app, + ) + icaModule := ica.NewAppModule(app.ICAKeeper) + // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // note replicate if you do not need to test core IBC or light clients. mockModule := ibcmock.NewAppModule(scopedIBCMockKeeper, &app.IBCKeeper.PortKeeper) @@ -328,6 +343,7 @@ func NewSimApp( // Create static IBC router, add transfer route, then set and seal it ibcRouter := porttypes.NewRouter() ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) + ibcRouter.AddRoute(icatypes.ModuleName, icaModule) ibcRouter.AddRoute(ibcmock.ModuleName, mockModule) app.IBCKeeper.SetRouter(ibcRouter) @@ -368,6 +384,7 @@ func NewSimApp( params.NewAppModule(app.ParamsKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), transferModule, + icaModule, mockModule, ) @@ -390,7 +407,7 @@ func NewSimApp( capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, stakingtypes.ModuleName, slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName, crisistypes.ModuleName, ibchost.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, authz.ModuleName, ibctransfertypes.ModuleName, - ibcmock.ModuleName, feegrant.ModuleName, + icatypes.ModuleName, ibcmock.ModuleName, feegrant.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) @@ -467,6 +484,7 @@ func NewSimApp( app.ScopedIBCKeeper = scopedIBCKeeper app.ScopedTransferKeeper = scopedTransferKeeper + app.ScopedICAKeeper = scopedICAKeeper // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // note replicate if you do not need to test core IBC or light clients. @@ -664,3 +682,10 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino return paramsKeeper } + +// Interchain Accounts code +func (*SimApp) OnTxSucceeded(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) { +} + +func (*SimApp) OnTxFailed(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) { +} From c3be1692adc3e4b45d4cb6d003d133d049d071eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Fri, 23 Jul 2021 14:10:34 +0200 Subject: [PATCH 05/66] Add interchain account OnChanOpenInit and InitInterchainAccount tests (#287) * add OnChanOpenInit test * add InitInterchainAccount test * Update modules/apps/27-interchain-accounts/keeper/relay.go --- .../27-interchain-accounts/keeper/account.go | 47 ++++----- .../keeper/account_test.go | 62 ++++++++++++ .../keeper/handshake.go | 22 ++++- .../keeper/handshake_test.go | 97 +++++++++++++++++++ .../27-interchain-accounts/keeper/keeper.go | 14 ++- .../27-interchain-accounts/keeper/relay.go | 8 +- modules/core/04-channel/types/errors.go | 2 + 7 files changed, 213 insertions(+), 39 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/keeper/account_test.go diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index 714b2258125..167e3d9e26f 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -4,51 +4,40 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/tendermint/tendermint/crypto/tmhash" + + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/modules/core/24-host" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - "github.com/tendermint/tendermint/crypto/tmhash" ) -// The first step in registering an interchain account -// Binds a new port & calls OnChanOpenInit +// InitInterchainAccount is the entry point to registering an interchain account. +// It generates a new port identifier using the owner address, connection identifier, +// and counterparty connection identifier. It will bind to the port identifier and +// call 04-channel 'ChanOpenInit'. An error is returned if the port identifier is +// already in use. Gaining access to interchain accounts whose channels have closed +// cannot be done with this function. A regular MsgChanOpenInit must be used. func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionId, owner string) error { portId := k.GeneratePortId(owner, connectionId) - // Check if the port is already bound - isBound := k.IsBound(ctx, portId) - if isBound == true { + // check if the port is already bound + if k.IsBound(ctx, portId) { return sdkerrors.Wrap(types.ErrPortAlreadyBound, portId) } portCap := k.portKeeper.BindPort(ctx, portId) err := k.ClaimCapability(ctx, portCap, host.PortPath(portId)) if err != nil { + return sdkerrors.Wrap(err, "unable to bind to newly generated portID") + } + + msg := channeltypes.NewMsgChannelOpenInit(portId, types.Version, channeltypes.ORDERED, []string{connectionId}, types.PortID, types.ModuleName) + handler := k.msgRouter.Handler(msg) + if _, err := handler(ctx, msg); err != nil { return err } - counterParty := channeltypes.Counterparty{PortId: "ibcaccount", ChannelId: ""} - order := channeltypes.Order(2) - channelId, cap, err := k.channelKeeper.ChanOpenInit(ctx, order, []string{connectionId}, portId, portCap, counterParty, types.Version) - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - channeltypes.EventTypeChannelOpenInit, - sdk.NewAttribute(channeltypes.AttributeKeyPortID, portId), - sdk.NewAttribute(channeltypes.AttributeKeyChannelID, channelId), - sdk.NewAttribute(channeltypes.AttributeCounterpartyPortID, "ibcaccount"), - sdk.NewAttribute(channeltypes.AttributeCounterpartyChannelID, ""), - sdk.NewAttribute(channeltypes.AttributeKeyConnectionID, connectionId), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, channeltypes.AttributeValueCategory), - ), - }) - - _ = k.OnChanOpenInit(ctx, channeltypes.Order(2), []string{connectionId}, portId, channelId, cap, counterParty, types.Version) - - return err + return nil } // Register interchain account if it has not already been created diff --git a/modules/apps/27-interchain-accounts/keeper/account_test.go b/modules/apps/27-interchain-accounts/keeper/account_test.go new file mode 100644 index 00000000000..064a9bc6413 --- /dev/null +++ b/modules/apps/27-interchain-accounts/keeper/account_test.go @@ -0,0 +1,62 @@ +package keeper_test + +import ( + ibctesting "github.com/cosmos/ibc-go/testing" +) + +func (suite *KeeperTestSuite) TestInitInterchainAccount() { + var ( + owner string + path *ibctesting.Path + err error + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + /* + // TODO: https://github.com/cosmos/ibc-go/issues/288 + { + "port is already bound", func() { + // mock init interchain account + portID := suite.chainA.GetSimApp().ICAKeeper.GeneratePortId(owner, path.EndpointA.ConnectionID) + suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) + }, false, + }, + */ + { + "MsgChanOpenInit fails - channel is already active", func() { + portID := suite.chainA.GetSimApp().ICAKeeper.GeneratePortId(owner, path.EndpointA.ConnectionID) + suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID) + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + owner = "owner" // must be explicitly changed + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + tc.malleate() // explicitly change fields in channel and testChannel + + err = suite.chainA.GetSimApp().ICAKeeper.InitInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, owner) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } +} diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index 614ed22882d..6a8bafe57cb 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -4,10 +4,20 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types" host "github.com/cosmos/ibc-go/modules/core/24-host" ) +// OnChanOpenInit performs basic validation of channel initialization. +// The channel order must be ORDERED, the counterparty port identifier +// must be the host chain representation as defined in the types package, +// the channel version must be equal to the version in the types package, +// there must not be an active channel for the specfied port identifier, +// and the interchain accounts module must be able to claim the channel +// capability. func (k Keeper) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, @@ -18,11 +28,19 @@ func (k Keeper) OnChanOpenInit( counterparty channeltypes.Counterparty, version string, ) error { - //TODO: - // check version string if order != channeltypes.ORDERED { return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "invalid channel ordering: %s, expected %s", order.String(), channeltypes.ORDERED.String()) } + if counterparty.PortId != types.PortID { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "counterparty port-id must be '%s', (%s != %s)", types.PortID, counterparty.PortId, types.PortID) + } + if version != types.Version { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "channel version must be '%s' (%s != %s)", types.Version, version, types.Version) + } + channelID, found := k.GetActiveChannel(ctx, portID) + if found { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel (%s) for portID (%s)", channelID, portID) + } // Claim channel capability passed back by IBC module if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index 9429264902a..7ac2b6ac0d0 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -1 +1,98 @@ package keeper_test + +import ( + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/testing" +) + +func (suite *KeeperTestSuite) TestOnChanOpenInit() { + var ( + channel *channeltypes.Channel + path *ibctesting.Path + chanCap *capabilitytypes.Capability + err error + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + { + "invalid order - UNORDERED", func() { + channel.Ordering = channeltypes.UNORDERED + }, false, + }, + { + "invalid counterparty port ID", func() { + channel.Counterparty.PortId = ibctesting.MockPort + }, false, + }, + { + "invalid version", func() { + channel.Version = "version" + }, false, + }, + { + "channel is already active", func() { + suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + }, false, + }, + { + "capability already claimed", func() { + err := suite.chainA.GetSimApp().ScopedICAKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + suite.Require().NoError(err) + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + // mock init interchain account + portID := suite.chainA.GetSimApp().ICAKeeper.GeneratePortId("owner", path.EndpointA.ConnectionID) + portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) + suite.chainA.GetSimApp().ICAKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) + path.EndpointA.ChannelConfig.PortID = portID + + // default values + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + channel = &channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: channeltypes.ORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: types.Version, + } + + chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(portID, path.EndpointA.ChannelID)) + suite.Require().NoError(err) + + tc.malleate() // explicitly change fields in channel and testChannel + + err = suite.chainA.GetSimApp().ICAKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), + ) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } +} diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index 1dd0cd99110..e8459b7cf85 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -8,7 +8,6 @@ import ( "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" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" host "github.com/cosmos/ibc-go/modules/core/24-host" @@ -145,13 +144,20 @@ func (k Keeper) SetActiveChannel(ctx sdk.Context, portId, channelId string) erro return nil } -func (k Keeper) GetActiveChannel(ctx sdk.Context, portId string) (string, error) { +func (k Keeper) GetActiveChannel(ctx sdk.Context, portId string) (string, bool) { store := ctx.KVStore(k.storeKey) key := types.KeyActiveChannel(portId) if !store.Has(key) { - return "", sdkerrors.Wrap(types.ErrActiveChannelNotFound, portId) + return "", false } activeChannel := string(store.Get(key)) - return activeChannel, nil + return activeChannel, true +} + +// IsActiveChannel returns true if there exists an active channel for +// the provided portID and false otherwise. +func (k Keeper) IsActiveChannel(ctx sdk.Context, portId string) bool { + _, found := k.GetActiveChannel(ctx, portId) + return found } diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index d434fcfac9e..daefcc8754a 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -5,19 +5,19 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/modules/core/24-host" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" "github.com/tendermint/tendermint/crypto/tmhash" ) func (k Keeper) TrySendTx(ctx sdk.Context, accountOwner sdk.AccAddress, connectionId string, data interface{}) ([]byte, error) { portId := k.GeneratePortId(accountOwner.String(), connectionId) // Check for the active channel - activeChannelId, err := k.GetActiveChannel(ctx, portId) - if err != nil { - return nil, err + activeChannelId, found := k.GetActiveChannel(ctx, portId) + if !found { + return nil, types.ErrActiveChannelNotFound } sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, portId, activeChannelId) diff --git a/modules/core/04-channel/types/errors.go b/modules/core/04-channel/types/errors.go index 30293eddf07..6a6d608fb29 100644 --- a/modules/core/04-channel/types/errors.go +++ b/modules/core/04-channel/types/errors.go @@ -30,4 +30,6 @@ var ( // ORDERED channel error ErrPacketSequenceOutOfOrder = sdkerrors.Register(SubModuleName, 21, "packet sequence is out of order") + + ErrInvalidChannelVersion = sdkerrors.Register(SubModuleName, 24, "invalid channel version") ) From a9cdf5aeb6b5059896370acdd60c0e559edaaf8b Mon Sep 17 00:00:00 2001 From: Sean King Date: Thu, 29 Jul 2021 17:54:45 +0200 Subject: [PATCH 06/66] feat: ica proto (#305) * feat: adding proto files for interchain accounts & updating references of IBCAccount -> InterchainAccount * doc: updating comments * docs: update comment * fix: updating proto yaml, query name, query params, comments --- docs/ibc/proto-docs.md | 214 ++++++++++++++ .../client/cli/query.go | 8 +- .../27-interchain-accounts/keeper/account.go | 16 +- .../keeper/grpc_query.go | 12 +- .../27-interchain-accounts/keeper/relay.go | 4 +- .../27-interchain-accounts/types/account.go | 28 +- .../types/account.pb.go | 98 ++++--- .../27-interchain-accounts/types/codec.go | 6 +- .../27-interchain-accounts/types/errors.go | 18 +- .../types/genesis.pb.go | 45 +-- .../27-interchain-accounts/types/query.pb.go | 227 ++++++++------- .../27-interchain-accounts/types/types.pb.go | 269 ++++-------------- .../interchain_accounts/v1/account.proto | 19 ++ .../interchain_accounts/v1/genesis.proto | 11 + .../interchain_accounts/v1/query.proto | 30 ++ .../interchain_accounts/v1/types.proto | 31 ++ .../proto/cosmos/auth/v1beta1/auth.proto | 51 ++++ .../proto/cosmos/auth/v1beta1/genesis.proto | 18 ++ .../proto/cosmos/auth/v1beta1/query.proto | 48 ++++ third_party/proto/cosmos_proto/cosmos.proto | 16 ++ 20 files changed, 734 insertions(+), 435 deletions(-) create mode 100644 proto/ibc/applications/interchain_accounts/v1/account.proto create mode 100644 proto/ibc/applications/interchain_accounts/v1/genesis.proto create mode 100644 proto/ibc/applications/interchain_accounts/v1/query.proto create mode 100644 proto/ibc/applications/interchain_accounts/v1/types.proto create mode 100644 third_party/proto/cosmos/auth/v1beta1/auth.proto create mode 100644 third_party/proto/cosmos/auth/v1beta1/genesis.proto create mode 100644 third_party/proto/cosmos/auth/v1beta1/query.proto create mode 100644 third_party/proto/cosmos_proto/cosmos.proto diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index cae068cf68c..5e242070c9d 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -4,6 +4,25 @@ ## Table of Contents +- [ibc/applications/interchain_accounts/v1/account.proto](#ibc/applications/interchain_accounts/v1/account.proto) + - [InterchainAccount](#ibc.applications.interchain_accounts.v1.InterchainAccount) + +- [ibc/applications/interchain_accounts/v1/genesis.proto](#ibc/applications/interchain_accounts/v1/genesis.proto) + - [GenesisState](#ibc.applications.interchain_accounts.v1.GenesisState) + +- [ibc/applications/interchain_accounts/v1/query.proto](#ibc/applications/interchain_accounts/v1/query.proto) + - [QueryInterchainAccountAddressRequest](#ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressRequest) + - [QueryInterchainAccountAddressResponse](#ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressResponse) + + - [Query](#ibc.applications.interchain_accounts.v1.Query) + +- [ibc/applications/interchain_accounts/v1/types.proto](#ibc/applications/interchain_accounts/v1/types.proto) + - [IBCAccountPacketData](#ibc.applications.interchain_accounts.v1.IBCAccountPacketData) + - [IBCTxBody](#ibc.applications.interchain_accounts.v1.IBCTxBody) + - [IBCTxRaw](#ibc.applications.interchain_accounts.v1.IBCTxRaw) + + - [Type](#ibc.applications.interchain_accounts.v1.Type) + - [ibc/applications/transfer/v1/transfer.proto](#ibc/applications/transfer/v1/transfer.proto) - [DenomTrace](#ibc.applications.transfer.v1.DenomTrace) - [FungibleTokenPacketData](#ibc.applications.transfer.v1.FungibleTokenPacketData) @@ -246,6 +265,201 @@ + +

Top

+ +## ibc/applications/interchain_accounts/v1/account.proto + + + + + +### InterchainAccount +An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `base_account` | [cosmos.auth.v1beta1.BaseAccount](#cosmos.auth.v1beta1.BaseAccount) | | | +| `account_owner` | [string](#string) | | | + + + + + + + + + + + + + + + + +

Top

+ +## ibc/applications/interchain_accounts/v1/genesis.proto + + + + + +### GenesisState +GenesisState defines the interchain_account genesis state + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `port_id` | [string](#string) | | | + + + + + + + + + + + + + + + + +

Top

+ +## ibc/applications/interchain_accounts/v1/query.proto + + + + + +### QueryInterchainAccountAddressRequest +Query request for an interchain account address + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `owner_address` | [string](#string) | | Owner address is the owner of the interchain account on the controller chain | +| `connection_id` | [string](#string) | | | + + + + + + + + +### QueryInterchainAccountAddressResponse +Query response for an interchain account address + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `interchain_account_address` | [string](#string) | | The corresponding interchain account address on the host chain | + + + + + + + + + + + + + + +### Query +Query defines the gRPC querier service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `InterchainAccountAddress` | [QueryInterchainAccountAddressRequest](#ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressRequest) | [QueryInterchainAccountAddressResponse](#ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressResponse) | Query to get the address of an interchain account | | + + + + + + +

Top

+ +## ibc/applications/interchain_accounts/v1/types.proto + + + + + +### IBCAccountPacketData +Packet data is comprised of raw transaction & type of transaction + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `type` | [Type](#ibc.applications.interchain_accounts.v1.Type) | | | +| `data` | [bytes](#bytes) | | | + + + + + + + + +### IBCTxBody +Body of a tx for an ics27 IBC packet + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `messages` | [google.protobuf.Any](#google.protobuf.Any) | repeated | | + + + + + + + + +### IBCTxRaw +Raw tx body + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `body_bytes` | [bytes](#bytes) | | | + + + + + + + + + + +### Type +The different types of interchain account transactions +EXECUTE_TX is used when sending a TX from the controller side to the host side. The host side will execute the tx on +behalf of the interchain account. + +| Name | Number | Description | +| ---- | ------ | ----------- | +| TYPE_EXECUTE_TX_UNSPECIFIED | 0 | Execute message type | + + + + + + + + + +

Top

diff --git a/modules/apps/27-interchain-accounts/client/cli/query.go b/modules/apps/27-interchain-accounts/client/cli/query.go index 73f4389fa58..9945d79bab8 100644 --- a/modules/apps/27-interchain-accounts/client/cli/query.go +++ b/modules/apps/27-interchain-accounts/client/cli/query.go @@ -19,12 +19,12 @@ func GetQueryCmd() *cobra.Command { RunE: client.ValidateCmd, } - cmd.AddCommand(GetIBCAccountCmd()) + cmd.AddCommand(GetInterchainAccountCmd()) return cmd } -func GetIBCAccountCmd() *cobra.Command { +func GetInterchainAccountCmd() *cobra.Command { cmd := &cobra.Command{ Use: "address [address] [connection-id]", RunE: func(cmd *cobra.Command, args []string) error { @@ -33,11 +33,11 @@ func GetIBCAccountCmd() *cobra.Command { return err } - address := args[0] + ownerAddress := args[0] connectionId := args[1] queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.IBCAccount(context.Background(), &types.QueryIBCAccountRequest{Address: address, ConnectionId: connectionId}) + res, err := queryClient.InterchainAccountAddress(context.Background(), &types.QueryInterchainAccountAddressRequest{OwnerAddress: ownerAddress, ConnectionId: connectionId}) if err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index 167e3d9e26f..6bad42a1133 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -41,7 +41,7 @@ func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionId, owner strin } // Register interchain account if it has not already been created -func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portId string) (types.IBCAccountI, error) { +func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portId string) (types.InterchainAccountI, error) { address := k.GenerateAddress(portId) account := k.accountKeeper.GetAccount(ctx, address) @@ -49,7 +49,7 @@ func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portId string) (types return nil, sdkerrors.Wrap(types.ErrAccountAlreadyExist, account.String()) } - interchainAccount := types.NewIBCAccount( + interchainAccount := types.NewInterchainAccount( authtypes.NewBaseAccountWithAddress(address), portId, ) @@ -71,7 +71,7 @@ func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portId string) (str store := ctx.KVStore(k.storeKey) key := types.KeyOwnerAccount(portId) if !store.Has(key) { - return "", sdkerrors.Wrap(types.ErrIBCAccountNotFound, portId) + return "", sdkerrors.Wrap(types.ErrInterchainAccountNotFound, portId) } interchainAccountAddr := string(store.Get(key)) @@ -83,15 +83,15 @@ func (k Keeper) GenerateAddress(identifier string) []byte { return tmhash.SumTruncated(append([]byte(identifier))) } -func (k Keeper) GetIBCAccount(ctx sdk.Context, addr sdk.AccAddress) (types.IBCAccount, error) { +func (k Keeper) GetInterchainAccount(ctx sdk.Context, addr sdk.AccAddress) (types.InterchainAccount, error) { acc := k.accountKeeper.GetAccount(ctx, addr) if acc == nil { - return types.IBCAccount{}, sdkerrors.Wrap(types.ErrIBCAccountNotFound, "there is no account") + return types.InterchainAccount{}, sdkerrors.Wrap(types.ErrInterchainAccountNotFound, "there is no account") } - ibcAcc, ok := acc.(*types.IBCAccount) + interchainAccount, ok := acc.(*types.InterchainAccount) if !ok { - return types.IBCAccount{}, sdkerrors.Wrap(types.ErrIBCAccountNotFound, "account is not an IBC account") + return types.InterchainAccount{}, sdkerrors.Wrap(types.ErrInterchainAccountNotFound, "account is not an interchain account") } - return *ibcAcc, nil + return *interchainAccount, nil } diff --git a/modules/apps/27-interchain-accounts/keeper/grpc_query.go b/modules/apps/27-interchain-accounts/keeper/grpc_query.go index 7f54be0f80a..9b072d28ef0 100644 --- a/modules/apps/27-interchain-accounts/keeper/grpc_query.go +++ b/modules/apps/27-interchain-accounts/keeper/grpc_query.go @@ -13,23 +13,23 @@ import ( var _ types.QueryServer = Keeper{} -// IBCAccount implements the Query/IBCAccount gRPC method -func (k Keeper) IBCAccount(ctx context.Context, req *types.QueryIBCAccountRequest) (*types.QueryIBCAccountResponse, error) { +// InterchainAccount implements the Query/InterchainAccount gRPC method +func (k Keeper) InterchainAccountAddress(ctx context.Context, req *types.QueryInterchainAccountAddressRequest) (*types.QueryInterchainAccountAddressResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } - if req.Address == "" { + if req.OwnerAddress == "" { return nil, status.Error(codes.InvalidArgument, "address cannot be empty") } sdkCtx := sdk.UnwrapSDKContext(ctx) - portId := k.GeneratePortId(req.Address, req.ConnectionId) + portId := k.GeneratePortId(req.OwnerAddress, req.ConnectionId) - address, err := k.GetInterchainAccountAddress(sdkCtx, portId) + interchainAccountAddress, err := k.GetInterchainAccountAddress(sdkCtx, portId) if err != nil { return nil, err } - return &types.QueryIBCAccountResponse{AccountAddress: address}, nil + return &types.QueryInterchainAccountAddressResponse{InterchainAccountAddress: interchainAccountAddress}, nil } diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index daefcc8754a..757a08fe7c3 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -72,7 +72,7 @@ func (k Keeper) createOutgoingPacket( } packetData := types.IBCAccountPacketData{ - Type: types.Type_RUNTX, + Type: types.EXECUTE_TX, Data: txBytes, } @@ -206,7 +206,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error } switch data.Type { - case types.Type_RUNTX: + case types.EXECUTE_TX: msgs, err := k.DeserializeTx(ctx, data.Data) if err != nil { return err diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index eed5f4c46e8..ebba17dc756 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -15,33 +15,33 @@ const ( IcaPrefix string = "ics27-1-" ) -type IBCAccountI interface { +type InterchainAccountI interface { authtypes.AccountI } var ( - _ authtypes.GenesisAccount = (*IBCAccount)(nil) - _ IBCAccountI = (*IBCAccount)(nil) + _ authtypes.GenesisAccount = (*InterchainAccount)(nil) + _ InterchainAccountI = (*InterchainAccount)(nil) ) -func NewIBCAccount(ba *authtypes.BaseAccount, accountOwner string) *IBCAccount { - return &IBCAccount{ +func NewInterchainAccount(ba *authtypes.BaseAccount, accountOwner string) *InterchainAccount { + return &InterchainAccount{ BaseAccount: ba, AccountOwner: accountOwner, } } // SetPubKey - Implements AccountI -func (IBCAccount) SetPubKey(pubKey crypto.PubKey) error { +func (InterchainAccount) SetPubKey(pubKey crypto.PubKey) error { return fmt.Errorf("not supported for interchain accounts") } // SetSequence - Implements AccountI -func (IBCAccount) SetSequence(seq uint64) error { +func (InterchainAccount) SetSequence(seq uint64) error { return fmt.Errorf("not supported for interchain accounts") } -func (ia IBCAccount) Validate() error { +func (ia InterchainAccount) Validate() error { return ia.BaseAccount.Validate() } @@ -53,13 +53,13 @@ type ibcAccountPretty struct { AccountOwner string `json:"address" yaml:"account_owner"` } -func (ia IBCAccount) String() string { +func (ia InterchainAccount) String() string { out, _ := ia.MarshalYAML() return out.(string) } -// MarshalYAML returns the YAML representation of a IBCAccount. -func (ia IBCAccount) MarshalYAML() (interface{}, error) { +// MarshalYAML returns the YAML representation of a InterchainAccount. +func (ia InterchainAccount) MarshalYAML() (interface{}, error) { accAddr, err := sdk.AccAddressFromBech32(ia.Address) if err != nil { return nil, err @@ -80,8 +80,8 @@ func (ia IBCAccount) MarshalYAML() (interface{}, error) { return string(bs), nil } -// MarshalJSON returns the JSON representation of a IBCAccount. -func (ia IBCAccount) MarshalJSON() ([]byte, error) { +// MarshalJSON returns the JSON representation of a InterchainAccount. +func (ia InterchainAccount) MarshalJSON() ([]byte, error) { accAddr, err := sdk.AccAddressFromBech32(ia.Address) if err != nil { return nil, err @@ -97,7 +97,7 @@ func (ia IBCAccount) MarshalJSON() ([]byte, error) { } // UnmarshalJSON unmarshals raw JSON bytes into a ModuleAccount. -func (ia *IBCAccount) UnmarshalJSON(bz []byte) error { +func (ia *InterchainAccount) UnmarshalJSON(bz []byte) error { var alias ibcAccountPretty if err := json.Unmarshal(bz, &alias); err != nil { return err diff --git a/modules/apps/27-interchain-accounts/types/account.pb.go b/modules/apps/27-interchain-accounts/types/account.pb.go index 85774b081af..4518d7581a9 100644 --- a/modules/apps/27-interchain-accounts/types/account.pb.go +++ b/modules/apps/27-interchain-accounts/types/account.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: ibc/account/account.proto +// source: ibc/applications/interchain_accounts/v1/account.proto package types @@ -25,23 +25,23 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// IBCAccount defines an account to which other chains have privileges -type IBCAccount struct { +// An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain +type InterchainAccount struct { *types.BaseAccount `protobuf:"bytes,1,opt,name=base_account,json=baseAccount,proto3,embedded=base_account" json:"base_account,omitempty" yaml:"base_account"` - AccountOwner string `protobuf:"bytes,2,opt,name=accountOwner,proto3" json:"accountOwner,omitempty"` + AccountOwner string `protobuf:"bytes,2,opt,name=account_owner,json=accountOwner,proto3" json:"account_owner,omitempty" yaml:"account_owner"` } -func (m *IBCAccount) Reset() { *m = IBCAccount{} } -func (*IBCAccount) ProtoMessage() {} -func (*IBCAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_be5ed7ee65e0e021, []int{0} +func (m *InterchainAccount) Reset() { *m = InterchainAccount{} } +func (*InterchainAccount) ProtoMessage() {} +func (*InterchainAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_5561bd92625bf7da, []int{0} } -func (m *IBCAccount) XXX_Unmarshal(b []byte) error { +func (m *InterchainAccount) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *IBCAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *InterchainAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_IBCAccount.Marshal(b, m, deterministic) + return xxx_messageInfo_InterchainAccount.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -51,47 +51,53 @@ func (m *IBCAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *IBCAccount) XXX_Merge(src proto.Message) { - xxx_messageInfo_IBCAccount.Merge(m, src) +func (m *InterchainAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_InterchainAccount.Merge(m, src) } -func (m *IBCAccount) XXX_Size() int { +func (m *InterchainAccount) XXX_Size() int { return m.Size() } -func (m *IBCAccount) XXX_DiscardUnknown() { - xxx_messageInfo_IBCAccount.DiscardUnknown(m) +func (m *InterchainAccount) XXX_DiscardUnknown() { + xxx_messageInfo_InterchainAccount.DiscardUnknown(m) } -var xxx_messageInfo_IBCAccount proto.InternalMessageInfo +var xxx_messageInfo_InterchainAccount proto.InternalMessageInfo func init() { - proto.RegisterType((*IBCAccount)(nil), "ibc.account.IBCAccount") + proto.RegisterType((*InterchainAccount)(nil), "ibc.applications.interchain_accounts.v1.InterchainAccount") } -func init() { proto.RegisterFile("ibc/account/account.proto", fileDescriptor_be5ed7ee65e0e021) } +func init() { + proto.RegisterFile("ibc/applications/interchain_accounts/v1/account.proto", fileDescriptor_5561bd92625bf7da) +} -var fileDescriptor_be5ed7ee65e0e021 = []byte{ - // 283 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0x4c, 0x4a, 0xd6, - 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0x81, 0xd1, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, - 0xdc, 0x99, 0x49, 0xc9, 0x7a, 0x50, 0x21, 0x29, 0xc9, 0xe4, 0xfc, 0xe2, 0xdc, 0xfc, 0xe2, 0x78, - 0xb0, 0x94, 0x3e, 0x84, 0x03, 0x51, 0x27, 0x25, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, 0x11, 0x07, 0xb1, - 0xa0, 0xa2, 0x72, 0x10, 0x35, 0xfa, 0x89, 0xa5, 0x25, 0x19, 0xfa, 0x65, 0x86, 0x49, 0xa9, 0x25, - 0x89, 0x86, 0x60, 0x0e, 0x44, 0x5e, 0x69, 0x35, 0x23, 0x17, 0x97, 0xa7, 0x93, 0xb3, 0x23, 0xc4, - 0x7c, 0xa1, 0x04, 0x2e, 0x9e, 0xa4, 0xc4, 0xe2, 0xd4, 0x78, 0xa8, 0x7d, 0x12, 0x8c, 0x0a, 0x8c, - 0x1a, 0xdc, 0x46, 0x0a, 0x7a, 0x50, 0x9b, 0xc0, 0x1a, 0xa1, 0xa6, 0xe8, 0x39, 0x25, 0x16, 0xa7, - 0x42, 0xf5, 0x39, 0x49, 0x5f, 0xb8, 0x27, 0xcf, 0xf8, 0xe9, 0x9e, 0xbc, 0x70, 0x65, 0x62, 0x6e, - 0x8e, 0x95, 0x12, 0xb2, 0x19, 0x4a, 0x41, 0xdc, 0x49, 0x08, 0x95, 0x42, 0x4a, 0x5c, 0x3c, 0x50, - 0x09, 0xff, 0xf2, 0xbc, 0xd4, 0x22, 0x09, 0x26, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x14, 0x31, 0x2b, - 0xf1, 0x8e, 0x05, 0xf2, 0x0c, 0x33, 0x16, 0xc8, 0x33, 0x5c, 0xda, 0xa2, 0xcb, 0x8d, 0x70, 0x9d, - 0xa7, 0x53, 0xf0, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, - 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x59, 0xa6, 0x67, - 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0x42, 0x83, 0x45, 0x3f, 0x33, 0xaf, 0x24, 0xb5, - 0x28, 0x39, 0x23, 0x31, 0x33, 0x4f, 0x17, 0x6a, 0x7a, 0xb1, 0x7e, 0x85, 0x7e, 0x66, 0x52, 0x32, - 0x8c, 0xab, 0x5f, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0x0e, 0x09, 0x63, 0x40, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x32, 0x59, 0x01, 0x7a, 0x84, 0x01, 0x00, 0x00, +var fileDescriptor_5561bd92625bf7da = []byte{ + // 338 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0xcd, 0x4c, 0x4a, 0xd6, + 0x4f, 0x2c, 0x28, 0xc8, 0xc9, 0x4c, 0x4e, 0x2c, 0xc9, 0xcc, 0xcf, 0x2b, 0xd6, 0xcf, 0xcc, 0x2b, + 0x49, 0x2d, 0x4a, 0xce, 0x48, 0xcc, 0xcc, 0x8b, 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0x29, + 0xd6, 0x2f, 0x33, 0xd4, 0x87, 0xb2, 0xf5, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0xd4, 0x33, 0x93, + 0x92, 0xf5, 0x90, 0xb5, 0xe9, 0x61, 0xd1, 0xa6, 0x57, 0x66, 0x28, 0x25, 0x99, 0x9c, 0x5f, 0x9c, + 0x9b, 0x5f, 0x1c, 0x0f, 0xd6, 0xa6, 0x0f, 0xe1, 0x40, 0xcc, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, + 0x87, 0x88, 0x83, 0x58, 0x50, 0x51, 0x39, 0x88, 0x1a, 0xfd, 0xc4, 0xd2, 0x92, 0x0c, 0xfd, 0x32, + 0xc3, 0xa4, 0xd4, 0x92, 0x44, 0x43, 0x30, 0x07, 0x22, 0xaf, 0x74, 0x85, 0x91, 0x4b, 0xd0, 0x13, + 0x6e, 0x97, 0x23, 0xc4, 0x2a, 0xa1, 0x04, 0x2e, 0x9e, 0xa4, 0xc4, 0xe2, 0x54, 0x98, 0xd5, 0x12, + 0x8c, 0x0a, 0x8c, 0x1a, 0xdc, 0x46, 0x0a, 0x7a, 0x50, 0x0b, 0xc1, 0xfa, 0xa1, 0x86, 0xe9, 0x39, + 0x25, 0x16, 0xa7, 0x42, 0xf5, 0x39, 0x49, 0x5f, 0xb8, 0x27, 0xcf, 0xf8, 0xe9, 0x9e, 0xbc, 0x70, + 0x65, 0x62, 0x6e, 0x8e, 0x95, 0x12, 0xb2, 0x19, 0x4a, 0x41, 0xdc, 0x49, 0x08, 0x95, 0x42, 0xb6, + 0x5c, 0xbc, 0x50, 0x89, 0xf8, 0xfc, 0xf2, 0xbc, 0xd4, 0x22, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x4e, + 0x27, 0x89, 0x4f, 0xf7, 0xe4, 0x45, 0x20, 0x9a, 0x51, 0xa4, 0x95, 0x82, 0x78, 0xa0, 0x7c, 0x7f, + 0x10, 0xd7, 0x4a, 0xae, 0x63, 0x81, 0x3c, 0xc3, 0x8c, 0x05, 0xf2, 0x0c, 0x97, 0xb6, 0xe8, 0x0a, + 0x61, 0xb8, 0xdf, 0xd3, 0x29, 0xe6, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, + 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, + 0x9c, 0xd2, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xa1, 0xe1, 0xa7, 0x9f, 0x99, + 0x94, 0xac, 0x9b, 0x9e, 0xaf, 0x9f, 0x9b, 0x9f, 0x52, 0x9a, 0x93, 0x5a, 0x0c, 0x8a, 0xbe, 0x62, + 0x7d, 0x23, 0x73, 0x5d, 0x44, 0x14, 0xe8, 0xc2, 0x63, 0xae, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, + 0x0d, 0x1c, 0x76, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x46, 0x61, 0xdb, 0x7e, 0xee, 0x01, + 0x00, 0x00, } -func (m *IBCAccount) Marshal() (dAtA []byte, err error) { +func (m *InterchainAccount) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -101,12 +107,12 @@ func (m *IBCAccount) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *IBCAccount) MarshalTo(dAtA []byte) (int, error) { +func (m *InterchainAccount) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *IBCAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *InterchainAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -144,7 +150,7 @@ func encodeVarintAccount(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *IBCAccount) Size() (n int) { +func (m *InterchainAccount) Size() (n int) { if m == nil { return 0 } @@ -167,7 +173,7 @@ func sovAccount(x uint64) (n int) { func sozAccount(x uint64) (n int) { return sovAccount(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *IBCAccount) Unmarshal(dAtA []byte) error { +func (m *InterchainAccount) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -190,10 +196,10 @@ func (m *IBCAccount) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: IBCAccount: wiretype end group for non-group") + return fmt.Errorf("proto: InterchainAccount: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: IBCAccount: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: InterchainAccount: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/modules/apps/27-interchain-accounts/types/codec.go b/modules/apps/27-interchain-accounts/types/codec.go index 72b907dae61..c46946deaa2 100644 --- a/modules/apps/27-interchain-accounts/types/codec.go +++ b/modules/apps/27-interchain-accounts/types/codec.go @@ -9,14 +9,14 @@ import ( // RegisterLegacyAminoCodec registers the account interfaces and concrete types on the // provided LegacyAmino codec. These types are used for Amino JSON serialization func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { - cdc.RegisterInterface((*IBCAccountI)(nil), nil) - cdc.RegisterConcrete(&IBCAccount{}, "27-interchain-accounts/IBCAccount", nil) + cdc.RegisterInterface((*InterchainAccountI)(nil), nil) + cdc.RegisterConcrete(&InterchainAccount{}, "27-interchain-accounts/InterchainAccount", nil) } // RegisterInterface associates protoName with AccountI interface // and creates a registry of it's concrete implementations func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterImplementations((*authtypes.AccountI)(nil), &IBCAccount{}) + registry.RegisterImplementations((*authtypes.AccountI)(nil), &InterchainAccount{}) } var ( diff --git a/modules/apps/27-interchain-accounts/types/errors.go b/modules/apps/27-interchain-accounts/types/errors.go index 8854c1df4e7..f05d8bc0a3d 100644 --- a/modules/apps/27-interchain-accounts/types/errors.go +++ b/modules/apps/27-interchain-accounts/types/errors.go @@ -5,13 +5,13 @@ import ( ) var ( - ErrUnknownPacketData = sdkerrors.Register(ModuleName, 1, "Unknown packet data") - ErrAccountAlreadyExist = sdkerrors.Register(ModuleName, 2, "Account already exist") - ErrPortAlreadyBound = sdkerrors.Register(ModuleName, 3, "Port is already bound for address") - ErrUnsupportedChain = sdkerrors.Register(ModuleName, 4, "Unsupported chain") - ErrInvalidOutgoingData = sdkerrors.Register(ModuleName, 5, "Invalid outgoing data") - ErrInvalidRoute = sdkerrors.Register(ModuleName, 6, "Invalid route") - ErrIBCAccountNotFound = sdkerrors.Register(ModuleName, 7, "Ibc account not found") - ErrIBCAccountAlreadySet = sdkerrors.Register(ModuleName, 8, "Interchain Account is already set") - ErrActiveChannelNotFound = sdkerrors.Register(ModuleName, 9, "No active channel for this owner") + ErrUnknownPacketData = sdkerrors.Register(ModuleName, 1, "Unknown packet data") + ErrAccountAlreadyExist = sdkerrors.Register(ModuleName, 2, "Account already exist") + ErrPortAlreadyBound = sdkerrors.Register(ModuleName, 3, "Port is already bound for address") + ErrUnsupportedChain = sdkerrors.Register(ModuleName, 4, "Unsupported chain") + ErrInvalidOutgoingData = sdkerrors.Register(ModuleName, 5, "Invalid outgoing data") + ErrInvalidRoute = sdkerrors.Register(ModuleName, 6, "Invalid route") + ErrInterchainAccountNotFound = sdkerrors.Register(ModuleName, 7, "Interchain account not found") + ErrInterchainAccountAlreadySet = sdkerrors.Register(ModuleName, 8, "Interchain Account is already set") + ErrActiveChannelNotFound = sdkerrors.Register(ModuleName, 9, "No active channel for this owner") ) diff --git a/modules/apps/27-interchain-accounts/types/genesis.pb.go b/modules/apps/27-interchain-accounts/types/genesis.pb.go index fddc8377b68..9e32a1c8abc 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.pb.go +++ b/modules/apps/27-interchain-accounts/types/genesis.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: ibc/account/genesis.proto +// source: ibc/applications/interchain_accounts/v1/genesis.proto package types @@ -23,7 +23,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// GenesisState defines the ibc-account genesis state +// GenesisState defines the interchain_account genesis state type GenesisState struct { PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` } @@ -32,7 +32,7 @@ func (m *GenesisState) Reset() { *m = GenesisState{} } func (m *GenesisState) String() string { return proto.CompactTextString(m) } func (*GenesisState) ProtoMessage() {} func (*GenesisState) Descriptor() ([]byte, []int) { - return fileDescriptor_c5549b69e3eeb3e4, []int{0} + return fileDescriptor_629b3ced0911516b, []int{0} } func (m *GenesisState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -69,26 +69,31 @@ func (m *GenesisState) GetPortId() string { } func init() { - proto.RegisterType((*GenesisState)(nil), "ibc.account.GenesisState") + proto.RegisterType((*GenesisState)(nil), "ibc.applications.interchain_accounts.v1.GenesisState") } -func init() { proto.RegisterFile("ibc/account/genesis.proto", fileDescriptor_c5549b69e3eeb3e4) } +func init() { + proto.RegisterFile("ibc/applications/interchain_accounts/v1/genesis.proto", fileDescriptor_629b3ced0911516b) +} -var fileDescriptor_c5549b69e3eeb3e4 = []byte{ - // 202 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0x4c, 0x4a, 0xd6, - 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0xd1, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, - 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xce, 0x4c, 0x4a, 0xd6, 0x83, 0x4a, 0x49, 0x89, 0xa4, - 0xe7, 0xa7, 0xe7, 0x83, 0xc5, 0xf5, 0x41, 0x2c, 0x88, 0x12, 0x25, 0x6b, 0x2e, 0x1e, 0x77, 0x88, - 0x9e, 0xe0, 0x92, 0xc4, 0x92, 0x54, 0x21, 0x6d, 0x2e, 0xf6, 0x82, 0xfc, 0xa2, 0x92, 0xf8, 0xcc, - 0x14, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0xa1, 0x4f, 0xf7, 0xe4, 0xf9, 0x2a, 0x13, 0x73, - 0x73, 0xac, 0x94, 0xa0, 0x12, 0x4a, 0x41, 0x6c, 0x20, 0x96, 0x67, 0x8a, 0x53, 0xf0, 0x89, 0x47, - 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, - 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x59, 0xa6, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, - 0x25, 0xe7, 0xe7, 0xea, 0x27, 0xe7, 0x17, 0xe7, 0xe6, 0x17, 0xeb, 0x67, 0xe6, 0x95, 0xa4, 0x16, - 0x25, 0x67, 0x24, 0x66, 0xe6, 0xe9, 0x42, 0x9d, 0x54, 0xac, 0x5f, 0xa1, 0x9f, 0x99, 0x94, 0x0c, - 0xe3, 0xea, 0x97, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x1d, 0x66, 0x0c, 0x08, 0x00, 0x00, - 0xff, 0xff, 0x01, 0x11, 0x9a, 0xe3, 0xd8, 0x00, 0x00, 0x00, +var fileDescriptor_629b3ced0911516b = []byte{ + // 241 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0xcd, 0x4c, 0x4a, 0xd6, + 0x4f, 0x2c, 0x28, 0xc8, 0xc9, 0x4c, 0x4e, 0x2c, 0xc9, 0xcc, 0xcf, 0x2b, 0xd6, 0xcf, 0xcc, 0x2b, + 0x49, 0x2d, 0x4a, 0xce, 0x48, 0xcc, 0xcc, 0x8b, 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0x29, + 0xd6, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, + 0xc9, 0x17, 0x52, 0xcf, 0x4c, 0x4a, 0xd6, 0x43, 0xd6, 0xa6, 0x87, 0x45, 0x9b, 0x5e, 0x99, 0xa1, + 0x94, 0x48, 0x7a, 0x7e, 0x7a, 0x3e, 0x58, 0x8f, 0x3e, 0x88, 0x05, 0xd1, 0xae, 0x64, 0xcd, 0xc5, + 0xe3, 0x0e, 0x31, 0x2f, 0xb8, 0x24, 0xb1, 0x24, 0x55, 0x48, 0x9b, 0x8b, 0xbd, 0x20, 0xbf, 0xa8, + 0x24, 0x3e, 0x33, 0x45, 0x82, 0x51, 0x81, 0x51, 0x83, 0xd3, 0x49, 0xe8, 0xd3, 0x3d, 0x79, 0xbe, + 0xca, 0xc4, 0xdc, 0x1c, 0x2b, 0x25, 0xa8, 0x84, 0x52, 0x10, 0x1b, 0x88, 0xe5, 0x99, 0xe2, 0x14, + 0x73, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, + 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x4e, 0xe9, 0x99, 0x25, 0x19, + 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0x99, 0x49, + 0xc9, 0xba, 0xe9, 0xf9, 0xfa, 0xb9, 0xf9, 0x29, 0xa5, 0x39, 0xa9, 0xc5, 0x20, 0x9f, 0x16, 0xeb, + 0x1b, 0x99, 0xeb, 0x22, 0x5c, 0xab, 0x0b, 0xf7, 0x64, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, + 0xd8, 0x85, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x89, 0x2b, 0x4e, 0x7c, 0x19, 0x01, 0x00, + 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/27-interchain-accounts/types/query.pb.go b/modules/apps/27-interchain-accounts/types/query.pb.go index eb7b28b6b77..56108e7f743 100644 --- a/modules/apps/27-interchain-accounts/types/query.pb.go +++ b/modules/apps/27-interchain-accounts/types/query.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: ibc/account/query.proto +// source: ibc/applications/interchain_accounts/v1/query.proto package types @@ -29,24 +29,25 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -type QueryIBCAccountRequest struct { - // address is the address to query. - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` +// Query request for an interchain account address +type QueryInterchainAccountAddressRequest struct { + // Owner address is the owner of the interchain account on the controller chain + OwnerAddress string `protobuf:"bytes,1,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` } -func (m *QueryIBCAccountRequest) Reset() { *m = QueryIBCAccountRequest{} } -func (m *QueryIBCAccountRequest) String() string { return proto.CompactTextString(m) } -func (*QueryIBCAccountRequest) ProtoMessage() {} -func (*QueryIBCAccountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5738b2fac406b004, []int{0} +func (m *QueryInterchainAccountAddressRequest) Reset() { *m = QueryInterchainAccountAddressRequest{} } +func (m *QueryInterchainAccountAddressRequest) String() string { return proto.CompactTextString(m) } +func (*QueryInterchainAccountAddressRequest) ProtoMessage() {} +func (*QueryInterchainAccountAddressRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_72a16b57c3343764, []int{0} } -func (m *QueryIBCAccountRequest) XXX_Unmarshal(b []byte) error { +func (m *QueryInterchainAccountAddressRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryIBCAccountRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryInterchainAccountAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryIBCAccountRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryInterchainAccountAddressRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -56,35 +57,36 @@ func (m *QueryIBCAccountRequest) XXX_Marshal(b []byte, deterministic bool) ([]by return b[:n], nil } } -func (m *QueryIBCAccountRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryIBCAccountRequest.Merge(m, src) +func (m *QueryInterchainAccountAddressRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryInterchainAccountAddressRequest.Merge(m, src) } -func (m *QueryIBCAccountRequest) XXX_Size() int { +func (m *QueryInterchainAccountAddressRequest) XXX_Size() int { return m.Size() } -func (m *QueryIBCAccountRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryIBCAccountRequest.DiscardUnknown(m) +func (m *QueryInterchainAccountAddressRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryInterchainAccountAddressRequest.DiscardUnknown(m) } -var xxx_messageInfo_QueryIBCAccountRequest proto.InternalMessageInfo +var xxx_messageInfo_QueryInterchainAccountAddressRequest proto.InternalMessageInfo -type QueryIBCAccountResponse struct { - // account defines the account of the corresponding address. - AccountAddress string `protobuf:"bytes,1,opt,name=account_address,json=accountAddress,proto3" json:"account_address,omitempty"` +// Query response for an interchain account address +type QueryInterchainAccountAddressResponse struct { + // The corresponding interchain account address on the host chain + InterchainAccountAddress string `protobuf:"bytes,1,opt,name=interchain_account_address,json=interchainAccountAddress,proto3" json:"interchain_account_address,omitempty"` } -func (m *QueryIBCAccountResponse) Reset() { *m = QueryIBCAccountResponse{} } -func (m *QueryIBCAccountResponse) String() string { return proto.CompactTextString(m) } -func (*QueryIBCAccountResponse) ProtoMessage() {} -func (*QueryIBCAccountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5738b2fac406b004, []int{1} +func (m *QueryInterchainAccountAddressResponse) Reset() { *m = QueryInterchainAccountAddressResponse{} } +func (m *QueryInterchainAccountAddressResponse) String() string { return proto.CompactTextString(m) } +func (*QueryInterchainAccountAddressResponse) ProtoMessage() {} +func (*QueryInterchainAccountAddressResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_72a16b57c3343764, []int{1} } -func (m *QueryIBCAccountResponse) XXX_Unmarshal(b []byte) error { +func (m *QueryInterchainAccountAddressResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryIBCAccountResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryInterchainAccountAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryIBCAccountResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryInterchainAccountAddressResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -94,54 +96,59 @@ func (m *QueryIBCAccountResponse) XXX_Marshal(b []byte, deterministic bool) ([]b return b[:n], nil } } -func (m *QueryIBCAccountResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryIBCAccountResponse.Merge(m, src) +func (m *QueryInterchainAccountAddressResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryInterchainAccountAddressResponse.Merge(m, src) } -func (m *QueryIBCAccountResponse) XXX_Size() int { +func (m *QueryInterchainAccountAddressResponse) XXX_Size() int { return m.Size() } -func (m *QueryIBCAccountResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryIBCAccountResponse.DiscardUnknown(m) +func (m *QueryInterchainAccountAddressResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryInterchainAccountAddressResponse.DiscardUnknown(m) } -var xxx_messageInfo_QueryIBCAccountResponse proto.InternalMessageInfo +var xxx_messageInfo_QueryInterchainAccountAddressResponse proto.InternalMessageInfo -func (m *QueryIBCAccountResponse) GetAccountAddress() string { +func (m *QueryInterchainAccountAddressResponse) GetInterchainAccountAddress() string { if m != nil { - return m.AccountAddress + return m.InterchainAccountAddress } return "" } func init() { - proto.RegisterType((*QueryIBCAccountRequest)(nil), "ibc.account.QueryIBCAccountRequest") - proto.RegisterType((*QueryIBCAccountResponse)(nil), "ibc.account.QueryIBCAccountResponse") -} - -func init() { proto.RegisterFile("ibc/account/query.proto", fileDescriptor_5738b2fac406b004) } - -var fileDescriptor_5738b2fac406b004 = []byte{ - // 312 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xcf, 0x4a, 0x03, 0x31, - 0x10, 0xc6, 0xb3, 0x82, 0xff, 0xe2, 0x3f, 0x08, 0x62, 0x6b, 0x91, 0x54, 0x5a, 0x41, 0x2f, 0x6e, - 0x40, 0x4f, 0x7a, 0x6b, 0x3d, 0xf5, 0x68, 0x3d, 0xe9, 0xa5, 0x24, 0xd9, 0xb0, 0x0d, 0xd8, 0xcc, - 0x76, 0x93, 0x05, 0xfb, 0x06, 0x1e, 0x7d, 0x84, 0x3e, 0x8e, 0xc7, 0x1e, 0x3d, 0x4a, 0xf7, 0xe2, - 0x63, 0xc8, 0xee, 0xa6, 0xb4, 0xa2, 0x78, 0x4a, 0xe6, 0xfb, 0x0d, 0xdf, 0x37, 0x33, 0xb8, 0xa6, - 0x85, 0x64, 0x5c, 0x4a, 0xc8, 0x8c, 0x63, 0xe3, 0x4c, 0xa5, 0x93, 0x30, 0x49, 0xc1, 0x01, 0xd9, - 0xd1, 0x42, 0x86, 0x1e, 0x34, 0x0e, 0x63, 0x88, 0xa1, 0xd4, 0x59, 0xf1, 0xab, 0x5a, 0x1a, 0x27, - 0x31, 0x40, 0xfc, 0xac, 0x18, 0x4f, 0x34, 0xe3, 0xc6, 0x80, 0xe3, 0x4e, 0x83, 0xb1, 0x9e, 0x1e, - 0xaf, 0x3a, 0xfb, 0xb7, 0x42, 0x2d, 0x8e, 0x8f, 0xee, 0x8b, 0xa8, 0x5e, 0xf7, 0xae, 0x53, 0x81, - 0xbe, 0x1a, 0x67, 0xca, 0x3a, 0x52, 0xc7, 0x9b, 0x3c, 0x8a, 0x52, 0x65, 0x6d, 0x3d, 0x38, 0x0d, - 0x2e, 0xb6, 0xfb, 0x8b, 0x92, 0xb4, 0xf1, 0x9e, 0x04, 0x63, 0x94, 0x2c, 0x32, 0x06, 0x3a, 0xaa, - 0xaf, 0x95, 0x7c, 0x77, 0x29, 0xf6, 0xa2, 0xdb, 0xad, 0xd7, 0x69, 0x13, 0x7d, 0x4d, 0x9b, 0xa8, - 0xd5, 0xc5, 0xb5, 0x5f, 0x11, 0x36, 0x01, 0x63, 0x15, 0x39, 0xc7, 0x07, 0x7e, 0x9c, 0xc1, 0xcf, - 0xac, 0x7d, 0x2f, 0x77, 0x2a, 0xf5, 0x4a, 0xe0, 0xf5, 0xd2, 0x83, 0x3c, 0x62, 0xbc, 0xf4, 0x21, - 0xed, 0x70, 0xe5, 0x34, 0xe1, 0xdf, 0x8b, 0x34, 0xce, 0xfe, 0x6f, 0xaa, 0x46, 0x69, 0xa1, 0xee, - 0xc3, 0xfb, 0x9c, 0x06, 0xb3, 0x39, 0x0d, 0x3e, 0xe7, 0x34, 0x78, 0xcb, 0x29, 0x9a, 0xe5, 0x14, - 0x7d, 0xe4, 0x14, 0x3d, 0xdd, 0xc4, 0xda, 0x0d, 0x33, 0x11, 0x4a, 0x18, 0x31, 0x09, 0x76, 0x04, - 0x96, 0x69, 0xe3, 0x54, 0x2a, 0x87, 0x5c, 0x9b, 0x4b, 0xef, 0x6c, 0xd9, 0x0b, 0xd3, 0x42, 0x2e, - 0x4a, 0xe6, 0x26, 0x89, 0xb2, 0x62, 0xa3, 0x3c, 0xf3, 0xf5, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x90, 0xc3, 0xe9, 0x06, 0xdd, 0x01, 0x00, 0x00, + proto.RegisterType((*QueryInterchainAccountAddressRequest)(nil), "ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressRequest") + proto.RegisterType((*QueryInterchainAccountAddressResponse)(nil), "ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressResponse") +} + +func init() { + proto.RegisterFile("ibc/applications/interchain_accounts/v1/query.proto", fileDescriptor_72a16b57c3343764) +} + +var fileDescriptor_72a16b57c3343764 = []byte{ + // 357 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x31, 0x4b, 0x33, 0x41, + 0x10, 0xbd, 0xfd, 0xe0, 0x13, 0x5d, 0xb4, 0x39, 0x2c, 0x8e, 0x43, 0x2e, 0x12, 0x15, 0x6d, 0xb2, + 0x4b, 0x12, 0x44, 0x10, 0x9b, 0xa4, 0x4b, 0xa1, 0x60, 0x4a, 0x11, 0xc2, 0xde, 0xde, 0x72, 0x59, + 0x48, 0x76, 0x2e, 0xb7, 0x7b, 0x91, 0xf8, 0x0b, 0x2c, 0xfd, 0x09, 0xf9, 0x1f, 0xd6, 0x82, 0x65, + 0x4a, 0x4b, 0x49, 0x1a, 0x7f, 0x86, 0xdc, 0x6d, 0x48, 0x44, 0x0d, 0xa6, 0xb0, 0x1b, 0x66, 0xde, + 0x9b, 0xf7, 0x76, 0xf6, 0xe1, 0xba, 0x0c, 0x39, 0x65, 0x49, 0xd2, 0x93, 0x9c, 0x19, 0x09, 0x4a, + 0x53, 0xa9, 0x8c, 0x48, 0x79, 0x97, 0x49, 0xd5, 0x61, 0x9c, 0x43, 0xa6, 0x8c, 0xa6, 0xc3, 0x2a, + 0x1d, 0x64, 0x22, 0x1d, 0x91, 0x24, 0x05, 0x03, 0xee, 0xb1, 0x0c, 0x39, 0xf9, 0x4c, 0x22, 0x3f, + 0x90, 0xc8, 0xb0, 0xea, 0xef, 0xc6, 0x10, 0x43, 0xc1, 0xa1, 0x79, 0x65, 0xe9, 0xfe, 0x5e, 0x0c, + 0x10, 0xf7, 0x04, 0x65, 0x89, 0xa4, 0x4c, 0x29, 0x30, 0xf3, 0x25, 0x76, 0x7a, 0xba, 0xae, 0xa3, + 0x79, 0x6d, 0x69, 0xe5, 0x7b, 0x7c, 0x78, 0x9d, 0x5b, 0x6c, 0x2d, 0xc0, 0x0d, 0x3b, 0x6f, 0x44, + 0x51, 0x2a, 0xb4, 0x6e, 0x8b, 0x41, 0x26, 0xb4, 0x71, 0x0f, 0xf0, 0x0e, 0xdc, 0x29, 0x91, 0x76, + 0x98, 0xed, 0x7b, 0x68, 0x1f, 0x9d, 0x6c, 0xb5, 0xb7, 0x8b, 0xe6, 0x1c, 0x9b, 0x83, 0x38, 0x28, + 0x25, 0x78, 0x6e, 0xa0, 0x23, 0x23, 0xef, 0x9f, 0x05, 0x2d, 0x9b, 0xad, 0xe8, 0x7c, 0xf3, 0x61, + 0x5c, 0x72, 0xde, 0xc7, 0x25, 0xa7, 0x2c, 0xf0, 0xd1, 0x2f, 0xda, 0x3a, 0x01, 0xa5, 0x85, 0x7b, + 0x81, 0xfd, 0xef, 0x8f, 0xf9, 0xe2, 0xc4, 0x93, 0x2b, 0xb6, 0xd4, 0x9e, 0x11, 0xfe, 0x5f, 0xe8, + 0xb8, 0x4f, 0x08, 0x7b, 0xab, 0xc4, 0xdc, 0x4b, 0xb2, 0xe6, 0xf7, 0x90, 0x75, 0x0e, 0xe6, 0x5f, + 0xfd, 0xd5, 0x3a, 0x7b, 0x83, 0xb2, 0xd3, 0xbc, 0x7d, 0x99, 0x06, 0x68, 0x32, 0x0d, 0xd0, 0xdb, + 0x34, 0x40, 0x8f, 0xb3, 0xc0, 0x99, 0xcc, 0x02, 0xe7, 0x75, 0x16, 0x38, 0x37, 0xcd, 0x58, 0x9a, + 0x6e, 0x16, 0x12, 0x0e, 0x7d, 0xca, 0x41, 0xf7, 0x41, 0x53, 0x19, 0xf2, 0x4a, 0x0c, 0xb4, 0x0f, + 0x51, 0xd6, 0x13, 0x3a, 0x0f, 0x86, 0xa6, 0xb5, 0xb3, 0xca, 0xd2, 0x42, 0x65, 0x91, 0x09, 0x33, + 0x4a, 0x84, 0x0e, 0x37, 0x8a, 0x3c, 0xd4, 0x3f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xc1, 0x93, 0x84, + 0xc3, 0xda, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -156,7 +163,8 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type QueryClient interface { - IBCAccount(ctx context.Context, in *QueryIBCAccountRequest, opts ...grpc.CallOption) (*QueryIBCAccountResponse, error) + // Query to get the address of an interchain account + InterchainAccountAddress(ctx context.Context, in *QueryInterchainAccountAddressRequest, opts ...grpc.CallOption) (*QueryInterchainAccountAddressResponse, error) } type queryClient struct { @@ -167,9 +175,9 @@ func NewQueryClient(cc grpc1.ClientConn) QueryClient { return &queryClient{cc} } -func (c *queryClient) IBCAccount(ctx context.Context, in *QueryIBCAccountRequest, opts ...grpc.CallOption) (*QueryIBCAccountResponse, error) { - out := new(QueryIBCAccountResponse) - err := c.cc.Invoke(ctx, "/ibc.account.Query/IBCAccount", in, out, opts...) +func (c *queryClient) InterchainAccountAddress(ctx context.Context, in *QueryInterchainAccountAddressRequest, opts ...grpc.CallOption) (*QueryInterchainAccountAddressResponse, error) { + out := new(QueryInterchainAccountAddressResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.interchain_accounts.v1.Query/InterchainAccountAddress", in, out, opts...) if err != nil { return nil, err } @@ -178,53 +186,54 @@ func (c *queryClient) IBCAccount(ctx context.Context, in *QueryIBCAccountRequest // QueryServer is the server API for Query service. type QueryServer interface { - IBCAccount(context.Context, *QueryIBCAccountRequest) (*QueryIBCAccountResponse, error) + // Query to get the address of an interchain account + InterchainAccountAddress(context.Context, *QueryInterchainAccountAddressRequest) (*QueryInterchainAccountAddressResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. type UnimplementedQueryServer struct { } -func (*UnimplementedQueryServer) IBCAccount(ctx context.Context, req *QueryIBCAccountRequest) (*QueryIBCAccountResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method IBCAccount not implemented") +func (*UnimplementedQueryServer) InterchainAccountAddress(ctx context.Context, req *QueryInterchainAccountAddressRequest) (*QueryInterchainAccountAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method InterchainAccountAddress not implemented") } func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) } -func _Query_IBCAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryIBCAccountRequest) +func _Query_InterchainAccountAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryInterchainAccountAddressRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(QueryServer).IBCAccount(ctx, in) + return srv.(QueryServer).InterchainAccountAddress(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/ibc.account.Query/IBCAccount", + FullMethod: "/ibc.applications.interchain_accounts.v1.Query/InterchainAccountAddress", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).IBCAccount(ctx, req.(*QueryIBCAccountRequest)) + return srv.(QueryServer).InterchainAccountAddress(ctx, req.(*QueryInterchainAccountAddressRequest)) } return interceptor(ctx, in, info, handler) } var _Query_serviceDesc = grpc.ServiceDesc{ - ServiceName: "ibc.account.Query", + ServiceName: "ibc.applications.interchain_accounts.v1.Query", HandlerType: (*QueryServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "IBCAccount", - Handler: _Query_IBCAccount_Handler, + MethodName: "InterchainAccountAddress", + Handler: _Query_InterchainAccountAddress_Handler, }, }, Streams: []grpc.StreamDesc{}, - Metadata: "ibc/account/query.proto", + Metadata: "ibc/applications/interchain_accounts/v1/query.proto", } -func (m *QueryIBCAccountRequest) Marshal() (dAtA []byte, err error) { +func (m *QueryInterchainAccountAddressRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -234,12 +243,12 @@ func (m *QueryIBCAccountRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryIBCAccountRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryInterchainAccountAddressRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryIBCAccountRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryInterchainAccountAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -251,17 +260,17 @@ func (m *QueryIBCAccountRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) i-- dAtA[i] = 0x12 } - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + if len(m.OwnerAddress) > 0 { + i -= len(m.OwnerAddress) + copy(dAtA[i:], m.OwnerAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.OwnerAddress))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *QueryIBCAccountResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryInterchainAccountAddressResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -271,20 +280,20 @@ func (m *QueryIBCAccountResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryIBCAccountResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryInterchainAccountAddressResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryIBCAccountResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryInterchainAccountAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.AccountAddress) > 0 { - i -= len(m.AccountAddress) - copy(dAtA[i:], m.AccountAddress) - i = encodeVarintQuery(dAtA, i, uint64(len(m.AccountAddress))) + if len(m.InterchainAccountAddress) > 0 { + i -= len(m.InterchainAccountAddress) + copy(dAtA[i:], m.InterchainAccountAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.InterchainAccountAddress))) i-- dAtA[i] = 0xa } @@ -302,13 +311,13 @@ func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *QueryIBCAccountRequest) Size() (n int) { +func (m *QueryInterchainAccountAddressRequest) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.Address) + l = len(m.OwnerAddress) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } @@ -319,13 +328,13 @@ func (m *QueryIBCAccountRequest) Size() (n int) { return n } -func (m *QueryIBCAccountResponse) Size() (n int) { +func (m *QueryInterchainAccountAddressResponse) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.AccountAddress) + l = len(m.InterchainAccountAddress) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } @@ -338,7 +347,7 @@ func sovQuery(x uint64) (n int) { func sozQuery(x uint64) (n int) { return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *QueryIBCAccountRequest) Unmarshal(dAtA []byte) error { +func (m *QueryInterchainAccountAddressRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -361,15 +370,15 @@ func (m *QueryIBCAccountRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryIBCAccountRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QueryInterchainAccountAddressRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryIBCAccountRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryInterchainAccountAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field OwnerAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -397,7 +406,7 @@ func (m *QueryIBCAccountRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Address = string(dAtA[iNdEx:postIndex]) + m.OwnerAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -452,7 +461,7 @@ func (m *QueryIBCAccountRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryIBCAccountResponse) Unmarshal(dAtA []byte) error { +func (m *QueryInterchainAccountAddressResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -475,15 +484,15 @@ func (m *QueryIBCAccountResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryIBCAccountResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryInterchainAccountAddressResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryIBCAccountResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryInterchainAccountAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AccountAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field InterchainAccountAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -511,7 +520,7 @@ func (m *QueryIBCAccountResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.AccountAddress = string(dAtA[iNdEx:postIndex]) + m.InterchainAccountAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/modules/apps/27-interchain-accounts/types/types.pb.go b/modules/apps/27-interchain-accounts/types/types.pb.go index d2eaf2455d8..62324b0be0a 100644 --- a/modules/apps/27-interchain-accounts/types/types.pb.go +++ b/modules/apps/27-interchain-accounts/types/types.pb.go @@ -1,11 +1,12 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: ibc/account/types.proto +// source: ibc/applications/interchain_accounts/v1/types.proto package types import ( fmt "fmt" types "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" math "math" @@ -23,21 +24,22 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// The different types of interchain account transactions +// EXECUTE_TX is used when sending a TX from the controller side to the host side. The host side will execute the tx on +// behalf of the interchain account. type Type int32 const ( - Type_REGISTER Type = 0 - Type_RUNTX Type = 1 + // Execute message type + EXECUTE_TX Type = 0 ) var Type_name = map[int32]string{ - 0: "REGISTER", - 1: "RUNTX", + 0: "TYPE_EXECUTE_TX_UNSPECIFIED", } var Type_value = map[string]int32{ - "REGISTER": 0, - "RUNTX": 1, + "TYPE_EXECUTE_TX_UNSPECIFIED": 0, } func (x Type) String() string { @@ -45,18 +47,19 @@ func (x Type) String() string { } func (Type) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_0902a1528b05ff0d, []int{0} + return fileDescriptor_39bab93e18d89799, []int{0} } +// Raw tx body type IBCTxRaw struct { - BodyBytes []byte `protobuf:"bytes,1,opt,name=body_bytes,json=bodyBytes,proto3" json:"body_bytes,omitempty"` + BodyBytes []byte `protobuf:"bytes,1,opt,name=body_bytes,json=bodyBytes,proto3" json:"body_bytes,omitempty" yaml:"body_bytes"` } func (m *IBCTxRaw) Reset() { *m = IBCTxRaw{} } func (m *IBCTxRaw) String() string { return proto.CompactTextString(m) } func (*IBCTxRaw) ProtoMessage() {} func (*IBCTxRaw) Descriptor() ([]byte, []int) { - return fileDescriptor_0902a1528b05ff0d, []int{0} + return fileDescriptor_39bab93e18d89799, []int{0} } func (m *IBCTxRaw) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -92,6 +95,7 @@ func (m *IBCTxRaw) GetBodyBytes() []byte { return nil } +// Body of a tx for an ics27 IBC packet type IBCTxBody struct { Messages []*types.Any `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` } @@ -100,7 +104,7 @@ func (m *IBCTxBody) Reset() { *m = IBCTxBody{} } func (m *IBCTxBody) String() string { return proto.CompactTextString(m) } func (*IBCTxBody) ProtoMessage() {} func (*IBCTxBody) Descriptor() ([]byte, []int) { - return fileDescriptor_0902a1528b05ff0d, []int{1} + return fileDescriptor_39bab93e18d89799, []int{1} } func (m *IBCTxBody) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -136,8 +140,9 @@ func (m *IBCTxBody) GetMessages() []*types.Any { return nil } +// Packet data is comprised of raw transaction & type of transaction type IBCAccountPacketData struct { - Type Type `protobuf:"varint,1,opt,name=type,proto3,enum=ibc.account.Type" json:"type,omitempty"` + Type Type `protobuf:"varint,1,opt,name=type,proto3,enum=ibc.applications.interchain_accounts.v1.Type" json:"type,omitempty"` Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` } @@ -145,7 +150,7 @@ func (m *IBCAccountPacketData) Reset() { *m = IBCAccountPacketData{} } func (m *IBCAccountPacketData) String() string { return proto.CompactTextString(m) } func (*IBCAccountPacketData) ProtoMessage() {} func (*IBCAccountPacketData) Descriptor() ([]byte, []int) { - return fileDescriptor_0902a1528b05ff0d, []int{2} + return fileDescriptor_39bab93e18d89799, []int{2} } func (m *IBCAccountPacketData) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -178,7 +183,7 @@ func (m *IBCAccountPacketData) GetType() Type { if m != nil { return m.Type } - return Type_REGISTER + return EXECUTE_TX } func (m *IBCAccountPacketData) GetData() []byte { @@ -188,84 +193,45 @@ func (m *IBCAccountPacketData) GetData() []byte { return nil } -type AccountAddress struct { - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` -} - -func (m *AccountAddress) Reset() { *m = AccountAddress{} } -func (m *AccountAddress) String() string { return proto.CompactTextString(m) } -func (*AccountAddress) ProtoMessage() {} -func (*AccountAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_0902a1528b05ff0d, []int{3} -} -func (m *AccountAddress) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *AccountAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_AccountAddress.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *AccountAddress) XXX_Merge(src proto.Message) { - xxx_messageInfo_AccountAddress.Merge(m, src) -} -func (m *AccountAddress) XXX_Size() int { - return m.Size() -} -func (m *AccountAddress) XXX_DiscardUnknown() { - xxx_messageInfo_AccountAddress.DiscardUnknown(m) -} - -var xxx_messageInfo_AccountAddress proto.InternalMessageInfo - -func (m *AccountAddress) GetAddress() string { - if m != nil { - return m.Address - } - return "" +func init() { + proto.RegisterEnum("ibc.applications.interchain_accounts.v1.Type", Type_name, Type_value) + proto.RegisterType((*IBCTxRaw)(nil), "ibc.applications.interchain_accounts.v1.IBCTxRaw") + proto.RegisterType((*IBCTxBody)(nil), "ibc.applications.interchain_accounts.v1.IBCTxBody") + proto.RegisterType((*IBCAccountPacketData)(nil), "ibc.applications.interchain_accounts.v1.IBCAccountPacketData") } func init() { - proto.RegisterEnum("ibc.account.Type", Type_name, Type_value) - proto.RegisterType((*IBCTxRaw)(nil), "ibc.account.IBCTxRaw") - proto.RegisterType((*IBCTxBody)(nil), "ibc.account.IBCTxBody") - proto.RegisterType((*IBCAccountPacketData)(nil), "ibc.account.IBCAccountPacketData") - proto.RegisterType((*AccountAddress)(nil), "ibc.account.AccountAddress") -} - -func init() { proto.RegisterFile("ibc/account/types.proto", fileDescriptor_0902a1528b05ff0d) } - -var fileDescriptor_0902a1528b05ff0d = []byte{ - // 340 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x91, 0xc1, 0x4a, 0x2b, 0x31, - 0x18, 0x85, 0x67, 0xee, 0xed, 0xbd, 0xb7, 0x93, 0x96, 0xd2, 0x1b, 0x0a, 0x56, 0xc1, 0x51, 0x06, - 0x84, 0x5a, 0x68, 0x22, 0x75, 0xe5, 0xc2, 0x45, 0xa7, 0x16, 0xe9, 0x46, 0x34, 0x1d, 0x41, 0xdc, - 0x48, 0x92, 0x89, 0xd3, 0x41, 0x3b, 0x29, 0x4d, 0x8a, 0xcd, 0x5b, 0xf8, 0x58, 0x2e, 0xbb, 0x74, - 0x29, 0xed, 0x8b, 0xc8, 0x64, 0x5a, 0xd1, 0xdd, 0x9f, 0xff, 0x1c, 0xce, 0xf9, 0xc8, 0x0f, 0x76, - 0x52, 0xc6, 0x31, 0xe5, 0x5c, 0xce, 0x33, 0x8d, 0xb5, 0x99, 0x0a, 0x85, 0xa6, 0x33, 0xa9, 0x25, - 0xac, 0xa4, 0x8c, 0xa3, 0x8d, 0xb0, 0xb7, 0x9b, 0x48, 0x99, 0x3c, 0x0b, 0x6c, 0x25, 0x36, 0x7f, - 0xc4, 0x34, 0x33, 0x85, 0x2f, 0x38, 0x06, 0xe5, 0x61, 0xd8, 0x8f, 0x16, 0x84, 0xbe, 0xc0, 0x7d, - 0x00, 0x98, 0x8c, 0xcd, 0x03, 0x33, 0x5a, 0xa8, 0xa6, 0x7b, 0xe8, 0xb6, 0xaa, 0xc4, 0xcb, 0x37, - 0x61, 0xbe, 0x08, 0xce, 0x81, 0x67, 0xad, 0xa1, 0x8c, 0x0d, 0x3c, 0x01, 0xe5, 0x89, 0x50, 0x8a, - 0x26, 0xd6, 0xf9, 0xbb, 0x55, 0xe9, 0x36, 0x50, 0xd1, 0x82, 0xb6, 0x2d, 0xa8, 0x97, 0x19, 0xf2, - 0xe5, 0x0a, 0x6e, 0x40, 0x63, 0x18, 0xf6, 0x7b, 0x05, 0xd2, 0x35, 0xe5, 0x4f, 0x42, 0x5f, 0x50, - 0x4d, 0xe1, 0x11, 0x28, 0xe5, 0xe0, 0xb6, 0xaf, 0xd6, 0xfd, 0x8f, 0xbe, 0x81, 0xa3, 0xc8, 0x4c, - 0x05, 0xb1, 0x32, 0x84, 0xa0, 0x14, 0x53, 0x4d, 0x9b, 0xbf, 0x2c, 0x96, 0x9d, 0x83, 0x36, 0xa8, - 0x6d, 0xf2, 0x7a, 0x71, 0x3c, 0x13, 0x4a, 0xc1, 0x26, 0xf8, 0x47, 0x8b, 0xd1, 0xe6, 0x79, 0x64, - 0xfb, 0x6c, 0x1f, 0x80, 0x52, 0x9e, 0x06, 0xab, 0xa0, 0x4c, 0x06, 0x97, 0xc3, 0x51, 0x34, 0x20, - 0x75, 0x07, 0x7a, 0xe0, 0x0f, 0xb9, 0xbd, 0x8a, 0xee, 0xea, 0x6e, 0x38, 0x7a, 0x5b, 0xf9, 0xee, - 0x72, 0xe5, 0xbb, 0x1f, 0x2b, 0xdf, 0x7d, 0x5d, 0xfb, 0xce, 0x72, 0xed, 0x3b, 0xef, 0x6b, 0xdf, - 0xb9, 0x3f, 0x4b, 0x52, 0x3d, 0x9e, 0x33, 0xc4, 0xe5, 0x04, 0x73, 0xa9, 0x26, 0x52, 0xe1, 0x34, - 0xd3, 0x62, 0xc6, 0xc7, 0x34, 0xcd, 0x3a, 0x1b, 0x56, 0x85, 0x17, 0x38, 0x65, 0xbc, 0xf3, 0xe3, - 0x18, 0xec, 0xaf, 0xfd, 0x8c, 0xd3, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x92, 0xef, 0xa7, 0x30, - 0xa8, 0x01, 0x00, 0x00, + proto.RegisterFile("ibc/applications/interchain_accounts/v1/types.proto", fileDescriptor_39bab93e18d89799) +} + +var fileDescriptor_39bab93e18d89799 = []byte{ + // 405 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x51, 0x41, 0x6b, 0xd4, 0x40, + 0x18, 0x4d, 0x34, 0x48, 0x3b, 0x4a, 0xd1, 0xb0, 0x42, 0x8d, 0x10, 0x4b, 0x2e, 0x16, 0x21, 0x33, + 0x76, 0x2b, 0x08, 0x42, 0xc1, 0x4d, 0x1a, 0x21, 0x17, 0x59, 0x62, 0x0a, 0x55, 0x84, 0x30, 0x33, + 0x19, 0xd3, 0xc1, 0x24, 0x13, 0x3a, 0x93, 0xd5, 0xf9, 0x07, 0xe2, 0xc9, 0x3f, 0xe0, 0xc9, 0x3f, + 0xe3, 0x71, 0x8f, 0x9e, 0x44, 0x76, 0xff, 0x81, 0xbf, 0x40, 0x32, 0xc1, 0x5d, 0x0f, 0x1e, 0x7a, + 0x7b, 0x33, 0xdf, 0xf7, 0x1e, 0xef, 0x7b, 0x0f, 0x1c, 0x73, 0x42, 0x11, 0xee, 0xba, 0x9a, 0x53, + 0xac, 0xb8, 0x68, 0x25, 0xe2, 0xad, 0x62, 0x97, 0xf4, 0x02, 0xf3, 0xb6, 0xc0, 0x94, 0x8a, 0xbe, + 0x55, 0x12, 0x2d, 0x8e, 0x90, 0xd2, 0x1d, 0x93, 0xb0, 0xbb, 0x14, 0x4a, 0xb8, 0x0f, 0x39, 0xa1, + 0xf0, 0x5f, 0x12, 0xfc, 0x0f, 0x09, 0x2e, 0x8e, 0xbc, 0x7b, 0x95, 0x10, 0x55, 0xcd, 0x90, 0xa1, + 0x91, 0xfe, 0x1d, 0xc2, 0xad, 0x1e, 0x35, 0xbc, 0x49, 0x25, 0x2a, 0x61, 0x20, 0x1a, 0xd0, 0xf8, + 0x1b, 0x3c, 0x07, 0x3b, 0x69, 0x14, 0xe7, 0x1f, 0x33, 0xfc, 0xc1, 0x7d, 0x02, 0x00, 0x11, 0xa5, + 0x2e, 0x88, 0x56, 0x4c, 0xee, 0xdb, 0x07, 0xf6, 0xe1, 0xad, 0xe8, 0xee, 0xef, 0x9f, 0x0f, 0xee, + 0x68, 0xdc, 0xd4, 0xcf, 0x82, 0xed, 0x2c, 0xc8, 0x76, 0x87, 0x47, 0x64, 0xf0, 0x09, 0xd8, 0x35, + 0x0a, 0x91, 0x28, 0xb5, 0xfb, 0x18, 0xec, 0x34, 0x4c, 0x4a, 0x5c, 0x19, 0x81, 0xeb, 0x87, 0x37, + 0xa7, 0x13, 0x38, 0x5a, 0x82, 0x7f, 0x2d, 0xc1, 0x59, 0xab, 0xb3, 0xcd, 0x56, 0xd0, 0x80, 0x49, + 0x1a, 0xc5, 0xb3, 0xf1, 0x86, 0x39, 0xa6, 0xef, 0x99, 0x3a, 0xc5, 0x0a, 0xbb, 0x33, 0xe0, 0x0c, + 0x09, 0x18, 0x1b, 0x7b, 0xd3, 0x10, 0x5e, 0x31, 0x01, 0x98, 0xeb, 0x8e, 0x65, 0x86, 0xea, 0xba, + 0xc0, 0x29, 0xb1, 0xc2, 0xfb, 0xd7, 0x86, 0x4b, 0x32, 0x83, 0x1f, 0x9d, 0x00, 0x67, 0xd8, 0x70, + 0x11, 0xb8, 0x9f, 0xbf, 0x9e, 0x27, 0x45, 0x72, 0x9e, 0xc4, 0x67, 0x79, 0x52, 0xe4, 0xe7, 0xc5, + 0xd9, 0xcb, 0x57, 0xf3, 0x24, 0x4e, 0x5f, 0xa4, 0xc9, 0xe9, 0x6d, 0xcb, 0xdb, 0xfb, 0xfc, 0xf5, + 0x00, 0x6c, 0xa7, 0x9e, 0xf3, 0xe9, 0x9b, 0x6f, 0x45, 0x6f, 0xbf, 0xaf, 0x7c, 0x7b, 0xb9, 0xf2, + 0xed, 0x5f, 0x2b, 0xdf, 0xfe, 0xb2, 0xf6, 0xad, 0xe5, 0xda, 0xb7, 0x7e, 0xac, 0x7d, 0xeb, 0x4d, + 0x54, 0x71, 0x75, 0xd1, 0x13, 0x48, 0x45, 0x83, 0xa8, 0x90, 0x8d, 0x90, 0x88, 0x13, 0x1a, 0x56, + 0x02, 0x35, 0xa2, 0xec, 0x6b, 0x26, 0x87, 0xd2, 0x25, 0x9a, 0x3e, 0x0d, 0xb7, 0xc6, 0xc3, 0x4d, + 0xdf, 0xa6, 0x6c, 0x72, 0xc3, 0x64, 0x74, 0xfc, 0x27, 0x00, 0x00, 0xff, 0xff, 0x70, 0xa3, 0x00, + 0x15, 0x24, 0x02, 0x00, 0x00, } func (m *IBCTxRaw) Marshal() (dAtA []byte, err error) { @@ -370,36 +336,6 @@ func (m *IBCAccountPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *AccountAddress) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *AccountAddress) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *AccountAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintTypes(dAtA, i, uint64(len(m.Address))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { offset -= sovTypes(v) base := offset @@ -455,19 +391,6 @@ func (m *IBCAccountPacketData) Size() (n int) { return n } -func (m *AccountAddress) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Address) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - return n -} - func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -745,88 +668,6 @@ func (m *IBCAccountPacketData) Unmarshal(dAtA []byte) error { } return nil } -func (m *AccountAddress) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: AccountAddress: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: AccountAddress: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Address = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/proto/ibc/applications/interchain_accounts/v1/account.proto b/proto/ibc/applications/interchain_accounts/v1/account.proto new file mode 100644 index 00000000000..b63aec16133 --- /dev/null +++ b/proto/ibc/applications/interchain_accounts/v1/account.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package ibc.applications.interchain_accounts.v1; + +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; +import "cosmos/auth/v1beta1/auth.proto"; + +option go_package = "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"; + +// An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain +message InterchainAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + option (cosmos_proto.implements_interface) = "InterchainAccountI"; + + cosmos.auth.v1beta1.BaseAccount base_account = 1 + [(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"base_account\""]; + string account_owner = 2 [(gogoproto.moretags) = "yaml:\"account_owner\""]; +} diff --git a/proto/ibc/applications/interchain_accounts/v1/genesis.proto b/proto/ibc/applications/interchain_accounts/v1/genesis.proto new file mode 100644 index 00000000000..3afb804eb69 --- /dev/null +++ b/proto/ibc/applications/interchain_accounts/v1/genesis.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; +package ibc.applications.interchain_accounts.v1; + +option go_package = "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"; + +import "gogoproto/gogo.proto"; + +// GenesisState defines the interchain_account genesis state +message GenesisState { + string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; +} diff --git a/proto/ibc/applications/interchain_accounts/v1/query.proto b/proto/ibc/applications/interchain_accounts/v1/query.proto new file mode 100644 index 00000000000..1787614df32 --- /dev/null +++ b/proto/ibc/applications/interchain_accounts/v1/query.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; +package ibc.applications.interchain_accounts.v1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "ibc/applications/interchain_accounts/v1/account.proto"; + +option go_package = "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"; + +// Query defines the gRPC querier service. +service Query { + // Query to get the address of an interchain account + rpc InterchainAccountAddress(QueryInterchainAccountAddressRequest) returns (QueryInterchainAccountAddressResponse) {} +} + +// Query request for an interchain account address +message QueryInterchainAccountAddressRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // Owner address is the owner of the interchain account on the controller chain + string owner_address = 1; + string connection_id = 2; +} + +// Query response for an interchain account address +message QueryInterchainAccountAddressResponse { + // The corresponding interchain account address on the host chain + string interchain_account_address = 1; +} diff --git a/proto/ibc/applications/interchain_accounts/v1/types.proto b/proto/ibc/applications/interchain_accounts/v1/types.proto new file mode 100644 index 00000000000..dc817a44963 --- /dev/null +++ b/proto/ibc/applications/interchain_accounts/v1/types.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; +package ibc.applications.interchain_accounts.v1; + +import "google/protobuf/any.proto"; +import "gogoproto/gogo.proto"; +option go_package = "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"; + +// Raw tx body +message IBCTxRaw { + bytes body_bytes = 1 [(gogoproto.moretags) = "yaml:\"body_bytes\""]; +} + +// Body of a tx for an ics27 IBC packet +message IBCTxBody { + repeated google.protobuf.Any messages = 1; +} + +// The different types of interchain account transactions +// EXECUTE_TX is used when sending a TX from the controller side to the host side. The host side will execute the tx on +// behalf of the interchain account. +enum Type { + option (gogoproto.goproto_enum_prefix) = false; + // Execute message type + TYPE_EXECUTE_TX_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "EXECUTE_TX"]; +} + +// Packet data is comprised of raw transaction & type of transaction +message IBCAccountPacketData { + Type type = 1; + bytes data = 2; +} diff --git a/third_party/proto/cosmos/auth/v1beta1/auth.proto b/third_party/proto/cosmos/auth/v1beta1/auth.proto new file mode 100644 index 00000000000..79071456f6e --- /dev/null +++ b/third_party/proto/cosmos/auth/v1beta1/auth.proto @@ -0,0 +1,51 @@ +syntax = "proto3"; +package cosmos.auth.v1beta1; + +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/auth/types"; + +// BaseAccount defines a base account type. It contains all the necessary fields +// for basic account functionality. Any custom account type should extend this +// type for additional functionality (e.g. vesting). +message BaseAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + option (gogoproto.equal) = false; + + option (cosmos_proto.implements_interface) = "AccountI"; + + string address = 1; + google.protobuf.Any pub_key = 2 + [(gogoproto.jsontag) = "public_key,omitempty", (gogoproto.moretags) = "yaml:\"public_key\""]; + uint64 account_number = 3 [(gogoproto.moretags) = "yaml:\"account_number\""]; + uint64 sequence = 4; +} + +// ModuleAccount defines an account for modules that holds coins on a pool. +message ModuleAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + option (cosmos_proto.implements_interface) = "ModuleAccountI"; + + BaseAccount base_account = 1 [(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"base_account\""]; + string name = 2; + repeated string permissions = 3; +} + +// Params defines the parameters for the auth module. +message Params { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = false; + + uint64 max_memo_characters = 1 [(gogoproto.moretags) = "yaml:\"max_memo_characters\""]; + uint64 tx_sig_limit = 2 [(gogoproto.moretags) = "yaml:\"tx_sig_limit\""]; + uint64 tx_size_cost_per_byte = 3 [(gogoproto.moretags) = "yaml:\"tx_size_cost_per_byte\""]; + uint64 sig_verify_cost_ed25519 = 4 + [(gogoproto.customname) = "SigVerifyCostED25519", (gogoproto.moretags) = "yaml:\"sig_verify_cost_ed25519\""]; + uint64 sig_verify_cost_secp256k1 = 5 + [(gogoproto.customname) = "SigVerifyCostSecp256k1", (gogoproto.moretags) = "yaml:\"sig_verify_cost_secp256k1\""]; +} + diff --git a/third_party/proto/cosmos/auth/v1beta1/genesis.proto b/third_party/proto/cosmos/auth/v1beta1/genesis.proto new file mode 100644 index 00000000000..5d6823e6b35 --- /dev/null +++ b/third_party/proto/cosmos/auth/v1beta1/genesis.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; +package cosmos.auth.v1beta1; + +import "google/protobuf/any.proto"; +import "gogoproto/gogo.proto"; +import "cosmos/auth/v1beta1/auth.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/auth/types"; + +// GenesisState defines the auth module's genesis state. +message GenesisState { + // params defines all the paramaters of the module. + Params params = 1 [(gogoproto.nullable) = false]; + + // accounts are the accounts present at genesis. + repeated google.protobuf.Any accounts = 2; +} + diff --git a/third_party/proto/cosmos/auth/v1beta1/query.proto b/third_party/proto/cosmos/auth/v1beta1/query.proto new file mode 100644 index 00000000000..2c438c7b5ed --- /dev/null +++ b/third_party/proto/cosmos/auth/v1beta1/query.proto @@ -0,0 +1,48 @@ +syntax = "proto3"; +package cosmos.auth.v1beta1; + +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; +import "google/api/annotations.proto"; +import "cosmos/auth/v1beta1/auth.proto"; +import "cosmos_proto/cosmos.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/auth/types"; + +// Query defines the gRPC querier service. +service Query { + // Account returns account details based on address. + rpc Account(QueryAccountRequest) returns (QueryAccountResponse) { + option (google.api.http).get = "/cosmos/auth/v1beta1/accounts/{address}"; + } + + // Params queries all parameters. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/cosmos/auth/v1beta1/params"; + } +} + +// QueryAccountRequest is the request type for the Query/Account RPC method. +message QueryAccountRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // address defines the address to query for. + string address = 1; +} + +// QueryAccountResponse is the response type for the Query/Account RPC method. +message QueryAccountResponse { + // account defines the account of the corresponding address. + google.protobuf.Any account = 1 [(cosmos_proto.accepts_interface) = "AccountI"]; +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params defines the parameters of the module. + Params params = 1 [(gogoproto.nullable) = false]; +} + diff --git a/third_party/proto/cosmos_proto/cosmos.proto b/third_party/proto/cosmos_proto/cosmos.proto new file mode 100644 index 00000000000..167b170757b --- /dev/null +++ b/third_party/proto/cosmos_proto/cosmos.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; +package cosmos_proto; + +import "google/protobuf/descriptor.proto"; + +option go_package = "github.com/regen-network/cosmos-proto"; + +extend google.protobuf.MessageOptions { + string interface_type = 93001; + + string implements_interface = 93002; +} + +extend google.protobuf.FieldOptions { + string accepts_interface = 93001; +} From 2a160ed1edaf1a9aac3552b58068c678d8a85a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 5 Aug 2021 12:11:23 +0200 Subject: [PATCH 07/66] ICA OnChanOpenTry update + tests (#299) * update OnChanOpenTry to match ICS specs * write OnChanOpenTry and OnChanOpenAck tests * update comment --- .../27-interchain-accounts/keeper/account.go | 7 +- .../keeper/handshake.go | 27 ++-- .../keeper/handshake_test.go | 134 ++++++++++++++++++ .../27-interchain-accounts/keeper/keeper.go | 5 + .../keeper/keeper_test.go | 24 ++++ .../27-interchain-accounts/types/errors.go | 19 +-- 6 files changed, 193 insertions(+), 23 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index 6bad42a1133..99bc84ce9c9 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -41,12 +41,13 @@ func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionId, owner strin } // Register interchain account if it has not already been created -func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portId string) (types.InterchainAccountI, error) { +func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portId string) { address := k.GenerateAddress(portId) account := k.accountKeeper.GetAccount(ctx, address) if account != nil { - return nil, sdkerrors.Wrap(types.ErrAccountAlreadyExist, account.String()) + // account already created, return no-op + return } interchainAccount := types.NewInterchainAccount( @@ -57,7 +58,7 @@ func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portId string) (types k.accountKeeper.SetAccount(ctx, interchainAccount) _ = k.SetInterchainAccountAddress(ctx, portId, interchainAccount.Address) - return interchainAccount, nil + return } func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portId string, address string) string { diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index 6a8bafe57cb..43a95088f37 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -18,6 +18,8 @@ import ( // there must not be an active channel for the specfied port identifier, // and the interchain accounts module must be able to claim the channel // capability. +// +// Controller Chain func (k Keeper) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, @@ -50,9 +52,10 @@ func (k Keeper) OnChanOpenInit( return nil } -// register account (if it doesn't exist) -// check if counterpary version is the same -// TODO: remove ics27-1 hardcoded +// OnChanOpenTry performs basic validation of the ICA channel +// and registers a new interchain account (if it doesn't exist). +// +// Host Chain func (k Keeper) OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, @@ -67,19 +70,21 @@ func (k Keeper) OnChanOpenTry( if order != channeltypes.ORDERED { return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "invalid channel ordering: %s, expected %s", order.String(), channeltypes.ORDERED.String()) } + if version != types.Version { + return sdkerrors.Wrapf(types.ErrInvalidVersion, "got: %s, expected %s", version, types.Version) + } + if counterpartyVersion != types.Version { + return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) + } - // TODO: Check counterparty version - // if counterpartyVersion != types.Version { - // return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid counterparty version: %s, expected %s", counterpartyVersion, "ics20-1") - // } - - // Claim channel capability passed back by IBC module + // On the host chain the capability may only be claimed during the OnChanOpenTry + // The capability being claimed in OpenInit is for a controller chain (the port is different) if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, err.Error()) + return err } // Register interchain account if it does not already exist - _, _ = k.RegisterInterchainAccount(ctx, counterparty.PortId) + k.RegisterInterchainAccount(ctx, counterparty.PortId) return nil } diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index 7ac2b6ac0d0..ef689f12f2c 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -96,3 +96,137 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { }) } } + +// ChainA is controller, ChainB is host chain +func (suite *KeeperTestSuite) TestOnChanOpenTry() { + var ( + channel *channeltypes.Channel + path *ibctesting.Path + chanCap *capabilitytypes.Capability + counterpartyVersion string + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + { + "invalid order - UNORDERED", func() { + channel.Ordering = channeltypes.UNORDERED + }, false, + }, + { + "invalid version", func() { + channel.Version = "version" + }, false, + }, + { + "invalid counterparty version", func() { + counterpartyVersion = "version" + }, false, + }, + { + "capability already claimed", func() { + err := suite.chainB.GetSimApp().ScopedICAKeeper.ClaimCapability(suite.chainB.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) + suite.Require().NoError(err) + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path = NewICAPath(suite.chainA, suite.chainB) + owner := "owner" + counterpartyVersion = types.Version + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, owner) + suite.Require().NoError(err) + + // default values + counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channel = &channeltypes.Channel{ + State: channeltypes.TRYOPEN, + Ordering: channeltypes.ORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointB.ConnectionID}, + Version: types.Version, + } + + chanCap, err = suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) + suite.Require().NoError(err) + + tc.malleate() // explicitly change fields in channel and testChannel + + err = suite.chainB.GetSimApp().ICAKeeper.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.GetConnectionHops(), + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), + counterpartyVersion, + ) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } +} + +// ChainA is controller, ChainB is host chain +func (suite *KeeperTestSuite) TestOnChanOpenAck() { + var ( + path *ibctesting.Path + counterpartyVersion string + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path = NewICAPath(suite.chainA, suite.chainB) + owner := "owner" + counterpartyVersion = types.Version + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, owner) + suite.Require().NoError(err) + + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + + tc.malleate() // explicitly change fields in channel and testChannel + + err = suite.chainA.GetSimApp().ICAKeeper.OnChanOpenAck(suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyVersion, + ) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } +} diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index e8459b7cf85..781a144f6a0 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -161,3 +161,8 @@ func (k Keeper) IsActiveChannel(ctx sdk.Context, portId string) bool { _, found := k.GetActiveChannel(ctx, portId) return found } + +// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function +func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { + return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) +} diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index 0e53d0d9b5f..a0819dcdf09 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/testing" ) @@ -31,10 +32,33 @@ func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { path := ibctesting.NewPath(chainA, chainB) path.EndpointA.ChannelConfig.PortID = types.PortID path.EndpointB.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointA.ChannelConfig.Version = types.Version + path.EndpointB.ChannelConfig.Version = types.Version return path } +// InitInterchainAccount is a helper function for starting the channel handshake +func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { + portID := endpoint.Chain.GetSimApp().ICAKeeper.GeneratePortId(owner, endpoint.ConnectionID) + channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) + + if err := endpoint.Chain.GetSimApp().ICAKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil { + return err + } + + // commit state changes for proof verification + endpoint.Chain.App.Commit() + endpoint.Chain.NextBlock() + + // update port/channel ids + endpoint.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + endpoint.ChannelConfig.PortID = portID + return nil +} + func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } diff --git a/modules/apps/27-interchain-accounts/types/errors.go b/modules/apps/27-interchain-accounts/types/errors.go index f05d8bc0a3d..40578c46cee 100644 --- a/modules/apps/27-interchain-accounts/types/errors.go +++ b/modules/apps/27-interchain-accounts/types/errors.go @@ -5,13 +5,14 @@ import ( ) var ( - ErrUnknownPacketData = sdkerrors.Register(ModuleName, 1, "Unknown packet data") - ErrAccountAlreadyExist = sdkerrors.Register(ModuleName, 2, "Account already exist") - ErrPortAlreadyBound = sdkerrors.Register(ModuleName, 3, "Port is already bound for address") - ErrUnsupportedChain = sdkerrors.Register(ModuleName, 4, "Unsupported chain") - ErrInvalidOutgoingData = sdkerrors.Register(ModuleName, 5, "Invalid outgoing data") - ErrInvalidRoute = sdkerrors.Register(ModuleName, 6, "Invalid route") - ErrInterchainAccountNotFound = sdkerrors.Register(ModuleName, 7, "Interchain account not found") - ErrInterchainAccountAlreadySet = sdkerrors.Register(ModuleName, 8, "Interchain Account is already set") - ErrActiveChannelNotFound = sdkerrors.Register(ModuleName, 9, "No active channel for this owner") + ErrUnknownPacketData = sdkerrors.Register(ModuleName, 2, "unknown packet data") + ErrAccountAlreadyExist = sdkerrors.Register(ModuleName, 3, "account already exist") + ErrPortAlreadyBound = sdkerrors.Register(ModuleName, 4, "port is already bound for address") + ErrUnsupportedChain = sdkerrors.Register(ModuleName, 5, "unsupported chain") + ErrInvalidOutgoingData = sdkerrors.Register(ModuleName, 6, "invalid outgoing data") + ErrInvalidRoute = sdkerrors.Register(ModuleName, 7, "invalid route") + ErrInterchainAccountNotFound = sdkerrors.Register(ModuleName, 8, "Interchain Account not found") + ErrInterchainAccountAlreadySet = sdkerrors.Register(ModuleName, 9, "Interchain Account is already set") + ErrActiveChannelNotFound = sdkerrors.Register(ModuleName, 10, "no active channel for this owner") + ErrInvalidVersion = sdkerrors.Register(ModuleName, 11, "invalid interchain accounts version") ) From 38ebbff9543c89fd42a330ff5ca4956fdc98656f Mon Sep 17 00:00:00 2001 From: Sean King Date: Thu, 5 Aug 2021 17:09:39 +0200 Subject: [PATCH 08/66] test: adding test for OnChanOpenConfirm (#312) --- .../keeper/handshake_test.go | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index ef689f12f2c..4b8a6f005fb 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -230,3 +230,53 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { }) } } + +// ChainA is controller, ChainB is host chain +func (suite *KeeperTestSuite) TestOnChanOpenConfirm() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path = NewICAPath(suite.chainA, suite.chainB) + owner := "owner" + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, owner) + suite.Require().NoError(err) + + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanOpenAck() + suite.Require().NoError(err) + + tc.malleate() // explicitly change fields in channel and testChannel + + err = suite.chainB.GetSimApp().ICAKeeper.OnChanOpenConfirm(suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } +} From 881276fd33725a75ea1fb9af36c187b8c6ea4e87 Mon Sep 17 00:00:00 2001 From: Sean King Date: Mon, 9 Aug 2021 11:42:11 +0200 Subject: [PATCH 09/66] fix: updating port-id & fixing OnChanOpenInit bug (#321) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: updating port-id & fixing OnChanOpenInit bug * Update modules/apps/27-interchain-accounts/keeper/handshake.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- modules/apps/27-interchain-accounts/keeper/handshake.go | 5 +++-- modules/apps/27-interchain-accounts/types/keys.go | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index 43a95088f37..647ef2e7d55 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -39,9 +39,10 @@ func (k Keeper) OnChanOpenInit( if version != types.Version { return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "channel version must be '%s' (%s != %s)", types.Version, version, types.Version) } - channelID, found := k.GetActiveChannel(ctx, portID) + + existingChannelID, found := k.GetActiveChannel(ctx, portID) if found { - return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel (%s) for portID (%s)", channelID, portID) + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel (%s) for portID (%s)", existingChannelID, portID) } // Claim channel capability passed back by IBC module diff --git a/modules/apps/27-interchain-accounts/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go index ab9aac7bbe2..321bfcee458 100644 --- a/modules/apps/27-interchain-accounts/types/keys.go +++ b/modules/apps/27-interchain-accounts/types/keys.go @@ -10,7 +10,7 @@ const ( // module supports Version = "ics27-1" - PortID = "interchain-account" + PortID = "ibcaccount" StoreKey = ModuleName RouterKey = ModuleName From 9d3f02c64926d59425081d3575b4993d906da0e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 9 Aug 2021 15:05:22 +0200 Subject: [PATCH 10/66] Add counterparty port ID to controller portID (#319) * refactor! move GeneratePortID to types, add counterpartyConnection sequence change all PortId -> PortID move GeneratePortID to types package add counterparty connection sequence argument utilize connectiontypes connectionID parsing function * refactor! use counterparty portID in interchain account address gRPC Remove existing args from gRPC request for interchain account address Use counterparty portID * tests add generate port id tests * apply self-review fixes --- docs/ibc/proto-docs.md | 3 +- .../client/cli/query.go | 7 +- .../27-interchain-accounts/keeper/account.go | 11 +- .../keeper/account_test.go | 6 +- .../keeper/grpc_query.go | 7 +- .../keeper/handshake_test.go | 4 +- .../27-interchain-accounts/keeper/keeper.go | 14 --- .../keeper/keeper_test.go | 8 +- .../27-interchain-accounts/keeper/relay.go | 11 +- .../27-interchain-accounts/types/account.go | 30 ++++- .../types/account_test.go | 90 +++++++++++++++ .../27-interchain-accounts/types/errors.go | 1 + .../27-interchain-accounts/types/query.pb.go | 109 +++++------------- .../interchain_accounts/v1/query.proto | 5 +- 14 files changed, 186 insertions(+), 120 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/types/account_test.go diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 5e242070c9d..6fd91fd126d 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -343,8 +343,7 @@ Query request for an interchain account address | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `owner_address` | [string](#string) | | Owner address is the owner of the interchain account on the controller chain | -| `connection_id` | [string](#string) | | | +| `counterparty_port_id` | [string](#string) | | Counterparty PortID is the portID on the controller chain | diff --git a/modules/apps/27-interchain-accounts/client/cli/query.go b/modules/apps/27-interchain-accounts/client/cli/query.go index 9945d79bab8..8b26d77dbff 100644 --- a/modules/apps/27-interchain-accounts/client/cli/query.go +++ b/modules/apps/27-interchain-accounts/client/cli/query.go @@ -26,18 +26,17 @@ func GetQueryCmd() *cobra.Command { func GetInterchainAccountCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "address [address] [connection-id]", + Use: "address [counterparty-port-id]", RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } - ownerAddress := args[0] - connectionId := args[1] + counterpartyPortID := args[0] queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.InterchainAccountAddress(context.Background(), &types.QueryInterchainAccountAddressRequest{OwnerAddress: ownerAddress, ConnectionId: connectionId}) + res, err := queryClient.InterchainAccountAddress(context.Background(), &types.QueryInterchainAccountAddressRequest{CounterpartyPortId: counterpartyPortID}) if err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index 99bc84ce9c9..0cfe330a261 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -17,8 +17,11 @@ import ( // call 04-channel 'ChanOpenInit'. An error is returned if the port identifier is // already in use. Gaining access to interchain accounts whose channels have closed // cannot be done with this function. A regular MsgChanOpenInit must be used. -func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionId, owner string) error { - portId := k.GeneratePortId(owner, connectionId) +func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpartyConnectionID, owner string) error { + portId, err := types.GeneratePortID(owner, connectionID, counterpartyConnectionID) + if err != nil { + return err + } // check if the port is already bound if k.IsBound(ctx, portId) { @@ -26,12 +29,12 @@ func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionId, owner strin } portCap := k.portKeeper.BindPort(ctx, portId) - err := k.ClaimCapability(ctx, portCap, host.PortPath(portId)) + err = k.ClaimCapability(ctx, portCap, host.PortPath(portId)) if err != nil { return sdkerrors.Wrap(err, "unable to bind to newly generated portID") } - msg := channeltypes.NewMsgChannelOpenInit(portId, types.Version, channeltypes.ORDERED, []string{connectionId}, types.PortID, types.ModuleName) + msg := channeltypes.NewMsgChannelOpenInit(portId, types.Version, channeltypes.ORDERED, []string{connectionID}, types.PortID, types.ModuleName) handler := k.msgRouter.Handler(msg) if _, err := handler(ctx, msg); err != nil { return err diff --git a/modules/apps/27-interchain-accounts/keeper/account_test.go b/modules/apps/27-interchain-accounts/keeper/account_test.go index 064a9bc6413..3d9cd9bae49 100644 --- a/modules/apps/27-interchain-accounts/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/keeper/account_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/testing" ) @@ -32,7 +33,8 @@ func (suite *KeeperTestSuite) TestInitInterchainAccount() { */ { "MsgChanOpenInit fails - channel is already active", func() { - portID := suite.chainA.GetSimApp().ICAKeeper.GeneratePortId(owner, path.EndpointA.ConnectionID) + portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + suite.Require().NoError(err) suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID) }, false, }, @@ -49,7 +51,7 @@ func (suite *KeeperTestSuite) TestInitInterchainAccount() { tc.malleate() // explicitly change fields in channel and testChannel - err = suite.chainA.GetSimApp().ICAKeeper.InitInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, owner) + err = suite.chainA.GetSimApp().ICAKeeper.InitInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, path.EndpointB.ConnectionID, owner) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/apps/27-interchain-accounts/keeper/grpc_query.go b/modules/apps/27-interchain-accounts/keeper/grpc_query.go index 9b072d28ef0..fd344e83dd5 100644 --- a/modules/apps/27-interchain-accounts/keeper/grpc_query.go +++ b/modules/apps/27-interchain-accounts/keeper/grpc_query.go @@ -19,14 +19,13 @@ func (k Keeper) InterchainAccountAddress(ctx context.Context, req *types.QueryIn return nil, status.Error(codes.InvalidArgument, "empty request") } - if req.OwnerAddress == "" { - return nil, status.Error(codes.InvalidArgument, "address cannot be empty") + if req.CounterpartyPortId == "" { + return nil, status.Error(codes.InvalidArgument, "counterparty portID cannot be empty") } sdkCtx := sdk.UnwrapSDKContext(ctx) - portId := k.GeneratePortId(req.OwnerAddress, req.ConnectionId) - interchainAccountAddress, err := k.GetInterchainAccountAddress(sdkCtx, portId) + interchainAccountAddress, err := k.GetInterchainAccountAddress(sdkCtx, req.CounterpartyPortId) if err != nil { return nil, err } diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index 4b8a6f005fb..253aff5f5d9 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -14,7 +14,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { channel *channeltypes.Channel path *ibctesting.Path chanCap *capabilitytypes.Capability - err error ) testCases := []struct { @@ -63,7 +62,8 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { suite.coordinator.SetupConnections(path) // mock init interchain account - portID := suite.chainA.GetSimApp().ICAKeeper.GeneratePortId("owner", path.EndpointA.ConnectionID) + portID, err := types.GeneratePortID("owner", path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + suite.Require().NoError(err) portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) suite.chainA.GetSimApp().ICAKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) path.EndpointA.ChannelConfig.PortID = portID diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index 781a144f6a0..93adf0f9e3f 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -2,7 +2,6 @@ package keeper import ( "fmt" - "strings" baseapp "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" @@ -123,19 +122,6 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability return k.scopedKeeper.ClaimCapability(ctx, cap, name) } -// Utility function for parsing the connection number from the connection-id -func getConnectionNumber(connectionId string) string { - ss := strings.Split(connectionId, "-") - return ss[len(ss)-1] -} - -func (k Keeper) GeneratePortId(owner, connectionId string) string { - ownerId := strings.TrimSpace(owner) - connectionNumber := getConnectionNumber(connectionId) - portId := types.IcaPrefix + connectionNumber + "-" + ownerId - return portId -} - func (k Keeper) SetActiveChannel(ctx sdk.Context, portId, channelId string) error { store := ctx.KVStore(k.storeKey) diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index a0819dcdf09..3e26679d10b 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -41,11 +41,15 @@ func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { } // InitInterchainAccount is a helper function for starting the channel handshake +// TODO: parse identifiers from events func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { - portID := endpoint.Chain.GetSimApp().ICAKeeper.GeneratePortId(owner, endpoint.ConnectionID) + portID, err := types.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) + if err != nil { + return err + } channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil { + if err := endpoint.Chain.GetSimApp().ICAKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, owner); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 757a08fe7c3..dad941a7ead 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -12,15 +12,16 @@ import ( "github.com/tendermint/tendermint/crypto/tmhash" ) -func (k Keeper) TrySendTx(ctx sdk.Context, accountOwner sdk.AccAddress, connectionId string, data interface{}) ([]byte, error) { - portId := k.GeneratePortId(accountOwner.String(), connectionId) +// TODO: implement middleware functionality, this will allow us to use capabilities to +// manage helper module access to owner addresses they do not have capabilities for +func (k Keeper) TrySendTx(ctx sdk.Context, portID string, data interface{}) ([]byte, error) { // Check for the active channel - activeChannelId, found := k.GetActiveChannel(ctx, portId) + activeChannelId, found := k.GetActiveChannel(ctx, portID) if !found { return nil, types.ErrActiveChannelNotFound } - sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, portId, activeChannelId) + sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, portID, activeChannelId) if !found { return []byte{}, sdkerrors.Wrap(channeltypes.ErrChannelNotFound, activeChannelId) } @@ -28,7 +29,7 @@ func (k Keeper) TrySendTx(ctx sdk.Context, accountOwner sdk.AccAddress, connecti destinationPort := sourceChannelEnd.GetCounterparty().GetPortID() destinationChannel := sourceChannelEnd.GetCounterparty().GetChannelID() - return k.createOutgoingPacket(ctx, portId, activeChannelId, destinationPort, destinationChannel, data) + return k.createOutgoingPacket(ctx, portID, activeChannelId, destinationPort, destinationChannel, data) } func (k Keeper) createOutgoingPacket( diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index ebba17dc756..f9f1634fd31 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -3,18 +3,46 @@ package types import ( "encoding/json" "fmt" + "strings" yaml "gopkg.in/yaml.v2" crypto "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types" ) const ( - IcaPrefix string = "ics27-1-" + ICAPrefix string = "ics-27" ) +// GeneratePortID generates the portID for a specific owner +// on the controller chain in the format: +// +// 'ics-27---' +// https://github.com/seantking/ibc/tree/sean/ics-27-updates/spec/app/ics-027-interchain-accounts#registering--controlling-flows +// TODO: update link to spec +func GeneratePortID(owner, connectionID, counterpartyConnectionID string) (string, error) { + ownerID := strings.TrimSpace(owner) + if ownerID == "" { + return "", sdkerrors.Wrap(ErrInvalidOwnerAddress, "owner address cannot be empty") + } + connectionSeq, err := connectiontypes.ParseConnectionSequence(connectionID) + if err != nil { + return "", sdkerrors.Wrap(err, "invalid connection identifier") + } + counterpartyConnectionSeq, err := connectiontypes.ParseConnectionSequence(counterpartyConnectionID) + if err != nil { + return "", sdkerrors.Wrap(err, "invalid counterparty connection identifier") + } + + portID := fmt.Sprintf("%s-%d-%d-%s", ICAPrefix, connectionSeq, counterpartyConnectionSeq, ownerID) + return portID, nil +} + type InterchainAccountI interface { authtypes.AccountI } diff --git a/modules/apps/27-interchain-accounts/types/account_test.go b/modules/apps/27-interchain-accounts/types/account_test.go new file mode 100644 index 00000000000..15bc23eb3e8 --- /dev/null +++ b/modules/apps/27-interchain-accounts/types/account_test.go @@ -0,0 +1,90 @@ +package types_test + +import ( + "testing" + + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/testing" + "github.com/stretchr/testify/suite" +) + +type TypesTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain +} + +func (suite *TypesTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) + + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) +} + +func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { + path := ibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig.PortID = types.PortID + path.EndpointB.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointA.ChannelConfig.Version = types.Version + path.EndpointB.ChannelConfig.Version = types.Version + + return path +} + +func TestTypesTestSuite(t *testing.T) { + suite.Run(t, new(TypesTestSuite)) +} + +func (suite *TypesTestSuite) TestGeneratePortID() { + var ( + path *ibctesting.Path + owner string + ) + var testCases = []struct { + name string + malleate func() + expValue string + expPass bool + }{ + {"success", func() {}, "ics-27-0-0-owner123", true}, + {"success with non matching connection sequences", func() { + path.EndpointA.ConnectionID = "connection-1" + }, "ics-27-1-0-owner123", true}, + {"invalid owner address", func() { + owner = " " + }, "", false}, + {"invalid connectionID", func() { + path.EndpointA.ConnectionID = "connection" + }, "", false}, + {"invalid counterparty connectionID", func() { + path.EndpointB.ConnectionID = "connection" + }, "", false}, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + owner = "owner123" // must be explicitly changed + + tc.malleate() + + portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + if tc.expPass { + suite.Require().NoError(err, tc.name) + suite.Require().Equal(tc.expValue, portID) + } else { + suite.Require().Error(err, tc.name) + suite.Require().Empty(portID) + } + }) + } +} diff --git a/modules/apps/27-interchain-accounts/types/errors.go b/modules/apps/27-interchain-accounts/types/errors.go index 40578c46cee..32425a81071 100644 --- a/modules/apps/27-interchain-accounts/types/errors.go +++ b/modules/apps/27-interchain-accounts/types/errors.go @@ -15,4 +15,5 @@ var ( ErrInterchainAccountAlreadySet = sdkerrors.Register(ModuleName, 9, "Interchain Account is already set") ErrActiveChannelNotFound = sdkerrors.Register(ModuleName, 10, "no active channel for this owner") ErrInvalidVersion = sdkerrors.Register(ModuleName, 11, "invalid interchain accounts version") + ErrInvalidOwnerAddress = sdkerrors.Register(ModuleName, 12, "invalid owner address") ) diff --git a/modules/apps/27-interchain-accounts/types/query.pb.go b/modules/apps/27-interchain-accounts/types/query.pb.go index 56108e7f743..271ba3b4827 100644 --- a/modules/apps/27-interchain-accounts/types/query.pb.go +++ b/modules/apps/27-interchain-accounts/types/query.pb.go @@ -31,9 +31,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Query request for an interchain account address type QueryInterchainAccountAddressRequest struct { - // Owner address is the owner of the interchain account on the controller chain - OwnerAddress string `protobuf:"bytes,1,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` - ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` + // Counterparty PortID is the portID on the controller chain + CounterpartyPortId string `protobuf:"bytes,1,opt,name=counterparty_port_id,json=counterpartyPortId,proto3" json:"counterparty_port_id,omitempty"` } func (m *QueryInterchainAccountAddressRequest) Reset() { *m = QueryInterchainAccountAddressRequest{} } @@ -125,30 +124,29 @@ func init() { } var fileDescriptor_72a16b57c3343764 = []byte{ - // 357 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x31, 0x4b, 0x33, 0x41, - 0x10, 0xbd, 0xfd, 0xe0, 0x13, 0x5d, 0xb4, 0x39, 0x2c, 0x8e, 0x43, 0x2e, 0x12, 0x15, 0x6d, 0xb2, - 0x4b, 0x12, 0x44, 0x10, 0x9b, 0xa4, 0x4b, 0xa1, 0x60, 0x4a, 0x11, 0xc2, 0xde, 0xde, 0x72, 0x59, - 0x48, 0x76, 0x2e, 0xb7, 0x7b, 0x91, 0xf8, 0x0b, 0x2c, 0xfd, 0x09, 0xf9, 0x1f, 0xd6, 0x82, 0x65, - 0x4a, 0x4b, 0x49, 0x1a, 0x7f, 0x86, 0xdc, 0x6d, 0x48, 0x44, 0x0d, 0xa6, 0xb0, 0x1b, 0x66, 0xde, - 0x9b, 0xf7, 0x76, 0xf6, 0xe1, 0xba, 0x0c, 0x39, 0x65, 0x49, 0xd2, 0x93, 0x9c, 0x19, 0x09, 0x4a, - 0x53, 0xa9, 0x8c, 0x48, 0x79, 0x97, 0x49, 0xd5, 0x61, 0x9c, 0x43, 0xa6, 0x8c, 0xa6, 0xc3, 0x2a, - 0x1d, 0x64, 0x22, 0x1d, 0x91, 0x24, 0x05, 0x03, 0xee, 0xb1, 0x0c, 0x39, 0xf9, 0x4c, 0x22, 0x3f, - 0x90, 0xc8, 0xb0, 0xea, 0xef, 0xc6, 0x10, 0x43, 0xc1, 0xa1, 0x79, 0x65, 0xe9, 0xfe, 0x5e, 0x0c, - 0x10, 0xf7, 0x04, 0x65, 0x89, 0xa4, 0x4c, 0x29, 0x30, 0xf3, 0x25, 0x76, 0x7a, 0xba, 0xae, 0xa3, - 0x79, 0x6d, 0x69, 0xe5, 0x7b, 0x7c, 0x78, 0x9d, 0x5b, 0x6c, 0x2d, 0xc0, 0x0d, 0x3b, 0x6f, 0x44, - 0x51, 0x2a, 0xb4, 0x6e, 0x8b, 0x41, 0x26, 0xb4, 0x71, 0x0f, 0xf0, 0x0e, 0xdc, 0x29, 0x91, 0x76, - 0x98, 0xed, 0x7b, 0x68, 0x1f, 0x9d, 0x6c, 0xb5, 0xb7, 0x8b, 0xe6, 0x1c, 0x9b, 0x83, 0x38, 0x28, - 0x25, 0x78, 0x6e, 0xa0, 0x23, 0x23, 0xef, 0x9f, 0x05, 0x2d, 0x9b, 0xad, 0xe8, 0x7c, 0xf3, 0x61, - 0x5c, 0x72, 0xde, 0xc7, 0x25, 0xa7, 0x2c, 0xf0, 0xd1, 0x2f, 0xda, 0x3a, 0x01, 0xa5, 0x85, 0x7b, - 0x81, 0xfd, 0xef, 0x8f, 0xf9, 0xe2, 0xc4, 0x93, 0x2b, 0xb6, 0xd4, 0x9e, 0x11, 0xfe, 0x5f, 0xe8, - 0xb8, 0x4f, 0x08, 0x7b, 0xab, 0xc4, 0xdc, 0x4b, 0xb2, 0xe6, 0xf7, 0x90, 0x75, 0x0e, 0xe6, 0x5f, - 0xfd, 0xd5, 0x3a, 0x7b, 0x83, 0xb2, 0xd3, 0xbc, 0x7d, 0x99, 0x06, 0x68, 0x32, 0x0d, 0xd0, 0xdb, - 0x34, 0x40, 0x8f, 0xb3, 0xc0, 0x99, 0xcc, 0x02, 0xe7, 0x75, 0x16, 0x38, 0x37, 0xcd, 0x58, 0x9a, - 0x6e, 0x16, 0x12, 0x0e, 0x7d, 0xca, 0x41, 0xf7, 0x41, 0x53, 0x19, 0xf2, 0x4a, 0x0c, 0xb4, 0x0f, - 0x51, 0xd6, 0x13, 0x3a, 0x0f, 0x86, 0xa6, 0xb5, 0xb3, 0xca, 0xd2, 0x42, 0x65, 0x91, 0x09, 0x33, - 0x4a, 0x84, 0x0e, 0x37, 0x8a, 0x3c, 0xd4, 0x3f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xc1, 0x93, 0x84, - 0xc3, 0xda, 0x02, 0x00, 0x00, + // 347 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x3f, 0x4b, 0x3b, 0x31, + 0x18, 0xbe, 0x0c, 0xbf, 0x1f, 0x9a, 0xf1, 0xe8, 0x50, 0x0e, 0xb9, 0x4a, 0x51, 0x74, 0x69, 0x62, + 0x5b, 0x44, 0x10, 0x97, 0x76, 0xeb, 0xa0, 0x68, 0x47, 0x11, 0x8e, 0x5c, 0x2e, 0x5c, 0x03, 0x6d, + 0xde, 0x34, 0xc9, 0x15, 0xfa, 0x0d, 0x1c, 0xfd, 0x08, 0xfd, 0x1e, 0xce, 0x82, 0x63, 0x47, 0x47, + 0x69, 0x17, 0x3f, 0x86, 0xf4, 0xae, 0xd4, 0x82, 0x16, 0x6f, 0x70, 0x7b, 0xc9, 0xf3, 0x3e, 0x7f, + 0x78, 0x9f, 0xe0, 0xb6, 0x8c, 0x39, 0x65, 0x5a, 0x0f, 0x25, 0x67, 0x4e, 0x82, 0xb2, 0x54, 0x2a, + 0x27, 0x0c, 0x1f, 0x30, 0xa9, 0x22, 0xc6, 0x39, 0x64, 0xca, 0x59, 0x3a, 0x69, 0xd2, 0x71, 0x26, + 0xcc, 0x94, 0x68, 0x03, 0x0e, 0xfc, 0x13, 0x19, 0x73, 0xb2, 0x4d, 0x22, 0x3f, 0x90, 0xc8, 0xa4, + 0x19, 0x54, 0x52, 0x48, 0x21, 0xe7, 0xd0, 0xd5, 0x54, 0xd0, 0x83, 0x83, 0x14, 0x20, 0x1d, 0x0a, + 0xca, 0xb4, 0xa4, 0x4c, 0x29, 0x70, 0x6b, 0x91, 0x02, 0x3d, 0x2f, 0x9b, 0x68, 0x3d, 0x17, 0xb4, + 0x7a, 0x8c, 0x8f, 0xee, 0x56, 0x11, 0x7b, 0x9b, 0xe5, 0x4e, 0x81, 0x77, 0x92, 0xc4, 0x08, 0x6b, + 0xfb, 0x62, 0x9c, 0x09, 0xeb, 0xfc, 0x33, 0x5c, 0xc9, 0x9f, 0x85, 0xd1, 0xcc, 0xb8, 0x69, 0xa4, + 0xc1, 0xb8, 0x48, 0x26, 0x55, 0x74, 0x88, 0x4e, 0xf7, 0xfb, 0xfe, 0x36, 0x76, 0x0b, 0xc6, 0xf5, + 0x92, 0xcb, 0xbd, 0xc7, 0x59, 0xcd, 0xfb, 0x98, 0xd5, 0xbc, 0xba, 0xc0, 0xc7, 0xbf, 0x78, 0x58, + 0x0d, 0xca, 0x0a, 0xff, 0x0a, 0x07, 0xdf, 0x43, 0x47, 0xac, 0xd8, 0x5a, 0x5b, 0x55, 0xe5, 0x0e, + 0x95, 0xd6, 0x0b, 0xc2, 0xff, 0x72, 0x1f, 0xff, 0x19, 0xe1, 0xea, 0x2e, 0x33, 0xff, 0x9a, 0x94, + 0xac, 0x81, 0x94, 0x39, 0x4c, 0x70, 0xf3, 0x57, 0x72, 0xc5, 0x0d, 0xea, 0x5e, 0xf7, 0xe1, 0x75, + 0x11, 0xa2, 0xf9, 0x22, 0x44, 0xef, 0x8b, 0x10, 0x3d, 0x2d, 0x43, 0x6f, 0xbe, 0x0c, 0xbd, 0xb7, + 0x65, 0xe8, 0xdd, 0x77, 0x53, 0xe9, 0x06, 0x59, 0x4c, 0x38, 0x8c, 0x28, 0x07, 0x3b, 0x02, 0x4b, + 0x65, 0xcc, 0x1b, 0x29, 0xd0, 0x11, 0x24, 0xd9, 0x50, 0xd8, 0xd5, 0x07, 0xb0, 0xb4, 0x75, 0xd1, + 0xf8, 0x8a, 0xd0, 0xd8, 0x74, 0xef, 0xa6, 0x5a, 0xd8, 0xf8, 0x7f, 0xde, 0x7b, 0xfb, 0x33, 0x00, + 0x00, 0xff, 0xff, 0x2e, 0x9f, 0x3c, 0xd1, 0xc2, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -253,17 +251,10 @@ func (m *QueryInterchainAccountAddressRequest) MarshalToSizedBuffer(dAtA []byte) _ = i var l int _ = l - if len(m.ConnectionId) > 0 { - i -= len(m.ConnectionId) - copy(dAtA[i:], m.ConnectionId) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ConnectionId))) - i-- - dAtA[i] = 0x12 - } - if len(m.OwnerAddress) > 0 { - i -= len(m.OwnerAddress) - copy(dAtA[i:], m.OwnerAddress) - i = encodeVarintQuery(dAtA, i, uint64(len(m.OwnerAddress))) + if len(m.CounterpartyPortId) > 0 { + i -= len(m.CounterpartyPortId) + copy(dAtA[i:], m.CounterpartyPortId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.CounterpartyPortId))) i-- dAtA[i] = 0xa } @@ -317,11 +308,7 @@ func (m *QueryInterchainAccountAddressRequest) Size() (n int) { } var l int _ = l - l = len(m.OwnerAddress) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.ConnectionId) + l = len(m.CounterpartyPortId) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } @@ -378,39 +365,7 @@ func (m *QueryInterchainAccountAddressRequest) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OwnerAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.OwnerAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyPortId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -438,7 +393,7 @@ func (m *QueryInterchainAccountAddressRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ConnectionId = string(dAtA[iNdEx:postIndex]) + m.CounterpartyPortId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/proto/ibc/applications/interchain_accounts/v1/query.proto b/proto/ibc/applications/interchain_accounts/v1/query.proto index 1787614df32..96232982f09 100644 --- a/proto/ibc/applications/interchain_accounts/v1/query.proto +++ b/proto/ibc/applications/interchain_accounts/v1/query.proto @@ -18,9 +18,8 @@ message QueryInterchainAccountAddressRequest { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; - // Owner address is the owner of the interchain account on the controller chain - string owner_address = 1; - string connection_id = 2; + // Counterparty PortID is the portID on the controller chain + string counterparty_port_id = 1; } // Query response for an interchain account address From b4d82a261ab6f61f1ce298ba1de0db2a2c7eeb43 Mon Sep 17 00:00:00 2001 From: Sean King Date: Fri, 13 Aug 2021 12:08:16 +0200 Subject: [PATCH 11/66] test: check active channel is correct (#324) * test: check active channel is correct * test: adding version string check --- .../27-interchain-accounts/keeper/handshake.go | 4 ++++ .../keeper/handshake_test.go | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index 647ef2e7d55..c226b226ba9 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -95,6 +95,10 @@ func (k Keeper) OnChanOpenAck( channelID string, counterpartyVersion string, ) error { + if counterpartyVersion != types.Version { + return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) + } + k.SetActiveChannel(ctx, portID, channelID) return nil diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index 253aff5f5d9..279cc2109e2 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -185,6 +185,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { func (suite *KeeperTestSuite) TestOnChanOpenAck() { var ( path *ibctesting.Path + expectedChannel string counterpartyVersion string ) @@ -193,10 +194,15 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { malleate func() expPass bool }{ - { "success", func() {}, true, }, + { + "invalid counterparty version", func() { + expectedChannel = "" + counterpartyVersion = "version" + }, false, + }, } for _, tc := range testCases { @@ -214,6 +220,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { err = path.EndpointB.ChanOpenTry() suite.Require().NoError(err) + expectedChannel = path.EndpointA.ChannelID tc.malleate() // explicitly change fields in channel and testChannel @@ -221,12 +228,15 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyVersion, ) + activeChannel, _ := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + + suite.Require().Equal(activeChannel, expectedChannel) + if tc.expPass { suite.Require().NoError(err) } else { suite.Require().Error(err) } - }) } } From 8acf6e6b13b2ba2b98d1ef0cbcd726c7d9921c35 Mon Sep 17 00:00:00 2001 From: Luke Rhoads <51463884+lukerhoads@users.noreply.github.com> Date: Tue, 24 Aug 2021 05:50:40 -0500 Subject: [PATCH 12/66] Removed memkey from ICA keeper (#342) * Removed memkey from ICA keeper * Removed memkey arg in call to NewKeeper from simapp --- modules/apps/27-interchain-accounts/keeper/keeper.go | 3 --- testing/simapp/app.go | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index 93adf0f9e3f..cea325ae1d4 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -29,12 +29,10 @@ type Keeper struct { scopedKeeper capabilitykeeper.ScopedKeeper msgRouter *baseapp.MsgServiceRouter - memKey sdk.StoreKey } // NewKeeper creates a new interchain account Keeper instance func NewKeeper( - memKey sdk.StoreKey, cdc codec.BinaryCodec, key sdk.StoreKey, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, accountKeeper types.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, hook types.IBCAccountHooks, @@ -47,7 +45,6 @@ func NewKeeper( accountKeeper: accountKeeper, scopedKeeper: scopedKeeper, msgRouter: msgRouter, - memKey: memKey, hook: hook, } } diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 96a891db2e2..e84e96bdf9e 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -330,7 +330,7 @@ func NewSimApp( transferModule := transfer.NewAppModule(app.TransferKeeper) app.ICAKeeper = icakeeper.NewKeeper( - keys[icatypes.MemStoreKey], appCodec, keys[icatypes.StoreKey], + appCodec, keys[icatypes.StoreKey], app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, scopedICAKeeper, app.MsgServiceRouter(), app, ) From 1bf79304f5b1698c8f95184719445ac0021ca6db Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Fri, 27 Aug 2021 11:36:04 +0200 Subject: [PATCH 13/66] moving stateless GenerateAddress func to types (#352) --- .../apps/27-interchain-accounts/keeper/account.go | 13 +++---------- .../apps/27-interchain-accounts/types/account.go | 6 ++++++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index 0cfe330a261..8fdf5383d12 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -4,7 +4,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/tendermint/tendermint/crypto/tmhash" "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" @@ -45,9 +44,9 @@ func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpart // Register interchain account if it has not already been created func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portId string) { - address := k.GenerateAddress(portId) - account := k.accountKeeper.GetAccount(ctx, address) + address := types.GenerateAddress(portId) + account := k.accountKeeper.GetAccount(ctx, address) if account != nil { // account already created, return no-op return @@ -57,11 +56,10 @@ func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portId string) { authtypes.NewBaseAccountWithAddress(address), portId, ) + k.accountKeeper.NewAccount(ctx, interchainAccount) k.accountKeeper.SetAccount(ctx, interchainAccount) _ = k.SetInterchainAccountAddress(ctx, portId, interchainAccount.Address) - - return } func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portId string, address string) string { @@ -82,11 +80,6 @@ func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portId string) (str return interchainAccountAddr, nil } -// Determine account's address that will be created. -func (k Keeper) GenerateAddress(identifier string) []byte { - return tmhash.SumTruncated(append([]byte(identifier))) -} - func (k Keeper) GetInterchainAccount(ctx sdk.Context, addr sdk.AccAddress) (types.InterchainAccount, error) { acc := k.accountKeeper.GetAccount(ctx, addr) if acc == nil { diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index f9f1634fd31..93f8b18e9a4 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -11,6 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/tendermint/tendermint/crypto/tmhash" connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types" ) @@ -19,6 +20,11 @@ const ( ICAPrefix string = "ics-27" ) +// GenerateAddress returns a truncated SHA256 hash using the provided port string +func GenerateAddress(port string) []byte { + return tmhash.SumTruncated([]byte(port)) +} + // GeneratePortID generates the portID for a specific owner // on the controller chain in the format: // From 599ad7f68602852779631401b3804e4e3b913bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Fri, 27 Aug 2021 12:46:11 +0200 Subject: [PATCH 14/66] update ica branch codeowners (#353) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cdb6284df09..472ca68e7f1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,4 +4,4 @@ # CODEOWNERS for interchain-accounts module -*/modules/apps/27-interchain-accounts @seantking @colin-axner @AdityaSripal +/modules/apps/27-interchain-accounts/ @seantking @colin-axner @AdityaSripal From 01748555b7e0fea1d0dd780b898a94bfea6c2164 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 30 Aug 2021 13:01:13 +0200 Subject: [PATCH 15/66] move Get/SetInterchainAccount to keeper.go, add tests (#355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * moving setter/getter funcs to keeper.go, adding tests * removing redundant var * fixing test assertion string typo * updating Get/SetInterchainAccount func signatures, tests and adding godocs * grouping imports according, updating suite.FailNow() -> suite.Require().NoError() Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- .../27-interchain-accounts/keeper/account.go | 20 +------- .../keeper/grpc_query.go | 9 ++-- .../keeper/handshake.go | 1 - .../27-interchain-accounts/keeper/keeper.go | 18 +++++++ .../keeper/keeper_test.go | 51 +++++++++++++++++++ .../27-interchain-accounts/keeper/relay.go | 4 +- 6 files changed, 76 insertions(+), 27 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index 8fdf5383d12..98883cd0dba 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -59,25 +59,7 @@ func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portId string) { k.accountKeeper.NewAccount(ctx, interchainAccount) k.accountKeeper.SetAccount(ctx, interchainAccount) - _ = k.SetInterchainAccountAddress(ctx, portId, interchainAccount.Address) -} - -func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portId string, address string) string { - store := ctx.KVStore(k.storeKey) - key := types.KeyOwnerAccount(portId) - store.Set(key, []byte(address)) - return address -} - -func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portId string) (string, error) { - store := ctx.KVStore(k.storeKey) - key := types.KeyOwnerAccount(portId) - if !store.Has(key) { - return "", sdkerrors.Wrap(types.ErrInterchainAccountNotFound, portId) - } - - interchainAccountAddr := string(store.Get(key)) - return interchainAccountAddr, nil + k.SetInterchainAccountAddress(ctx, portId, interchainAccount.Address) } func (k Keeper) GetInterchainAccount(ctx sdk.Context, addr sdk.AccAddress) (types.InterchainAccount, error) { diff --git a/modules/apps/27-interchain-accounts/keeper/grpc_query.go b/modules/apps/27-interchain-accounts/keeper/grpc_query.go index fd344e83dd5..205722addef 100644 --- a/modules/apps/27-interchain-accounts/keeper/grpc_query.go +++ b/modules/apps/27-interchain-accounts/keeper/grpc_query.go @@ -4,6 +4,7 @@ import ( "context" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -23,11 +24,9 @@ func (k Keeper) InterchainAccountAddress(ctx context.Context, req *types.QueryIn return nil, status.Error(codes.InvalidArgument, "counterparty portID cannot be empty") } - sdkCtx := sdk.UnwrapSDKContext(ctx) - - interchainAccountAddress, err := k.GetInterchainAccountAddress(sdkCtx, req.CounterpartyPortId) - if err != nil { - return nil, err + interchainAccountAddress, found := k.GetInterchainAccountAddress(sdk.UnwrapSDKContext(ctx), req.CounterpartyPortId) + if !found { + return nil, status.Error(codes.NotFound, sdkerrors.Wrap(types.ErrInterchainAccountNotFound, req.CounterpartyPortId).Error()) } return &types.QueryInterchainAccountAddressResponse{InterchainAccountAddress: interchainAccountAddress}, nil diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index c226b226ba9..e4677b72188 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -110,7 +110,6 @@ func (k Keeper) OnChanOpenConfirm( portID, channelID string, ) error { - return nil } diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index cea325ae1d4..17dd769295e 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -149,3 +149,21 @@ func (k Keeper) IsActiveChannel(ctx sdk.Context, portId string) bool { func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) } + +// GetInterchainAccountAddress retrieves the InterchainAccount address from the store keyed by the provided portID +func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (string, bool) { + store := ctx.KVStore(k.storeKey) + key := types.KeyOwnerAccount(portID) + + if !store.Has(key) { + return "", false + } + + return string(store.Get(key)), true +} + +// SetInterchainAccountAddress stores the InterchainAccount address, keyed by the associated portID +func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portID string, address string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyOwnerAccount(portID), []byte(address)) +} diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index 3e26679d10b..d3cc61c8d6a 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "testing" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/suite" "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" @@ -40,6 +41,27 @@ func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { return path } +// SetupICAPath invokes the InterchainAccounts entrypoint and subsequent channel handshake handlers +func SetupICAPath(path *ibctesting.Path, owner string) error { + if err := InitInterchainAccount(path.EndpointA, owner); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenTry(); err != nil { + return err + } + + if err := path.EndpointA.ChanOpenAck(); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenConfirm(); err != nil { + return err + } + + return nil +} + // InitInterchainAccount is a helper function for starting the channel handshake // TODO: parse identifiers from events func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { @@ -76,3 +98,32 @@ func (suite *KeeperTestSuite) TestGetPort() { port := suite.chainA.GetSimApp().ICAKeeper.GetPort(suite.chainA.GetContext()) suite.Require().Equal(types.PortID, port) } + +func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, "testing") + suite.Require().NoError(err) + + counterpartyPortID := path.EndpointA.ChannelConfig.PortID + expectedAddr := authtypes.NewBaseAccountWithAddress(types.GenerateAddress(counterpartyPortID)).GetAddress() + + retrievedAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), counterpartyPortID) + suite.Require().True(found) + suite.Require().Equal(expectedAddr.String(), retrievedAddr) + + retrievedAddr, found = suite.chainA.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), "invalid port") + suite.Require().False(found) + suite.Require().Empty(retrievedAddr) +} + +func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() { + expectedAddr, portID := "address", "port" + suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), portID, expectedAddr) + + retrievedAddr, found := suite.chainA.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), portID) + suite.Require().True(found) + suite.Require().Equal(expectedAddr, retrievedAddr) +} diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index dad941a7ead..5aa0ddda8be 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -136,8 +136,8 @@ func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portId string) e } } - interchainAccountAddr, err := k.GetInterchainAccountAddress(ctx, portId) - if err != nil { + interchainAccountAddr, found := k.GetInterchainAccountAddress(ctx, portId) + if !found { return sdkerrors.ErrUnauthorized } From 01bb9bfb38b99e4e0dd6bd863d0b7dcb26ffe699 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 31 Aug 2021 11:54:34 +0200 Subject: [PATCH 16/66] chore: interchain accounts cleanup, cli alias (#362) * adding ica alias for interchain-accounts queries * refactoring bind port and claim capability functionality, code cleanup and godocs --- .../client/cli/query.go | 1 + .../apps/27-interchain-accounts/genesis.go | 7 +- .../27-interchain-accounts/keeper/account.go | 23 +++---- .../27-interchain-accounts/keeper/keeper.go | 66 +++++++++---------- 4 files changed, 47 insertions(+), 50 deletions(-) diff --git a/modules/apps/27-interchain-accounts/client/cli/query.go b/modules/apps/27-interchain-accounts/client/cli/query.go index 8b26d77dbff..55149f2b0fd 100644 --- a/modules/apps/27-interchain-accounts/client/cli/query.go +++ b/modules/apps/27-interchain-accounts/client/cli/query.go @@ -13,6 +13,7 @@ import ( func GetQueryCmd() *cobra.Command { cmd := &cobra.Command{ Use: "interchain-accounts", + Aliases: []string{"ica"}, Short: "Querying commands for the interchain accounts module", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, diff --git a/modules/apps/27-interchain-accounts/genesis.go b/modules/apps/27-interchain-accounts/genesis.go index 5a9569b54e6..44b15e0065b 100644 --- a/modules/apps/27-interchain-accounts/genesis.go +++ b/modules/apps/27-interchain-accounts/genesis.go @@ -6,12 +6,15 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/keeper" "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + + host "github.com/cosmos/ibc-go/modules/core/24-host" ) +// InitGenesis initializes the interchain accounts application state from a provided genesis state func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState) { if !keeper.IsBound(ctx, state.PortId) { - err := keeper.BindPort(ctx, state.PortId) - if err != nil { + cap := keeper.BindPort(ctx, state.PortId) + if err := keeper.ClaimCapability(ctx, cap, host.PortPath(state.PortId)); err != nil { panic(fmt.Sprintf("could not claim port capability: %v", err)) } } diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index 98883cd0dba..43e3bc4b143 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -17,23 +17,21 @@ import ( // already in use. Gaining access to interchain accounts whose channels have closed // cannot be done with this function. A regular MsgChanOpenInit must be used. func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpartyConnectionID, owner string) error { - portId, err := types.GeneratePortID(owner, connectionID, counterpartyConnectionID) + portID, err := types.GeneratePortID(owner, connectionID, counterpartyConnectionID) if err != nil { return err } - // check if the port is already bound - if k.IsBound(ctx, portId) { - return sdkerrors.Wrap(types.ErrPortAlreadyBound, portId) + if k.IsBound(ctx, portID) { + return sdkerrors.Wrap(types.ErrPortAlreadyBound, portID) } - portCap := k.portKeeper.BindPort(ctx, portId) - err = k.ClaimCapability(ctx, portCap, host.PortPath(portId)) - if err != nil { + cap := k.BindPort(ctx, portID) + if err := k.ClaimCapability(ctx, cap, host.PortPath(portID)); err != nil { return sdkerrors.Wrap(err, "unable to bind to newly generated portID") } - msg := channeltypes.NewMsgChannelOpenInit(portId, types.Version, channeltypes.ORDERED, []string{connectionID}, types.PortID, types.ModuleName) + msg := channeltypes.NewMsgChannelOpenInit(portID, types.Version, channeltypes.ORDERED, []string{connectionID}, types.PortID, types.ModuleName) handler := k.msgRouter.Handler(msg) if _, err := handler(ctx, msg); err != nil { return err @@ -43,23 +41,22 @@ func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpart } // Register interchain account if it has not already been created -func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portId string) { - address := types.GenerateAddress(portId) +func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portID string) { + address := types.GenerateAddress(portID) account := k.accountKeeper.GetAccount(ctx, address) if account != nil { - // account already created, return no-op return } interchainAccount := types.NewInterchainAccount( authtypes.NewBaseAccountWithAddress(address), - portId, + portID, ) k.accountKeeper.NewAccount(ctx, interchainAccount) k.accountKeeper.SetAccount(ctx, interchainAccount) - k.SetInterchainAccountAddress(ctx, portId, interchainAccount.Address) + k.SetInterchainAccountAddress(ctx, portID, interchainAccount.Address) } func (k Keeper) GetInterchainAccount(ctx sdk.Context, addr sdk.AccAddress) (types.InterchainAccount, error) { diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index 17dd769295e..d45fd9037aa 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -9,10 +9,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - host "github.com/cosmos/ibc-go/modules/core/24-host" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + host "github.com/cosmos/ibc-go/modules/core/24-host" ) // Keeper defines the IBC transfer keeper @@ -49,6 +49,7 @@ func NewKeeper( } } +// SerializeCosmosTx marshals data to bytes using the provided codec func (k Keeper) SerializeCosmosTx(cdc codec.BinaryCodec, data interface{}) ([]byte, error) { msgs := make([]sdk.Msg, 0) switch data := data.(type) { @@ -86,68 +87,63 @@ func (k Keeper) SerializeCosmosTx(cdc codec.BinaryCodec, data interface{}) ([]by return bz, nil } +// Logger returns the application logger, scoped to the associated module func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) } -// IsBound checks if the interchain account module is already bound to the desired port -func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { - _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) - return ok +// GetPort returns the portID for the interchain accounts module. Used in ExportGenesis +func (k Keeper) GetPort(ctx sdk.Context) string { + store := ctx.KVStore(k.storeKey) + return string(store.Get([]byte(types.PortKey))) } -// BindPort defines a wrapper function for the port Keeper's BindPort function in -// order to expose it to module's InitGenesis function -func (k Keeper) BindPort(ctx sdk.Context, portID string) error { - // Set the portID into our store so we can retrieve it later +// BindPort stores the provided portID and binds to it, returning the associated capability +func (k Keeper) BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability { store := ctx.KVStore(k.storeKey) store.Set([]byte(types.PortKey), []byte(portID)) - cap := k.portKeeper.BindPort(ctx, portID) - return k.ClaimCapability(ctx, cap, host.PortPath(portID)) + return k.portKeeper.BindPort(ctx, portID) } -// GetPort returns the portID for the interchain accounts module. Used in ExportGenesis -func (k Keeper) GetPort(ctx sdk.Context) string { - store := ctx.KVStore(k.storeKey) - return string(store.Get([]byte(types.PortKey))) +// IsBound checks if the interchain account module is already bound to the desired port +func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { + _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) + return ok } -// ClaimCapability allows the transfer module that can claim a capability that IBC module -// passes to it -func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { - return k.scopedKeeper.ClaimCapability(ctx, cap, name) +// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function +func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { + return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) } -func (k Keeper) SetActiveChannel(ctx sdk.Context, portId, channelId string) error { - store := ctx.KVStore(k.storeKey) - - key := types.KeyActiveChannel(portId) - store.Set(key, []byte(channelId)) - return nil +// ClaimCapability wraps the scopedKeeper's ClaimCapability function +func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { + return k.scopedKeeper.ClaimCapability(ctx, cap, name) } +// GetActiveChannel retrieves the active channelID from the store keyed by the provided portID func (k Keeper) GetActiveChannel(ctx sdk.Context, portId string) (string, bool) { store := ctx.KVStore(k.storeKey) key := types.KeyActiveChannel(portId) + if !store.Has(key) { return "", false } - activeChannel := string(store.Get(key)) - return activeChannel, true + return string(store.Get(key)), true } -// IsActiveChannel returns true if there exists an active channel for -// the provided portID and false otherwise. -func (k Keeper) IsActiveChannel(ctx sdk.Context, portId string) bool { - _, found := k.GetActiveChannel(ctx, portId) - return found +// SetActiveChannel stores the active channelID, keyed by the provided portID +func (k Keeper) SetActiveChannel(ctx sdk.Context, portID, channelID string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyActiveChannel(portID), []byte(channelID)) } -// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function -func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { - return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) +// IsActiveChannel returns true if there exists an active channel for the provided portID, otherwise false +func (k Keeper) IsActiveChannel(ctx sdk.Context, portID string) bool { + _, ok := k.GetActiveChannel(ctx, portID) + return ok } // GetInterchainAccountAddress retrieves the InterchainAccount address from the store keyed by the provided portID From 2a3e5261bb5dc41e45ce0cafa5cd5798bc2cf94c Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 1 Sep 2021 13:18:34 +0200 Subject: [PATCH 17/66] updating interchain accounts pkg naming (#364) --- modules/apps/27-interchain-accounts/genesis.go | 2 +- modules/apps/27-interchain-accounts/module.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/27-interchain-accounts/genesis.go b/modules/apps/27-interchain-accounts/genesis.go index 44b15e0065b..7f225f54150 100644 --- a/modules/apps/27-interchain-accounts/genesis.go +++ b/modules/apps/27-interchain-accounts/genesis.go @@ -1,4 +1,4 @@ -package ibc_account +package interchain_accounts import ( "fmt" diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 9ba760952c8..d515b5f667d 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -1,4 +1,4 @@ -package ibc_account +package interchain_accounts import ( "encoding/json" From 74fb34ed85153b37b90f7b5a6affa8f9f886018e Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 2 Sep 2021 17:08:54 +0200 Subject: [PATCH 18/66] adding ica grpc query tests (#368) --- .../keeper/grpc_query_test.go | 80 +++++++++++++++++++ .../keeper/keeper_test.go | 7 ++ 2 files changed, 87 insertions(+) create mode 100644 modules/apps/27-interchain-accounts/keeper/grpc_query_test.go diff --git a/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go b/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go new file mode 100644 index 00000000000..6841f45963b --- /dev/null +++ b/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go @@ -0,0 +1,80 @@ +package keeper_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" +) + +func (suite *KeeperTestSuite) TestQueryInterchainAccountAddress() { + var ( + req *types.QueryInterchainAccountAddressRequest + expAddr string + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &types.QueryInterchainAccountAddressRequest{} + }, + false, + }, + { + "invalid counterparty portID", + func() { + req = &types.QueryInterchainAccountAddressRequest{ + CounterpartyPortId: "", + } + }, + false, + }, + { + "interchain account address not found", + func() { + req = &types.QueryInterchainAccountAddressRequest{ + CounterpartyPortId: "ics-27", + } + }, + false, + }, + { + "success", + func() { + expAddr = authtypes.NewBaseAccountWithAddress(types.GenerateAddress("ics-27")).GetAddress().String() + req = &types.QueryInterchainAccountAddressRequest{ + CounterpartyPortId: "ics-27", + } + + suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), "ics-27", expAddr) + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + + res, err := suite.queryClient.InterchainAccountAddress(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(expAddr, res.GetInterchainAccountAddress()) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index d3cc61c8d6a..06e0e2530c8 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "testing" + "github.com/cosmos/cosmos-sdk/baseapp" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/suite" @@ -20,6 +21,8 @@ type KeeperTestSuite struct { chainA *ibctesting.TestChain chainB *ibctesting.TestChain chainC *ibctesting.TestChain + + queryClient types.QueryClient } func (suite *KeeperTestSuite) SetupTest() { @@ -27,6 +30,10 @@ func (suite *KeeperTestSuite) SetupTest() { suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2)) + + queryHelper := baseapp.NewQueryServerTestHelper(suite.chainA.GetContext(), suite.chainA.GetSimApp().InterfaceRegistry()) + types.RegisterQueryServer(queryHelper, suite.chainA.GetSimApp().ICAKeeper) + suite.queryClient = types.NewQueryClient(queryHelper) } func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { From d37f2ecba7086a518dd5a54934d5a2284fa3b068 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 6 Sep 2021 15:36:06 +0200 Subject: [PATCH 19/66] updating grpc query tests, removing queryClient on KeeperTestSuite (#379) --- modules/apps/27-interchain-accounts/keeper/grpc_query.go | 3 ++- .../apps/27-interchain-accounts/keeper/grpc_query_test.go | 6 +++--- modules/apps/27-interchain-accounts/keeper/keeper_test.go | 7 ------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/grpc_query.go b/modules/apps/27-interchain-accounts/keeper/grpc_query.go index 205722addef..dacf55efeb1 100644 --- a/modules/apps/27-interchain-accounts/keeper/grpc_query.go +++ b/modules/apps/27-interchain-accounts/keeper/grpc_query.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -20,7 +21,7 @@ func (k Keeper) InterchainAccountAddress(ctx context.Context, req *types.QueryIn return nil, status.Error(codes.InvalidArgument, "empty request") } - if req.CounterpartyPortId == "" { + if strings.TrimSpace(req.CounterpartyPortId) == "" { return nil, status.Error(codes.InvalidArgument, "counterparty portID cannot be empty") } diff --git a/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go b/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go index 6841f45963b..c5ea7a3cd84 100644 --- a/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go +++ b/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go @@ -23,7 +23,7 @@ func (suite *KeeperTestSuite) TestQueryInterchainAccountAddress() { { "empty request", func() { - req = &types.QueryInterchainAccountAddressRequest{} + req = nil }, false, }, @@ -31,7 +31,7 @@ func (suite *KeeperTestSuite) TestQueryInterchainAccountAddress() { "invalid counterparty portID", func() { req = &types.QueryInterchainAccountAddressRequest{ - CounterpartyPortId: "", + CounterpartyPortId: " ", } }, false, @@ -66,7 +66,7 @@ func (suite *KeeperTestSuite) TestQueryInterchainAccountAddress() { tc.malleate() ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) - res, err := suite.queryClient.InterchainAccountAddress(ctx, req) + res, err := suite.chainA.GetSimApp().ICAKeeper.InterchainAccountAddress(ctx, req) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index 06e0e2530c8..d3cc61c8d6a 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -3,7 +3,6 @@ package keeper_test import ( "testing" - "github.com/cosmos/cosmos-sdk/baseapp" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/suite" @@ -21,8 +20,6 @@ type KeeperTestSuite struct { chainA *ibctesting.TestChain chainB *ibctesting.TestChain chainC *ibctesting.TestChain - - queryClient types.QueryClient } func (suite *KeeperTestSuite) SetupTest() { @@ -30,10 +27,6 @@ func (suite *KeeperTestSuite) SetupTest() { suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2)) - - queryHelper := baseapp.NewQueryServerTestHelper(suite.chainA.GetContext(), suite.chainA.GetSimApp().InterfaceRegistry()) - types.RegisterQueryServer(queryHelper, suite.chainA.GetSimApp().ICAKeeper) - suite.queryClient = types.NewQueryClient(queryHelper) } func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { From e8d0ddeab230e03081ae09c2be61d73bc63c51a1 Mon Sep 17 00:00:00 2001 From: Sean King Date: Mon, 13 Sep 2021 13:02:12 +0200 Subject: [PATCH 20/66] ICA: Adding tests for relay.go (#337) * test: adding test for TrySendTx * test: adding tests for data check * test: adding check for SendTx with []sdk.Message * chore: seperate imports * test: add helper function for creating ICA path * test: adding cases for incorrect outgoing data & channel does not exist --- .../keeper/handshake_test.go | 2 +- .../keeper/keeper_test.go | 21 +++++ .../27-interchain-accounts/keeper/relay.go | 1 - .../keeper/relay_test.go | 93 +++++++++++++++++++ .../apps/27-interchain-accounts/types/keys.go | 2 +- testing/app.go | 2 +- 6 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/keeper/relay_test.go diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index 279cc2109e2..35f09372f76 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -278,7 +278,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenConfirm() { tc.malleate() // explicitly change fields in channel and testChannel - err = suite.chainB.GetSimApp().ICAKeeper.OnChanOpenConfirm(suite.chainA.GetContext(), + err = suite.chainB.GetSimApp().ICAKeeper.OnChanOpenConfirm(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) if tc.expPass { diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index d3cc61c8d6a..7064d6ebc07 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -127,3 +127,24 @@ func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() { suite.Require().True(found) suite.Require().Equal(expectedAddr, retrievedAddr) } + +func (suite *KeeperTestSuite) SetupICAPath(path *ibctesting.Path, owner string) error { + if err := InitInterchainAccount(path.EndpointA, owner); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenTry(); err != nil { + return err + } + + if err := path.EndpointA.ChanOpenAck(); err != nil { + return err + } + + if err := suite.chainB.GetSimApp().ICAKeeper.OnChanOpenConfirm(suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID); err != nil { + return err + } + + return nil +} diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 5aa0ddda8be..baf6009b2e1 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -40,7 +40,6 @@ func (k Keeper) createOutgoingPacket( destinationChannel string, data interface{}, ) ([]byte, error) { - if data == nil { return []byte{}, types.ErrInvalidOutgoingData } diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go new file mode 100644 index 00000000000..66c3b22d51a --- /dev/null +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -0,0 +1,93 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + ibctesting "github.com/cosmos/ibc-go/testing" +) + +func (suite *KeeperTestSuite) TestTrySendTx() { + var ( + path *ibctesting.Path + msg interface{} + portID string + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() { + amount, _ := sdk.ParseCoinsNormalized("100stake") + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + }, true, + }, + { + "success with []sdk.Message", func() { + amount, _ := sdk.ParseCoinsNormalized("100stake") + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + msg1 := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + msg2 := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + msg = []sdk.Msg{msg1, msg2} + }, true, + }, + { + "incorrect outgoing data", func() { + msg = []byte{} + }, false, + }, + { + "active channel not found", func() { + amount, _ := sdk.ParseCoinsNormalized("100stake") + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + portID = "incorrect portID" + }, false, + }, + { + "channel does not exist", func() { + amount, _ := sdk.ParseCoinsNormalized("100stake") + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), portID, "channel-100") + }, false, + }, + { + "data is nil", func() { + msg = nil + }, false, + }, + { + "data is not an SDK message", func() { + msg = "not an sdk message" + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path = NewICAPath(suite.chainA, suite.chainB) + owner := "owner" + suite.coordinator.SetupConnections(path) + + err := suite.SetupICAPath(path, owner) + suite.Require().NoError(err) + portID = path.EndpointA.ChannelConfig.PortID + tc.malleate() + _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), portID, msg) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/modules/apps/27-interchain-accounts/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go index 321bfcee458..909813ec46d 100644 --- a/modules/apps/27-interchain-accounts/types/keys.go +++ b/modules/apps/27-interchain-accounts/types/keys.go @@ -3,7 +3,7 @@ package types import "fmt" const ( - // ModuleName defines the IBC transfer name + // ModuleName defines the Interchain Account module name ModuleName = "interchainaccounts" // Version defines the current version the IBC tranfer diff --git a/testing/app.go b/testing/app.go index f14178b9d53..a50d87d7868 100644 --- a/testing/app.go +++ b/testing/app.go @@ -89,8 +89,8 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs } validators = append(validators, validator) delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec())) - } + // set validators and delegations stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations) genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis) From e0cef86f86f36b2904ecc4bbd6bcdf2e4a0a316f Mon Sep 17 00:00:00 2001 From: Sean King Date: Tue, 14 Sep 2021 11:48:14 +0200 Subject: [PATCH 21/66] Update ICA on main + add app version negotiation stub (#403) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump github.com/cosmos/cosmos-sdk from 0.43.0-rc1 to 0.43.0-rc2 (#269) Bumps [github.com/cosmos/cosmos-sdk](https://github.com/cosmos/cosmos-sdk) from 0.43.0-rc1 to 0.43.0-rc2. - [Release notes](https://github.com/cosmos/cosmos-sdk/releases) - [Changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-rc2/CHANGELOG.md) - [Commits](https://github.com/cosmos/cosmos-sdk/compare/v0.43.0-rc1...v0.43.0-rc2) --- updated-dependencies: - dependency-name: github.com/cosmos/cosmos-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * generate swagger files (#267) * Reject Redundant Tx Antedecorator (#235) * writeup simple antedecorator * only do antehandler on checkTx * Update modules/core/04-channel/ante.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * enable 2 antehandler strategies, and write tests * remove strict decorator and pass on non-packet/update type * move ante logic into its own package * changelog Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * perform a no-op on redundant relay messages (#268) * create initial changes for delivertx handling * handle closed channel no-ops, fix tests * self review nits * add changelog * add events for no op messages * add back comment * Bump codecov/codecov-action from 1.5.2 to 2.0.1 (#273) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1.5.2 to 2.0.1. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v1.5.2...v2.0.1) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * remove ChanCloseInit function from transfer keeper (#275) * remove CloseChanInit from transfer * add changelog Co-authored-by: Aditya * Bump codecov/codecov-action from 2.0.1 to 2.0.2 (#296) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 2.0.1 to 2.0.2. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v2.0.1...v2.0.2) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump github.com/spf13/cast from 1.3.1 to 1.4.0 (#301) Bumps [github.com/spf13/cast](https://github.com/spf13/cast) from 1.3.1 to 1.4.0. - [Release notes](https://github.com/spf13/cast/releases) - [Commits](https://github.com/spf13/cast/compare/v1.3.1...v1.4.0) --- updated-dependencies: - dependency-name: github.com/spf13/cast dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump technote-space/get-diff-action from 4.2 to 5 (#306) Bumps [technote-space/get-diff-action](https://github.com/technote-space/get-diff-action) from 4.2 to 5. - [Release notes](https://github.com/technote-space/get-diff-action/releases) - [Changelog](https://github.com/technote-space/get-diff-action/blob/main/.releasegarc) - [Commits](https://github.com/technote-space/get-diff-action/compare/v4.2...v5) --- updated-dependencies: - dependency-name: technote-space/get-diff-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * bump to SDK v0.43.0-rc3 (#308) * SDK v0.43.0-rc3 * add capability fixes * add @seantking as codeowner to interchain accounts (#309) * Bump google.golang.org/grpc from 1.39.0 to 1.39.1 (#320) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.39.0 to 1.39.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.39.0...v1.39.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump github.com/cosmos/cosmos-sdk from 0.43.0-rc3 to 0.43.0 (#325) Bumps [github.com/cosmos/cosmos-sdk](https://github.com/cosmos/cosmos-sdk) from 0.43.0-rc3 to 0.43.0. - [Release notes](https://github.com/cosmos/cosmos-sdk/releases) - [Changelog](https://github.com/cosmos/cosmos-sdk/blob/master/CHANGELOG.md) - [Commits](https://github.com/cosmos/cosmos-sdk/compare/v0.43.0-rc3...v0.43.0) --- updated-dependencies: - dependency-name: github.com/cosmos/cosmos-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * module: improve 04-channel logging (#323) * module: improve 04-channel logging * update log Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * update changelog (#326) * Bump google.golang.org/grpc from 1.39.1 to 1.40.0 (#332) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.39.1 to 1.40.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.39.1...v1.40.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump github.com/spf13/cast from 1.4.0 to 1.4.1 (#338) Bumps [github.com/spf13/cast](https://github.com/spf13/cast) from 1.4.0 to 1.4.1. - [Release notes](https://github.com/spf13/cast/releases) - [Commits](https://github.com/spf13/cast/compare/v1.4.0...v1.4.1) --- updated-dependencies: - dependency-name: github.com/spf13/cast dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump github.com/tendermint/tendermint from 0.34.11 to 0.34.12 (#341) Bumps [github.com/tendermint/tendermint](https://github.com/tendermint/tendermint) from 0.34.11 to 0.34.12. - [Release notes](https://github.com/tendermint/tendermint/releases) - [Changelog](https://github.com/tendermint/tendermint/blob/master/CHANGELOG.md) - [Commits](https://github.com/tendermint/tendermint/compare/v0.34.11...v0.34.12) --- updated-dependencies: - dependency-name: github.com/tendermint/tendermint dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix broken links in integration.md (#340) * fix broken link in integration.md * fix: broken link to simulator.md file in cosmos-sdk docs Co-authored-by: Carlos Rodriguez * Created helper functions for emitting packet events (#343) * Created helper functions for emitting packet events * Fixed comments and re-ordered helper functions Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Merge pull request from GHSA-qrhq-96mh-q8jv * Bump codecov/codecov-action from 2.0.2 to 2.0.3 (#346) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 2.0.2 to 2.0.3. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v2.0.2...v2.0.3) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Bump actions/setup-go from 2.1.3 to 2.1.4 (#349) Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2.1.3 to 2.1.4. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v2.1.3...v2.1.4) --- updated-dependencies: - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * increase port identifier limit to 128 characters (#344) * increase port identifier limit to 128 characters increase port limit and add tests for port validation * add changelog * fix tests * update codeowners to include new team members and granular ownership (#354) * update codeowners * add proto files to ownership * bump SDK dependency (#367) * update SDK dependency and fix changes Removes tests from sdk_test.go which are no longer needed to upstream changes in the SDK Fixes client_test.go due to inclusion of the fee in tx events * bump SDK version to v0.44.0 * adding client status cli query (#372) * adding client status cli query * adding query client status cli to changelog * updating long CLI help usage * adding markdown link checker to ci workflows (#377) * packet acknowledgment filtering (#375) * adding packet commitments to QueryPacketAcknowledgementsRequest for filtering * adding testcase for filtered packet ack query * adding changelog entry for packet ack filtering * updating packet sequences type to repeated uint64 * updating to query specific packet acks outside bounds of paginated req * updating changelog field naming, removing redundant pagination in query test * continue in favour of returning an error on query PacketAcknowledgements * updating to return empty array of acks if none of the provided commitments are found Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Bump github.com/tendermint/tendermint from 0.34.12 to 0.34.13 (#386) Bumps [github.com/tendermint/tendermint](https://github.com/tendermint/tendermint) from 0.34.12 to 0.34.13. - [Release notes](https://github.com/tendermint/tendermint/releases) - [Changelog](https://github.com/tendermint/tendermint/blob/v0.34.13/CHANGELOG.md) - [Commits](https://github.com/tendermint/tendermint/compare/v0.34.12...v0.34.13) --- updated-dependencies: - dependency-name: github.com/tendermint/tendermint dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Change ICS 20 packet data amount to be string (#350) * modify proto defintions * fix non string usage in code and various tests * fix mbt tests * fix bug in data validation * fix various build issues fix unaddressed issues from changing amount from uint64 to string * add changelog entry * apply review suggestions Add check that amount is strictly positive Construct granular error messages to indicate invalid amount value or failure to parse amount * verify and fix telemetry bug Verify msg panics on amounts > int64 by adding tests Add checks to telemetry emission of transfer amounts to handle when the amount cannot be casted to float32 * fix: ibc build docs (#361) * initial fix commit * add release v1.0.1 to versions * improvements for docs website * add new version * address review comments Co-authored-by: Carlos Rodriguez Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * feat: scalable version queries (#384) * adding protos for port query interface * adding NegotiateAppVersion method to IBCModule interface * adding grpc port query implementation and module surrounds * adding NegotiateAppVersion implementation to apps/transfer and mocks * updating ErrInvalidVersion error code * adding grpc query tests for 05-port * updating grpc naming, adding godocs, removing redundant query cli * updating grpc query tests * adding changelog entry for #384 app version negotiation * fixing error formatting in transfer version negotiation Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * removing client/cli query * updating grpc query naming, adding new fields and associated surrounds Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Bump codecov/codecov-action from 2.0.3 to 2.1.0 (#399) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 2.0.3 to 2.1.0. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v2.0.3...v2.1.0) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: adding fn stub for version negotiation Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya Co-authored-by: Aleksandr Bezobchuk Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez Co-authored-by: Luke Rhoads <51463884+lukerhoads@users.noreply.github.com> Co-authored-by: Damian Nolan Co-authored-by: Charly --- .github/CODEOWNERS | 27 +- .github/workflows/link-check.yml | 8 + .github/workflows/test.yml | 14 +- CHANGELOG.md | 18 +- docs/.vuepress/config.js | 56 +- .../public/android-chrome-192x192.png | Bin 4110 -> 12115 bytes .../public/android-chrome-256x256.png | Bin 5421 -> 15284 bytes .../public/apple-touch-icon-precomposed.png | Bin 1473 -> 6733 bytes docs/.vuepress/public/apple-touch-icon.png | Bin 3744 -> 12367 bytes docs/.vuepress/public/favicon-16x16.png | Bin 632 -> 1385 bytes docs/.vuepress/public/favicon-32x32.png | Bin 942 -> 1893 bytes docs/.vuepress/public/mstile-150x150.png | Bin 3039 -> 5759 bytes docs/.vuepress/styles/index.styl | 3 + docs/client/config.json | 42 + docs/client/swagger-ui/swagger.yaml | 13961 ++++++++++++++++ docs/ibc/integration.md | 4 +- docs/ibc/proto-docs.md | 128 +- docs/package-lock.json | 522 +- docs/package.json | 5 +- docs/pre.sh | 3 + docs/versions | 3 + go.mod | 8 +- go.sum | 82 +- modules/apps/27-interchain-accounts/module.go | 4 + modules/apps/transfer/keeper/MBT_README.md | 2 +- modules/apps/transfer/keeper/keeper.go | 13 - .../apps/transfer/keeper/mbt_relay_test.go | 10 +- .../model_based_tests/Test5Packets.json | 12 +- .../Test5PacketsAllDifferentPass.json | 12 +- .../TestOnRecvAcknowledgementErrorFail.json | 4 +- .../TestOnRecvAcknowledgementErrorPass.json | 6 +- .../TestOnRecvAcknowledgementResultFail.json | 4 +- .../TestOnRecvAcknowledgementResultPass.json | 4 +- .../TestOnRecvPacketFail.json | 4 +- .../TestOnRecvPacketPass.json | 4 +- .../model_based_tests/TestOnTimeoutFail.json | 4 +- .../model_based_tests/TestOnTimeoutPass.json | 6 +- .../TestSendTransferFail.json | 4 +- .../TestSendTransferPass.json | 6 +- .../model_based_tests/TestUnescrowTokens.json | 8 +- modules/apps/transfer/keeper/relay.go | 58 +- modules/apps/transfer/keeper/relay_test.go | 14 +- modules/apps/transfer/module.go | 24 +- modules/apps/transfer/transfer_test.go | 14 +- modules/apps/transfer/types/coin.go | 4 +- modules/apps/transfer/types/errors.go | 2 +- .../apps/transfer/types/expected_keepers.go | 1 - modules/apps/transfer/types/msgs_test.go | 3 +- modules/apps/transfer/types/packet.go | 10 +- modules/apps/transfer/types/packet.pb.go | 481 + modules/apps/transfer/types/packet_test.go | 12 +- modules/apps/transfer/types/transfer.pb.go | 362 +- modules/core/02-client/client/cli/cli.go | 1 + modules/core/02-client/client/cli/query.go | 33 + modules/core/02-client/keeper/client_test.go | 5 +- modules/core/04-channel/keeper/events.go | 139 + modules/core/04-channel/keeper/grpc_query.go | 22 + .../core/04-channel/keeper/grpc_query_test.go | 27 + modules/core/04-channel/keeper/packet.go | 132 +- modules/core/04-channel/keeper/packet_test.go | 20 +- modules/core/04-channel/keeper/timeout.go | 48 +- .../core/04-channel/keeper/timeout_test.go | 24 +- modules/core/04-channel/types/errors.go | 6 + modules/core/04-channel/types/msgs_test.go | 3 +- modules/core/04-channel/types/query.pb.go | 370 +- modules/core/05-port/keeper/grpc_query.go | 52 + .../core/05-port/keeper/grpc_query_test.go | 103 + modules/core/05-port/keeper/keeper.go | 2 + modules/core/05-port/module.go | 24 + modules/core/05-port/types/module.go | 12 + modules/core/05-port/types/query.go | 9 + modules/core/05-port/types/query.pb.go | 843 + modules/core/24-host/validate.go | 6 +- modules/core/24-host/validate_test.go | 30 + modules/core/ante/ante.go | 72 + modules/core/ante/ante_test.go | 485 + modules/core/keeper/grpc_query.go | 6 + modules/core/keeper/keeper.go | 2 + modules/core/keeper/msg_server.go | 69 +- modules/core/keeper/msg_server_test.go | 76 +- modules/core/types/query.go | 4 + .../applications/transfer/v1/transfer.proto | 13 - .../ibc/applications/transfer/v2/packet.proto | 20 + proto/ibc/core/channel/v1/query.proto | 2 + proto/ibc/core/port/v1/query.proto | 35 + scripts/protoc-swagger-gen.sh | 2 +- testing/chain.go | 5 +- testing/mock/mock.go | 59 +- testing/sdk_test.go | 59 - testing/simapp/app.go | 17 +- testing/values.go | 14 +- 91 files changed, 17677 insertions(+), 1150 deletions(-) create mode 100644 .github/workflows/link-check.yml mode change 100644 => 100755 docs/.vuepress/public/android-chrome-192x192.png mode change 100644 => 100755 docs/.vuepress/public/android-chrome-256x256.png mode change 100644 => 100755 docs/.vuepress/public/apple-touch-icon-precomposed.png mode change 100644 => 100755 docs/.vuepress/public/apple-touch-icon.png mode change 100644 => 100755 docs/.vuepress/public/mstile-150x150.png create mode 100644 docs/.vuepress/styles/index.styl create mode 100644 docs/client/config.json create mode 100644 docs/client/swagger-ui/swagger.yaml create mode 100755 docs/pre.sh create mode 100644 docs/versions create mode 100644 modules/apps/transfer/types/packet.pb.go create mode 100644 modules/core/04-channel/keeper/events.go create mode 100644 modules/core/05-port/keeper/grpc_query.go create mode 100644 modules/core/05-port/keeper/grpc_query_test.go create mode 100644 modules/core/05-port/module.go create mode 100644 modules/core/05-port/types/query.go create mode 100644 modules/core/05-port/types/query.pb.go create mode 100644 modules/core/ante/ante.go create mode 100644 modules/core/ante/ante_test.go create mode 100644 proto/ibc/applications/transfer/v2/packet.proto create mode 100644 proto/ibc/core/port/v1/query.proto diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 472ca68e7f1..743e1c582b5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,7 +1,32 @@ # CODEOWNERS: https://help.github.com/articles/about-codeowners/ -* @colin-axner @fedekunze @AdityaSripal +* @colin-axner @AdityaSripal @crodriguezvega @seantking @charleenfei @damiannolan + +# Order is important; the last matching pattern takes the most +# precedence. When someone opens a pull request that only +# modifies 27-interchain-accounts files, only the interchain account owners +# and not the global owner(s) will be requested for a review. + +# CODEOWNERS for the CODEOWNER file + +/.github/CODEOWNERS @colin-axner @AdityaSripal @crodriguezvega + +# CODEOWNERS for the core IBC module + +/modules/core/ @colin-axner @fedekunze @AdityaSripal +/proto/core/ @colin-axner @fedekunze @AdityaSripal + +# CODEOWNERS for the light-clients + +/modules/light-clients/ @colin-axner @fedekunze @AdityaSripal +/proto/lightclients/ @colin-axner @fedekunze @AdityaSripal + +# CODEOWNERS for ICS 20 + +/modules/apps/transfer/ @colin-axner @fedekunze @AdityaSripal +/proto/applications/transfer/ @colin-axner @fedekunze @AdityaSripal # CODEOWNERS for interchain-accounts module /modules/apps/27-interchain-accounts/ @seantking @colin-axner @AdityaSripal +/proto/applications/interchain_accounts/ @seantking @colin-axner @AdityaSripal diff --git a/.github/workflows/link-check.yml b/.github/workflows/link-check.yml new file mode 100644 index 00000000000..6d2c00bb0f0 --- /dev/null +++ b/.github/workflows/link-check.yml @@ -0,0 +1,8 @@ +name: Check Markdown links +on: [push, pull_request] +jobs: + markdown-link-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: gaurav-nelson/github-action-markdown-link-check@v1 \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6259fb604df..6db36727899 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: install-tparse: runs-on: ubuntu-latest steps: - - uses: actions/setup-go@v2.1.3 + - uses: actions/setup-go@v2.1.4 with: go-version: 1.15 - name: Display go version @@ -38,10 +38,10 @@ jobs: go-arch: ["amd64", "arm", "arm64"] steps: - uses: actions/checkout@v2.3.4 - - uses: actions/setup-go@v2.1.3 + - uses: actions/setup-go@v2.1.4 with: go-version: 1.15 - - uses: technote-space/get-diff-action@v4.2 + - uses: technote-space/get-diff-action@v5 id: git_diff with: PATTERNS: | @@ -86,10 +86,10 @@ jobs: part: ["00", "01", "02", "03"] steps: - uses: actions/checkout@v2.3.4 - - uses: actions/setup-go@v2.1.3 + - uses: actions/setup-go@v2.1.4 with: go-version: 1.15 - - uses: technote-space/get-diff-action@v4.2 + - uses: technote-space/get-diff-action@v5 with: PATTERNS: | **/**.go @@ -113,7 +113,7 @@ jobs: needs: tests steps: - uses: actions/checkout@v2.3.4 - - uses: technote-space/get-diff-action@v4.2 + - uses: technote-space/get-diff-action@v5 with: PATTERNS: | **/**.go @@ -150,7 +150,7 @@ jobs: sed -i.bak "/$(echo $filename | sed 's/\//\\\//g')/d" coverage.txt done if: env.GIT_DIFF - - uses: codecov/codecov-action@v1.5.2 + - uses: codecov/codecov-action@v2.1.0 with: file: ./coverage.txt if: env.GIT_DIFF diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c2de271a62..d3516b2eea0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,10 +36,23 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### API Breaking + * (core) [\#227](https://github.com/cosmos/ibc-go/pull/227) Remove sdk.Result from application callbacks +* (transfer) [\#350](https://github.com/cosmos/ibc-go/pull/350) Change FungibleTokenPacketData to use a string for the Amount field. This enables token transfers with amounts previously restricted by uint64. Up to the maximum uint256 value is supported. + +### State Machine Breaking +* (24-host) [#\344](https://github.com/cosmos/ibc-go/pull/344) Increase port identifier limit to 128 characters. + +### Improvements +* [\#373](https://github.com/cosmos/ibc-go/pull/375) Added optional field `PacketCommitmentSequences` to `QueryPacketAcknowledgementsRequest` to provide filtering of packet acknowledgements + +### Features +* [\#372](https://github.com/cosmos/ibc-go/pull/372) New CLI command `query ibc client status ` to get the current activity status of a client +* [\#384](https://github.com/cosmos/ibc-go/pull/384) Added `NegotiateAppVersion` method to `IBCModule` interface supported by a gRPC query service in `05-port`. This provides routing of requests to the desired application module callback, which in turn performs application version negotiation. -## [v1.0.0-rc0](https://github.com/cosmos/ibc-go/releases/tag/v1.0.0-rc0) - 2021-07-07 +## [v1.0.0](https://github.com/cosmos/ibc-go/releases/tag/v1.0.0) - 2021-08-10 ### Bug Fixes @@ -68,6 +81,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core) [\#109](https://github.com/cosmos/ibc-go/pull/109) Remove connection and channel handshake CLI commands. * (modules) [\#107](https://github.com/cosmos/ibc-go/pull/107) Modify OnRecvPacket callback to return an acknowledgement which indicates if it is successful or not. Callback state changes are discarded for unsuccessful acknowledgements only. * (modules) [\#108](https://github.com/cosmos/ibc-go/pull/108) All message constructors take the signer as a string to prevent upstream bugs. The `String()` function for an SDK Acc Address relies on external context. +* (transfer) [\#275](https://github.com/cosmos/ibc-go/pull/275) Remove 'ChanCloseInit' function from transfer keeper. ICS20 does not close channels. ### State Machine Breaking @@ -77,6 +91,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/02-client) [\#8405](https://github.com/cosmos/cosmos-sdk/pull/8405) Refactor IBC client update governance proposals to use a substitute client to update a frozen or expired client. * (modules/core/02-client) [\#8673](https://github.com/cosmos/cosmos-sdk/pull/8673) IBC upgrade logic moved to 02-client and an IBC UpgradeProposal is added. * (modules/core/03-connection) [\#171](https://github.com/cosmos/ibc-go/pull/171) Introduces a new parameter `MaxExpectedTimePerBlock` to allow connections to calculate and enforce a block delay that is proportional to time delay set by connection. +* (core) [\#268](https://github.com/cosmos/ibc-go/pull/268) Perform a no-op on redundant relay messages. Previous behaviour returned an error. Now no state change will occur and no error will be returned. ### Improvements @@ -89,6 +104,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (core/04-channel) [\#197](https://github.com/cosmos/ibc-go/pull/197) Introduced a `packet_ack_hex` attribute to emit the hex-encoded acknowledgement in events. This allows for raw binary (proto-encoded message) to be sent over events and decoded correctly on relayer. Original `packet_ack` is DEPRECATED. All relayers and IBC event consumers are encouraged to switch to `packet_ack_hex` as soon as possible. * (modules/light-clients/07-tendermint) [\#125](https://github.com/cosmos/ibc-go/pull/125) Implement efficient iteration of consensus states and pruning of earliest expired consensus state on UpdateClient. * (modules/light-clients/07-tendermint) [\#141](https://github.com/cosmos/ibc-go/pull/141) Return early in case there's a duplicate update call to save Gas. +* (modules/core/ante) [\#235](https://github.com/cosmos/ibc-go/pull/235) Introduces a new IBC Antedecorator that will reject transactions that only contain redundant packet messages (and accompany UpdateClient msgs). This will prevent relayers from wasting fees by submitting messages for packets that have already been processed by previous relayer(s). The Antedecorator is only applied on CheckTx and RecheckTx and is therefore optional for each node. ### Features diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index c8ea7715ab9..17b7752035d 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -7,13 +7,22 @@ module.exports = { }, }, base: process.env.VUEPRESS_BASE || "/", + head: [ + ['link', { rel: "apple-touch-icon", sizes: "180x180", href: "/apple-touch-icon.png" }], + ['link', { rel: "icon", type: "image/png", sizes: "32x32", href: "/favicon-32x32.png" }], + ['link', { rel: "icon", type: "image/png", sizes: "16x16", href: "/favicon-16x16.png" }], + ['link', { rel: "manifest", href: "/site.webmanifest" }], + ['meta', { name: "msapplication-TileColor", content: "#2e3148" }], + ['meta', { name: "theme-color", content: "#ffffff" }], + ['link', { rel: "icon", type: "image/svg+xml", href: "/favicon-svg.svg" }], + ['link', { rel: "apple-touch-icon-precomposed", href: "/apple-touch-icon-precomposed.png" }], + ], themeConfig: { repo: "cosmos/ibc-go", docsRepo: "cosmos/ibc-go", docsDir: "docs", editLinks: true, label: "ibc", - // label: "ibc-go", // TODO //algolia: { // id: "BH4D9OD16A", @@ -24,8 +33,19 @@ module.exports = { { "label": "main", "key": "main" - } + }, + { + "label": "v1.1.0", + "key": "v1.1.0" + }, + { + "label": "v1.2.0", + "key": "v1.2.0" + } ], + topbar: { + banner: true + }, sidebar: { auto: false, nav: [ @@ -105,11 +125,41 @@ module.exports = { } }, footer: { - logo: "/logo-bw.svg", + question: { + text: "Chat with IBC developers in Discord." + }, textLink: { text: "ibcprotocol.org", url: "https://ibcprotocol.org" }, + services: [ + { + service: "medium", + url: "https://blog.cosmos.network/" + }, + { + service: "twitter", + url: "https://twitter.com/cosmos" + }, + { + service: "linkedin", + url: "https://www.linkedin.com/company/interchain-gmbh" + }, + { + service: "reddit", + url: "https://reddit.com/r/cosmosnetwork" + }, + { + service: "telegram", + url: "https://t.me/cosmosproject" + }, + { + service: "youtube", + url: "https://www.youtube.com/c/CosmosProject" + } + ], + smallprint: + "The development of IBC-Go is led primarily by [Interchain GmbH](https://interchain.berlin/). Funding for this development comes primarily from the Interchain Foundation, a Swiss non-profit.", links: [ { title: "Documentation", diff --git a/docs/.vuepress/public/android-chrome-192x192.png b/docs/.vuepress/public/android-chrome-192x192.png old mode 100644 new mode 100755 index 6d04cf4c08573ab91036925d6df3bd4142e75c7a..5ad0a90a17a09085aa1325a57b3bd264370943d7 GIT binary patch literal 12115 zcmbW7WmHvPwDvdMAtK!%-5}E4DV?H#(%sFWLxDdaEl5arcc*lBhct+kl6U!je8>HC z83WD$&OUqZwdQ>0Z$5KJzEPFKLMK6oAP7rAURndZcK-WDMFu}LR%}tg3!0<6z6%6l zJpcC%2c>-_f*^D?D=DcrZ!8^L9b7CO9H|tfq^KO79n7t4KSGe_Qii65mgWJ0$j#cN zq*4Uzi;{!J3sfo%$xkr+IC^GkG+f09>g>fA>Rr!dWDrRQvmy{;Vql+NsIy{5p)a89 zQ0K%1=SD;g-EI2h+RU}y{2YC(n-|?Hy~wB;N9jbxOp@nOe+9!VlB9UH5j@b_zq!LM z9*9oo2;rjEe4uuDpoN3}_zMfO&~&1-LvWtc7^qOEN_r0D? z2^EG9iF?OL=0oDLaIlONdQB(`5qdvtX1Wc%VT0Z?1pJ(aU>Sc>ec&L&FVrvKvf?1B z=N}`aAxj~sbX+G&2GZk%@XeKa1)v2sh*Lq=Tpp@yfI7!;F{&X{Oo&rGB9sY2^nu~CG+bCz=4J!Y^{snx@cCh#U{;_TgC zsl?oYyf_;dBM_7o_X6DQ#e?S#v|nYf(6#IJUyKW(e0x47hr( zom)2$^t;8OYlaaO0cIJzIqvavCiWng^%8=aE5tiNkg+r!yVg*R*Z?X7NoNHzS4xmx zb`i05B9nC?t#o1Bzvl~)r0eaL#Fa$<03&mL&r}*D$rv_TNzVM9V@8~uw^Q9REWr_* zy<58xTf`CP)&w=Pi?KBj4N+nc^|=Z4QUsi7lpbviDq(8qAL=f7M7&RQR6io{)oGOC zUdeN5L}^iJ%ai{WafTNNHlLgYLsx<+#2CR;!E5VAe@B6}~13kr`MK~y}w7Yik}rN!ECsSrWCWJpQKW! z6rm;Z%51#K0}(G!rW1`1(L<8TghE1IPgzfOLB5cRjE?u&654Atgb?*^2AYIIrCR#t zXMcN%Ou4zj_2gM;=kQ{mbKv?!NcFy^!;6&SW@!2kUZLu{))d~9?3BF*?E!01Ir{(0$*6ESO!CPGIn})cy>s4sDB%xXPAmRegC7m#i%i4tw_9!yUV+a{4s@F zLOVB2W3@0_>)ESV1Ie=NdW{P8@WSW3ZfOFe!2}9Qd1X0?(xH;Rud^y zlP7eih7aWSllKuWJutDtUIY(BSTGW&6QK}U5PJ|+q$uYTPk$mF(Bgc}b(FG~ij(S~ zt;bx??E4~a2t83Tkv@@>nM13nIKOzU7(@F)dsr*B$XL^_TvnS$bGry_CaFZbIOENc zCaI=Hkx*fHu|=VSme_ZH{f9_o{T}5WHL36FSyk`0Tl=Xn%!q3|S*dNXO2XU%U-i;g zjV}7SGq5Fy1|tSJi`X%wj6Kao&D8?* z0s<8g!K-riVw*hD>=tQ{4*P=Bl+1QxSf;W=!J1dw-YuCQ$Ai{`-EF~@9Ht&}4JIA( zGUgbOaNjE@2VruKf#q{`skc4iQh6qcCdr#2aZQuLxwEp-vN)fu`i-{fw(a`u`g7@# z>8a_JR1Q^6(==3?@|p65l!cTBMn^_-M(0vrrHgRQbMK|^rO&6YH@r9SG+?bStZ)3N zP`zW2uYX$KY9DGKpr5CwZSb~6wk)IU>lS~R%?UqpP0R0fcH z={H$T%S6wh)Q0-*q!`AxL{6LaQhzlmwLpuy zJz5SkjyT=2`O1bokK!AXGeXg8QRi>lqT9l+*SOd8-;KQPY#3}9R_k%dd>6Vd6+rv+ z;mP}H5-NbbgtI`143r2ogunaa?MvMeBPO`~@w$5PMB;N+lf(;&*r2kY-L5if%faLS z%BXMlQpV!Otgu7h`0vk6pqTtL`PAc&$q*VIsv9O2;~1ewGRc+v%42dx%4J>pRys*~ zE!~1kO`w8J@fEXZF}tKKoA%92AKtKWu9LD@D?0L$8<2-`6r=oM%R+`~tblJ%Dezuib3seg`c`c)Fzd&LM z(?Kp3Zj7pDwwqNeInhln_iv;3RdKeeqLSXG598)j<_AC5*fI^VlZumnCS%)U zEiTn!t?SgDTwTj7b0m*4F1G~NOEu+o2sgHVEch`tDkP@$UF%ZoR*Ua+YPHT}{*V3S zDXCBEHSh84vSI7ZgXoX;WopQ z-{YS%5;Oe#+5fJ*U(Tub*)tnkx5jZeYsPimoRWF^v?tUmG-mX>(e-!r^6qopM%}au z!FP6tu7|>p3Dar=Eni#G%A1UAnohmj>U_*^4oEX!kF8#|d7TqH&CO;Ch^)3s$4hu3zHB=zT`y~Xyf+6Vd6L>vfdw}&(q+-i68UA+iC9JPnBtAL#P6m{&WV9?qhfn3$q^d!?zfoL{kFgL}t1ebFx&LL56_w%8HS zah4k^+Rbj%nB~e(Mg*afq`&0EypWTVOR%!Cnj_{h|J5Hu&VmAQS&tHci?pOJc{*uW zpKHCEGtA+!7#oCxQ4WO0vF!!_wSx=LI3zq8AD z!|2-8rdRY+)D^s=sIjpz-h_zKdb8403Le$MX35r#n3y;b+Q6CKc)Fp*izK7;{S}yL zLd0Qx@XL+Z06rA0W8EQ>$0Ek!Y^{w1+Ng~fCm9ea(XFUAx3G|dgV1F$d+<;*5JKRh za*T$PIc~t>G}tI%`9n}zzKlcr-~9WUaZw(q_#moP{3N7vEJG+7oY6WhAF1p-)bIAP zicH9z6_=8dGCGZN6taubDXD9Fdb|sw$Mz?I7|8~RF?;sCZ75uwCr_3eXq{bLm>|a- z3QLN?vN=qmuycpi=GlO|Yde)ngbuk_iqpwlIm7-~O0}U6+%F)+S_8K8n~tZq>KYm} zZv12tfA4S3);ZF_?YQg=#+iy!vyC1~?;xSa9UfY1eiQX8?ecW;6wb8h3PPHF?Xbo> z=i}^)+4CP}4&ab)7*{a`IlXVqUxKs#+jyKb+D(0)n(Mk8B;&ydxj-~!+uD{2 zQB!xl*z!OH2c?z8vJzknY&vH7OT$~b-EbZCZTX6Rdxnar%yS#|>T?>M!sna`L>S^k z^Lzf7n(`wX8=Jq{+S=W?9X)c>wP<>(5xdR;Yy_XwBNgdjb9S$*^hO3aODA77Pg;Ii zZ+627$8F`MQ{c83&%~-k6VIK5X%tC|1c8t1?eA~i+S(dnt#FE=5IICcgwM?P_xJK@ zy4au0Wv&<1D4FHXe#0pF@6E-R$BWNN1zi~p_jz=Tj7mkFcOnqdbQG4GoVH~vbV}@8 z-#$Y!i$hXt6hzF-I=s zE{&j6nPX69POqG@A=eg&I6-gs+G>if0{rP}HaR(2PUP;mrZpG^=Mb**fmAZ9)tIBo zd3UHe6ob&+Nif6K0!7)`xjGjt`?Erpw9Qd*G_LIJo4Zwz|F!DtwlaJr?u;6;f4+NXd~t>TAJ;i3za5yC^!^5GP1I= zIrcz`gpl5R@mZ|?m|tfz-!F;r6JZ@EyyyJ!;@cCi$kmKy+T86JiZ*14GjZR=_&ELT zk&c}ELqtxuHpJ(A zMl^WhKF;*Q_rH3cee?Yt$s;P-o+pi)!taz*URn8uCQ)%R{smgrLs^)Hre?0#-7$}v zqN1YS(e(!Z>DyY%IREu_zxap<)SYY0f?dhxs1GF|{7BA`P z)2eG~5H5a>CYTb@OO=tXsc_UDE4T@VRwQzIOQGUn2|Er@=k zF>rt1(m_@hIW8`a`gk%o{IDI%q0^RcS&KOlZ@_8iNe)%QX7m7ZVlL}Aod-ff}`407w>4Po3&z|TPs?RL68 z))y&83qd!lBj#0UA>c4B4SkxqZhfL|aXXS_ecN1ne|a!nr&BUJ9pZ!RTcDaz{I>do zf{c+78Qcw?^&sl&nWyohEHOd zyQ{!T@Cofod0GM<)#R$iWlwefM*@Ss6rQP>*$D;#Yo`F2Dr2BcknTIb#Ply;q$}Gz zkLK9=Zm*6IpbeSTV8n@>nb}!=K8LjtlxtR2@3mI1azGldLiE}Mn3v z6c-nNNq_ACHqj~DUJ~B&+38A?l>7Yo8xugUehX@r^koc4!p++vcl;CwRvf2>4m^m zwnG8$%R=lcBIn?+=N`t!6d!9A^@5QHV#tp?uNN&|nqH7_ zAHMnPOE6<+iHwS}Q)M=AX~v z`;A8IH_dKG{Pqp$v&mv+{g}gpakScOR}Gh^t3u8{;$L>{kX?Xu?4wUWYm%9yZ`6MS zG=d&fnjv>WqQY5gA9we9T!VT81Tk7#DZ%%hFu{64hm}U^b#T)-6G-0jP_`s4VwL$Q z33U&rZL-mui@kA=OORuIF7C9nv@evBSkX54$8-|D7;0(Jl@}IP=IBFcRCGsAlX8?^ zW8cKaz1yrbG~z#k&8L1FMyU8Lub@DQ!snQaW%(1(|Dk`f1#L*JMj}qoVIl|T0o}y? zeD$u;F}nk(`_SC&GFW9_a3`2C+qMPm3+;Y)bcF0i;uO?$FnS65l}0Yd?S3qs1`BIz z>s1i>G83);h35x}{M|{2x0=p>2KF%F$9KINb1YSLeDpYRc+{BcYVM=*w=Hy?c)vTh z&wT^#w<)bcC9`c$I-d1#{tZIH;LOwbAz1n8)29~$v6L1sFaX^{oh{b0%oVBy7(XY5 z`9OJ8Fs$1yRL|W3yKd3u&xDH_@h_{`72^43+T@{ViEn~#L$wy;6m#A}!W84_iHS03 zq22YRbM*SHo?Q8pmUSP*haZ3T!1u9_r{laBZG1GaSI`zSaCh$ia7Yw%)O-Wu;T3 zRW0`PcU%-ZyoaySOUV8BKM;4zF?_x9(9^5Jjz3!%dq4nQ*v@t6Rv2G=9 z94bkjAr>G?j~BUM4mb95G@TagiB7mT1sdoFSy@?YpYAWl73&G_ZqC&HaRX}E^WPIY z`tQ3#(6#{IE-xg#wr?ZPvac-Cb0dT|kJjdAPm${NsaZ%ln{IKm{L1Qn-d4-U%j9aVH-`-*nZuJ(5SYX}$x1XAm)FG1Ge zgPP?o!7xg8^aUOj5q|8I&73%{SNjYQu9J?t)ic4B+3#nz(Yks%{Qk)CFWdkE6M=ArNo| zSqY)?u6%I+{X?UZ?obTtdcx;;cwZ~pZ;Nps@A3y?koT$vC^Vxf#WG(7EF8Eh0ze>c z^f*Al>kO86bE|XP9ZD>v9w7=tB4E|qh>DKZcE4O_#YOD}4IE07(W!~g4N$wdaBT8w zxZzo4d5HYE8i;^~>gxEq{_)O0gcATw&pjsUo}Mn9fIRd9c^CzH0Kn?cuO6Jg*x|Vs zD*|)+*xi82tY49+NEzFj#omAemrzb_0Qt_l9ZdBNUEehsm0N(0u~}6^r^AZ~w|1YJ&R20M z`2L-d@{&)zNUQkca8i>18TK+O%E*@84CKA|aFC zO|a~X2K-F5$jS8mtuWUHTeT-7Bp}eBQ&<8=5E+!s8SCi{B3zS_7tOy5SS^~g%*no> z^4-husJs;#Ajv?A`t*sm{q~TBP&g~x45t|Kr3|>Q+B=*rDV=+YlcV4o&k%ZT`&!T) zw~|^atk8Tk?ITLkm%-Z}F3&eO0~GRbD?q2(O?r^$qDJ{+dxLwgU<8kklt3TVZ&o%RvQShVvwd}R*?#>)&)cfYm57dDVqb>xK&X3s9)kKSkyjZ{Q?V(^l*1$LB5ce zmsiYYSdW~LN&G0FnQp%}yo z)k;0qx$bUBIH=O#X=Fs%M?*sck>uhjn2v!VT!#_AG~Dc4z+=-fFdJNH;c9UTLC z)HLqV34?P3RfYiW?!d9&!~R6}GmegXZX2T7f$cba0)n7{ZR-D^C89QCht)b8LQ1_Y z&qkwihx4tzFN%2@IoXftsMXcg{Gj`?MIaRd9q%DXQ1<-|Z92hbXb@b`+11hfB72<~ z5IEWI1qB${Zf6%Kj+ckCN>@`#98H038ege6IAYHn`Ag*?yWY|C*GGp+>1MWbVqn{- z5`OGhM%1LZV{VUr6Z@8&k}^ng=K@rF@c!PH&~>Ay3Y!Irr^^7|6{ZC4zf1%Y-aAvI z**BpeMUhq?ZFIuTJ%16jw zj#f_5VkBiVgvvg1WO#U69bX0{3$A(1;%yfSWC@Q*~afllntgM#+6BFv}$6;^?5y1J0%FbBdUr^s)@91FW;Yn~K zfS@jbyMN4UQUS>E{3~a+D~;;#$4v)*vSzf+!My=|`kiz?LrpPxd6NJuMC&EMWc^X>)5Kck0 zvHGvdUP3Ko{p{;28-l8UCx4X(ig;xemAaohJD$^1Q#6~#8hFSMos9aIA0K`bVIm*J ziaj#&5n*z7taJ1`ef=U&HwL;n8YZU55-sLg^w1#W>yUg$soHDIjemaBDnPoD{%BI& zS;`4^?K3ZB@t35bkw%_>d3`T*e_kH@nl|Ibm{>Crq=I*Scf(#fj zND%zu;-X+wj_{yt!+ojW&yiG;ROO$@(AiX;Qi%$E!nvrD>T^Vs+vA$?OP9T|G73T0 zLLNT8dTa<4`ZasQg$A)lN}C?eSA25=n^K?1qN@XJ8XVa$6S6V^gxVyCF?Z6^sNOcU z9z+q=Fd=h_3LEqvV2$|r_z^%ab4^CnWyse^GN_HG^`aOO%L!wh`c1xb^!ElLAxQ+!#NX71O3Y< zJ}$0FqYB@AVjKbAKaShL4=6cJ#{!!`}9UUI0E$N4f@|b zW$!wSmEym*Nnv!J-59QU?PXX8if>q(=iX0^nu9)RH9((Idbvq1mP|k+E+s{ea7+{# z3NSY}&s((RbJv2?Gxj-oW%oS4i(Z63rsZF!LJp{o7kT+K!W@`TFSt`jR`C2Vp&j6Y z8>;K->dsFhZWy%tHkIcgKl#O4Tpi8|rsX48vevinKK&l%7*15os|&qLQB+f__|)djEDuOq5eN1#J*Wb*+tqHs+PGFopw|u;Op!XUzz*LQcHMuYozfskuLr&t2jm(200U9+&7qF*yn^X<$!1HQTQ?|Me6$o*@2!FQc#)@Z^`hYLDaa-HONp`VFN1 z)w5^MV&1>z2iNDeTyMwH;k+A_S6w}2$4e6V`?vEA@Kd9`yu7q=L@xhh(!-c+@o-20 z^8u>6m15U4h!ziX0p`ao{=zdg*0g_Xl{aG& zbUT`B*%!`|$?mv2ZLuaB5b45P0J@x34#cnQX69jO>g9&3;0Y<8ZQ;(jXV)?D0jL;h zz{s6EMSKHx`))rs7I_=vy5r$`c^9*XKe&z`_=0mNPR`0t>rW5gt_VqAHn(q1KEJ(q z2R}GCScqukRCy5y8Zob_$jRyM=fsRL z*=L63OHT9VzG18cCy{gJCsU=ur5ei=Aw^@I3U)S2&Z}3KlYTV{6KpeJ78ZE2! zoL8Ds!Pi$9qyZRo0Ys(=?&>sCh{(1WO$&wd*$jHx+zhAu34DdQ4!{Yr>vzEQBCeRn zxH9=YO2caZCd_0X%#rG?yE!c#fW-x%Os<${25R0@bg-ei`UgC8%&whZnG7qa43(Ui?+YJ^PzZ&E0?CihM!t8C;1F2))4% zm388=xVh^UpKUmCIPLkW$}oO*6Yh(k);35&o(#aZ+ew)9Z@*^>A`CP{l?DbGs(aUW z57ZfRB$&uupr8$=9gpog=V9p#nb!oa+RNoO5_`6-1&kLmCl38E&j9{#_pbA+ugknI zlKV{2{@>`P5jYo%_J|N<6fN7+Jb4csx)-nQS5QCBnG6jNp8zp7Wr^I^Ez+8(gySKJ z7A~2MvJbIBMh?!Vjzj}SHW_+ojyl3m=cZpEoaRGmpqjaMpaZuN^nUo&WsW+-!+q`rPFhn3I#kjM)=}{zZd1u^#A+j#Zt(bVV=H;_%SW z2yi4SaM430Ud}~G)7*d=r_CEqqhSqweXChZUJ03lE&kJhgS_NoFb`vpdf;#Aa1aKw zn`+<>+JW*L9DRG$ao$fldjlHrpzB=m%jttAzq@*BFha$bq||ggBguQykJ4n?7gc=g z%zE{?3eQ)=9`k?m1hYw%E8_OLo50>gmc7JX5c%&w=_|I+CNfd!0 zWlDi^Y7T}j!nvog1>maCuJ?sfJr#Z%=bokiYCk}P&9w6$n?2#AV8D=zlRI3ag6PPx zIek+9Z{FUl_DvKSwN2cf>gCJ4dhmEd8W>)axSu$f`5w+Ny#>XwojBc$n}(+Q7Rbrb zXW86DtG_(thBj+BxP@h9ugVPSimgHGOb{oJulyI^ph#;;_A`+Q6Ekx$crXL8hm(%P z=7eBq`)jU*AL>mcuv=k|Y(h z?5Uc-ylnHnDxR?A`vjOkjS>IW%*^a9hy*I1%l&K;Vb4mBnL>3M=uHk!A$I7|P$Ek& zsD>}S+t%DqmR=PW7UKE{Q^0|u4mx%Q0fEJg|Nf(jjg8&Q&&xvs`ft;!n?k*G81+5i z8#6p?-n7bb)&6xdox<1Q-6`iLVXEX|((;kb+^U)EY^ZbBxe3&d#z1jc@HRg!KDt7k z0eL6qXPjt;MX?F+6wDGHyqq0ue*`>v^Zz{`^MC!-@(F$;%Us-5gWm|Ml<<4OH$xGj eYJMO2L3ex?J*o(Ek80TsJ)c literal 4110 zcmcInS6I{Av;EPeNDo~My$T^9H3S4CK#2565u}DDN(bqL-iZ)O=)DRYfk;&Z>AkA_ zJshO>4k9S%<=nUXaNq8In7wAr%=+eG_TJw&35NRGbTnKv007V-bu^7{u=`)5BELB= zK9wim0J*ceo;m{JaTaw*bHo3IIE{001KZ0J~>? zhY|cHL28fE)&%~<;l@7PFltX73m*Wu4f@wefZTkJn;@kxQV&77M#W4HFs6MgvH$@3 zLZqfTI^gSmLEx*${j6~x6n^C?+{x?YbypK>bJMl30y$WXYL;bs+so1<)9e7fkVGo# zbvBkdbZHaEs34b~EOwgeb8!p}vouXSm8O#e8;6ra)&vhjY|irgFQKgmBtL`0d(Pg6 z9$x+v?EY=GYLbpRqMw_8_>75r+nj{ffdZP$+6^@YdjC%eCHhTbP|*)p3d71+rG*}i z+|YmA61Qhz=;}4DoShm2o|>2{=A_c(E40cbB&$S841J6NdE$uM63L2l+a+B$(vJFeHA`fBa=}=>{FG z^wECm)bqpnkclb*$43>J$|^Aa-N+T=aSwaNqSTC2g0nW}sUdf5VE!e|;d^cAsF08D zolK@!!XAeHl-c^4QZXjRYOh70Q(uuyZp<#C^zwdN+ARFck>?|2$xaBspNx@FfuA{1 zY-y~d892*u_6r(pw3Zb^6n#|72ussf=k!~etjz&kDjRqLl|YV0;ihUmu#c9}{?AoT zvVAGTMk^`Nr1v?SXzqh3BbMpe>@WsblCO+{znZF|1PYIbSFCOF4Kg0;01?IMhoV*K z;yW(IX<9Q8vNOZ{d5dQy3ZV&%-o(vX0@LJtG$%66W8;A!xl2Ws%;(0ezvk72{N`rW zP*w7L8s&Io^rIjjnTMQ@9t4R}j65UsllFUs6Q&=X4PWjlpB!)}GG?4oxLsi7_DXY1 zKjHaP(E3i~4>>;$mkYUA4nJQnj`}bm5|sFlDb`f}L?Q7q+M6MGc*7U6EFOyoogRLI z_ndmITt6LNQWc*1``heZA?e%+XOcyayp5AJetS4@%|}|qH}J4-pU}FL5S#<^geBh>45%%don15W@E1~Vff<%zVUuwAJk?|ljGc64Q&ko5vFqQAaQ9%ckIQdHJ8z}DW+nV870C6$ z1>3ptfWmWIIm`Knc#*2C9v8_8kwiX{&xS+KDEIGg4aQjY8~%KyuR9hHerH^^semB> zhZFS)#E@vhLH27Zwj!7B$`)WbKJ76m&U9$qLKNz*s>&9Z!3R{Kqbsqk#eQ|2CGRrqbTpU@__ z^@%{Z4YX_fdPhh$uRowP6Re}Q-jk94by}&>iFS7aZw7Of?qk>{mBJJ*lG)|r5JZ|c z5$x4zExH@da74I)$|oJO*1pO#MBS__a{(#wI4crIcMNj!j;t!I&Dmbr!JV*%Ps`q8 zLX-iP=9+oLPnq!T;~gA~=LbU0detpdYgz=m* zEZO{rosPdhk3+g_c^2CI}kDY$*G!5Th!7b!E+ox;5;O$4GG8{MFwzKM0YWVR1uboj~a7*A) zK%jg-%c!PTHi&$FC_9~P(6f1W(1RKjs6Ks(G3v(r#7m9)U+@&|KvTdZsu_zDo8B#> zq1n;}h(wDy&i&VxvASlh3dfCE&*|t$iAObp-I-%4kkO|Z_j6(rOQN6@j~24mv&LVf zn|L_Z9}0;(l&E80JkKC*jUpP(tya3PELflwp|vUrJUSry)<(I2)h)&)i9P-y52Bzo0)g z-=I#p?twO{MRNLxgWd`Yt0CK2HpI#ZA2+Q8KZ_<69t>PKPi^)-0a#Nj&;DU*1HR87 zhpc`o&f8F%SX3(>Ok&WHSHD5!)aIYKOeM(+bIm6q$fQMjng^!P@rYBT)uf0?5arx2 za{(AQ;`SRet}-KoC`rde@5_L|$Uq>HsxR5BWXW=LFkR@EL#oF|HKD{VMD4I}xn+ z7DU?kaaC^0(LTIRs76CSsgG&D@I%$g?oNc77K#siiLY7iyS&J@Ei7IBImfHE@>)lf z@OCWX^tibYm+IoOL|TqoRG{b-3a+-5L9rCznuAoor^72`i*~$(_&rIC%SXli`Ir}k zroF$`CYt>*ds@FOxIuQDIY*1E)se^)na0%I)xrCi>Fi}@MN8ux#po1QAtmU)SeP%znIO2OJ7k6 z-lt8dv5%0wl`$yC_0iLaSfBpxYuuMy31R2}-ot(6W!;L0CP|ep54VH!v9h6;Ky2st=wz{&ZZ5^<2n>Oj~jTxM0VM} zd(b3yvK3-`-=rLcD0Or8)l~mcW`y-USkf@F+>q%hJB|1&AfAEcYs%8Cdbtqd=i6M} zQdWv-R59QJoGsmt(-w{TEY+)A2j5)Hm%~k5UiH2F_DU;_q2JzlqRIju(i-jDL$V|a zzrQtYBj**PI2>`=++SvotNN|mPrE*nke!gyF+N?XBG>pJ^sYo0O3U!@>$U6=_%zT) zy8BDES7BGmKJ)v??8MH@4^}MKG5xG7kBxTPg0{eox(oMGnfcbG`o~x$gHrgS4?Ko4 zpat1hYYW;O6Mj~R2gaFS&EBNHyo`%N_=~X|#SbJ-?{8hjKBB;z?{(Zl-ilI8a#JcQ zEKduXI?|gOvG#9{SZ8Tow5v(ELzryrpq<`+^Okx^um=w2<3C$MPb{HRt3G>2-<-tC8f-oenRv$s0-3*Y8p)Elh~s za?AHc>KGo*JFY;|Zr)nEWr&nhJP484>r&Hf)4{>F$k_Qkj(a7RpOo1)uFdjtw7cDY zqYLZPe4)7jnx`zl_c0z5=AFK-Jte1FQz_0DlQ5p}gseo+<5S+&t*|bZ%zSy=A(lU~ zztEi%@h(%S&v}ShJD=*A2N^$?)CV$q!U)ep{=cycMKnDAPR52l7!5F0vTstV7?C9_CJo*IZJCHEX5hFBTSRe%{V6_okprFBf0#io1~7og&z^9RJQt$ zG5ERb@x|qg5Kwo`Dd(zK@8uiyi!)*FPVuS zo|0)24sMyKx(%k7??(S_u+o`vOWjqKaC)(oNl4vR`3Y} z+EuYw!HeLzOY_sg!8r4&xP`%R```Vy?v`JqaVjJ`JHSf0l~0Viv&CkX;h|HjiX9DK zU_6{%F=fii{JSA6$5Ki!IVOq9r7kKwZegq;V>28*_h|=$Rf+^|7m2K!$z9D3aAc9jaDUmRo8?u=7h&#; zvGa9=Ie0tX03ZXEfl5LZC8ZV7P+1rh3X_(<2bH;TWHs78{tv+m4~(l*;QuZ_@Bm>q z0<$2rxv#O^OI}ZJ4=2~>j=a8so{qe(p1uwM5RkumLQCakDk?f+Fgk`@HwMTAZbKYy zg9Jb*JPR3!R}(ASiy;$eM)Qu&&kgmB^>O!6j$(C+bs@kGJCpB;hFs=N3jm4G*KE+R Gjr=dd&}xVP diff --git a/docs/.vuepress/public/android-chrome-256x256.png b/docs/.vuepress/public/android-chrome-256x256.png old mode 100644 new mode 100755 index 1c30cc026781e0ba3288a23e0e2f37ee1e553e62..99f29130a4da9a166ed37f7364adc8d798959566 GIT binary patch literal 15284 zcmbtaWl&XJxZd=kL%Kl}q)U*7LwARObV-XyNjHKZA|M?q-AK2zba#VDw=~?v_wW9^ zbD22E2-fO+2*Q?^lhS}71n?&U1VaVC3|;c9z%O)XxtDJt z2=mdy3js<_C50di)z^}eYHBu4u1;@loSbRpB_(N{U7W05+gn1A$84IWwU*`%2 zDO@q!|BIrN1`&)_10Ly582gl&4joS+oGxpINWBeTS{j+6Co>!=I@&*qNSzhy1I9Gk zI$d^j(6{gpzpq!`f3urxJpVIrS2ZQNS#*+CIfT{W-=vrB4 z7Z1Q-aE9<;l@@ewZyzH-7rw&6EcC5t%@Bge7$yvARZeN;qzt>q-G(O_BKQX*w7SN= zP=xstLgHT0@Ek~72Ejk=>r+iA6B#n;GdEj<)Yu>sM!!E}kbl}m(t8BR;0qlQLS`&P z`^Yj}3bGM`iiUJPNJDy@5TTV~hX6Fq264*kTFF6WHBjpy9%cmu!-6=~!$Y1y$nPPO zp2v?ppx`8kQ07=y_=u$hZ<86UR8oa-9fN>$fB}r{4VtblJ2lgwJP8XSpDChgvN-!M z&m=PL0AAeXlYR)wj3ok3dvfbBh*L5+$QNCWW6ZYQf_hJHX0~>>F;wU*4nZrfz9V<6 z9F^q$La6=@ciB(&k!_4HGvA#@T24OVES9v z=g#_=ZQCR|e|coQv^9CgC|gFXWO`B~?a(R+*4CDv;s(WU25nXM?o`&hQTSLR6n6dCdK zTw7PqA?UclscoDIhU9M(v@+y=e;{@%oB0Itx03(-27-*F7}&LbSBiDRAV?}RfVoV9 z;7azWQ7hfEO3K-(Kms7|jK z`&^DoxkwaW*5+`b4eo4=sAM;1>t9kdo(_9X_O5n#`3qL`IP<=8`Xa2tF7h&+ zBBX|hGxMQxcVvP9=~i?;WOq2NDYb;0o|2x*v|Ju7B?B-1EIL0rQn30jM*6rs#h*{> z@h>|_&A7S3^yF9{PZGpD;=p?!F4@7)KoB9x%~5dIB(#*u)e813KWzzU*C$H;9+Y|dYo{&lU#Ux=qx zNgUQ4?c0+5oA?*$)Ex^ulqje>+?t6jg%pj{n#`TF^s7=1*;pi5w-zTq*Us0?B-|t? zZ9V2{W^ba{-x%=<@lWF^m^rla3vvn;3ox}$wEMJT@{KfoN@TQoG}rRc#}f**3)0kf zG$}N#^M&%l3as;-w8XyqzPybyD;=!!1Io$ zbt0MGEq>1SEMBcyuc@PQF-)p{;#=bCK$*g1*U=n|R{;VUh6Q+3GWj z9A2e5E=xnZf`r5by+XM{^+MU5Cccur+_an~>4ulr0XP!f3XFz~veq$!C~2FTGnxyz z7`epCB7$cn>;-l|D6$%)+*=%T_rIn$8~LXzIpr>THf>%}`f%K8-8x+5p2=eAp;lrs zpw3|pk_vY|f8!)f#nC-?q%QfYU0m{qX}oFTN^or5i14=wnU6BKQLnoU*BI6ux*WQ` zJw<&=_f%1NTX{cOL%A;JS&opBkW%+R|3LP@WYY5#5w0oj&6LfQsg$J}6MYYT*6O_K zT1)wgb^V-|`_+w(A^HL@f9PrJzp9iePAh&g*-+e&i=SJk5~os_K55-vc2wP4onJ#% zwlR%5S5oaz?PF?fMq*vlS<=2A*A(Yd@AL6i1PwcE2B(lppUU^`PZvT#9l^!q!PI>* zpU%^SEe>nFA-th!p0(;nea|{xr)j2)$y$?G*S!ro36G3W4D4f16lG7L=vwG$T32vA zd-H0=YxFEFr84E$Ufx{kKHvW9{jm9re%_2{=`VTS4!8G6E~{^hh+$^LbJ{Hx`Kn5) z23S{ZKISmzh}A8gDy#Y7UT|)DKqC52)Foq0bWNClk$dr_aX)`+O;1gqYP(aqambRS z-{X6Wd$0QuDA)f9f;Cb^fJA@+;`N1>H(g7#nBbh{zlxbXiKxsv2_lJ@z~aD-wqiP) zp50HybmyC22V)0c{kcuJYo`p#&at9&yx@<45jKqA@&wQT?)} z=NRD|37?iUWTsX*mSa}-`n((4_}r7BljjHPMqMyt{-;JIY^8-1!F1weH(Cd75y2*| zpwF?N-oOj!l;f(cx2^wJx%CxUhE&{jI!4xTP{*V7+EsokLV3xCQ4P=etEJC0#f(;A zZK-S3G7#}wAfYgwWnizr^7q^){?vnv`#pkR1S_Abe}pRPvQg>%X)3Z6s1SbRIft=E zgu)W4gIXk9`=OfIVM4WVPdBl|x9O>uvR!~t+wZ`(Dg?V7Ol^#f5TBj-sl8XKdK@p8 zs!Xp!(x!#nc1J%OFBRI&i+ZyaU>2f%{2s7OV)jB5w2~t%|0 zb>TR&Pw~F-AMftOoI&IHt!QuaoHl~C@`Tld<+c2E<+)f%M8VcY!nMPzVikusd)-K* zNVjN@ajK{4#wVyoMYJ?xCRui5ak^=m@6rz3*|7PrwLhkItv+^^@?76KM_)Rp#ul7) zi+W$Qf;L9uMrBRKVGB<_PL@g0OujZSGpJYX7af`0Ui7+=ouk1`v6^0#v|QY z-Q-e1V~1_mZQ;APG1cyd)Q04eIzzjbTyD2+awUf>hMuOA+-2YOm5>l~_+CuxObw2F z9mz^OPK;}D@cwbT-MT|oI@k59i@LejgNMuLROfoH&3)dT>fqZFuIjostsm39&1LzS z=5X$H99dl4Ju=eQlN)m$wmHBzY0c#{lp)CL2?Y5ELD1zr_`L-|?>Hf7+XR9Hzd{g+ z(`VyO83^KBl9!Uu@|fLCbNBwDJ=uN0)5I7j&%N~>4>2zbg~)THsAMz&?+06Lq-8vc z1-eAC#x8vz!lUI%UR{${_)(;>j^X%Eq&`@nBXDn7+H&`v{_B6cB-ZLPL9#G!@wuO2 z^ZK%1>~ekZq@S(j{XyMkx}<58GK@|X5z1^?S)~m|hS5=vqd=!ZOvG@QqzEM5f?S!2 z17+SLB7)}t&*BeW5cnGcT;~7qk6|%n$b7erv>{U;A=AM5aj=b_5dvq87zACAdShlp zb3}8rL}fF<*fF35DfcLjGQirWAHM2=y(5Dc9(aj^*Z=y*6-1dA=o>;tXHl)k`g6jz zQ>QR~)%k@SE3tV9T%vr&o(?XDaEpix{T1Rhu6ONqUG0cC%*lD0K4UL~8ieq&SjVDD zf5ZVn93uoVBs7#hR&HHIQPD0{*t0@0ORa-GxI-<377{mU`&m_`?KE8$aJ%5X^lW=) z$MfUIkMzNxU~~-EPL`M6zRn5?ANcwBCPkbUg|%g5WGLZG$OTmg5~fjUFuK}~G5*8q z>gs~2Vgu{zo0Fln3ESsz7qExtZ$9TAVv-qab2BF?EBx1k^o^S2U5 zcD~!4F8>{ZN%EBZqfBfm+Ox<`v#uzzu`=r+>ZebhJRzWC2)0E-fV^l_9UO{9g@jVr znV7;QVC4-brtqxc&v9{@_x(IWSj#7u8hO5WQ094N-|ycA>0aCUnH3ckJ=ESMYg@S) zI-7s~Fn`y0&B==dgN8Bt?%r+=Y73u@YyK`MC>UPU^HfUam4AP@EK#nhCu${bHTT$WjSw3kzNvL06{W?zJ{IS_lOyszV5GGs#O9d}r&*f$JNLx9WY= zNx~IL!lCmxSa_H_01YPYZ(5~4XVw3et~ftG_Oh3yT~4hJqFmtUG_q{XhzT z4KWExA0GV6QqkjA?7liWI`CJoUh(kagS${RZ1Sq|8A=zS>%kpbPDx3*EN!_Hq@c41 zPQajSC3@j(bG;md+jw?%*7oZ1a{v`LHPXls-EC$fEa3hi9o7H+qy4>9cVnL-r7Y zzfr06-b`hftiB3!yr9_K#ahbD%nZ^GjeHng$DTNsueZ1NZW51mZH&l2JrQ`1;&K1v zGVBUAVk!$%&9)roM>3wSe~B$O(gAnZxA(?R`1tskI5>t1 z)R<=Fep8A03afk@In3M=hy2-Bk38}o%SPkX*|HE~oE&fT4G=^y6h+2tie4-SNo;Lx zN#Tg<6lyOnE;=$Shyo;O<#29T*c}}mg?;8eIyx$fc*KbD2{$!l+P>QC_m^inv2qqq zpXH9&oWe9Z0f@e8-#M#KPEMAya`E~*oMrVPJKN_BM^*SJm_<}H-G;9;FYhqZfDsAc z)bML0Ncqt~qak}DwUAp8!sRev>+!#z5TK9nNqrkBBMr^UM3I2}ONyaXhWnwlBWE+S z>{7Nv7ve~1LW5x&UYABAP6U7Oogp^FourRrx;GP#Nk=z?BRk=QD3}16G8LU)P-aJp zu_s1qzkJzyc4S9N7D}fd5gZyi%1Z3Y@$inanO$1Glm%0}`l+1_@7uE}^`0=)7awKD z7AGhF&_8?h=uwaaKsf)BQfN9NB0`^FAg{Q1!&5k2-gK zfQOsuUgI+Fj-H77l3!4eeRnzJ$K8X5?`6-Iva;SAhZt(gz_9T};RnIHx8W`ja;8`j zH2me6X87;vJ-63JM(Kv7Q#GzfM}s#v-hEqRxe?LOhD)6adtzUfANX`pPNeVOzcYLq z`~!|;(8WfgarG##!_Mw#OLeu*$)M0d@Gvixl!o(U(aY_g9yv5#Dj2jJ#P=a8YW+uU zuI{6RN4pCR{I(mv_4diHM=jRPmVq@u=d~XHc^xrSt?z_i&iyA}9Xo%1SRA(5S z;d}L(n*QhR7%$smg{9(Ze-h7`%(rs%h5FPJgQYf)CZi!;W1q7FF7vM7#Kc4vxuti@ ztpV8Q^KWs{BudcnpjPYfvC&ZrBvdRLdZTV0toy^2c651p`C~SNYQy~EVu$DCAEW0A z5n13p+pdDe+ccwC*PBK)ys24)uMnb{Ksaf)E z@HyL_h=pa9P?pzqN0Disw<6){(La9t5+@8vTU$G8ELT;wU}8JGq%l(?pZ5Xh2Hzhv z@e?Pr(E5*?1atrtn}}mn{iCg`8+J9<08n&ld!ldxfRz^v&IHqE0cX4#LXZMoWVLF_ z$c_jjC(Kzs70KCV1&l!RNcVF#)kJl zH2hdLW4|?+CiEjeKi@YtAS|27$;ik^T3=sZ`1qTvB?J@Ckfx6f&JgvPO-oIkpY01; zs&3aP*YgH6+C!9;l@;||l{D_9w?iT_knGeqzLcVixr{ z%(R#&&}I%+tI5D&U}P+ep%gGPtaUb}+=dS#w5kf?T_Bv2v2G4!@Uw#lu5(_2!}-0% zZjbvojQ#fOHq9Op5J=_O4a)iZLDAv?;q5EKo=rvpQuMKRW<;_n16G@$gbQ^_49SXh z3WF$d&~hlfU}*H<+D^JjukyerFj@hCiQ5)zU^KKp4r16^H4K2j`KMMX>+x>EymNgMXWo$wDI z%mM=gUw~~b=^GsU6C4tPE#;20zoM3})z#mx+blk+gt+ua^Xje zLHlAE7Z)D4plotESXdfBS9{mKCQ?;ZMdWw8WBeRodc9CnkQ9A6rLad?c}hC2KXht5 z?^xrzKVPT)_x`i%{FbDwtZa?7l@(uxnBN^}y?=vbDHIhH*e$HA3P8EdjT8@CwEXi< zO;0!aHnsC^*o+qPKgf)s7Ag4S{NmpdxwjY*V!7Tf76t})ny{zFL@(KlrlH|HQ)1so zv-0T(M*;HNDQita>4T+~7UC;y6BzUY5v8j<;|V|i6nxB8wi3DAfsZ1idu^t@y#o(gp@8wmqNd z6w*{=UALaHu@&E@I5oe4h5V8;Zba*v7JjoT)!iG%*e+N75pYL!LqkImuhYK`SZYdll`;2hRYXIN#c{e5c3 zA>_}gsyKA>rBJtY(&ubKS0flN7T;;U_6?h6juKh8H)XmVxEuF@RDrk`9Btq+YA-J@ zW!8hFen9pJS13lMQx~A{>P0Wt%gotQHHA9q*mh#4?Ef8hmfz)WYH+?l^k9mJGz+d%!LqS1- z0R;txJ@^xLGD$Vm>NHf51A0`s0QSnr%{9GPFdcwqxT({NP82Q-L| za`SH9JhWd42((au;I+_X$*Y|+uO=zJB#9u@=ayDhzx7ykRFT(~Rg$4QCmeyb6T z!eO{H(c%_e3J0Kk3PQ0d5)g|QcUqtMw;W#Wl%~j|wSZ&G@v@?0Ua{M5<>5|57#KR_ z^`finXSng%-evQh?+AQ_9+M;Iad;NESf?cHoRnj0>f&KJ$Yf`dPK zUB0Ptn9DizYWg^QLkr!K<d-A?ElAIZ(F#>!HU%=_KnN_t(R^=uqpZ1g1-!Xnjy zI?7f~;Zuhh21`I!EN%@87kAeOirA<~v17O~-IWe=)dO<|iucA99!IOw!NJHHxDq4Q z89rU3TdrPz(ZRRip94Nk$*7Ww_ldY4sHT_?A3mHX($Et`Sb!#15;08d-+X`fegm{z z5f~kdD;l1^Z-`N;`=9l74=Nm4PWd_nBvf7wqsAA(?JH`&r*Eg@o+^K!6!Z0_dR_Ob z!7W0IIUalAgBunALQKOY-|OP)yu9#>3w9QkJ_;%-s&yv^MuG?_u+s!|!AcApPO>wQd!FA!quTaFQDKC9uWO!qJKVFB%8pCPi8O%P_7VvGuQD^m)+OXMnyB*CkTl_QU6vD+=x#_;fPXTMuhN*u=BA-_AGguV?2h7DnA zTma;lk87F6*Zf(WhlcL30f=Y0HKeW2)5K8ltDJ)!7!jr(TGDi`8Ojh_st0rwCgrRk zp-w33d*jgws_Y=pX!Natx*o!*b4cl{hRN48a}f!L0F2|)(j2h;+hXwGZGDLx?m&GL z)WOW7)ZN_NUclv$7LcnUpU;>i?Bn}OEn=v#3p3V08brm2-PO{o`C4mejQWGNjY=H3 z@#N)49c^ut&Gq%#R$|D&zge#DbZcx2h)8FGm5r0j)AJ?2QUzsYDgrsN$rb0nadB~V z0|Nt6Dk_p;IL`@*iS_B}=?Sv>T8T4DTfsq}_FC;gr`sy98%z}_7#|-G2>2HSkj}%= z(eW|8@KTHKt(TmmV+o$bjrcU;DbcQ5gXzIy6J^Q(v6KdoX8McXC(2~-aEkDj>k(NR zD%bnl^C|pU#A!5K>JD%=c<7yR5E1@j_7w#NBC1MANN~Pxn<&)fmy(hSM%l(qRQRzA zs+Nu~MVSz_sJ>p%c5^W8=h#-TxdfhnYnKgg{i5H!4>_F_Va3jV!-1pMpCs!qti+KN ztzsEM_S0pD0&oA|8DGrQy|s3>w6tUioDT$DI%@M|NK7{|A>niA&T)T+7)@AMn4;Rb z%;laNuppL0NQ{Uc(% zIdH&Ak%Ys@URgnbUYX!`62FsC?bOb533o&U7!xS(owqJ7azpz`OZRu@lb$Dk%CGe2 zu*i9tOaaK_Jg6}QxgQ!K-iK{y*f14jaR?FC7s=5azUL;Seha#is+(Ii86DvQ+D`C8 zm!_nlagsq!_cba_JejpCee(0?PhRmF@KvzEbdf>*etV0z(MUTjiOVtzJt$=baKHCuGYQyXJ=g>N)^H(2#j?{f&r4$52&Hj&vAz zo9P9R&L3eMHz0P(1ZR>qSdGP%XBzS13E2E|P&=OUj{LD>s?N^NbAc$B*`G3`F83T| zK9UoO0E2?!J74hLT#X{A(lrSaJY^?0|d!%e0+TD{z@?bqV|!Ik;Xe6 zYkNL}YLhm^l}w2sxdZe=Bi~EQ>h86G9nduI0!D1c8;`muI;_uuQ}Ol5c<9elBr;J&NYsBtvPO39A zGlzW*-Ltg|bv#3HX;g$$N?%q!UEFeoyQt&&FaD^gIPL;VFGb#rk(-;_kgJ?R91M%W zye0=m#NCW_hJyqQ{|V}ATU&yrRlt4HYHqLf1WiQG>_qsa+=U;ndU;^V&~myu06oSgXFD` zW-6@32X{~lDMR_IPKgud1$IjVJl*GIq$3aE zxvR6CnX>IGff(Uqxz(Sq$K(#~-hvWkzxU!Ibd5ZvKft~rP+)~-QVF@$E;zblYSF>OV=_l#t~%xb{I;mFxjiXGk0hl(J-xkL^uKC0kqVBLJoX3Ey~*D1vIz22*lOjTj*zy)hT?$u<}V%e8K3v4Og$UcjT>a(4x$V}7* z8NhX2fY*Wjx-L7L{w`lLce$DtCZ1SELP%K4VOT5P7`#+w8YDv>DW5fU9K0n`2IkoXu_7x7hJIkv~BeH;`^9RPOK3nQL~QlCJ(yi3v{64(Q%nHo_ zbcJ5GIW=ECT?ICZ0}Kl^pS0FD$LqZbDf~_Z1FN7@`ELD4taYgqUeHT@MF3eNJE7}z%?q!x4{pnY$C zVRASFT|8oMWMDw?_U|yA96JW0crZT)hpH1_N<^wVkmvm;n?svuXlN{%7(O_DfBKXD z0uJc(ctO8dubf`JaDq>Q2vkJ)&Q$5t`uaMv9V&HPgb&gsW(d-KJ{9R03lG- zYr#$b-oI~y;DN)0{C5VCrW4p-F-ryGzX$wb7x=7I^uetgH59%5{a8(aANGfHa`oKZ zUYmmzRzrCXLp)4*pxz~AWuIK}#&E@MoOklnztN7WoVekg&_ZnrOwVV20D$e}ude`4MF!x{NhimG zis+ns)B@sxZoqqnq=UQN{jTShY>6;Xf^+r-rVkoVq5D?iw4mx!s(klmod0-XXshp55p%yt|w*8=HfdMqjuItwvi9@XdP zM=(vJNvlT#XpICe7GXiz)be2R^T_Kku^S1=*#khWC}yUoZ4eOrXO>PuyYGC=-Av|RFZko3A`_GV}UjA1~!y8g$FCBqO#I6kA{(CZwPU?!u!(Y*~%zQ?}p3y?|2p} zSe6>8`(68Vx%syo<&>PKhA3q~WMqq8@A5o+zByo)#XuN1kY+){Ad_)uyxwo18;!ZA z^97i%r;-1qM|yhgs0`4iK(f%+5W-)^Vcu6Y=G`~~U0)S7*jZWo&$=j_!tqw#&<*nd ziixFHX*Hlc%B7~S&)hdKVEN7WtKm;E41epf9OZf7eXVZXQ#duMKZ#c`H_5wn^794W z+p3wFS-1=GC@-6^$0057U8-myAIgt1<~>70vfnE&KG8{z`(2G?5a0)29@_!$K?>v= zY%n@p`MS@aKYzs)y@1T4_P{lSQRNQj`wROZ0{U!qaRlmMDIyhA+_gv?AI`A zukh1!s0!S^ilk%^+1a;4(_4AS`Q5uJ5Ubob;Ni>cCUILTv`gZOe3x22eZ*7<-GO9b z#-6Vs?YkjJh1L_;3}yjq!bTjP;=7}cvD=v}X0xr*m)DYD)p;OM$OI9{pS_WXnU~#L zuG4G)t>haGoU3t)DJ(5@lDcL1{=Nm@AGmLO)edt6^19fnB4=OD+`brpy+wk>$`Kv| zpP_*eBP8~F>f9c2%i%9f!hCE5)yTw*072g!gLJ{=oQ1y zG;?a1KG4sO0b`<*h=^zb;PqodBBF^@Q6IsG?^x36r$DqgfLH`?RmeHE*r;i?NR27H z8j)AIva+Hg+a`H32tpQ}1=!3rzH>%EwS!~LU3=FM!7&oHLUT531KQ!cB zSGu=ck57(|13`$E0*EzXat_5qr0^SvK=tI3@Nn2eh9ikjdUu747(h$U&tH@Da~?F9 zAMeliiD-X?OVUEVh$#cng1`-Vcevc9*dB^KhK?KOTPwsf-6Q_w%>r)J=Tz-HuzNx!A|Dzh$CGM}Dt3+t-{2-yZK;(Lyu3X9($)5o`U`DC>deX0ZE(f4t0ZNhZL_|acmG0CIKYJDsx#H&L z^o99()(ZV%@5H`NS&*z}93&|G7z7!~dqcxiUC;pW;VxpO1c_pp{(bg*{10^N^Y*r_ z5h!0pPfr0wup8imNEd$pYL}^@ZxCEvU1beI!*#3YayerBQUjZ8RDksFsEb0Yiz6i)%#C^{<+$ zi;Ihzmev;&U{cou%j5~1sfVWftC%A~Dk$oW2NTM%|0@@{D~sWyr#H2zSfs27fYOPpnB5d0&lSz8f&%vedbAR{g;02ViuR)YK&`tgQB} zq$&G{rGG%uYR6;MZv!}-0~|IZID+c{TsZd=a9#{lQeV8mHlN>jG9So5_6O-^6_52` z5%6sJvJ6VT))vwPh?|g!de=S^6T4p`HSeZMx0|VUFu2W@j&$@ArhbGK+dNcdH)RX7 zf!h(FkrN9Nhe^lB$A#b^dI8Z7uW>|mtD@m{shd9)yFU@D2bsA`6c;w);Ulm|Z$Zz| z1$bxwH(?Fs-&t7qS{*kJ&yK6$t1~L{g*9Ld{5gqxso`||%5>@!2@g8JczkOY=5L`29 z3bdHDy}Z06RZk^?@tOe*n*h!tb5wa@3xRnXLg^}p*`N8u=Jp}Y zxK;sc-7!m1F)>ctTfU?;G^HG@tc}2&Kj%j{H`y-`*#?n~)U0lpYyslCHEl~qB ztoj0E+yleIY7S0k?T3fX?IYi0`?$Im@8}^VMMXs)Tib#x614jmnrk3`4Ax|2$THEM zv9p(`F~>J8;>H6J3>ssjG0Y!Clp?3Yk{^9JFSy{aNU7{;3#>s-bUmX=Vt77{DcM#t4il8ev~U3j`s`5 zrLkJWlF9U<57bRqS|H(Sa$0Ie2p$6+9|!$Guwp1N@*JP1^f-h+JlS3|<` z>>2v+fr01q{~Y%WY7kzrC%OUQjsa-*9@@fGK4gZ~p4br=dL(@f|;rv|1 z5wDoQ5W!x9+a7^Ql+Vh(18~Ta!9V~uyeGJxRPIa8>lFYV@yziGQ<`TZn&%5iz+Cct z;P0|&szoc_H%Hxefa;Uvs4*cc{P>IyL!LI_Gt$+~y*_Nml?KnL>3I#vm>H<5 zF0kHn7Thm6vEoG|HsVx8-y|d^cDs4yWHOBbCub=Yw5Vr^eJ}Cx@v*wTa+6}!R#i=C z85u1$0yMTs&IuBFrj`vrU=GArCNd)U9}5`mA(dRs+l#dr_t`_hdTI+m_*lPa!Ts8A zV|NimKVRbGt4fSp?#QLp(~jo44B4lyz^uz_&Uv)IaR7GSDk&-D4qa#X-CZ67B0|<^ zRQgZ1>tmcL>4Vrk0|3-8`O@iEM@L5&@cRp{qwo*M^EHdTMKdmHLqHJe=Jrn;RQFTo zgfe1cVm>e;V=FiY73vh%12=P*)9@;N?*MFf!Qd%6U&`JcnA&iBkv3S3lRm|xk~@~1 zkzqWz;+&d>hu{U&kbYEo69-KE8c-%%L9UBefYhoaP3`PO)li@8)hrb}rl${QYXZtN zZ^E`sATP$Wa)uJnGq!^cOYZ9|$uL{4t~7LlwHH2DKNXnc>*X?pK(^^pI59iAfH=H& z1Vzbwdjon>GPq_zx`GEV`l4H~N9{p@fedL?`M@NseGQc23Ya!xDjWiSbLmG?F0;QJ zyF~xyP~mbo+xKdJbsEF(zxz2kI#zdfbyaY7Q4JpStQ{GaHvQ9YFVHT8t8WIq*Q;?_ zT0E_3xpjcrIjMZX43ndX`+n+!2_wX#QCGhJ(*w~XD?9sB?*7j1?wtoFs7`_^28X?& z_Pcqr^+;8Cq~2*sbYE4d-EXarqvdA|DHr0sYndOYw}jA8R9tCwR#IbM(W_^_&w3um zILky+UVbZ&0iH)e8|jkdu?T3=JP-OLyq~+&b`A zJ@8R_aBxa)zh5>U04Lw`^8p@4NHs963cc6qwihd{Rhz_VIpZ4J!O`JxbJ9;hMG&D3YkBh&h^1gU6 z{SnrvW1z2p!K>`PgOO?Q(I2Z_jW{wydfG$Sb*E_3T1pyhvre}$l6llC_NgHqy0*49 zLh!MV{2~7Vt4iOInrA5kGOK~n=4NKQ&Az1o(8nBtjKaFoCTxi~u^!d3Kp(Qp#A!`n z(m^t?I-g5w2M33*rainNeH(ZE$J=fV_+4d4FyzDH(5sh0CmzDMrWr?`M&WaXpKv%H zqaX%^b(*dC6G1p(L4+6;yR%@1Bm%DjJT4%iUD;dFOC;G$A38Tr{P@gms`Qn{c$vf@ z@iAV>v7bA+kJO!=Ipse%PkyA}_f8`pTo@gtmqC{GqNAfz;Y%4nE`n%-^?(Z`HHQ_i z5CXDb@5^sVAOdGFiIV3#B#i04P8#Vk;VhHWj6!M(n%lEtCC0qfL;xh5^Yf_z7#fj< zJ-;|iOP-yb4KGQ-rF=0wxOswP0A*)qho>@)+g9BG?UmI$i~4oo&o)3+(OxGiP80w1 zPP5y7q(U(3vh3C%0lb`sh3Mzx*mn_7=Ji3#lF~7iU|O`O=kfQ_Rmo)l6DvUf;}a<; zDxSbX;DkMht$^CD5K70UX1tC3@S&)0Gu0Tse_ zPD4_oyBL++wNx>`JL|{Rz$}yUS+L-iueP5dkREfj(_QLbJ0b;lPs^R8l*O=tic3v7 zzF_{d0mc7AM8umYQm*Xu@56u=kyO4}lhGm3MOeJLy6OT3h>4WPl1v(@++^Y{KWKp^n<0EW&ufW3&|*TD6?!GA0>-k<#3PR$xMz0JfXNz|wQdqoBJ z*RoZr-rnA$7LTWu9!F-yGT&C{YO&VOO`?tf($Caf^P|y8fe5x2(0ujlc3d$m20awy z7U0EtjOVFiKPVb_8q9KPdRp(nzV8J-SHxoiFJS)f5IlPH7$2VPPYen-P(xFbtKM?v zpiC&IZ$rbv(lYB|))I83?l`6_qf)0-J_qvi)y_za(et$Db~@U6dV0S(-m!v^&E>re z0s;)eu3a#`> z>xQQJ$G(doWZ!vnkYk5fkM;++0DJJPvL8IR^xWK|#~{-&>LjHQJY>BE-HqAI+*~Mb zh8$#|HZ7NbD5&=D)XqeRiRW+s%{lEjQXmPvZRq=^#XJBaw3Z@`{1OT*R8u$;HJGt?v%bzc2b05gr(R9upwvv&Nap$&} zrmL%K8<@tb|Ju`su&0NIhbch|;~#kk=;VW2pzA{v0E5B)0;E=mkXq$01Qj-K?05T4 zH8*!B?R43CD7|>&$b;BV&t)J@=sdK0t^C*5zwR&o9V{7lnU&wrsXnRnyT5apKgr*I zFAH&YMT51U4DU3P<KuTn6yNmX;ua2Wk94W_ zjiiX*-A&4Z4=<1F-{CGWvsCC+H;N$k3jIq$0-wrP&aB@g&CD%lNgx#|C@WJ7I!N8D zxJQS&NO`cvG}P3FAH)K)vF?k=&Wc75QEY(O%D)^fB!{Z{1_lOTVf=UisovS~B_$^> z0CZaQot<4_o2qZgJ*?GX-m7U*OHEBp6nwP|PT1PscU7@=vvM0C-28x1T%x6|y>%<@ z5YXDT2==NOP|rSv9~B`3R%2cHU)m5wBSuA2IS zOPv-E85kv@2HxV<`^Q3QDw|*`LJJt!31C5RK>GJ{z^a`u<>NacvxAr#B(e|Lq!CiT zz#eyOo_GRX<|L`3li&$3tQRpreE3m~6Z)IWLgqgrQ)@#$$M-XtYB zFbQJi7*u{}yarKQ6`+xb0Oi#p@IC}KW4a|PXbHoViYoh{f=k2EOM`f5qs zni8?$IS;xQaPHnCC|jWJob}2;^z|DYU&9RwGA-y0jJfz8+x}X6wZ7~8V|3RypnIpg zIl^CXS7{Y6#};KNOFg?3mJ`#!??71#+s`*b^eyCv)0laMCQ-dhX}fSCO| zZz>Qzuj0Jhi|2MH)k0uM8DkK=n4@rlRnOiD&Ywsc{=;bn$#+NU9_Z+Awh-AXbIXF65j^l?`*g;ggZQ3>G z&sjt+3C749;3CaDn)kaUuaJCca)&NRPIlAYZHwU+uZ--^t$1yuh<1cnQHiC^lIpVL zwZTn3^O5xoEvjy3M(ceEbTW>kHJ548((r3`ST0miuXLJI(B|4zwJQRTwQuhie>B=4 zckqD%Wqlws2MX?+{JB1?z@!R&3F95=4Faa7@9tR`zZX@_eDTQ-&j^{l4Fwt%j<Ss=0RomFBfM1FPA5`9psmh3T zPL6oBsNeqOFL_|oe!2t+hcs6%smH{Hg~dtX07|SfY2{2cTXrckB<1oLg?#n zod2;1y@llal>g*uML#@19L=DFtjHTwOc(#UIm7V^_Ba#Z*PXep4|xT>iyiY)N2!a` zUUH%1siiN)NyT3^tl8BZ7!PAlkXfP{(HUG9Mj)7Ri@U@yBTntNX}=8_U2lz#rozbu_r27yV;rR(V%BB_m2BEXQcAn*gO<^1z%sW>cNF;jU?P^eZ;vq zS(I3`_dWlh2{ zEwC0#08^o?YZFRwmf7!f!HS;@`z&Oh?z#RtU~4)Qj5UQ*)JV!%K~s0vy+POed}Svk zJEnc-kH` zZih8|s`&PRmK&Ea`C)rF?E7S;(Au`xQ_8Y(lHhf@D|;H3vfWn3j#s89->xGIpGuG9 zwb+1OU6K3HRW0g#7{=zLKi`y{x47x`hdqwqKqr)7GinOTJ%ENWhw*Rf(o#fm_YV(? zThe1cZf^?TYRRrTa&%KZg=*^RPRHs>uB;Av%4JcW7Le(B2IL*!O8+Eg^AdbG6S)#j zrinOK!KNzrM-M4t<9~zeoMMitH_8AX-AV0%kQbfFh9iNpIS(nIcFg0ra+_1A4B^5B zzBt)U#3LQ}EatxQd^5(D3e3EC)2U5BfXrjuuoxdX8n@6y;a&I7*T%vqDpEq`Uzuv? zv5S*~$*z4P5ljO9a0{&h1(raI@{m4#=9w(xN=}))I`|bxp@)+MtDF^)b;y+KpFh`c2yO>uif+L2gdCZm zQUv$3>C>tykNiVBhXYl}I`xhXpGvrPWrn7&Ccf*WCsXPsv)I}PbdMVkM19~YI9 zxs@_NeVBF~-fU9X2Ffw;zaVjTGc$}J5F^qcU_k!({O|H`7E+zy)ZTRy(Yhj;gV?C% z5BXVmZt&1?zH*Yd`%rXRY|{;?$wm3|iO-tWBda&8tK{{x zqho^y!=GBB=upUL?8&xr@~!d?%c~%3>FEqGn9Zm9g`RWk%4KRt#oL)vyGys%=0AIx zXP4{{08rrKP5}2$K0!VNX0ANQWyE}(!i0-WvDIf_JLqYf>6wJU?Q8~xCCt!v{|QL`3PT)Qyk!O%Hh~Ha z`K$Vc2sYHex^H$hFqLtQ{IHwQT-La5z4MQMZz<6h%j<4_gUy-^f363GBvrYCjRWzP z-KP7aVbrzlqc@c`q_CSg{%q=%j0ZH;vWo}ZpB<<}6*8)|5jsiZ6^<8!NKAC}@LzGz zt7g_M#T)uNPW`&RDn_vP?d9tZcd58|C=5TAlRpK^H+HRQVvBhV=_E1tJZo1&1ClON ztmBkFtfNYG^^GRGCd_}OF-kwfsNS>v_}FW7e5S2J=!S{x*5Z477JFuiRE#G<3U(w! z;Knvz^8aGWKItOHpZM3#TA7?>92f);sxnA}7^5!I{&UZ+CW_AjS^l@~t16>95cshp zJJ;`(sLqG{3Y=mInj2mBabLJ;#{vl~BHAovOqcc4gdJP$v}x~!`VJQo_E(qBPb*h4 zGP~lTdJG&!nHelw&s@fpcPM|KZ~SGyO#f?MhdL;lz%n$QQu8fjo7Ztg^ePo2KHK}D z>KY{jMUBO?F|vxJPx!8#cRGx{pMDPYjaW&zVCAAE8Od-S$I#gM=OZrt^y+}zIK`{1 z2A1$qx_J#Fd?`JVmZpTx{tgyMO7Sb{e4fnoc+=+M#`jYXzS!~;u@M*@Q3DN(RaOvO z(MTqtzp+}J&BgI{8I^fWO#Qqfp8t?M*EvZ3p?*gvyGAluKj`naWN``|2MPWgKipI| z7xjc7xqxJC0A!WN1>hs0YpA_2A6>X$zr8^J!wCxAtyo%cc3dorX@Nl!p$hI}pK^T5 zA|}5!?qZ8yM&A^7!lz}`YYd^FR>9yPJfGkZZy?*!h>pzPYqFew?zlg0b&d%3Eh2Gq zaFB%NxPnuG*}IU`?_l){`z8*r2NlTt{oPNc-TeL~&G;U;8aZ((8v_Mei4!g}Pk`cs z%R8-!K!oniqhAvS^N>}r^$T!WCI4oC(!uc_RTP_j*<~sC9o9>8%YMwJSaE~aNBH)d z!%xLC>PcAGC8mUph0Ob-k`vTWBDz4&M8dj#Bu9 zVLH)&upj#JP7f07tx^#8oHWeLsy4*An_AZuSwi5FSOV;!62KNN=Mw0W-IxPAIgwCg zNN0oVoEzne`U#ap3)h9W*X>^zJ`K!F6#X~aYU2lo7u3&`7sHxDe`hXFzU@7zrsUt+ zL)1`BkHSk6;YQvP6F4&)53r;%ILgOmg?!j$Id`yfo}}f(lB**!>Md~_Tuy+4l%cO3 z@AgNiMx8w|Yu;@h_71tWoOs!69zYwLQdo-K6|A{P%UM}4T_{#jDVI%ubUMP4ZvfJe zjWrb-d~}s)(_G%wBiHE|6k3<(N$L*=qhl3Gx>D<^_jO92iO~Y*ky-r^&b_{+5`93% zs|>($^xJVQyKMVso-*gDWObzaQRFvJ?5|F3JS&0cU8zCw38R`;Be`=%M<7L-&D&x|zuK?GfCQbP_FaZ4>17sbr{KrK=}2MC={H4iD`W{9*)T$nlsn zU>67Mb(LPW&#{agLg>Oy?Vz$~7Mm9XqrXnQ755|f2l>sgcLZDpZ;w0nzd96V6c$2h zhEjg;sa2+CNM^*8S?Z*d;~PCXXLR-ld&Vq+w=Bl@TDx*i#hoV$?C?QlKy8C>=|08& zr5C)WGdq0Cd}VLGIn6mb&kDR5Z%uLv<##cIV=Z~nK2%v{sG;a3l>+W^wfgM{^#hLO zV@rRt-FIDg)4*BdY4|JPVlvY(dEs5T?(M?MsKc=uVON{oA`&h;Y;i{MR&!~}xBEh2 zSUFNlNmh0oMTgwV&Qn?DsIb73s8 zQ^@+?VZ0?0Xsv%GNxurDcrz4WimE=n&eMJzMQTR|m~2_F1Gax_DAc!5nw%13tb>;N z-Fh8o?#Ej?64t4Co;Z3Zy;9D}ylEpud?7-9Fh`IwCsGB$4BtJ+m#E%>g~VIMjn31H zK`?J{JHywfykPxX+UpkA7%l3-@0%MKhEe6qokNvK)EcubUeki&3d!tOLlK>`5zV7E z5vkJXl~M3_uafc0x?%{WCbx7P6*^c@ko`> zk_?0aWJ80tle6~nz1@U$`I9@Vnhz`Fw8N1L%1MnoqWbg~@fDPe7tNUzd&#F8^7_?x zemW54<_QC!?g*)ce4A_U+z)Tdn1ZN7?gTx*?Edcy7$dEU18`I8BlCfqnZl!Dm(Hz1 z2YoChACxr<+kD_D15P%ZWDKM}d?SkXj4X>twVAe-uySx9MXsupuw;J{*Um3m>xj+a zEd~;ZGbA@f{!s6yQr7(8`kuU}9x@dlT%li2nPi-fBkP;C><9d?>c?9u*)2zv{Ljaf z+pl%lBy+nudcdLO2?J{X3Dm(*ftq5^u-{XBeGJWcgzQ&w}X~0 z^)9^EXG2+IHUvvI?&J!~i;8WMW`#p(n-9|7FV#McK&2Z=x7@$oSCN|lvdmn6 z3-5lFI($Xk^_a7r%!GFW5fyxDx0G{JT!uKWp74JJR9P{D$~z1zOiL6x!)0WnXICCY zVEN43vt!<{o)to<2Gu5bx(45STjGs$!PKN`13cZ-cKC#3`%5xY9uCBT$mqu?w$$dJ z*!Un=ypC+O;SCGnL`}H<+6=im2lX5iH`GLAt>OoEA)cF@km1oDl_;``0mF@714_ol zqCclshAop!Y;Ul6b3a(37#R+R?@z6+Y}h89Q1;|2nrCsu7)RI$>>P4+L{$7?pqmow z5OgRW9RF8Ad-m2&h&3o1pB}uW3WE30Boce07RE< z9gja&sqKJ=<7iNrC9rUJ?Xmx;1etbVRG&LkL#59RF ctu$8zz6x+h9vZ6MJ39g}GqE;qH1tUR4?GnS-O#yhFwy+yIW}q>4pWQySr0*DFI25mM$p~5Ky}L_dj#q zyg6s)%zN*C-*@l*qSRF6aIwg-006*MkeAj#&Q|{q5IXYivX!cZoG@MF^*;ar_KW`q z3XqjU3IJHD_Ar>5nw_(|^9MU;7a9c^jK;;y*~Z?%8UQ{n=W5z&Y3>t?U9F!(72!cC ziq0A@K{OiBm>{A=Mpg(W_$?e#xb#xJk3dESjbfw#jv5yi^y#HKJ5Ds#BE}A+C@!=Z z9{ufZ)3^BjeAm^l@yC`0@x7X}+@?v4UJy>2Jg+)`5KbkOn&4;X@W9aK4yR-=7QG7q z1~pkhK0MH&0M`McqHMIi7(D>W$60I;(5sx?`>e?M0$rJPK{46|7M6)$(+hW&I;HA_37V1dwMCE8Xe zbd8hF`gF!qN*e`DVi{zZd9vEtV825Z-{1!t-if35CUR65TcTbnGJ*Bnd$+Ct;Iz}Z z?*}soHOMY>bJFYSMB+iNfB^`yQAlzH0266?POWcE62l+>kS+*jZIGfk?;~aJMW^h0 zzS@U61qzjG?C)g%hdMDkk#Fb8AFv(P+z4 zor<|V6N)sF?MM_E0eC|0Bf8|cQ-T}S#eU$lzz`LJ&E#UA z1Pb@2s_pQX@#f*PW2FZgH8=AjE7wBOwd7iJi&^8_ySHS!;9b65bn6TrDedAcjkStGEdu^{ z188kwt46(gWW@_Uk1V0_P+|qe(%PcbS#moPyDR(p-|ig*YpK*K=~KEhWBYQy(|@C$ zd*R?lybK+N+cJ}7lVXtCl6jHVXDF4C&Bl-oYrPiaKFrw5#Lslr)?;mD^?RB44J-9+ zDq|`IE0gpE$f!))V~YHlNx@@WW*$A8$aU}9i zVW+g$7pL;$jJzI`pgbk#@^$a-y<19ut_Q6L$J_D?IUGIoCLDV76`ToD(LsJ!XHhDy z;gx^tFypV1uu}6>^YqQIM8vdc@tka|EdD3^A){^jZO0+Up<+gKMhK&#@`3VkmWDE- zjHOIONknOQ{QG#(_j z3mn@YN3Q07=gViw)93v#^>qaHQ+;<@0y{tT_4|#Q09BZ3ux-m89hW6nqHgU%LtCj= z)s^`PiTI_sTmH8Awy5Ab&$_HJ>PtFR9n(znuS((Bo_+^RzL9B=tq#j7~q zi7pFv@O4NGaoXsApVQ0LQ*cnE6yjv96L50q*|fH!rt~J$>16>cJVHp=syoH zC$8iqWEW18RD!F#N%<=UX00Ip#Bln;iy;onyPvAxmX>Q;U>d#%Gh(GyIhAKs_DTAa z*v0QnKge6kzKaNBs!Zro!c|(!7S1Ei@}zO(5fkp_4oyl-aD`Sul#^R+4{U$gc#hRr zhc`YBI>oecQKw>zzHdsXd9Kfa)e0^9t!2Qxz>3jmYprYZWjyMeP+D~!+xXG7&bpi2Xj%r3sOCx@s?NAPH z_*Kti?ui!%t^lrfY|hXYor|>h&i)nV#uYWL@UrJ8-*9jf2Or{@pWeeUH}Ug78PiRyd5J<}SsU)~RyO}0Iq{FIxT>mR^*vud_d)atuu zIkE8$-}$5i?7lf8^Axiu(j_usblUEI+PJd&LbqKvt6tdD@xc8+^f7r>b+|L9Gpi0^ z^d52S)7|20bG1*ACpfWo-tGO5_-TGFPe^R7`^?ArYVhh}gLo~#jp<=xtaHhW>A1E_ zwafHe@BB+qAzA&(Q2!8h z&*(>9Zj*DJyQ4m@RWGWO;thP&9Y2~t<|n(G&lj3g<#)+s$;nS>s2OMXmb@G*NWV#A zDX*an06q)=5EKdkH&4iU9{@aF1Hge900?IQ0Eu&w>7XnC;D1z*meTsT{KweWfoP7R zyXi!3rR8X*6pdB8fan-ZL16sciG(p$?6)g(B?a>lDT^_|4>g(F0?Q4wPot z^*%rFk>&p3YNK&@dlLs8H7O;{{b;C_{L8jtD&x*n2?!y1DEiSyN`5zyuaaQ)2S)Y&P#k8 zhE3&pFftc39L^5QZ_FKbz0Hrb4C<$3=iOWX5an=Y2Cm5ZbNT%kOR zd`u3!{};*4$vIKApWvi%a5!HJd$4~mA5&8MM23SNu+ihcZl`{rzHJ>HS)?qGcey(ba-g>>y&-gQy95AGrqoShD+cp9Yqj<2zeLx70L*j=?iKlCtu>ODB z!~cXn{Q8)y!gTbi&gyA^6NmCmf zZ+1y$J3I~tZqD`$Q2_YL(JwC39)|+vXbj*tAt51-<#3#~hNdP503f=$a`X{yrTa^^ z`7hfXmIx`Hvz1J9SDJSFq`JJJyozAq77@u_?C_}8RZsE#5Q+v#Ie9SF(TPyb6}~We zi{mIjp{uVS^&X~kB{?!aeo?g-#iChehV!*S>J>4X)6gffircd$+sUDqG6a0k4mfh< zP4v)U{69vWYZJL|T>Dq%y;#}U{sqB90H9)ae;_(KT3$7fE*qS;x0I7Z3C)$_FzH&v zhU~1wR9TOunIG_{V7_1k(<{u7L#{Ba_a<^PRLbAC6c(C(2{@mt)*X%OG1AqQD=R5c zdxxTLU=S_qk|NCsL4LnI9Iq=EX{4tIzh(M|H}^nd>K9xYzJn|xf3M@!LO!T4!og5O zBc$>uAtiXvt%D@OlDFYno~c$TyeG}u&b7) zhB&ol|5>PiMYR|V3W1Aw9e15{Ye(Wyos!26=~RADQo`{)UKKK;D?ue_ci*2WaOXz` z0*n@X^cMZ$8(TeE)R=yg&1Mq4D>=mR=gw%dN%h?FJJnQ^dXhLwp{=6>XVZ2Ul=!Hq zO|3*GWa1B36A(TtVs_)|xh}fp)FI|H`h8UP*@Tsu8T2+Z-|tkRfA5T&9Kx!lrG=(X zkEAz*`@Tk-HO#}qW2ZnW)bHKrYa}_yeOuocp$Ri56+l*qJlD?No>!Ymg2dDPSpkmI zNCHGF3_b{_kzQ)H*G$m)z41lDe|sp_X#s0|eEbKTfbPf6Sha3F-U7<+l`u0>S$qls z_KHws#HUoEdmGe|S#_gJZWuL~*N##Y3r4iJzp*P)R#jyZqgIW_g;2p|{uMIpYy>`C zFfcLA9w>OumMM!Jjj$qPG4S1nx7@^5$oG={v4N15)3ira9?izahLA|+;yNpwUSV|= z@c|Yk<4huB=T7MMZ%fA6$cVCHU-`iy!){&=zDv8KhZQSfpUJ z$$|m`w?9$QC(r&MIr;z7aYYZV)0Gq!_K{c^#x(~#`20bUlf%ZN7X7U)GC>>@F5-X7 zx4r;M)TuKfqklFWN2Pe{*8^W_XB=yM?R9MAk_u%4IC%Y86A+o1!8-iHmi+4LCiBeg?Beg^%_0uG{oNy(v?1EcmALqz7B0XLNK_ z%h;F-r5KG*nHMSU8giIM9qyI7N%W9+puX3isCjKZEt{mr#KidWtoovTdAzM&Fnirh z?pdqD=CMD+AWDdt_)^CF>Fz|Lr>BS7N0b^5IsyfSBR?Fwnh-f@{v%B($Vl;la)4A zA&it1`!H%i;4m7|^?KeU8IL@4wd%!0XvgqE&XoWF3t^81UDl%HR}v%4$ytf(Q+ z&)S*+Vb=Go-S5UNBR}7H$d&T(d{(s|sZ>(R%CT|uqk2tC-%CqMT#z7*AQ>U?(Oo3sQS(>pzFdF3PwgVw zJ&z3VLuec_9Mf$k^Nt`2Ne3*@u={(zn&d%K8bI>)dON7OP6Fk# zqj99%Axa7g=F6l*$49)$ow4A!?KgpySQX2GWA}f*;@iPssIl8`Obrbckx|jD_`0dK zFdiO5%n=>&77G$th1^yBvO}{$Z9h}KUx<#buI8J#v)I_!@5r)kKt@7#?GlOHv*CX( zo}a_gt&Q7V`qFcA9SfMhk*nP#b8&ImmZ|0+tEJBVZxG~6O-%BP!C`6N3KSF+{)A(b zlmw$<46Sx~C#PDI9k?gzn}eYsnlKk6^2AwXgGg=br4V##)@qtPywFfk!2Im6)c6LF zG`rB$)7Mw{o+C87`s0Tc?sb>T?GcQ{;6=>vxp&r=CmScp z^qBT`c6QoZqHJt2{)e?~4y;Ij4R~)wF8pg(Jr%xaDCiDfJR^cQ>L>XFV zaJR>M@5Y*%@5H1KpKcR!WCtR|zQX*yIemO|6mz-b)vH&NHKt#vYinyu#i-*yKHPe| z8_(je7`MTmVM8DgCV|V)`83vhC9#Cjl%jF=4vo!XlACiCMB%=NUj zWv;QEB2H`DkxtojszAz!qF-&X(OQug=Y$|;LZ9j6%aiy#=Bw)PhOMnF`P!b@%sCiN z*gqZ~eskxpf9Ufs<`u@KT98h{SwyA$_NT=CUsz3~&Vmm`|AJ}Y5oWQC%UEo?%Vz(t zJU)_>4u_-x|Fdzy@lXu>%a#`$Gsx!3AKCnjH#}(gsoNI+S?eUB67%6(%6rJm$x*5| z?j+v!?rFk*SiO3ds$pt6i6k{SVI*_9At91XDiMM}f)y1NVT`JIID6ySw(i2Y0#jEe zE;z1~wq7Ue)c@!6oP+~nSSIs=`bb&$r*aLoxj@1W1LuI)VUi z0J{hPfXq4aF){$u-ca1|mIVOWUnq8DYLwKcf_0ZU6U4PF&brq5I7eAqX*jjL6!4No z+|_;waIXSNwsIu385clCZDz=pu@&8e*_D6v;p?i^H%zl9>O1A+ATLUDCiuc%)n4IS zj*A@^jQzA@?7b(MYU)cuW(jSI#osu)>1=l;iMkM#BRv+yZ5 zSscNa@6c&uyPnZe>Q?$_oD&X_L4>UQbe`{m#W4^Db6Z=2*YSq9D0)s#PLPVo+NYtR zp^OjE<3sK2`#Q9x`3Tgo-$tjYZ46FTsxk!^u#(PVNry*7?D?8W>g7*tl6u>(RJXlX zrt-og>ix9@8V$8L{WD*<6#63AAhq3HdO2Tx|F6Yw{ zPQeNz7BfVxizQK7Qp*aW{$v9GD4Ng$#!AwhD|~&qPUd;*C>xwAQ)2E`8_#ct4Y={V zHN!;m?w+2P1jU9BrT!qbazfJLPos64cIbCigsP52QjNH6t*sV=j<-yR9wac`yO|k) zzvz~fH@Hku!^KxM@*f@$ibO-v0}~UsD?vUs$~{Db{Go2U`OZ?O*O69ORtv zp^3e$ey6u;8lViNZ8T!es~@xYB-z;bxPcK0h1pVtkWE)b&E6fW*uxU!*r2ys05K%k z*v*WPIbF z$<9pptll-^gqxe4eQE{fy+6Wi>BmFe-G)d-3u|K!Cnu+Qvq%ExQW ztgWpLH@HU=cOz}N51;#MjNWg0!wYycsfWxq0?WSWIyLIg|3E5;QU38#4-dMHFJa=i zTBkZRRQN>H1y6PRRuEKVi%BTP6xJs+b#rqQ-CWk=Qk0&1&&a_diY`R3ijoM{ed=Mc zm5wksc@3ZB#H0+?*sNtDjNE?`^C!5JJ7`;Xb(4@@*VuR%J#QI$0B?K0raS;$9}Qb@ z)tFb~H(f6UEGS{-h$e_+_tFtd#N5{VnU;<;wxgw^^tYq)Bs1jeZypgB@VtFPd{~LV z*^?$?b~kvu%G7|&sod*Ib)cO;GFv^eIRBR~r#52d)!BllZu!4%vJN~wf%|`K*F39Q c=`|359xCoBDTTWE+vf{V?49j+;MuEx1Jpm6+5i9m diff --git a/docs/.vuepress/public/apple-touch-icon.png b/docs/.vuepress/public/apple-touch-icon.png old mode 100644 new mode 100755 index 397e21af2a526405cec535e36de67f0b6ea35f05..4da9a9eea4284e757b4e536fa7f4163583708de9 GIT binary patch literal 12367 zcmZ8nWn5HIo4q~Ryr4VE>bXD=Cc(cS z1StIzDFk7typ@npRfRjaI=H|c9BJevBxoF+9W3A4T0oHJe5Qt#rp7L@(ADy}xI(yp zqJo1u5gLuUc%(mJ96b{)I-YzuZO$B#TGwMKDP-~=+2Kgh(f%Ka)R?g%FlJFVXmg{3 z^1>qqZdQHrY^K|;wubNPXN0%Q&N6F9Q9IGFl4Uv7xc#w;#i<_u3hMjzeRYFXGyntU z2;rgCzM*xwdxijA`w0rZc-o2D4k36>VxmEvN*SH(6k!jzd*W$^2>!tcovv|w3TXa> zkf?XGcmX6Tjo_b|O0NNBBSR*G=4R`VDhp)7@P2C&^3S|Z^Fe?N5^0GLvg05c0*i1- z2rdAXjcP|oLAvY^p{2sNSI{gA#4e{}DGOCKLY*Ucm^Ba@7R0U=9`YPQ_JK@(JbUH| z1*buT(x*CtCod}Swwb_6rPT;F!(K@R7@)B@q3YnmNmGd^-%Wiyv~{9zqOIdiEW;n+uYcgmH#GgU^<}l?%t}~ zxKroO_K%<7?bXGv_BB|*OQQf8{7c|MY`+{PSMAiHA39E6g`Y!YkZRm9;Q}PaI2;kvY<(0t23|Yv3-uP2En>;TI6lV+_uA*czVf!gc$vHW`k@fEqQSpIG%0%|*Oq!P2>yV{cqJ(qo9T zGsc|j$b>%f>ep-fA`kkywy9}xI z!-e^1wFfeOfK(?s53+|ijVYCwtgfQ2@~mtT4F!zr@jN;&I#RG&H^b9}B858omdAg- zk(#~a2-B5iem0FCL%@dT6E5+M7l!{q;w3|KETUZX7tIO$3F!%Y^=G@x#Ti_(WX}@% z=ik`WpuS3Erg`xrWFvEFP^GIhv2TWAw$#a~jku)xwGhxZKiT4F?g+Ddd;uCQXvTN#Iv+D|cL59xo+PDW{C- zObqVI?4;}^aY;eRatWr^nbx3YOz~@tcNNlFoEq!J=s%N7wMsHo_ch2h ztcnGS!b+@)95h9~`03q!K+)?_>`{^UqLy84yx#Vm2GjgWttT_B4R&d$TLAYr`s(31 zUw5X~)H}-7NTHJAoL3T@@|-%g>Su|TBB<-BPS>AYmC?5u3scVgB9;k{pRYY9FW^#a z=CCldDM?OA)-9DSRV$U*|H@NwSeRMxRjO6*CICmQPoBY$LB=X(WJeti4ga2>X8_ucM$9z6;@ zExm%$p3+gex>9q&^8x`y0mZ)Iq2b)&=``*PA&!}s+Zo##GZ`z5Cio2ij8DPu)q)$9^<79ROQA#jj2MVK{%{QJ_6uN(5N7fwd2 z-V+y@8MPVRheZpOM?6PwkHQu|4{?2do~6g>GS>4$;+NXyxCrLwBzBvXGCvgwl>n>y z?PqM}Y;ii}GgXcG9wk?%$0Wj+!p@)9h1UgnmtQXH84vMxHvVWFROxZZG7edhc>nC- z&4c&DI8^9QhhT;DAwVp^0P*J9+n2T@T7-YW;<9G$Q0!xNvlx+BOkjE7W>+~a{Kr9T zIqlVU>PXzkTbvM8zn$qZRMRcf$R0l|hLErjolucz$8cS;agG#jkMTtbmlesslF5?G z8CD!BuPRyOxtWAZSgi%;d0V(zM830H>J3flX6nk>Dp0&)Wvbw@w{2g!Jv<9r%Ur`; z_aRAT`(fnhl{3i1;JjDS-!FG=^6G<=*A$~XhYJ5X}sDcg)rS8_(GV510f=*rw80$ojUW96+ zlnFLPG%(pssgxe-q*VBQrT12{33%N#5ZG0ZV6%^@g|Qj(Zhvv+&`3p>O>d>%^lxY; zxiHa(hzi05k`$u%vy6+Lo8(~*1089LiFL)L-(Bq->?&*kjMl z*I}<{*BxG5N-eOZ3^OjY1~o`D=XD4+wOJJQj|>ZlXnxT=*Zix=b2PD3Z#r{rKYm2+ z({{;qFtuRNc6BG*-@c%QprtfrIc0GpcT;;MQt_c=_d5B;&Zu13&grlZX#(jE^%+jX zO!Lnv$_XJ&^_b}w`!YCv)b00~#~v)$JlI-MpT4g>bCmSj*u6quxuU}6pLhT0Q?`ma zN$pN)MagC@o_?AxouQF_V_;^`qB0~rKE1c>eJis-jr)m9P|r*LOtb&({BGc6g4OBh z$IPV6cYdsY7EKm%8+^9SM^>zH9gbV@TvsQg9wN5|+5|=nPn%p%YZf*MbeeS1EBTG> z_FVS_?-M3f`dUA=rdKo@+B6?|f35eiyxJwt;vHE!|LS!@{4hP0^-5^z>zTL1Rqxfs z3h|PkGsE4;VC$R*!%=ygN}KVy=%Lu0#8TLlh{65h?D67z>rRjCv++flE0mC+(fhcI z7+i@*F=;V_q1d7OS$x8;Uag5Z-|gNON{qf4rOzU{&%Gb4AR%V+yPn#g85vI<&q+B= zN$9Zi&A;30+<#KJ@V)yxReQfDC&%k^?VH0ck3|p4EB*ip6=MOTyTnV)<`;1wPzIwQe6Qj|>5Yc<^k&!6_B}Ka!X(Z|J(eR&zni^XE zd_pwJm>0xpnTW?j3quQU`gjn?ToZAiFiZPlS9xM-w?4UI^X@*|=_YM2*cC}`dHWN8 zp9^zK>+;Rk^t-DiA8HiZHVg<20g{CR;H|$Pe`$OO5B!JpdH@{NgbxyxT=$1Fg!7Rh zN&1`#;Gx0b$cX4<0iuD@G_l!_WyjEv@wpHKkfTIt#Gc^=;By752IFDCukjGXp~lpB zvE?-qasQe#JOo5>a1E%ZYT+3it4EgWAY3%SG!^mB|9t*`zc8FQD3>Te0uieEB^`c7 zj|XK#5aal78nMPlG*G9Jnp&4po2S~YBi|?D$dG#daz43unx{_@LxY2N#3dyDBqkE_ zaB*pF6Y++I;-LSnsQDg9!`Em#*L^r&k1621fyT(j#;|1Xfi_r^+qaHD8j6r4|45UG z=m{Yq?0j!Zf#T(x@b%R&>d>oYpGqnyTdZf+n;k9Z34|9Kx|VEubuedc(Bw$#^{W#h zX&kPJ0EJuX8lgeI&kyDjC^;>$uDUVVOoY78(GVe3xU9nyOnlcDi%WREW^3$oAnVHd4jy&mN&1J*u z`pfw4?rw^+tzphn!O?8mcDfR^UMgdRWOjR)h2HRDv&&RpG^Gu4N3{8~*zCK$-bfP4M~@!Ks}W`pedu&D zR4vwQQ!Y%X(=RX5Wbzst5_HZRC%qkge@`&MbtwKUW^D|idL)vBjo8N8`l;`d0$%X! zS04`^7M5XQ?{m0{uC6W~B--SCQF1oO*1<&~yHeq$ap`$*ATBM!( zaUu?}k9cIarPFG6Na*aWZfm7frgWaEi?j1b3k!=2JaJ<2A3h4xlE?2`c^#H*DfnIC zpgRI9M|}>e`#y3hwT@wBGlq#g#>BwbbEMeb_*ST1JlnY9*Qy`?McOznJ|Y6c#oOCk zs7Xy^X2VKaQnE=oOYp6vhJP-Fp9G=Q%y^!RlU)3Uuhq#1hODag+tWcZte(JkzA$1E z5|Y1NsMID`i!L!nN7AKJ@&};OHodc@avs>z6em6qFbFz74g>e>y)~5fMY#~udaKXu z?(fCq*4EZ3vY6w`_lhN;IBXyYD;*sM?{K{P>o#0(Gb3(6?4)jOU6L3dpKHImru549 z+ObR~hDu5LB|8?9cIgx?8X`Uye%<@&Vdg<+($L~JN2>|(@$jIou?bmZVgdq*-riod zmyzze1_qdvIH>=={QaXqnjq6un7LFhxS>#3e=^TX7eFSgo;qjV<|X?;Q_>BYXJR*x zuoh)^6A1_{c`}mXVf8=7C9rzn6n%Pn9g@Yt7$Jyyo=*N&Ch!v1$;oN0GXRNBv0!d~b1XHTC}bjnP9&@Qd-001zP zsa$9j4?B4{^iqf~1XnhluX`))pef0dVt)O572Ca)a?_d1WuJVCkcS}IV)yN2!Q4!_ z!OUDr{Wm8=c?E^i!GQtw^W8~QX&ITbKpK;o3Zp!~+Y=eT{&>29)6-KEw48%&6VmT2 zMlC;Int%ToKJB`3Ae#Mjj+o|fuD0-gT!wn8)sWSW^C61#$&BXO$qt;3_*2Ecg#)w=O7nl95(a)7r`xhu& zKLJEx<~ppjufEW!2v!lgNR%qpoG3SP1WO^X?7h#jAVdA`3obUcRAi??JrCo+xbulu zc?~`UeNrxb2hdva?c3*00A__C(W$`EK(eUNksm)Ct*orf!9tA(d|vS9SUwh&Mh!Vc zlrb{O%=_}?TUJ_Hab#p9rzeSB7O0Vlg+_-$UfbDhL7&UA+=2p>tBAA4NdDLP>eWWA z?vErwv7A&=*%4F}6f{sDJz6R|ATBK}r5sFQ^Vr_l*lBe?1fG}@onO_Hm_`51$ml38 z*irKp&voq4@W;>2e{Bn5ZvDO3S9f!(Kbx&K|J5CW*#%bqvDA3bI$!8|lYZsQ`rXZy z!@*Q(N(*S*#MhNN0pv@$6_tbou%5zw)05~iM z5}yal=Ucl|ko7rTeEUF9Oe+!kL*E#z^YCX8<9_y!M8jzKt~UP0z9%6*07%4~n+E}a zr=_LY0-PqUV@^YB-Olp)sZpqGAs3%W!0mo8%W)S^r@#mKqbgzIpR=sGx7rORvph3o zO)(5$Y6B3HHZ-J&u{b|&yVpnk-cZPSLzXvI&fSa@h3)zC9Htj94k2zanZWi(*Ao-! zN58s)P-rxAay6OKo^V<^e)#ZV-rz2`sEE<%_3JD=eEg>~ixg}xUU2%J_A>|u$4X5G zAul~uq)!07A=$rl;Gc;yt+oK^W%q*6TxQ7VY1=5 zTB{{^C|DuHMzdawqmBLq?`94RY-|g_w%@9%s`^oaU zP1hf90-he5ozV*bn=(H?pDcQPqpX(8>>HZ*&muMJU!U`Yexp)(igLOi=zmzX0N2wXhwVg%Ge)?Yn&!CvIkm|AbWA}-HL|t2iSGS%*#XjsP?wC~-_=XU!_=ic)up9F*8wg6M0%LMHSO>3 z7t_uDi3xy+AozXw0Uu2-s*CI1sVbPTMr&o*T{&4+%GaZx&Z926h+^OXx+9t z=#~t5W##1hcKb#HBSS;QbVYjC19JTH#%c9(`Jk1){0}Ix%DK9?1gPob-dN}@L8d$zX+$ryq0%WPn@pd}gSYQjLr7%t zX21BD0dm>9Iqp~qFx5?H=jwCXOM0QB4!DwWEdcrMh2YA&t4tpt0`-ljy?~Uk1!NM0 zbQc7)7p;hhu_hy7jcFUT-?dn)-<>zHT?38SgQSH8U8CpY;P-&MQt^BjQ2Sia@tHY3xY!9`Dj%;hXqI-83=!=z@yY~0B3m$^76h~shx#c z-UC@#Srw=r1(Cwj;LCp9-ujaKuAaIZ=3RkzJly+u$TUn)YL9U#)qeK-TWp(213}2B zr~<}bn?&(2x#7&e<;Y@;1xgtON^)`>gG+riW$q_yz1bBNBT?YdVwFGfiB%f4PN%pL z10r1CnXBE-tQiq`{NzdTJ3yY25xH*$>)nqQpVZkc@U-OV@8Ud%hnhA$!Xyp{tnJ-= zgHJ$ks8OIe9t-p86Cg1qm5wIkmgfb{F&9B37q1C6j`l4V*^=xSj@$u_C261D;!^bwZw#=;S_1&$016h$nM@MHrhCqy>lKY<9&X(pmR3FIr>|){RHdsuyKW~!ERyNw9HlJF_(d+ z=C_oTltKGkNhzu3nwlE4udge=E>MTlplt#`>j%BiZ~s9cQ&~$)3_)tL4hg;G9fV6Q zd~khxHhSUg76?IpYu`Q`0HW8ldt+Gj?VIG`&ti>75xE=Pp4ULOW*gL6DuvD3zP$HtpFQ$1fYiu6@oAPGH0S!OwA?}^5%*J2%??7&gZ<;;x-TH zXm0)tv04aoUPE2In?l%Ew?R1;Cg%?LE(>t^$_ZFbsl0LI&8;mA4h|0Ib}n}Sz!www z3Ql5paM%t{X#X4MyBWQ=a$3{awYSb^bzWb~Crl^lt{0te-!G%pD!s6EZRe!$LzF!g^SyYOO|5fb6K* z)Cbg`zP4ue$wH3=-<3S4t!)utlK40mOQRc0L4N)#&X+HL9$HX%Ume-~7#jM59vHiT z&%oobT(%653VYtPw$GgbE*C$WuaJUaHJX*A#2gVGZgO^dDp{^wY9kXvOS3 z*E(fat;+>0DLpf>LaP9F_E&U$LGSaTvq=?^DcSg+UyeVTrY2@(9eMxmLdEXv7$!dE z18Na_V0hTgXH?kMc^Py_sX?nd3+}w$h-)i8R}cHp>E@uRl2VlIHH)C&r~7^52Mi*N z5aK$K#JRb-`2Zx;0Vz;|=8 zPl7lPPaPpa38KBOpLxALWnF(@Ie4<(=e9pxPB1@dsnGhkZrIW#B{>9jxwT9basl@;(}US+cbZzdku$-10RE={C~6G0fgGnc1&BHHaDOFY{6Xrr zc2syjIw}eq@sJ`O#?97#{S*xoGof6!*>yMG6zFfkJ||}UbECliH@QGlbEFqols0K- zXdHq^8Ww748aCJkP4q}9OK@(r=Py$-n{kD(->qjW+Il^z*qK3tZH~vmEG>CK5BtZ# z(a|eOX=yT1)Bu>Ao1dTXYH3vJoGlK>8lKe6*@CNNK6(ur-AGgO3m&pqL+wB6Fb5q$ zHa61j+Ab?Ek1;Yh=yFrlKAX;M!{q~N;0&}vUA9-&w#dx^=N3@kDAdUj_miLRVZi7K z?U=;Eihls>b#b^bL+?S|=QJOJNn&3ju}yMwt}FN!{kQM0-BcddRsq1dcwIpN6fGE7NBjceYZ8*6FNkr!~1VvPVe z!{^UbM&f5g7K$?tB9i+;i<4`oes@O}+3_Vl$xC zUT|}3;qtrhn=r#*l6NT`w^Hh*Q#D>x49cI_%k=99kZ1{GvmFSS2WtTA#?RR%FSQ&k ze{Hn`U@M;_pO1{T7Jy1MW@TyF;_piuqhD?I$n9{RTLAyu?w@OJh$815peHsZ{Vw!y zdnWGdduuc^vag&ov!C?p)hka&$0}RW51?4hoiPO!D4W2lnsFgVVGP=fnr+j9x$x7Mzl(k1Auu|xs(<_`k)9p^Bv$GYq|J0 z87$FHIR6>R9Y%E7Mhs$V>dOA%;R`qyS+lL+EzsAY7yC1{*-JftLi!N`#p-XwK7V)BuJ# zoi~2qr1-m*y6*jyOGrp~791S>!(z@9Z1Whf{E4VgmF!q~U%g2eVs1%^e8ZfXxH#fJ z!&0Qm_*1rISegUu!4%-2H$9$$qZ&X{&vROhGy!QIR_C^_eFYXq6Holr=h=j~xGpSm z9z{&m)Cwu^Fn54w^HWnv=adqGowWg;hh7W~Xp6=@K9^7CK-UD1!xQUUfG$1&Fc7)Q zS0RCK$MJ1vJkKpg@HCvfr;7fJmnL|Fcf~hvsoABlvfKr>Q?Tq>s$ITzc`)~Ep8#Z! zD%#q_ldT>ONE2Hup@Qs+H-I{O08!5U?I|f?vM@EJb>jVu;>e3hM$f>I@Xx^tv9gYY ztY07h@pSyv8E_7Oi74BS*Pw0v{CH(0HZ5&VGl;C;gxynJLxXa6clT+ZlZOK#I*3FY zNzlcAI8*fLmTR}?N&P9F$c#6;6-#arMz<6OFU`b&MJ+Jh;a5MVZ(zU zZZd43*bOmh!SRc!pVQOnz_Qs~v=D-~K+eSLx-%BKwzj69Y+;8d-sRJZM*D^|)Rcu7 z)7aP;cYl9Br`PPUZn6bUaGA&bmxXIIODu6X3KYDAL(*;E$eF@w)NO5Jvs+X1@(37z z?@&|Mcvu{vRI|C6neDs3=K+9uC;R&Pf`A`ZB@JDwLm4SIXq*7q>2-xstGJ{ZOgf5e zs>*3yIwH5o+tKiF**zxgkF~F$4KtT{M%Ict%y1c zyyULXt1Ynqd%jz6eSIzMAVbaD6qm*5&4P#vIhvDh;o#zWL{q$~xd+h%FQtgz;@X`} z7@l}>PEL;fbeZ0TQHyJ}?R;JTHKtAUZzT8DB_Ig2Q&LmmOHEGZl)+=0cg9%?DXe;6 z{Xc>vsWkG#2PdF)U8uZ{Ddc}i`-Llj_@}zMdPFXPev0*VTT?}DZZ{(B2BKXK5)0fL zx$L#_WGn=c$KlpS^4Ih$JaM$rk`l7lo~t4HA>ymnn-t>Z+WWqnNjld1 zdwW9&-nA%_|GtL{_`=rd8~H%LmSCWu4BQXrwPF@OF7$x>eNQ@?LT}v-`;I&207y+6 zzyy1UCW*If@WRQrpE<3RL0*4P5&ZeJF&Gn69W69gBJ{IVC8ngzU{eb(?p%Dh6N*^` z7QNDkrQUT01E{#IOpj#_b;4d06FfhBH*0Ha2{$)4p?D(`&;U^h^hz%S$&C^bxnr^b zAm&Z(x-ORoUfM1+lxtVc2q5yI@v`}W4U`tcGnDo73(ExgxLZW7U_h2kzPcQne%($B z4cg)oJ-oP};Cpgb*6W$TM>K^q`^`H$a2H?Sw&vxjaP=@vv_24QH>XkY$EDw}#0 zbzoqCti^5L(&lIZzlUA9a)uLRwijT7FF;gdsNj3_6 zF5sF4nx1sIq{hdafpF9rn@UiZ8XrFw*w^66-NXvRW;4A;d&+;f&)DZwbKy@MDOC?2 zf662zlu0XxPe=FXIdxf4k!(>##bvWv$a<62&R9-Eu}0zP^XJdSP=dss%i&io9A*J! zsSg59ZjfbRAP7580vP`SZa(wR#f6mRdb#Xj=CgLrmU*#ZgI7tDLDlZaY&} zGB?lD!b7IIZ|h|dL!%SJaRtR;=?KO}g#QR2rLuhRvfU4)=3<75q#lnlvvj z&rbLoGjMd;0u(r{Di2ceg1`c~t*)-tajW@9e{0_m1Y+!A*j>qd`AsiX)^I+2CZ^BS3if< z2n9wD`)7vm=SlL1fP;F0F&aPZB{7!d*^E9FtP}x4o6CNYPpw$9p~SahDsamytFov_ z6@t=zMFVM?fPfe)H{f-{#Mk8Fv>bA@pRfBMVc_Pkvh0BlfU|e_05w9dgnInFz~g-_sAJKo|V|{$2Vn2xuW_?9F~1C}(~F0dgk7 zh}f+HeN1gNUIT5Vlv(ZM=87+_r%81pdUFrangk&($Gq)n8kr;|lZ?%KLhcWYzn z6H0xw(9_GoN6vwGM;_T$X9Ld(Yxav=mf9F*7S7gW;s_Kq!b-Q`=fJwMhA;v}y;lNt z39jTpm)jB~Np$wznlmL0JY#^z^hsa@`mZ>Ny&%LWn%SqL*8UWNH<7*BoAfV+>Sf2G zr^fGf$fCkDVkPTz-XlPcyH zzXgvGAQRB9tU+Bg9=XhVMn+K!whhU|Kg7d&Oe@REzHDxZ(9(8M;^TLNJ0?KR!9Yjn z_@TD~##eWjhYPguxj55_)t)d);9E6++$uk3W*(XXl}QFcW!f*afbzkbzpC!@TL&|c z2!I)k;5Z}jCBBA+pUUW(JWrmsgBS>Bu}Jl8gHDUXits2%-D3ELr;%T01rff2__;0OzuDp>zfk@v&#p zAFF@^bGIM40z!y~RkzCj)Kk#e$%a)}`1NK?g-$s!aPPmCeU9nO%*}fT2IOgKBe>f@ z*nc4w92B%3*R}a950c zFXycGNm%p=&m*-_!>3o%z)a+V`r%rpXi@xjE3yt?)ld(v$iWT>?u40{v3?7xfT6^{ z*&djUdW23-O+C-3RyGI9itMw`Q8PP5U$OSR-$Ok|m411&RhHLx5!yyprg}8W>&g5fBgz({v``5K1{w`~L27lZ)4diFK^&ef4$& z!HNZvPz-CnV6Zmz_5N%zVS-|N℞zIJYI+%-durT=6-TgR<) z{_Dy@vHgrkVvc!{#WqKa&05TZC}vbh^B5n&48Y~E%Cv_}e{R}8COX=^?c_VT7EV}C z#2a@XFvU~T)N~bk{=6SUe3m`~ZSa`+%d{bfuNTu78yg$a zA>!kUCHCl0rwqs&8I;mBAC^2;(rAKNmj@HY$w zo3$KHw`c(=O%U%TC8NE8fYHBjwgS+SEQtFl!O)_(Vd1cC&Xyj`eRqdb2?B$H{=~-O zJrxu*lvPsNr1IK$%ns%$M35-%7;U--(h=y@W*+;+a7tm{)R$yY@)^VQz%_{zN`c9$ zTs)zKghU7!e!qPAGM@aEGYk+i+;=Qn%$i1HYJ-8fu~vi&g4luPDk>_%`zW2a4(>)C zIC;R+WBV7j;^Kj=;1LD@t0)1hit=V40MCO^M@b30tfImaOi$B*-7K}`$pG`6=ZuWu z`*XDnOCV4&0@FvJgE2g}Puv|B9^Fl{CR}y53CNLNH+Qh3_|jeT$C z=j3>!a#p`s+#-N@`|!p=Gk@ul#$xL#+Fvplt^-aPfn!Ji_Y@L1cJ!a8kpAEM|9ML3 y+IVc|2cx7<01X19{oBQb1UZ+5eEa(YImA)-5}g#IeH5J7g5;!>B`d^D0{;slblmCy literal 3744 zcmb_fX*3k>+n%Bj$}-6^CR-R=m?XQEA!0l`AA^`tM_f=+WvYs zE&zaL9sqDDsHoLkn^`#RW{5%n{yxhX?qo(BL3;Kf001Zdf9w>Xph%FJWW(wkBiWYO z`B(uLKwn%*CF{@Y5SjKw{I{RH=0o9?`lhA%dv6Eb@s;UcPZ*?0bBs-hmU-Op=Ht0r0dZJc zKUw$L$j+1jlnHZx<6P5HGiy08&=hHEqy6;aydQQ}oOO4vOB z&uVA~OAK1&K&SVEqard$mXlmhw7Wx3rB4!~vE(f&A#>>lh36~aS%SY48`e9oiwsat z3yZ4psn{xm@=DiB)va)DeWvR22bae&5ZqU4Y{s?IF2+C;c0O+P*QE)VkW*qo3(DL@ z3)hU7dBjsd>ru2jqF2-TORcC8-d}Zud1$5$gb2NP1ARbU~6# zVt?r+jolTC4=Oq4T;6p*XX^@7Kg$>0P9Q39qo6`l1jkBuSRrwN(*YJsju**)cW-7G zAOYDUx`X|*914e%c{WBw^>mZ&FNx9L8fmckY)|Q?rU-UplLd86x;_i9G+d`$mCTgI z*$WT0Q&?`RK82BW?&Hwn2`?+rGMpZSq76)fLw?P{A;dytqqi4|*tOj*GJ5We*Msly z<1$rEf0UIk34T&FmN59MkMs2ZdMS^i)U;nNUwjI00GC-8J}i!bNT^vuctI_Uy zXpihOZX8GCWp^p~8>MCbu)7q=;&K8~@ju(19PD&T4%*u_=M z@5}3CEOgo9`O4lFqGF{n@%~G;y^yLultgVng0!#(!cf*5i2aRNU*m2lMjgKE{#OI2 zoW+sq${PDU_Ik~Id=hNUP5vTiv9ixTGX#+jjQEW>(@jW+Wkt29UvLA3E9X}aNakP* z^n7SH9PLMstqxznjCa}(*OCg-POTbPsk{=Az0ebhmhCoWn@ z4<9pZwYL19EY{^A1$!A8Skt`pF+D@oInqH+Vt#@*pyKW>3iD>1p7DH@{(O^A^I`~y z^d52xxfE!!8<&sA{z8)N7dtX66epx!#r$k>mNRmSn;BaS5V;DGs#@NL+F&dPKk=&n z$Q$*$0F`l!%$)FIb*V%>s0#YlkCR!}i+8sgvZABb^Ix8h>`Mheo6{|~<9}XR9gOki z3gY_x2}in##7rjoNH(XNqWNnv2apWh<}rKKfKyVy*2VIuzIX=zN%0@0V z#qye88sQeBLno%4to)_&c64&zo0D;GFsxE0yxa{YvTHbYwKdK5###&NfkFO4TkNN0 z(j;i9wqxhu6IJOb1Rgx)etMs0XDTXsU4QI*fx*87$H#Hh&H9PpV?Z)wYpTg_JxL@w z(y{sMY-z@}X>JjLIJ45QzBkRkUqfJ5ZzK5!p8Guu8W>ZEViOTAcxWPq2O87p@E+ZpxtV1$brd4V zXbDVP;o^T?+Pw2-X|EnGS1q5{=Y8%NDZ6G7ty<&{+P~QqRxG!hJf}-o+SB^}v%VLT zoE;V7wyu9Ox8gQor4MgI)dE2?kD{G{ugi?;)lCih@k4HJm--1wSFu%Nkk(%MAAvjC zb2kPdVQH#(7)9Rx{H!(l`vE1^;nJyV$#8@ArM>qhx*+Q;vN`0dl85~`sP*(&tvFH% z;mCsloYi~Gtb=tnG07L%utdWpHp(y$n3e|@(u8K41kD5=i{<*PgR-+^eZx#P2A3pq zcVOkFPd|cVr+@WGD&@wW-=yiwoxKs)aiz?tW7%hoS|Qp8s!zuv)#dW4uZ^2Q(l!kz z#mC^0csSRUgdTJ!O&^09w>v7KBKQC8=D*p~I5_q-tS4AlW}`I*D5X81eJy!|9&stX zEmi-~Q<(uD?6BM5udO)NO`jM+FBxL*#<2Obd)CR4+<|Xoo{7E`j%8WSZXwj8_Ji|P zHM7X3&v;9uFyo$Taq**Xz-r89tEv|8B8lMg7kqGQuBLV?%Jmkh!CiAu(9xZ0pH-gY zp)$*L+7p?izHdt{v2}*G__@+bLnzFfJBP`fe4PK0Bzz3AZFNs=F?$vs#N961)MOs& zJSK8KVm$lCr}RueugGwv_r9}IM-f^YSlg;zO~u#_p@k8 z42^82eW0^JWoe-X9|zB^S8`ACmSA-whUmp&OWz5WPn@ZgnGM0GoR`U>%n!#t?@6h3 zIR&+XGAnk>M{{~TlQ?ZBNIMcnT-9oE* zPv?3#5mQx@pN(=rd()ugZZjz2WQ9^z`u$3gDbQ(}kgeyT1qx`CrY z(#}-)Whch5=lW`*a-k>J{^570w+q{^3VDsFuWxrU%#F^)BqJ5JXA8eY6dNn8k7AQt zyKl8I0#;ZHE~cnHqjy9@YiJjgQb^tT>uok)hC+S31LEPLG^LXBJO%+YNC$>j`Elma zl{_A&cd>APcEZdE8BlOxOX_9o8uU@LsJBN~SO4Og)T^Tds{{!FwiaIy4f5q&pKJr# z@03nALcFp6ETzjmEzD@8p9Db7$aI=TAP0S>ymaGUw`g)>Snt)t4Q zuLJXTM5_!83#Zc$hpwJH#<@8QQVV=I@axAvsk_*y;2-wAg9)L9%Up{py7{dUsqOnD zw1)LBE)~)uxMNhX+&)ntY+I$)41eG-6%&W7&vbQS^K$k_>k~(9)wn#h`6-X(2gJ4X zPd@8H*@!NRB1H4JLW``I4G8~MqtnueT+1%+Q>up1mhZAty?}QF^#aN9HV(cnm)nT= z0s?4fEG|_dr){z!Aw7<24Q$i(u0kYcnw}r)@-2AR_uy_qDFFJggR0nyru6i2P0i4w zv!!{W<`YTI(QZ%CU^o0j2-U*}=wxEA>kIBjC%<_WtARIej9O0;BCUQIHY2fcUN$bZ z#)tMJIBaA$&DzhSZ za=+0b8X-(q%P*tL7fFnpg0tj&)zm_lm5IPs#t0^5(e}ZgeCbJTmWG-4+`3xxWxaT6kgf zr*x+dVQW^CryJK?0n)@ju{j^|ytcBU#LHxiYZ-?E{}JlHh}H$$dz42XtYF0Pi6obj z#g;=7cDTs%G+)<<5lovSXC~B@-;Vjh`gO}B&f@q|Yk$*6(&0`AtPy&B5buuhcoK}_ zZ`WF@_L`MJt&Y_5&6N8PFpuP&WqS$J{3vWNg>S6=JB`~&7^TfVh>XWP`D4|MyPq*n zo8|F>0B@bGhJANF02Z5aaH6f)n8E#nIKdV34?53;$R(mBQhY9xnSE%1GQFA~-)Z_1 z4^QW4ulz#1aK6`#L!8!q8kx2AHL_jPXI+0^YHRl%yqrB{w1clD_O}OfCHW?(;PO@K2;S{;^(|X3D86Sfm}+!xihP>5lPa0zg$+RasH_ zhN8+1E9GmN%F3E5YVyjeOy^8h>D~W9xEJW*>lOLG6R`WjOH6`ol$9OU!Zlnh2ovb# z8{jF1jSTV>^9{nf0{{_4OWR!R!8Wq8gQi2n`g98bizKI#J14&+zab9D!Y_u1zt-)+ tBH3UiHuQC}zh}4y)WbFuulJ9E65z)rUhKAxS~hb8Kp$y>AnCX~`Y(6_1egE- diff --git a/docs/.vuepress/public/favicon-16x16.png b/docs/.vuepress/public/favicon-16x16.png index 5f15c3b0af35e87882b492291e93fced03e0842f..8820f9a1c67f581ffe999cc1d360eb378ff8af38 100644 GIT binary patch literal 1385 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+m zvN13NS&R%!Ktc%0W(2aO7(gZiSqx!}(r|VhqXt5KdnN-5R81O?1_2Ks2I+y&ObeLc zDg+iVBiJCN%S#O&04dG_kH}&M25w;xW@MN(M}mQY=}~4#L`j6Nk5zJhu3lnFep0Gl zMQ#B|7lTcO6_A;mT9T+xk(-lOY*k^a1Xf`MWP^nDl@!2AO0sR0B76fBob!uP70mPu z^bC~jxD*r=Y>HCStb$zJpxS{vTcwPWk^(Dz{qpj1y>er{{GxPyLrY6beFGzXBO_g) z3fVr~?^K(i;z6j0BEU`0!YC#i5*A4 zA#~MXYa(%3gCqgfXrm8G1xTp^lH|amz%*yaWup&IzjjNL zcB`XA+i^>axj`JVUUdxtQ+U1WAG|2>3fuIRStmDTX-=;0l&MK4oq{%P7SN23o-+5w zk6rI(RvNWO&e^@LeBRFImFe?-7U->?)-(6BQRX?(MYr8|^Y6YOYb)Iy`@CrLHltsR zzdkZ~8L)g#NN#a7`uECO%6tp+1-7ouzruwg!>$SzvRXY5nKkL}noaK)$X7jNJf#rX z_g>`h_wS2~_9uwOB}m^(U|IH%L8pB~;5ON}zs0ufTG{R}k1u%BoeSOZXLWK9&gwsu z^=$ovw<>i!&X?t?7jLuRrj$U*OzTzxPK{F~u&tgy>cqOM>Sc*0+E0I7t!J>? WX!7QD$&m_B0pjWE=d#Wzp$Pz$Kf!VU delta 539 zcmaFK^@C-CBnJxv1H;x|=C39y+H*4{dAqwX{BQ3+vwz}S@p=aK5>H=O_9q-dEDZcI z*C(xEU|{6%ba4#PIA3~Uzg}~p$gz+9(L#r0JNB;JR9u>xrquD zCetL$SY0!}SPIHm3*=l~e9%De$S+Y*7qKZ5ny1;fmujEt)~TH2nu)QjdW;!mC0e zN`ey06$*;-(=u~X6-p`#QWY`_N|G5ED&{=?#KTb-rlE1l|MVHpr$G$N%G`R%+``Jj z-jhX`g%w;HOb(|oD{l@_IDO;Fi6du@$Q)rm-QcmnOON4|xM0aAC)24wD;PXo{an^L HB{Ts5-b>VO diff --git a/docs/.vuepress/public/favicon-32x32.png b/docs/.vuepress/public/favicon-32x32.png index 9433c807fd08ae205cc8ec2c19345c0e6d57e482..a3af2276d9751123e81e8db174ae712597df1649 100644 GIT binary patch literal 1893 zcmZ`)3p7-D82`@Ffc*^H2l(^!zdV=0wgnxKsX9F zkE2l53;b*W(3s=I!xnk`;DcypExH&z&%hUB7BE8fC^LTq8y%_NRtNxH1LUAUet`)9 z=m9|}Th0y)pztIjA~#MF%O@&DQbYx)N(u}`d^s1d6bZ!;MM)#5859^JZV~~nrpUL` z2<$)>-diH$<6VhlBAGzP;_-N@EH0iB!q_+`hreiqM7dl_A(0dc1ySKdl*kfD>)qYm zNn}ToqoV`NaDbARcbtW>{S_ATNgb5mFXC11#92t<6bdP*0#=T8Qf3cV#liEN9M%i|+Aqn0dkEoH0AZ2erB zMS(dXm4s};qOF)+IkgwwIXad~n%`eKmY~Pz1^^SuWO#w>Cob1xaL&1kXQOM-nuHLgurHc<=f|08Cj}ogInr@ zy%?PpiLoukyC2g2sTuBzJUARxGc(pP?KGU;QQ!_qwr?7ATow^rXl1+iZ6{+Ot-54r z{6==yw(J6j!meS>_HSw~-A>nwSX)@qjLQuZlJz# zzd+~Je=+E((<|)y<;`BhVO)yA%jD)`lAq)_x%-tB0QIn=?)L+TU5C3{y^hTBeC*y9@;F;EVmnQw@dlh@`Fb=g(^`V=C zc8p*4e&y%tVS#HHyAgOa!hFn>6Y#RU{ITx!_$bjk9m}(kMP`iswRR7DpJ?UeB?vtK zQVv74Dxmk|Y1|ss&03CecBKJ?nH;q{WQ_~^UDbmLcz(u-_8t579nI2;33H)1^I}?& z)znG!z`ao6t1A!57Vmu8o$X)7TBMR8iwCXLp}a=kxrQHJ%}~Bu$mql@c|StBx8URB?=KzD6Q>T6q7oiOzNx1!M}al)eIDPO8aw5M$LwbEMq z-nHS&g_8$HlkNAr)LgAQe5=@YrtO5>K$*BZTSvO08B=+u%JFby;&eU+i+Iv!) jcXIfgVSIE}HAWSU_Jk^b&D78IKz<%fpCCrHS4`%ANLIZH delta 852 zcmaFLw~l>+BnJxv1H;YYP4yEM?YWtfyxmyy?nFfiG9x;Tb-9G^Soymv^T$Z`9rQN6lOB8JC#w2rL_&2xFN+%(zXtJqG>oa=`) zI-8mfycPJz_?4Z-@k=-7q!-6E9M{E&aO&mEGF-iK%?6$~qGromum8R`w_N_Bb^h0L z*7J+sS>7*}ci9@(c2lZ;rkbl@;tbu3ALNz^vOKI4`7_}d_m{Tz(9Ml=-=xaR9$9(u zpNTQod^J(F>%~pcK8DAcxX(;fKkYfI!6e`GUUK{D0*S}lxjxTxJ$CZNVe!KsB${iC zHym})TIg_Tb^5p3iQcR3>-QKOt6tD*`(~M+yXcGO8~6S*tW)4fmAl}&^;`Y*2@BV} zj^~q(o%3AliCXWm>092#3aDjlRhI||joY-7DPAn^r^xf%3SIw@3o`|3x?X23S-gf@ zEn{(u!WoJ1BbWC&m~-A!waQvt>+Gj#T-qqa}RpS#w=fEcUu2x z;SMiu2G?JeEIVp~iq>y`&v<~VH-6#G`U8K}4vGb>YF&PXsqfXb8&-D@`SY;}=R9U^ z3RpCEi)ed`RA#5y>>kUlf6HsW+h!h_6FmFFgc-TQ=YCzg+NM6kMc`in*XrCSt^DW1 zzufc*tCd{dDIk5RVkS@amU`3Ql7Y{E=lwhO$H+?NduQb=zIh+n6#c|^Px++hobvXn z?ZZFylQpFC<99x=4(FJce&LsQ@yUrvSNDHddeZ#DabC5bXKX&7F*<14SM@qN(|t{L zu&c85izSoanzV$ny;!}Y@PF?2D>LGX6}b4;-f^vPEjN)#5Z+$6=ukalSE|kG*t927 zz=Wq-;u=wsl30>zm0Xkxq!^40j0|)QEOZSmLJaCntPBjS3{ABSjDQT*Rg2@?GjNP(yfCNJL3cV!1*=QGQxxPO3slWkIS!WZ(KQX_`rHu!0_Sp!oQ;jPX=Toq zP879b5g)a@3~9hDhKlhB>Ld;*D*?G?ENj6mjX^twiV6;6Uw$n1yLX5L8Ur5UIKmnH z4c1TZA_`;U2Ci0v3*D!h&wdTx)=kT9p^kHEe&A!k#Hs4S2BHY!GDT*Jm5AQ1p4AOL zc_iT@Z-5+J+qh)58|FX^ck z7(orl2fb4)2IN&ih@5l|BOo6KfDb;iUkCJg0XS#auWR+j`Y!wU##m^rBf=mr2YLQYf-fQbPCgV?Ai08TIf?_*~V z1R^s4YSkk%>A&1nJ5NW^gD^cybf#~iUGS1eeVc!UY zQm-3O`n*%lOgI)QVtb?b;Ys)7u{(#gWu7Z+*=11x?IsHfPU0=Keun)|i<2DYhgmxV zfTQnT?Gs#JY=le1>W_fCL%AEZ{Ko*oN#lbL0N5x$;xitok?REmfO0+(idJAeX{YDG z;4!u1F0>O}!^I*MA9Zyok}DEAAeemNPf+2CT+zd52o%mgArBG37`Q|ydz12Yn0zCZ z@g}>p1LwALH6sad6#BqacC2%;Ap1BN`#UgQM$|cLyE+bK{3DkBSZV_{tt3%(LBlv> z787;Ik&G{vM2wYcQ<794AQXNb-K-|~5m{{@GeKOZ)L1J1AX4=c(N70I!OTS3{H&k8 zwGU(x#0s{4R=AMOCCV!G3SfTI;|q5^7vSsZRQ&pshamac;8!*jaYfGqv?&Vv`qJ?5*LA~J@gP2k(5&uky;Rsp{t)j|LDdP`Z=v>ZRzx?)VqF78})=m3qHa57e z_B-u2_DKLSNi%#HLl!+gy)#1q{g-s@VutZ}hF)U&-nZM9&y%0(n^7Nh+fKk)mB3Ux#O3zl45I zzkz&@mnknRkWdoV6gI0dJpSk;hrgcgbDr&|OR&XNl6D*#w?uvTWbFxKv50n~pre(0 zd1_iJtU|rQph9i8MXYMSB&WDV<-7S6l2oBrlhcY*%{g%dH)qRe)@ZSWu!L4eM)I_Z zuiU+evEaLMK$~aDL3(bh4I)?Dt7Pd_%hn}R2>*@ojmKrlsTwg1uZH*$-aPRLy>z#z zkC!xrzjywxfs%Enyi$=}ie1`jWK!d(bm64xTUD|I*B-0&N9!Iv9zBH|cpR)8S~@#A z2bqRCjm1xjrL?8AdxwXHKMhZ1h-S$MP77^iZDmboEjPd|0xfvzOY6TmYE*An6q_H^ zH+x1|NSGJFOf0NxR4a2TA5VR+{9Zy)(x{uPTai2E+=>2M-(O$Wz<}PI!JDtD_oxrC zbGD~*Zs@M+JVr#w%GZf@h6#8 zPNN%&0?N*_q{HEY{DImvm)f7P@53JLj*3N#9d;g#W=?Uk%9eS7aKS}us=Rir?$eKd6v&~av2PM_9~B#ool&xaGV30x zLv?~a>?JjezIxOxT*R~47|B`ozFC_@dofEgmp1byi-(YmWQ$q4x${Rs&BhJ;~V&yQ}FxUYu=-9&3Osy6^nlxTX0Q7@vEI3&79hX-wa5kR^)OI z?+?`s%)b}UKFqt@r|h6y{ZL;Nt!2gwf&FShxk*$@`@EVbT&Kb1jyAv0hk8uv zRqUIkRfV>21nIaVZQ2LI+v`B?yF@00n^7UV3)B17dN6+Tzf z%2drV%Dl3)w`|fIk{zAeSqi#Vn}0}_Eh26HO7qyb-*s*~d_39t=tn|MN=`^9-^Bua z{!@MM*0YgiH!`ooCUU>kF_pXcEvaUy5v!wben-{wn^b1s%rd`7+IsBx?MUAykL&e* z&;FiS)oA73co5W57wmMl&6q1bvUt++>M!lx)MT!N%wo%Nkk?uF+37OvVyG|Y&B);Q z*#ORi%4WT0+Y|YHg;}M=m`ORy+l86Kg)lcvK>qRQg4!8gRK$vJw(&a=tg)*Ck3n9DZ=*(%pW#9jv0GNg#({Ht zIl=F#yCJ=DL`=+NulhT&+m-a0ZP;kZl`g=gMX_DdwbC?3Dk4vmLt%HO$qmWRz?Vu#Iyg%Yidm8y=Re1pT2gm`@K*g#s3;Qu);MSr5> zHEj+f0ud0eq5qPoJk9L$f9hW?P#p3cbT>vsKdowMwJe~As~==j)g=%AYrOAwG!`$z zD%1s{L6h)zbh+K%O+FOhqq6A^`K*XS`dKPuOitNE| z!+Eze)xQ}?1S2M zw+P2z;!rVVb27#OS3evPfB1zYK}gf;f-KxWwwjqWa0JaMFxN}?j|P=Yyj8!e`@N#x zZIG>$UtAw^q*fgIBk8>(1oUq6!W_$V;6$#o(arcVD8+oZE`94!7= zIAY~bp%c6zO>}R&)Vun?8~^REDaqU4(b%WazAv$4x;+2jqYf})@tbJvfYt~RoWLo= zp2TL4Na@_MM#xp|&>`Yj>ZCCU+YEH)8+a#T+ddEp;z;iQT$US+#g7%i`^9~kCl{3rmPO}gD4d=jVd-$0%LeiyUMc_y#@~ zZJ(7Q!r^Jd>|pPq{ra3GJ_?T;_AqkA*kX=wP+!aufe+5!e@aQMKA=Ef1H07lFQ7=L zj_zkUZzPgVAw#YXSf-k_Lt`D+Jc&YwUq3b)Vl>5JqN!6w6!ghzjV9@DCksEbM5RdyA~jBYq)Y)>!k;AyQ1i%3s<{QA=W@#_taDG?g<+-^K=>8)X;u0K@A2vnhi zjhrSHKc{zV<#%gLFLow`_2ceZrlvmgr;wX>%Dh#?XmY?xu)P>P_v}_sY@xUMi+MsB z#YVWO4df}JsQX(3&axeHQ|ekmqqq!#`%p28G^_r}lWxu6G9jH1eC`O%x8jRK^IGR2 zhR-rDNmF^xJvpJFEylirI$K1rzor53!cC6QV&dh&Zjnk#^jZZYuf7M{f?J5eKq~o_ zHHbTRr{dv@;;ge#q0qLjtm4*i|18|{68k?8Dv0Y2JFHXC%YGIon=0Zk!)1Iz4c+SH zO2C{j8lZ!6-C=}1>}uxM#r~DUrCHgPS=@>|P2c1Qk&0fHNGdMVgIl}&jj`!$?QxNq zAfdreQWFJKk)=roIv37ctBm3 zEgwPcIxcF=m3jNki_6?i3sW$xXq0@#f5>M~L(@4xP=}u!9rvX>)%G0vp@iSEYFp38 z1vySU#ZcOUrz55K$fuu$ZoJkM1I=ZwHoo=!P+^|x9$dCi>}t`T8E!$%Te@~uz)_eC zr5pFlMbK0VVIF7|h2?CxKj^lmP{ZuxbMxr8gj=A+NUAf6wQx}`epu*P!&&k7%-vHW zI*c%J^ZYr4<|p-Jd)Lfj0@N+0jW;E`XE-UkdsIY+3Kjs%5BhKdeR)3)BT17&=rtGO z?i<&>L-IT^*)@|EeNbb(qo>|x@0eK(LJ?qsqX}hj5{>{AETh;J*!9tJ45bRAW*isU zhFcTY(nF8hFf7*}c7HlMrHAPegwIE6s>t9-51p zzf~qm&?Q@E6zKd1Pvr+*`fwfhU8sVzqMEZKEaFO$)Lv7N0zN_koje7{*fV}{ScU+` zK`7&OsCA)%kx0q!B->=>#R=D|e8H_#QB00RVOtAkmMg$~!X^=9wsRLypjh+53}+8X z2u6*D%xF${GM$!g;_v8FT@+xTy2rn&pvE)3cp-uckfTKm+0)RvmaJ11e(F#xe_Ckc zM#H7reEHwfg~9zxH706?YMO8H@e^%#PEL!?R6D`>H3 zqzjXxOQ2^TwU+j8^@XZV=kK2enlZf$Gi_DWQbo*ej$dNfH(`L zAd7{p#|FXvTGp;*SDfB?*w5wn>dvkrIpKq_ZMgK3uaNL34#AB~8GvtmL)m}TN?BpL>dRz(~6oeV8@mR-j zdoS-e0^S*$%v-potT|^S(Jy55nWs`nH-~zfD}MK6kNoDEoAUdk)9IhL#quY--cE9y zp_CzBh179L^$J!sqWbB=zk?{21(IN~?~uRBJ9w&s_tsFBKpG)&eiyW|b$M5CnY7}b z=iU%Xof|WE!BcAKO`T4(;Lha^8fa?Q?|C#~{C?-|qd@pX{e(VkorPv4-q#Ym_1DJm zJdY(eaW|;?gpIWikEWqoMV!45I5LxxOZ9h8(6y+NbzQZ(|J{0co+kyu1a!@@MiiV( zzdug*jHJEQ>)FgRcF+sVCRm3VxMuxCG_O}(AI06!^GPwTFpe3*pb;kB;Skq~>7=ll zaj<(_t6C^_$MgAMdhT_HZ%Np&>abi?W2x#y!ZnNCBQFy-TQ{%1rZ7nQ;hJj?Yj>;M z9|_}u0QPo`?e2isHgbL*8?`+}t0(V`}M)K?Ux>A7z%!}TWcY+J;Z z#0tjtRJyl=b(Eu!WNP~we)KeVw`>C~%M`^JeN@+TDjx&Q36*mB|8ea-HhVYWAiXFO1zE8H2x6DsCSnYk9!(1K|&xk=~A4 zfz~J9Y@sWZwQQ^*xq(f6p^qiuN>=VRRu}DNEad_(?)bvi(ac_jnLc} zPgPrdPk^%%37wq$d~8E@-_hz;4_BH38aY~2jW-`!er`8%heBs1Rh~MpQiOkitxwwQ z>=Y8qyMR$)ALEfx$5!0*D+%ZkoL!Xiz*SD@M{P)de+5lS49ihQ8)0At>6zY$6v?;J zTNS(0PwzE_-Q|bup6%Dgs4E5BAA7>qt@TTu(BCwK&@RyN%Z-^fWeXb8#~JGN_Ct{# z-lrz=Aa3QzV4ReFj=ya7^PE4!)-`O!wbrJvOzmC8{D7V242(6|4_=A~31@t@(tlaI zU>Gy^9h`wtBQM6TRjU(V*Pt~dc0rOd1dd2TOCIfem()&w5Ok|(Dg!gSWKxsUF{kE8oFM|GJ#3%uEV}Zz zCMyOKpoBic2KmV&CCtm;a+>mMbQfA-xb2L26h+xzMUWR&l{>cPB_6A5ef}A?f>+4g z!TN~rZ0~vN6`m(8np=9kdXSq{MJI=SI-Z6s2UA!cs-W2SUi=!lzETaZ65Z_&<#lgJ zL==>+Y5ZAu3KAHO6rT907HWKqYyiL6;e4VtwV2LUTc|V@sP?sL981!|Xb z@tfI_qTag|xp=clJc)GGH;p5rz=&JQ9voCV5@*u!RC(kZp3SMV%5&;aPw0Ma+j*Gz zFLmz4JrOa_>H~Reze%yq8h-t&h_N-OAQN`E+Q-dr_Hm-NDW^Cs^;SP511qi?jd{`k z+;tv@|McNY74Gxnm>cVLR`~{kpp>I-(Hg{=?<13R)#-TV$otcbhn6LI>x+!$;eGHv z{wnUkQYKO~!7QCaP#6r2lsrcZKjq%sd5f@J9XCMwdSP&`ZZKa>D6A_grOeavQDh2+ z*Ymi4JafvL{134Mz8vz~*fq`hOVxU0;crOPH*IQL;#w<~)wAjEoIy*~Vp;|*IDheH zPjxRstXb=eNPqenk;mne1bP93IUUpWStdT5;zlym83<)-NZy@XLj2nIuYhCPIpu9jag) z)c9;jYm|%(VBPIXxgCpB^>P%J z#6sJ=dRgODrQUYqk;(G!6Jt%gam{I6y7dnHJz7!;ZaN_omKi0$2x(dg5<0Ifh5CGP z(b|AIGP5&rj+)x4iUyx`&+>+6M+aBT?QFveKbGD0)^SXAj7aN#djdG z^0Qc~?l7`Fjfi-IxSmk6E*-6$bpb|7wOZ;;eJZ6A=wk73B5KOE(sNp~sRu5#J{!JU zej#s^v9nD#;~fBB@_?>9*OL?-3dL^3zx?a(`rL(T8FX zj_r7Sw7WrUc+Vx_ddN8%TyYbhguii5yD8^aYI9*5)Okbg{zT{lrspqnigF{^C`iJe z`AAZa5MrIWJd}2vY)QS(m;GgZ%?J{LZvSWiLI3O?j!`lqUVh{gla_rC!|Ml8YB#L& zZ);u#LR_;`vW02voOQ@^>bpIdA+l= z&J6$hP1AJ+syuWmo!`KuV_n~H(U8HmXeM|JMI$muWunKK4Qivav>cu>9m-fZS>(8+ zQvde1Nzv6Vqa0zC1h1kscy27YtKD-OR)0ILHv-4!sWbDeDr~KQB4e_(Xz~G)SV1BY z8%hWaU*RN3mg}vmbf%_e59qQ=-}>p3t_g!}aRU(!e92pkSFg)(U?B*~XzJJ7j|PiidDdyQ2Vx}LpRF6^U2w42tY z?XOiARE>|I`d?N!_U6HFz@645t2NHOG2|~HQSx6S>%8P&v(g~sQny#;qF`+0!R*sN zG}3-=RT+ftaQq4yll}gAC7nL;T7EB3OnAan{`&9$$YEfDkhStC^s)r4A78d`qNH2z z(Oks1?9m

_8ju(l@pww|Mh*NR<%_+Q#?hG;hd z^OwComNJRHWgIavaaC}5`WZ;NGmW3iTb#@$XQVo9O9-KnNtDG3{9EwFIa?bs@M?9& zHbc?I0rBx%er?r-PWuP`qOOlu*=W@N+vJ%)Pqyd;90=4?jOLE03PiLE(FaHL)$=C! zavh)n(}1bNbkyNGPB4TX45kOyIs?<-9u7XKyz(DFaEMQUU-W+mh&zxaE^sNv$%W{M zi;@i`g!lzq^_3+?hx*C}gc7|0fK;}$0XiJ!tgJj>H%PZ&I|96Nf>3WkQ8`ho++)0= zvZy2k)rVKE(Mfi2a{O%%y+^9&&|s4JeM>0tSzMU7VXBqSEdf}dZBccmp2`0P(>;9C diff --git a/docs/.vuepress/styles/index.styl b/docs/.vuepress/styles/index.styl new file mode 100644 index 00000000000..a76b4921baf --- /dev/null +++ b/docs/.vuepress/styles/index.styl @@ -0,0 +1,3 @@ +:root + --color-link #E6900A + --color-primary #E6900A \ No newline at end of file diff --git a/docs/client/config.json b/docs/client/config.json new file mode 100644 index 00000000000..cfc6dc7b9c4 --- /dev/null +++ b/docs/client/config.json @@ -0,0 +1,42 @@ +{ + "swagger": "2.0", + "info": { + "title": "IBC-GO - gRPC Gateway docs", + "description": "A REST interface for state queries", + "version": "1.0.0" + }, + "apis": [ + { + "url": "./tmp-swagger-gen/ibc/applications/transfer/v1/query.swagger.json", + "operationIds": { + "rename": { + "Params": "TransferParams" + } + } + }, + { + "url": "./tmp-swagger-gen/ibc/core/client/v1/query.swagger.json", + "operationIds": { + "rename": { + "Params": "ClientParams" + } + } + }, + { + "url": "./tmp-swagger-gen/ibc/core/connection/v1/query.swagger.json", + "operationIds": { + "rename": { + "Params": "ConnectionParams" + } + } + }, + { + "url": "./tmp-swagger-gen/ibc/core/channel/v1/query.swagger.json", + "operationIds": { + "rename": { + "Params": "ChannelParams" + } + } + }, + ] +} diff --git a/docs/client/swagger-ui/swagger.yaml b/docs/client/swagger-ui/swagger.yaml new file mode 100644 index 00000000000..835c894c1a9 --- /dev/null +++ b/docs/client/swagger-ui/swagger.yaml @@ -0,0 +1,13961 @@ +swagger: '2.0' +info: + title: IBC-GO - gRPC Gateway docs + description: A REST interface for state queries + version: 1.0.0 +paths: + /ibc/apps/transfer/v1/denom_traces: + get: + summary: DenomTraces queries all denomination traces. + operationId: DenomTraces + responses: + '200': + description: A successful response. + schema: + type: object + properties: + denom_traces: + type: array + items: + type: object + properties: + path: + type: string + description: >- + path defines the chain of port/channel identifiers used + for tracing the + + source of the fungible token. + base_denom: + type: string + description: base denomination of the relayed fungible token. + description: >- + DenomTrace contains the base denomination for ICS20 fungible + tokens and the + + source tracing information path. + description: denom_traces returns all denominations trace information. + pagination: + description: pagination defines the pagination in the response. + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + QueryConnectionsResponse is the response type for the + Query/DenomTraces RPC + + method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + parameters: + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query + '/ibc/apps/transfer/v1/denom_traces/{hash}': + get: + summary: DenomTrace queries a denomination trace information. + operationId: DenomTrace + responses: + '200': + description: A successful response. + schema: + type: object + properties: + denom_trace: + type: object + properties: + path: + type: string + description: >- + path defines the chain of port/channel identifiers used + for tracing the + + source of the fungible token. + base_denom: + type: string + description: base denomination of the relayed fungible token. + description: >- + DenomTrace contains the base denomination for ICS20 fungible + tokens and the + + source tracing information path. + description: >- + QueryDenomTraceResponse is the response type for the + Query/DenomTrace RPC + + method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + parameters: + - name: hash + description: hash (in hex format) of the denomination trace information. + in: path + required: true + type: string + tags: + - Query + /ibc/apps/transfer/v1/params: + get: + summary: Params queries all parameters of the ibc-transfer module. + operationId: TransferParams + responses: + '200': + description: A successful response. + schema: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + send_enabled: + type: boolean + format: boolean + description: >- + send_enabled enables or disables all cross-chain token + transfers from this + + chain. + receive_enabled: + type: boolean + format: boolean + description: >- + receive_enabled enables or disables all cross-chain token + transfers to this + + chain. + description: >- + QueryParamsResponse is the response type for the Query/Params RPC + method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + tags: + - Query + /ibc/client/v1/params: + get: + summary: ClientParams queries all parameters of the ibc client. + operationId: ClientParams + responses: + '200': + description: A successful response. + schema: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + allowed_clients: + type: array + items: + type: string + description: >- + allowed_clients defines the list of allowed client state + types. + description: >- + QueryClientParamsResponse is the response type for the + Query/ClientParams RPC + + method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + tags: + - Query + /ibc/core/client/v1/client_states: + get: + summary: ClientStates queries all the IBC light clients of a chain. + operationId: ClientStates + responses: + '200': + description: A successful response. + schema: + type: object + properties: + client_states: + type: array + items: + type: object + properties: + client_id: + type: string + title: client identifier + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's + path must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be + in a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the + binary all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can + optionally set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results + based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available + in the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty + scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the + above specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any + values in the form + + of utility functions or additional generated methods of + the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and + the unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will + yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the + regular + + representation of the deserialized, embedded message, + with an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a + custom JSON + + representation, that representation will be embedded + adding a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message + [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state + description: >- + IdentifiedClientState defines a client state with an + additional client + + identifier field. + description: list of stored ClientStates of the chain. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + description: >- + QueryClientStatesResponse is the response type for the + Query/ClientStates RPC + + method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query + '/ibc/core/client/v1/client_states/{client_id}': + get: + summary: ClientState queries an IBC light client. + operationId: ClientState + responses: + '200': + description: A successful response. + schema: + type: object + properties: + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state associated with the request identifier + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + description: >- + QueryClientStateResponse is the response type for the + Query/ClientState RPC + + method. Besides the client state, it includes a proof and the + height from + + which the proof was retrieved. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: client_id + description: client state unique identifier + in: path + required: true + type: string + tags: + - Query + '/ibc/core/client/v1/client_status/{client_id}': + get: + summary: Status queries the status of an IBC client. + operationId: ClientStatus + responses: + '200': + description: A successful response. + schema: + type: object + properties: + status: + type: string + description: >- + QueryClientStatusResponse is the response type for the + Query/ClientStatus RPC + + method. It returns the current status of the IBC client. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: client_id + description: client unique identifier + in: path + required: true + type: string + tags: + - Query + '/ibc/core/client/v1/consensus_states/{client_id}': + get: + summary: |- + ConsensusStates queries all the consensus state associated with a given + client. + operationId: ConsensusStates + responses: + '200': + description: A successful response. + schema: + type: object + properties: + consensus_states: + type: array + items: + type: object + properties: + height: + title: consensus state height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each + height while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as + the RevisionHeight + + gets reset + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's + path must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be + in a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the + binary all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can + optionally set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results + based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available + in the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty + scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the + above specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any + values in the form + + of utility functions or additional generated methods of + the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and + the unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will + yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the + regular + + representation of the deserialized, embedded message, + with an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a + custom JSON + + representation, that representation will be embedded + adding a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message + [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: consensus state + description: >- + ConsensusStateWithHeight defines a consensus state with an + additional height + + field. + title: consensus states associated with the identifier + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + title: |- + QueryConsensusStatesResponse is the response type for the + Query/ConsensusStates RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: client_id + description: client identifier + in: path + required: true + type: string + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query + '/ibc/core/client/v1/consensus_states/{client_id}/revision/{revision_number}/height/{revision_height}': + get: + summary: >- + ConsensusState queries a consensus state associated with a client state + at + + a given height. + operationId: ConsensusState + responses: + '200': + description: A successful response. + schema: + type: object + properties: + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: >- + consensus state associated with the client identifier at the + given height + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: >- + QueryConsensusStateResponse is the response type for the + Query/ConsensusState + + RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: client_id + description: client identifier + in: path + required: true + type: string + - name: revision_number + description: consensus state revision number + in: path + required: true + type: string + format: uint64 + - name: revision_height + description: consensus state revision height + in: path + required: true + type: string + format: uint64 + - name: latest_height + description: >- + latest_height overrrides the height field and queries the latest + stored + + ConsensusState. + in: query + required: false + type: boolean + format: boolean + tags: + - Query + /ibc/core/client/v1/upgraded_client_states: + get: + summary: UpgradedClientState queries an Upgraded IBC light client. + operationId: UpgradedClientState + responses: + '200': + description: A successful response. + schema: + type: object + properties: + upgraded_client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state associated with the request identifier + description: |- + QueryUpgradedClientStateResponse is the response type for the + Query/UpgradedClientState RPC method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + tags: + - Query + /ibc/core/client/v1/upgraded_consensus_states: + get: + summary: UpgradedConsensusState queries an Upgraded IBC consensus state. + operationId: UpgradedConsensusState + responses: + '200': + description: A successful response. + schema: + type: object + properties: + upgraded_consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: Consensus state associated with the request identifier + description: |- + QueryUpgradedConsensusStateResponse is the response type for the + Query/UpgradedConsensusState RPC method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + tags: + - Query + '/ibc/core/connection/v1/client_connections/{client_id}': + get: + summary: |- + ClientConnections queries the connection paths associated with a client + state. + operationId: ClientConnections + responses: + '200': + description: A successful response. + schema: + type: object + properties: + connection_paths: + type: array + items: + type: string + description: slice of all the connection paths associated with a client. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was generated + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryClientConnectionsResponse is the response type for the + Query/ClientConnections RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: client_id + description: client identifier associated with a connection + in: path + required: true + type: string + tags: + - Query + /ibc/core/connection/v1/connections: + get: + summary: Connections queries all the IBC connections of a chain. + operationId: Connections + responses: + '200': + description: A successful response. + schema: + type: object + properties: + connections: + type: array + items: + type: object + properties: + id: + type: string + description: connection identifier. + client_id: + type: string + description: client associated with this connection. + versions: + type: array + items: + type: object + properties: + identifier: + type: string + title: unique version identifier + features: + type: array + items: + type: string + title: >- + list of features compatible with the specified + identifier + description: >- + Version defines the versioning scheme used to + negotiate the IBC verison in + + the connection handshake. + title: >- + IBC version which can be utilised to determine encodings + or protocols for + + channels or packets utilising this connection + state: + description: current state of the connection end. + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + default: STATE_UNINITIALIZED_UNSPECIFIED + counterparty: + description: counterparty chain associated with this connection. + type: object + properties: + client_id: + type: string + description: >- + identifies the client on the counterparty chain + associated with a given + + connection. + connection_id: + type: string + description: >- + identifies the connection end on the counterparty + chain associated with a + + given connection. + prefix: + description: commitment merkle prefix of the counterparty chain. + type: object + properties: + key_prefix: + type: string + format: byte + title: >- + MerklePrefix is merkle path prefixed to the key. + + The constructed key from the Path and the key will + be append(Path.KeyPath, + + append(Path.KeyPrefix, key...)) + delay_period: + type: string + format: uint64 + description: delay period associated with this connection. + description: >- + IdentifiedConnection defines a connection with additional + connection + + identifier field. + description: list of stored connections of the chain. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + description: >- + QueryConnectionsResponse is the response type for the + Query/Connections RPC + + method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query + '/ibc/core/connection/v1/connections/{connection_id}': + get: + summary: Connection queries an IBC connection end. + operationId: Connection + responses: + '200': + description: A successful response. + schema: + type: object + properties: + connection: + title: connection associated with the request identifier + type: object + properties: + client_id: + type: string + description: client associated with this connection. + versions: + type: array + items: + type: object + properties: + identifier: + type: string + title: unique version identifier + features: + type: array + items: + type: string + title: >- + list of features compatible with the specified + identifier + description: >- + Version defines the versioning scheme used to negotiate + the IBC verison in + + the connection handshake. + description: >- + IBC version which can be utilised to determine encodings + or protocols for + + channels or packets utilising this connection. + state: + description: current state of the connection end. + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + default: STATE_UNINITIALIZED_UNSPECIFIED + counterparty: + description: counterparty chain associated with this connection. + type: object + properties: + client_id: + type: string + description: >- + identifies the client on the counterparty chain + associated with a given + + connection. + connection_id: + type: string + description: >- + identifies the connection end on the counterparty + chain associated with a + + given connection. + prefix: + description: commitment merkle prefix of the counterparty chain. + type: object + properties: + key_prefix: + type: string + format: byte + title: >- + MerklePrefix is merkle path prefixed to the key. + + The constructed key from the Path and the key will be + append(Path.KeyPath, + + append(Path.KeyPrefix, key...)) + delay_period: + type: string + format: uint64 + description: >- + delay period that must pass before a consensus state can + be used for + + packet-verification NOTE: delay period logic is only + implemented by some + + clients. + description: >- + ConnectionEnd defines a stateful object on a chain connected + to another + + separate one. + + NOTE: there must only be 2 defined ConnectionEnds to establish + + a connection between two chains. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + description: >- + QueryConnectionResponse is the response type for the + Query/Connection RPC + + method. Besides the connection end, it includes a proof and the + height from + + which the proof was retrieved. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: connection_id + description: connection unique identifier + in: path + required: true + type: string + tags: + - Query + '/ibc/core/connection/v1/connections/{connection_id}/client_state': + get: + summary: |- + ConnectionClientState queries the client state associated with the + connection. + operationId: ConnectionClientState + responses: + '200': + description: A successful response. + schema: + type: object + properties: + identified_client_state: + title: client state associated with the channel + type: object + properties: + client_id: + type: string + title: client identifier + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type + of the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be + in a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can + optionally set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results + based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty + scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the + above specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any + values in the form + + of utility functions or additional generated methods of + the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and + the unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will + yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a + custom JSON + + representation, that representation will be embedded + adding a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state + description: >- + IdentifiedClientState defines a client state with an + additional client + + identifier field. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryConnectionClientStateResponse is the response type for the + Query/ConnectionClientState RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: connection_id + description: connection identifier + in: path + required: true + type: string + tags: + - Query + '/ibc/core/connection/v1/connections/{connection_id}/consensus_state/revision/{revision_number}/height/{revision_height}': + get: + summary: |- + ConnectionConsensusState queries the consensus state associated with the + connection. + operationId: ConnectionConsensusState + responses: + '200': + description: A successful response. + schema: + type: object + properties: + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: consensus state associated with the channel + client_id: + type: string + title: client ID associated with the consensus state + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryConnectionConsensusStateResponse is the response type for the + Query/ConnectionConsensusState RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: connection_id + description: connection identifier + in: path + required: true + type: string + - name: revision_number + in: path + required: true + type: string + format: uint64 + - name: revision_height + in: path + required: true + type: string + format: uint64 + tags: + - Query + /ibc/core/channel/v1/channels: + get: + summary: Channels queries all the IBC channels of a chain. + operationId: Channels + responses: + '200': + description: A successful response. + schema: + type: object + properties: + channels: + type: array + items: + type: object + properties: + state: + title: current state of the channel end + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: >- + State defines if a channel is in one of the following + states: + + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. + ordering: + title: whether the channel is ordered or unordered + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: >- + - ORDER_NONE_UNSPECIFIED: zero-value for channel + ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + counterparty: + title: counterparty channel end + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other + end of the channel. + channel_id: + type: string + title: channel end on the counterparty chain + connection_hops: + type: array + items: + type: string + title: >- + list of connection identifiers, in order, along which + packets sent on + + this channel will travel + version: + type: string + title: >- + opaque channel version, which is agreed upon during the + handshake + port_id: + type: string + title: port identifier + channel_id: + type: string + title: channel identifier + description: >- + IdentifiedChannel defines a channel with additional port and + channel + + identifier fields. + description: list of stored channels of the chain. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + description: >- + QueryChannelsResponse is the response type for the Query/Channels + RPC method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}': + get: + summary: Channel queries an IBC Channel. + operationId: Channel + responses: + '200': + description: A successful response. + schema: + type: object + properties: + channel: + title: channel associated with the request identifiers + type: object + properties: + state: + title: current state of the channel end + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: >- + State defines if a channel is in one of the following + states: + + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. + ordering: + title: whether the channel is ordered or unordered + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: |- + - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + counterparty: + title: counterparty channel end + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other + end of the channel. + channel_id: + type: string + title: channel end on the counterparty chain + connection_hops: + type: array + items: + type: string + title: >- + list of connection identifiers, in order, along which + packets sent on + + this channel will travel + version: + type: string + title: >- + opaque channel version, which is agreed upon during the + handshake + description: >- + Channel defines pipeline for exactly-once packet delivery + between specific + + modules on separate blockchains, which has at least one end + capable of + + sending packets and one end capable of receiving packets. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + description: >- + QueryChannelResponse is the response type for the Query/Channel + RPC method. + + Besides the Channel end, it includes a proof and the height from + which the + + proof was retrieved. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/client_state': + get: + summary: >- + ChannelClientState queries for the client state for the channel + associated + + with the provided channel identifiers. + operationId: ChannelClientState + responses: + '200': + description: A successful response. + schema: + type: object + properties: + identified_client_state: + title: client state associated with the channel + type: object + properties: + client_id: + type: string + title: client identifier + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type + of the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be + in a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can + optionally set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results + based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty + scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the + above specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any + values in the form + + of utility functions or additional generated methods of + the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and + the unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will + yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a + custom JSON + + representation, that representation will be embedded + adding a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state + description: >- + IdentifiedClientState defines a client state with an + additional client + + identifier field. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryChannelClientStateResponse is the Response type for the + Query/QueryChannelClientState RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/consensus_state/revision/{revision_number}/height/{revision_height}': + get: + summary: |- + ChannelConsensusState queries for the consensus state for the channel + associated with the provided channel identifiers. + operationId: ChannelConsensusState + responses: + '200': + description: A successful response. + schema: + type: object + properties: + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: consensus state associated with the channel + client_id: + type: string + title: client ID associated with the consensus state + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryChannelClientStateResponse is the Response type for the + Query/QueryChannelClientState RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: revision_number + description: revision number of the consensus state + in: path + required: true + type: string + format: uint64 + - name: revision_height + description: revision height of the consensus state + in: path + required: true + type: string + format: uint64 + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/next_sequence': + get: + summary: >- + NextSequenceReceive returns the next receive sequence for a given + channel. + operationId: NextSequenceReceive + responses: + '200': + description: A successful response. + schema: + type: object + properties: + next_sequence_receive: + type: string + format: uint64 + title: next sequence receive number + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QuerySequenceResponse is the request type for the + Query/QueryNextSequenceReceiveResponse RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_acknowledgements': + get: + summary: >- + PacketAcknowledgements returns all the packet acknowledgements + associated + + with a channel. + operationId: PacketAcknowledgements + responses: + '200': + description: A successful response. + schema: + type: object + properties: + acknowledgements: + type: array + items: + type: object + properties: + port_id: + type: string + description: channel port identifier. + channel_id: + type: string + description: channel unique identifier. + sequence: + type: string + format: uint64 + description: packet sequence. + data: + type: string + format: byte + description: embedded data that represents packet state. + description: >- + PacketState defines the generic type necessary to retrieve + and store + + packet commitments, acknowledgements, and receipts. + + Caller is responsible for knowing the context necessary to + interpret this + + state as a commitment, acknowledgement, or a receipt. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryPacketAcknowledgemetsResponse is the request type for the + Query/QueryPacketAcknowledgements RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_acks/{sequence}': + get: + summary: PacketAcknowledgement queries a stored packet acknowledgement hash. + operationId: PacketAcknowledgement + responses: + '200': + description: A successful response. + schema: + type: object + properties: + acknowledgement: + type: string + format: byte + title: packet associated with the request fields + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: >- + QueryPacketAcknowledgementResponse defines the client query + response for a + + packet which also includes a proof and the height from which the + + proof was retrieved + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: sequence + description: packet sequence + in: path + required: true + type: string + format: uint64 + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments': + get: + summary: |- + PacketCommitments returns all the packet commitments hashes associated + with a channel. + operationId: PacketCommitments + responses: + '200': + description: A successful response. + schema: + type: object + properties: + commitments: + type: array + items: + type: object + properties: + port_id: + type: string + description: channel port identifier. + channel_id: + type: string + description: channel unique identifier. + sequence: + type: string + format: uint64 + description: packet sequence. + data: + type: string + format: byte + description: embedded data that represents packet state. + description: >- + PacketState defines the generic type necessary to retrieve + and store + + packet commitments, acknowledgements, and receipts. + + Caller is responsible for knowing the context necessary to + interpret this + + state as a commitment, acknowledgement, or a receipt. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryPacketCommitmentsResponse is the request type for the + Query/QueryPacketCommitments RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{packet_ack_sequences}/unreceived_acks': + get: + summary: >- + UnreceivedAcks returns all the unreceived IBC acknowledgements + associated + + with a channel and sequences. + operationId: UnreceivedAcks + responses: + '200': + description: A successful response. + schema: + type: object + properties: + sequences: + type: array + items: + type: string + format: uint64 + title: list of unreceived acknowledgement sequences + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryUnreceivedAcksResponse is the response type for the + Query/UnreceivedAcks RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: packet_ack_sequences + description: list of acknowledgement sequences + in: path + required: true + type: array + items: + type: string + format: uint64 + collectionFormat: csv + minItems: 1 + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{packet_commitment_sequences}/unreceived_packets': + get: + summary: >- + UnreceivedPackets returns all the unreceived IBC packets associated with + a + + channel and sequences. + operationId: UnreceivedPackets + responses: + '200': + description: A successful response. + schema: + type: object + properties: + sequences: + type: array + items: + type: string + format: uint64 + title: list of unreceived packet sequences + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryUnreceivedPacketsResponse is the response type for the + Query/UnreceivedPacketCommitments RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: packet_commitment_sequences + description: list of packet sequences + in: path + required: true + type: array + items: + type: string + format: uint64 + collectionFormat: csv + minItems: 1 + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{sequence}': + get: + summary: PacketCommitment queries a stored packet commitment hash. + operationId: PacketCommitment + responses: + '200': + description: A successful response. + schema: + type: object + properties: + commitment: + type: string + format: byte + title: packet associated with the request fields + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: >- + QueryPacketCommitmentResponse defines the client query response + for a packet + + which also includes a proof and the height from which the proof + was + + retrieved + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: sequence + description: packet sequence + in: path + required: true + type: string + format: uint64 + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_receipts/{sequence}': + get: + summary: >- + PacketReceipt queries if a given packet sequence has been received on + the + + queried chain + operationId: PacketReceipt + responses: + '200': + description: A successful response. + schema: + type: object + properties: + received: + type: boolean + format: boolean + title: success flag for if receipt exists + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: >- + QueryPacketReceiptResponse defines the client query response for a + packet + + receipt which also includes a proof, and the height from which the + proof was + + retrieved + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: sequence + description: packet sequence + in: path + required: true + type: string + format: uint64 + tags: + - Query + '/ibc/core/channel/v1/connections/{connection}/channels': + get: + summary: |- + ConnectionChannels queries all the channels associated with a connection + end. + operationId: ConnectionChannels + responses: + '200': + description: A successful response. + schema: + type: object + properties: + channels: + type: array + items: + type: object + properties: + state: + title: current state of the channel end + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: >- + State defines if a channel is in one of the following + states: + + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. + ordering: + title: whether the channel is ordered or unordered + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: >- + - ORDER_NONE_UNSPECIFIED: zero-value for channel + ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + counterparty: + title: counterparty channel end + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other + end of the channel. + channel_id: + type: string + title: channel end on the counterparty chain + connection_hops: + type: array + items: + type: string + title: >- + list of connection identifiers, in order, along which + packets sent on + + this channel will travel + version: + type: string + title: >- + opaque channel version, which is agreed upon during the + handshake + port_id: + type: string + title: port identifier + channel_id: + type: string + title: channel identifier + description: >- + IdentifiedChannel defines a channel with additional port and + channel + + identifier fields. + description: list of channels associated with a connection. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryConnectionChannelsResponse is the Response type for the + Query/QueryConnectionChannels RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: connection + description: connection unique identifier + in: path + required: true + type: string + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query +definitions: + cosmos.base.query.v1beta1.PageRequest: + type: object + properties: + key: + type: string + format: byte + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + offset: + type: string + format: uint64 + description: |- + offset is a numeric offset that can be used when key is unavailable. + It is less efficient than using key. Only one of offset or key should + be set. + limit: + type: string + format: uint64 + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + count_total: + type: boolean + format: boolean + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in UIs. + + count_total is only respected when offset is used. It is ignored when + key + + is set. + description: |- + message SomeRequest { + Foo some_parameter = 1; + PageRequest pagination = 2; + } + title: |- + PageRequest is to be embedded in gRPC request messages for efficient + pagination. Ex: + cosmos.base.query.v1beta1.PageResponse: + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: |- + total is total number of results available if PageRequest.count_total + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + google.protobuf.Any: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a canonical + form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types that + they + + expect it to use in the context of Any. However, for URLs which use + the + + scheme `http`, `https`, or no scheme, one can optionally set up a type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along with + a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + grpc.gateway.runtime.Error: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types + that they + + expect it to use in the context of Any. However, for URLs which + use the + + scheme `http`, `https`, or no scheme, one can optionally set up + a type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning + with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might + be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any + type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + ibc.applications.transfer.v1.DenomTrace: + type: object + properties: + path: + type: string + description: >- + path defines the chain of port/channel identifiers used for tracing + the + + source of the fungible token. + base_denom: + type: string + description: base denomination of the relayed fungible token. + description: >- + DenomTrace contains the base denomination for ICS20 fungible tokens and + the + + source tracing information path. + ibc.applications.transfer.v1.Params: + type: object + properties: + send_enabled: + type: boolean + format: boolean + description: >- + send_enabled enables or disables all cross-chain token transfers from + this + + chain. + receive_enabled: + type: boolean + format: boolean + description: >- + receive_enabled enables or disables all cross-chain token transfers to + this + + chain. + description: >- + Params defines the set of IBC transfer parameters. + + NOTE: To prevent a single token from being transferred, set the + + TransfersEnabled parameter to true and then set the bank module's + SendEnabled + + parameter for the denomination to false. + ibc.applications.transfer.v1.QueryDenomTraceResponse: + type: object + properties: + denom_trace: + type: object + properties: + path: + type: string + description: >- + path defines the chain of port/channel identifiers used for + tracing the + + source of the fungible token. + base_denom: + type: string + description: base denomination of the relayed fungible token. + description: >- + DenomTrace contains the base denomination for ICS20 fungible tokens + and the + + source tracing information path. + description: |- + QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC + method. + ibc.applications.transfer.v1.QueryDenomTracesResponse: + type: object + properties: + denom_traces: + type: array + items: + type: object + properties: + path: + type: string + description: >- + path defines the chain of port/channel identifiers used for + tracing the + + source of the fungible token. + base_denom: + type: string + description: base denomination of the relayed fungible token. + description: >- + DenomTrace contains the base denomination for ICS20 fungible tokens + and the + + source tracing information path. + description: denom_traces returns all denominations trace information. + pagination: + description: pagination defines the pagination in the response. + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + QueryConnectionsResponse is the response type for the Query/DenomTraces + RPC + + method. + ibc.applications.transfer.v1.QueryParamsResponse: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + send_enabled: + type: boolean + format: boolean + description: >- + send_enabled enables or disables all cross-chain token transfers + from this + + chain. + receive_enabled: + type: boolean + format: boolean + description: >- + receive_enabled enables or disables all cross-chain token + transfers to this + + chain. + description: QueryParamsResponse is the response type for the Query/Params RPC method. + ibc.core.client.v1.ConsensusStateWithHeight: + type: object + properties: + height: + title: consensus state height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types + that they + + expect it to use in the context of Any. However, for URLs which + use the + + scheme `http`, `https`, or no scheme, one can optionally set up a + type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: consensus state + description: >- + ConsensusStateWithHeight defines a consensus state with an additional + height + + field. + ibc.core.client.v1.Height: + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: |- + Normally the RevisionHeight is incremented at each height while keeping + RevisionNumber 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 RevisionNumber is incremented so that + height continues to be monitonically increasing even as the RevisionHeight + gets reset + title: >- + Height is a monotonically increasing data type + + that can be compared against another Height for the purposes of updating + and + + freezing clients + ibc.core.client.v1.IdentifiedClientState: + type: object + properties: + client_id: + type: string + title: client identifier + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types + that they + + expect it to use in the context of Any. However, for URLs which + use the + + scheme `http`, `https`, or no scheme, one can optionally set up a + type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state + description: |- + IdentifiedClientState defines a client state with an additional client + identifier field. + ibc.core.client.v1.Params: + type: object + properties: + allowed_clients: + type: array + items: + type: string + description: allowed_clients defines the list of allowed client state types. + description: Params defines the set of IBC light client parameters. + ibc.core.client.v1.QueryClientParamsResponse: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + allowed_clients: + type: array + items: + type: string + description: allowed_clients defines the list of allowed client state types. + description: >- + QueryClientParamsResponse is the response type for the Query/ClientParams + RPC + + method. + ibc.core.client.v1.QueryClientStateResponse: + type: object + properties: + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types + that they + + expect it to use in the context of Any. However, for URLs which + use the + + scheme `http`, `https`, or no scheme, one can optionally set up a + type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state associated with the request identifier + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + description: >- + QueryClientStateResponse is the response type for the Query/ClientState + RPC + + method. Besides the client state, it includes a proof and the height from + + which the proof was retrieved. + ibc.core.client.v1.QueryClientStatesResponse: + type: object + properties: + client_states: + type: array + items: + type: object + properties: + client_id: + type: string + title: client identifier + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally set + up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on + the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning + with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the Any + type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state + description: >- + IdentifiedClientState defines a client state with an additional + client + + identifier field. + description: list of stored ClientStates of the chain. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + description: >- + QueryClientStatesResponse is the response type for the Query/ClientStates + RPC + + method. + ibc.core.client.v1.QueryClientStatusResponse: + type: object + properties: + status: + type: string + description: >- + QueryClientStatusResponse is the response type for the Query/ClientStatus + RPC + + method. It returns the current status of the IBC client. + ibc.core.client.v1.QueryConsensusStateResponse: + type: object + properties: + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types + that they + + expect it to use in the context of Any. However, for URLs which + use the + + scheme `http`, `https`, or no scheme, one can optionally set up a + type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: >- + consensus state associated with the client identifier at the given + height + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: >- + QueryConsensusStateResponse is the response type for the + Query/ConsensusState + + RPC method + ibc.core.client.v1.QueryConsensusStatesResponse: + type: object + properties: + consensus_states: + type: array + items: + type: object + properties: + height: + title: consensus state height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally set + up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on + the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning + with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the Any + type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: consensus state + description: >- + ConsensusStateWithHeight defines a consensus state with an + additional height + + field. + title: consensus states associated with the identifier + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + title: |- + QueryConsensusStatesResponse is the response type for the + Query/ConsensusStates RPC method + ibc.core.client.v1.QueryUpgradedClientStateResponse: + type: object + properties: + upgraded_client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types + that they + + expect it to use in the context of Any. However, for URLs which + use the + + scheme `http`, `https`, or no scheme, one can optionally set up a + type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state associated with the request identifier + description: |- + QueryUpgradedClientStateResponse is the response type for the + Query/UpgradedClientState RPC method. + ibc.core.client.v1.QueryUpgradedConsensusStateResponse: + type: object + properties: + upgraded_consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types + that they + + expect it to use in the context of Any. However, for URLs which + use the + + scheme `http`, `https`, or no scheme, one can optionally set up a + type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: Consensus state associated with the request identifier + description: |- + QueryUpgradedConsensusStateResponse is the response type for the + Query/UpgradedConsensusState RPC method. + ibc.core.commitment.v1.MerklePrefix: + type: object + properties: + key_prefix: + type: string + format: byte + title: |- + MerklePrefix is merkle path prefixed to the key. + The constructed key from the Path and the key will be append(Path.KeyPath, + append(Path.KeyPrefix, key...)) + ibc.core.connection.v1.ConnectionEnd: + type: object + properties: + client_id: + type: string + description: client associated with this connection. + versions: + type: array + items: + type: object + properties: + identifier: + type: string + title: unique version identifier + features: + type: array + items: + type: string + title: list of features compatible with the specified identifier + description: >- + Version defines the versioning scheme used to negotiate the IBC + verison in + + the connection handshake. + description: >- + IBC version which can be utilised to determine encodings or protocols + for + + channels or packets utilising this connection. + state: + description: current state of the connection end. + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + default: STATE_UNINITIALIZED_UNSPECIFIED + counterparty: + description: counterparty chain associated with this connection. + type: object + properties: + client_id: + type: string + description: >- + identifies the client on the counterparty chain associated with a + given + + connection. + connection_id: + type: string + description: >- + identifies the connection end on the counterparty chain associated + with a + + given connection. + prefix: + description: commitment merkle prefix of the counterparty chain. + type: object + properties: + key_prefix: + type: string + format: byte + title: >- + MerklePrefix is merkle path prefixed to the key. + + The constructed key from the Path and the key will be + append(Path.KeyPath, + + append(Path.KeyPrefix, key...)) + delay_period: + type: string + format: uint64 + description: >- + delay period that must pass before a consensus state can be used for + + packet-verification NOTE: delay period logic is only implemented by + some + + clients. + description: |- + ConnectionEnd defines a stateful object on a chain connected to another + separate one. + NOTE: there must only be 2 defined ConnectionEnds to establish + a connection between two chains. + ibc.core.connection.v1.Counterparty: + type: object + properties: + client_id: + type: string + description: >- + identifies the client on the counterparty chain associated with a + given + + connection. + connection_id: + type: string + description: >- + identifies the connection end on the counterparty chain associated + with a + + given connection. + prefix: + description: commitment merkle prefix of the counterparty chain. + type: object + properties: + key_prefix: + type: string + format: byte + title: >- + MerklePrefix is merkle path prefixed to the key. + + The constructed key from the Path and the key will be + append(Path.KeyPath, + + append(Path.KeyPrefix, key...)) + description: >- + Counterparty defines the counterparty chain associated with a connection + end. + ibc.core.connection.v1.IdentifiedConnection: + type: object + properties: + id: + type: string + description: connection identifier. + client_id: + type: string + description: client associated with this connection. + versions: + type: array + items: + type: object + properties: + identifier: + type: string + title: unique version identifier + features: + type: array + items: + type: string + title: list of features compatible with the specified identifier + description: >- + Version defines the versioning scheme used to negotiate the IBC + verison in + + the connection handshake. + title: >- + IBC version which can be utilised to determine encodings or protocols + for + + channels or packets utilising this connection + state: + description: current state of the connection end. + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + default: STATE_UNINITIALIZED_UNSPECIFIED + counterparty: + description: counterparty chain associated with this connection. + type: object + properties: + client_id: + type: string + description: >- + identifies the client on the counterparty chain associated with a + given + + connection. + connection_id: + type: string + description: >- + identifies the connection end on the counterparty chain associated + with a + + given connection. + prefix: + description: commitment merkle prefix of the counterparty chain. + type: object + properties: + key_prefix: + type: string + format: byte + title: >- + MerklePrefix is merkle path prefixed to the key. + + The constructed key from the Path and the key will be + append(Path.KeyPath, + + append(Path.KeyPrefix, key...)) + delay_period: + type: string + format: uint64 + description: delay period associated with this connection. + description: |- + IdentifiedConnection defines a connection with additional connection + identifier field. + ibc.core.connection.v1.QueryClientConnectionsResponse: + type: object + properties: + connection_paths: + type: array + items: + type: string + description: slice of all the connection paths associated with a client. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was generated + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryClientConnectionsResponse is the response type for the + Query/ClientConnections RPC method + ibc.core.connection.v1.QueryConnectionClientStateResponse: + type: object + properties: + identified_client_state: + title: client state associated with the channel + type: object + properties: + client_id: + type: string + title: client identifier + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally set + up a type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on + the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning + with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might + be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any + type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state + description: |- + IdentifiedClientState defines a client state with an additional client + identifier field. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryConnectionClientStateResponse is the response type for the + Query/ConnectionClientState RPC method + ibc.core.connection.v1.QueryConnectionConsensusStateResponse: + type: object + properties: + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types + that they + + expect it to use in the context of Any. However, for URLs which + use the + + scheme `http`, `https`, or no scheme, one can optionally set up a + type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: consensus state associated with the channel + client_id: + type: string + title: client ID associated with the consensus state + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryConnectionConsensusStateResponse is the response type for the + Query/ConnectionConsensusState RPC method + ibc.core.connection.v1.QueryConnectionResponse: + type: object + properties: + connection: + title: connection associated with the request identifier + type: object + properties: + client_id: + type: string + description: client associated with this connection. + versions: + type: array + items: + type: object + properties: + identifier: + type: string + title: unique version identifier + features: + type: array + items: + type: string + title: list of features compatible with the specified identifier + description: >- + Version defines the versioning scheme used to negotiate the IBC + verison in + + the connection handshake. + description: >- + IBC version which can be utilised to determine encodings or + protocols for + + channels or packets utilising this connection. + state: + description: current state of the connection end. + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + default: STATE_UNINITIALIZED_UNSPECIFIED + counterparty: + description: counterparty chain associated with this connection. + type: object + properties: + client_id: + type: string + description: >- + identifies the client on the counterparty chain associated + with a given + + connection. + connection_id: + type: string + description: >- + identifies the connection end on the counterparty chain + associated with a + + given connection. + prefix: + description: commitment merkle prefix of the counterparty chain. + type: object + properties: + key_prefix: + type: string + format: byte + title: >- + MerklePrefix is merkle path prefixed to the key. + + The constructed key from the Path and the key will be + append(Path.KeyPath, + + append(Path.KeyPrefix, key...)) + delay_period: + type: string + format: uint64 + description: >- + delay period that must pass before a consensus state can be used + for + + packet-verification NOTE: delay period logic is only implemented + by some + + clients. + description: >- + ConnectionEnd defines a stateful object on a chain connected to + another + + separate one. + + NOTE: there must only be 2 defined ConnectionEnds to establish + + a connection between two chains. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + description: >- + QueryConnectionResponse is the response type for the Query/Connection RPC + + method. Besides the connection end, it includes a proof and the height + from + + which the proof was retrieved. + ibc.core.connection.v1.QueryConnectionsResponse: + type: object + properties: + connections: + type: array + items: + type: object + properties: + id: + type: string + description: connection identifier. + client_id: + type: string + description: client associated with this connection. + versions: + type: array + items: + type: object + properties: + identifier: + type: string + title: unique version identifier + features: + type: array + items: + type: string + title: list of features compatible with the specified identifier + description: >- + Version defines the versioning scheme used to negotiate the + IBC verison in + + the connection handshake. + title: >- + IBC version which can be utilised to determine encodings or + protocols for + + channels or packets utilising this connection + state: + description: current state of the connection end. + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + default: STATE_UNINITIALIZED_UNSPECIFIED + counterparty: + description: counterparty chain associated with this connection. + type: object + properties: + client_id: + type: string + description: >- + identifies the client on the counterparty chain associated + with a given + + connection. + connection_id: + type: string + description: >- + identifies the connection end on the counterparty chain + associated with a + + given connection. + prefix: + description: commitment merkle prefix of the counterparty chain. + type: object + properties: + key_prefix: + type: string + format: byte + title: >- + MerklePrefix is merkle path prefixed to the key. + + The constructed key from the Path and the key will be + append(Path.KeyPath, + + append(Path.KeyPrefix, key...)) + delay_period: + type: string + format: uint64 + description: delay period associated with this connection. + description: |- + IdentifiedConnection defines a connection with additional connection + identifier field. + description: list of stored connections of the chain. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + description: >- + QueryConnectionsResponse is the response type for the Query/Connections + RPC + + method. + ibc.core.connection.v1.State: + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + default: STATE_UNINITIALIZED_UNSPECIFIED + description: |- + State defines if a connection is in one of the following states: + INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A connection end has just started the opening handshake. + - STATE_TRYOPEN: A connection end has acknowledged the handshake step on the counterparty + chain. + - STATE_OPEN: A connection end has completed the handshake. + ibc.core.connection.v1.Version: + type: object + properties: + identifier: + type: string + title: unique version identifier + features: + type: array + items: + type: string + title: list of features compatible with the specified identifier + description: |- + Version defines the versioning scheme used to negotiate the IBC verison in + the connection handshake. + ibc.core.channel.v1.Channel: + type: object + properties: + state: + title: current state of the channel end + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: |- + State defines if a channel is in one of the following states: + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. + ordering: + title: whether the channel is ordered or unordered + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: |- + - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + counterparty: + title: counterparty channel end + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other end of the + channel. + channel_id: + type: string + title: channel end on the counterparty chain + connection_hops: + type: array + items: + type: string + title: |- + list of connection identifiers, in order, along which packets sent on + this channel will travel + version: + type: string + title: 'opaque channel version, which is agreed upon during the handshake' + description: |- + Channel defines pipeline for exactly-once packet delivery between specific + modules on separate blockchains, which has at least one end capable of + sending packets and one end capable of receiving packets. + ibc.core.channel.v1.Counterparty: + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other end of the + channel. + channel_id: + type: string + title: channel end on the counterparty chain + title: Counterparty defines a channel end counterparty + ibc.core.channel.v1.IdentifiedChannel: + type: object + properties: + state: + title: current state of the channel end + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: |- + State defines if a channel is in one of the following states: + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. + ordering: + title: whether the channel is ordered or unordered + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: |- + - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + counterparty: + title: counterparty channel end + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other end of the + channel. + channel_id: + type: string + title: channel end on the counterparty chain + connection_hops: + type: array + items: + type: string + title: |- + list of connection identifiers, in order, along which packets sent on + this channel will travel + version: + type: string + title: 'opaque channel version, which is agreed upon during the handshake' + port_id: + type: string + title: port identifier + channel_id: + type: string + title: channel identifier + description: |- + IdentifiedChannel defines a channel with additional port and channel + identifier fields. + ibc.core.channel.v1.Order: + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: |- + - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + title: Order defines if a channel is ORDERED or UNORDERED + ibc.core.channel.v1.PacketState: + type: object + properties: + port_id: + type: string + description: channel port identifier. + channel_id: + type: string + description: channel unique identifier. + sequence: + type: string + format: uint64 + description: packet sequence. + data: + type: string + format: byte + description: embedded data that represents packet state. + description: |- + PacketState defines the generic type necessary to retrieve and store + packet commitments, acknowledgements, and receipts. + Caller is responsible for knowing the context necessary to interpret this + state as a commitment, acknowledgement, or a receipt. + ibc.core.channel.v1.QueryChannelClientStateResponse: + type: object + properties: + identified_client_state: + title: client state associated with the channel + type: object + properties: + client_id: + type: string + title: client identifier + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally set + up a type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on + the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning + with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might + be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any + type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state + description: |- + IdentifiedClientState defines a client state with an additional client + identifier field. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryChannelClientStateResponse is the Response type for the + Query/QueryChannelClientState RPC method + ibc.core.channel.v1.QueryChannelConsensusStateResponse: + type: object + properties: + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types + that they + + expect it to use in the context of Any. However, for URLs which + use the + + scheme `http`, `https`, or no scheme, one can optionally set up a + type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: consensus state associated with the channel + client_id: + type: string + title: client ID associated with the consensus state + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryChannelClientStateResponse is the Response type for the + Query/QueryChannelClientState RPC method + ibc.core.channel.v1.QueryChannelResponse: + type: object + properties: + channel: + title: channel associated with the request identifiers + type: object + properties: + state: + title: current state of the channel end + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: |- + State defines if a channel is in one of the following states: + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. + ordering: + title: whether the channel is ordered or unordered + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: |- + - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + counterparty: + title: counterparty channel end + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other end of the + channel. + channel_id: + type: string + title: channel end on the counterparty chain + connection_hops: + type: array + items: + type: string + title: >- + list of connection identifiers, in order, along which packets sent + on + + this channel will travel + version: + type: string + title: 'opaque channel version, which is agreed upon during the handshake' + description: >- + Channel defines pipeline for exactly-once packet delivery between + specific + + modules on separate blockchains, which has at least one end capable of + + sending packets and one end capable of receiving packets. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + description: >- + QueryChannelResponse is the response type for the Query/Channel RPC + method. + + Besides the Channel end, it includes a proof and the height from which the + + proof was retrieved. + ibc.core.channel.v1.QueryChannelsResponse: + type: object + properties: + channels: + type: array + items: + type: object + properties: + state: + title: current state of the channel end + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: |- + State defines if a channel is in one of the following states: + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. + ordering: + title: whether the channel is ordered or unordered + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: |- + - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + counterparty: + title: counterparty channel end + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other end of + the channel. + channel_id: + type: string + title: channel end on the counterparty chain + connection_hops: + type: array + items: + type: string + title: >- + list of connection identifiers, in order, along which packets + sent on + + this channel will travel + version: + type: string + title: >- + opaque channel version, which is agreed upon during the + handshake + port_id: + type: string + title: port identifier + channel_id: + type: string + title: channel identifier + description: |- + IdentifiedChannel defines a channel with additional port and channel + identifier fields. + description: list of stored channels of the chain. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + description: >- + QueryChannelsResponse is the response type for the Query/Channels RPC + method. + ibc.core.channel.v1.QueryConnectionChannelsResponse: + type: object + properties: + channels: + type: array + items: + type: object + properties: + state: + title: current state of the channel end + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: |- + State defines if a channel is in one of the following states: + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. + ordering: + title: whether the channel is ordered or unordered + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: |- + - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + counterparty: + title: counterparty channel end + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other end of + the channel. + channel_id: + type: string + title: channel end on the counterparty chain + connection_hops: + type: array + items: + type: string + title: >- + list of connection identifiers, in order, along which packets + sent on + + this channel will travel + version: + type: string + title: >- + opaque channel version, which is agreed upon during the + handshake + port_id: + type: string + title: port identifier + channel_id: + type: string + title: channel identifier + description: |- + IdentifiedChannel defines a channel with additional port and channel + identifier fields. + description: list of channels associated with a connection. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryConnectionChannelsResponse is the Response type for the + Query/QueryConnectionChannels RPC method + ibc.core.channel.v1.QueryNextSequenceReceiveResponse: + type: object + properties: + next_sequence_receive: + type: string + format: uint64 + title: next sequence receive number + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QuerySequenceResponse is the request type for the + Query/QueryNextSequenceReceiveResponse RPC method + ibc.core.channel.v1.QueryPacketAcknowledgementResponse: + type: object + properties: + acknowledgement: + type: string + format: byte + title: packet associated with the request fields + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryPacketAcknowledgementResponse defines the client query response for a + packet which also includes a proof and the height from which the + proof was retrieved + ibc.core.channel.v1.QueryPacketAcknowledgementsResponse: + type: object + properties: + acknowledgements: + type: array + items: + type: object + properties: + port_id: + type: string + description: channel port identifier. + channel_id: + type: string + description: channel unique identifier. + sequence: + type: string + format: uint64 + description: packet sequence. + data: + type: string + format: byte + description: embedded data that represents packet state. + description: >- + PacketState defines the generic type necessary to retrieve and store + + packet commitments, acknowledgements, and receipts. + + Caller is responsible for knowing the context necessary to interpret + this + + state as a commitment, acknowledgement, or a receipt. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryPacketAcknowledgemetsResponse is the request type for the + Query/QueryPacketAcknowledgements RPC method + ibc.core.channel.v1.QueryPacketCommitmentResponse: + type: object + properties: + commitment: + type: string + format: byte + title: packet associated with the request fields + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: >- + QueryPacketCommitmentResponse defines the client query response for a + packet + + which also includes a proof and the height from which the proof was + + retrieved + ibc.core.channel.v1.QueryPacketCommitmentsResponse: + type: object + properties: + commitments: + type: array + items: + type: object + properties: + port_id: + type: string + description: channel port identifier. + channel_id: + type: string + description: channel unique identifier. + sequence: + type: string + format: uint64 + description: packet sequence. + data: + type: string + format: byte + description: embedded data that represents packet state. + description: >- + PacketState defines the generic type necessary to retrieve and store + + packet commitments, acknowledgements, and receipts. + + Caller is responsible for knowing the context necessary to interpret + this + + state as a commitment, acknowledgement, or a receipt. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryPacketCommitmentsResponse is the request type for the + Query/QueryPacketCommitments RPC method + ibc.core.channel.v1.QueryPacketReceiptResponse: + type: object + properties: + received: + type: boolean + format: boolean + title: success flag for if receipt exists + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: >- + QueryPacketReceiptResponse defines the client query response for a packet + + receipt which also includes a proof, and the height from which the proof + was + + retrieved + ibc.core.channel.v1.QueryUnreceivedAcksResponse: + type: object + properties: + sequences: + type: array + items: + type: string + format: uint64 + title: list of unreceived acknowledgement sequences + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryUnreceivedAcksResponse is the response type for the + Query/UnreceivedAcks RPC method + ibc.core.channel.v1.QueryUnreceivedPacketsResponse: + type: object + properties: + sequences: + type: array + items: + type: string + format: uint64 + title: list of unreceived packet sequences + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber 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 RevisionNumber is incremented so + that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryUnreceivedPacketsResponse is the response type for the + Query/UnreceivedPacketCommitments RPC method + ibc.core.channel.v1.State: + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: |- + State defines if a channel is in one of the following states: + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. diff --git a/docs/ibc/integration.md b/docs/ibc/integration.md index b294b54be6c..162fbc35b7c 100644 --- a/docs/ibc/integration.md +++ b/docs/ibc/integration.md @@ -139,7 +139,7 @@ func NewApp(...args) *App { ### Module Managers -In order to use IBC, we need to add the new modules to the module `Manager` and to the `SimulationManager` in case your application supports [simulations](./../building-modules/simulator.md). +In order to use IBC, we need to add the new modules to the module `Manager` and to the `SimulationManager` in case your application supports [simulations](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/simulator.md). ```go // app.go @@ -221,4 +221,4 @@ different chains. If you want to have a broader view of the changes take a look ## Next {hide} -Learn about how to create [custom IBC modules](./custom.md) for your application {hide} +Learn about how to create [custom IBC modules](./apps.md) for your application {hide} diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 6fd91fd126d..995c07be5a0 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -25,7 +25,6 @@ - [ibc/applications/transfer/v1/transfer.proto](#ibc/applications/transfer/v1/transfer.proto) - [DenomTrace](#ibc.applications.transfer.v1.DenomTrace) - - [FungibleTokenPacketData](#ibc.applications.transfer.v1.FungibleTokenPacketData) - [Params](#ibc.applications.transfer.v1.Params) - [ibc/applications/transfer/v1/genesis.proto](#ibc/applications/transfer/v1/genesis.proto) @@ -56,6 +55,9 @@ - [Msg](#ibc.applications.transfer.v1.Msg) +- [ibc/applications/transfer/v2/packet.proto](#ibc/applications/transfer/v2/packet.proto) + - [FungibleTokenPacketData](#ibc.applications.transfer.v2.FungibleTokenPacketData) + - [ibc/core/channel/v1/channel.proto](#ibc/core/channel/v1/channel.proto) - [Acknowledgement](#ibc.core.channel.v1.Acknowledgement) - [Channel](#ibc.core.channel.v1.Channel) @@ -208,6 +210,12 @@ - [Msg](#ibc.core.connection.v1.Msg) +- [ibc/core/port/v1/query.proto](#ibc/core/port/v1/query.proto) + - [QueryAppVersionRequest](#ibc.core.port.v1.QueryAppVersionRequest) + - [QueryAppVersionResponse](#ibc.core.port.v1.QueryAppVersionResponse) + + - [Query](#ibc.core.port.v1.Query) + - [ibc/core/types/v1/genesis.proto](#ibc/core/types/v1/genesis.proto) - [GenesisState](#ibc.core.types.v1.GenesisState) @@ -483,26 +491,6 @@ source tracing information path. - - -### FungibleTokenPacketData -FungibleTokenPacketData defines a struct for the packet payload -See FungibleTokenPacketData spec: -https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#data-structures - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `denom` | [string](#string) | | the token denomination to be transferred | -| `amount` | [uint64](#uint64) | | the token amount to be transferred | -| `sender` | [string](#string) | | the sender address | -| `receiver` | [string](#string) | | the recipient address on the destination chain | - - - - - - ### Params @@ -888,6 +876,42 @@ Msg defines the ibc/transfer Msg service. + +

Top

+ +## ibc/applications/transfer/v2/packet.proto + + + + + +### FungibleTokenPacketData +FungibleTokenPacketData defines a struct for the packet payload +See FungibleTokenPacketData spec: +https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#data-structures + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `denom` | [string](#string) | | the token denomination to be transferred | +| `amount` | [string](#string) | | the token amount to be transferred | +| `sender` | [string](#string) | | the sender address | +| `receiver` | [string](#string) | | the recipient address on the destination chain | + + + + + + + + + + + + + + +

Top

@@ -1379,6 +1403,7 @@ Query/QueryPacketCommitments RPC method | `port_id` | [string](#string) | | port unique identifier | | `channel_id` | [string](#string) | | channel unique identifier | | `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination request | +| `packet_commitment_sequences` | [uint64](#uint64) | repeated | list of packet sequences | @@ -3086,6 +3111,67 @@ Msg defines the ibc/connection Msg service. + +

Top

+ +## ibc/core/port/v1/query.proto + + + + + +### QueryAppVersionRequest +QueryAppVersionRequest is the request type for the Query/AppVersion RPC method + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `port_id` | [string](#string) | | port unique identifier | +| `connection_id` | [string](#string) | | connection unique identifier | +| `ordering` | [ibc.core.channel.v1.Order](#ibc.core.channel.v1.Order) | | whether the channel is ordered or unordered | +| `counterparty` | [ibc.core.channel.v1.Counterparty](#ibc.core.channel.v1.Counterparty) | | counterparty channel end | +| `proposed_version` | [string](#string) | | proposed version | + + + + + + + + +### QueryAppVersionResponse +QueryAppVersionResponse is the response type for the Query/AppVersion RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `port_id` | [string](#string) | | port id associated with the request identifiers | +| `version` | [string](#string) | | supported app version | + + + + + + + + + + + + + + +### Query +Query defines the gRPC querier service + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `AppVersion` | [QueryAppVersionRequest](#ibc.core.port.v1.QueryAppVersionRequest) | [QueryAppVersionResponse](#ibc.core.port.v1.QueryAppVersionResponse) | AppVersion queries an IBC Port and determines the appropriate application version to be used | | + + + + +

Top

diff --git a/docs/package-lock.json b/docs/package-lock.json index 8e79e60db7e..5e6b7b1c547 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -9,6 +9,9 @@ "license": "ISC", "dependencies": { "vuepress-theme-cosmos": "^1.0.182" + }, + "devDependencies": { + "watchpack": "^2.2.0" } }, "node_modules/@algolia/cache-browser-local-storage": { @@ -8629,9 +8632,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "node_modules/picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "optional": true, "engines": { "node": ">=8.6" @@ -12565,16 +12568,16 @@ } }, "node_modules/watchpack": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", - "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", + "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "dev": true, "dependencies": { - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" }, - "optionalDependencies": { - "chokidar": "^3.4.1", - "watchpack-chokidar2": "^2.0.1" + "engines": { + "node": ">=10.13.0" } }, "node_modules/watchpack-chokidar2": { @@ -12586,142 +12589,11 @@ "chokidar": "^2.1.8" } }, - "node_modules/watchpack/node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "optional": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/watchpack/node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/watchpack/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "optional": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/watchpack/node_modules/chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", - "optional": true, - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.1" - } - }, - "node_modules/watchpack/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "optional": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/watchpack/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/watchpack/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "optional": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/watchpack/node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "optional": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/watchpack/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "optional": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/watchpack/node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "optional": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/watchpack/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "optional": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } + "node_modules/watchpack/node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true }, "node_modules/wbuf": { "version": "1.7.3", @@ -12999,6 +12871,119 @@ "node": ">=0.4.0" } }, + "node_modules/webpack/node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "optional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/webpack/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "optional": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack/node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "optional": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/webpack/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "optional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/webpack/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "optional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/webpack/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "optional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "optional": true, + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/webpack/node_modules/mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -13010,6 +12995,18 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/webpack/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "optional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/webpack/node_modules/schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -13023,6 +13020,31 @@ "node": ">= 4" } }, + "node_modules/webpack/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "optional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/webpack/node_modules/watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "dependencies": { + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + }, + "optionalDependencies": { + "chokidar": "^3.4.1", + "watchpack-chokidar2": "^2.0.1" + } + }, "node_modules/webpackbar": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-3.2.0.tgz", @@ -14701,6 +14723,7 @@ "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-4.5.12.tgz", "integrity": "sha512-8q67ORQ9O0Ms0nlqsXTVhaBefRBaLrzPxOewAZhdcO7onHwcO5/wRdWtHhZgfpCZlhY7NogkU16z3WnorSSkEA==", "requires": { + "@babel/core": "^7.11.0", "@babel/helper-compilation-targets": "^7.9.6", "@babel/helper-module-imports": "^7.8.3", "@babel/plugin-proposal-class-properties": "^7.8.3", @@ -14713,6 +14736,7 @@ "@vue/babel-plugin-jsx": "^1.0.3", "@vue/babel-preset-jsx": "^1.2.4", "babel-plugin-dynamic-import-node": "^2.3.3", + "core-js": "^3.6.5", "core-js-compat": "^3.6.5", "semver": "^6.1.0" } @@ -20308,9 +20332,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "optional": true }, "pify": { @@ -23579,16 +23603,80 @@ } }, "watchpack": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", - "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", + "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "dev": true, "requires": { - "chokidar": "^3.4.1", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.1" + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" }, "dependencies": { + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + } + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "optional": true, + "requires": { + "chokidar": "^2.1.8" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "webpack": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + }, "anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -23615,19 +23703,19 @@ } }, "chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", "optional": true, "requires": { - "anymatch": "~3.1.1", + "anymatch": "~3.1.2", "braces": "~3.0.2", - "fsevents": "~2.3.1", - "glob-parent": "~5.1.0", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "readdirp": "~3.6.0" } }, "fill-range": { @@ -23669,83 +23757,6 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "optional": true }, - "readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "optional": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "optional": true, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "watchpack-chokidar2": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", - "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", - "optional": true, - "requires": { - "chokidar": "^2.1.8" - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" - }, - "webpack": { - "version": "4.46.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", - "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/wasm-edit": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "acorn": "^6.4.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.5.0", - "eslint-scope": "^4.0.3", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.3", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.3", - "watchpack": "^1.7.4", - "webpack-sources": "^1.4.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" - }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -23754,6 +23765,15 @@ "minimist": "^1.2.5" } }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "optional": true, + "requires": { + "picomatch": "^2.2.1" + } + }, "schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -23763,6 +23783,26 @@ "ajv-errors": "^1.0.0", "ajv-keywords": "^3.1.0" } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "optional": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + } } } }, diff --git a/docs/package.json b/docs/package.json index 0770590f9fc..e97a0bad3ed 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,7 +1,7 @@ { "name": "docs", "version": "1.0.0", - "description": "IBC-GO Documentation", + "description": "IBC-Go Documentation", "main": "index.js", "scripts": { "serve": "trap 'exit 0' SIGINT; vuepress dev --no-cache", @@ -14,5 +14,8 @@ "license": "ISC", "dependencies": { "vuepress-theme-cosmos": "^1.0.182" + }, + "devDependencies": { + "watchpack": "^2.2.0" } } diff --git a/docs/pre.sh b/docs/pre.sh new file mode 100755 index 00000000000..06058a768ce --- /dev/null +++ b/docs/pre.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +echo "Nothing to do in pre step" \ No newline at end of file diff --git a/docs/versions b/docs/versions new file mode 100644 index 00000000000..40bbbb4309e --- /dev/null +++ b/docs/versions @@ -0,0 +1,3 @@ +release/v1.2.x v1.2.0 +release/v1.1.x v1.1.0 +main main diff --git a/go.mod b/go.mod index a647d655cf3..7aaa19dc2e9 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alp require ( github.com/armon/go-metrics v0.3.9 github.com/confio/ics23/go v0.6.6 - github.com/cosmos/cosmos-sdk v0.43.0-rc1 + github.com/cosmos/cosmos-sdk v0.44.0 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 github.com/gorilla/mux v1.8.0 @@ -15,14 +15,14 @@ require ( github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 github.com/regen-network/cosmos-proto v0.3.1 - github.com/spf13/cast v1.3.1 + github.com/spf13/cast v1.4.1 github.com/spf13/cobra v1.2.1 github.com/spf13/viper v1.8.1 github.com/stretchr/testify v1.7.0 - github.com/tendermint/tendermint v0.34.11 + github.com/tendermint/tendermint v0.34.13 github.com/tendermint/tm-db v0.6.4 google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c - google.golang.org/grpc v1.39.0 + google.golang.org/grpc v1.40.0 google.golang.org/protobuf v1.27.1 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index d98c79735f6..854384596a5 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -44,6 +45,9 @@ github.com/99designs/keyring v1.1.6/go.mod h1:16e0ds7LGQQcT59QqkTg72Hh5ShM51Byv5 github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= @@ -63,6 +67,11 @@ github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= @@ -74,6 +83,8 @@ github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/ github.com/Workiva/go-datastructures v1.0.52 h1:PLSK6pwn8mYdaoaCZEMsXBpBotr4HHn9abU0yMQt0NI= github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6/go.mod h1:eSYp2T6f0apnuW8TzhV3f6Aff2SE8Dwio++U4ha4yEM= +github.com/adlio/schema v1.1.13 h1:LeNMVg5Z1FX+Qgz8tJUijBLRdcpbFUElz+d1489On98= +github.com/adlio/schema v1.1.13/go.mod h1:L5Z7tw+7lRK1Fnpi/LT/ooCP1elkXn0krMWBQHUhEDE= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -103,6 +114,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= @@ -127,6 +139,7 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= @@ -134,9 +147,11 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= @@ -154,6 +169,10 @@ github.com/confio/ics23/go v0.0.0-20200817220745-f173e6211efb/go.mod h1:E45Nqnlp github.com/confio/ics23/go v0.6.3/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/confio/ics23/go v0.6.6 h1:pkOy18YxxJ/r0XFDCnrl4Bjv6h4LkBSpLS6F38mrKL8= github.com/confio/ics23/go v0.6.6/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -165,8 +184,8 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cosmos/cosmos-sdk v0.43.0-rc1 h1:3QGgMqwLmzW+015P4ZEIQ+wRj7TrVU063D2QpHc2Syw= -github.com/cosmos/cosmos-sdk v0.43.0-rc1/go.mod h1:ctcrTEAhei9s8O3KSNvL0dxe+fVQGp07QyRb/7H9JYE= +github.com/cosmos/cosmos-sdk v0.44.0 h1:eOSjACNtTnThEJ62IsS+pMm3OIU6hgMVqrp4TZClLZo= +github.com/cosmos/cosmos-sdk v0.44.0/go.mod h1:orG0jzFJ2KsDfzLd/X0JSOMzF4Oxc/BQz2GkcYF4gRE= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= @@ -183,6 +202,7 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -206,6 +226,10 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= @@ -246,6 +270,7 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -388,6 +413,8 @@ github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qH github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -495,12 +522,15 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= @@ -544,12 +574,14 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -587,6 +619,16 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -595,6 +637,8 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ= github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -694,12 +738,17 @@ github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZ github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= @@ -714,8 +763,9 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= @@ -756,6 +806,7 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= @@ -770,8 +821,9 @@ github.com/tendermint/tendermint v0.34.0-rc4/go.mod h1:yotsojf2C1QBOw4dZrTcxbyxm github.com/tendermint/tendermint v0.34.0-rc6/go.mod h1:ugzyZO5foutZImv0Iyx/gOFCX6mjJTgbLHTwi17VDVg= github.com/tendermint/tendermint v0.34.0/go.mod h1:Aj3PIipBFSNO21r+Lq3TtzQ+uKESxkbA3yo/INM4QwQ= github.com/tendermint/tendermint v0.34.10/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0= -github.com/tendermint/tendermint v0.34.11 h1:q1Yh76oG4QbS07xhmIJh5iAE0fYpJ8P8YKYtjnWfJRY= -github.com/tendermint/tendermint v0.34.11/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0= +github.com/tendermint/tendermint v0.34.12/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0= +github.com/tendermint/tendermint v0.34.13 h1:fu+tsHudbOr5PvepjH0q47Jae59hQAvn3IqAHv2EbC8= +github.com/tendermint/tendermint v0.34.13/go.mod h1:6RVVRBqwtKhA+H59APKumO+B7Nye4QXSFc6+TYxAxCI= github.com/tendermint/tm-db v0.6.2/go.mod h1:GYtQ67SUvATOcoY8/+x6ylk8Qo02BQyLrAs+yAcLvGI= github.com/tendermint/tm-db v0.6.3/go.mod h1:lfA1dL9/Y/Y8wwyPp2NMLyn5P5Ptr/gvDFNWtrCWSf8= github.com/tendermint/tm-db v0.6.4 h1:3N2jlnYQkXNQclQwd/eKV/NzlqPlfK21cpRRIx80XXQ= @@ -793,6 +845,8 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vmihailenco/msgpack/v5 v5.1.4/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI= github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= @@ -920,6 +974,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -943,12 +998,14 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg= +golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -990,15 +1047,18 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1040,9 +1100,12 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210903071746-97244b99971b h1:3Dq0eVHn0uaQJmPO+/aYPI/fRMqdrVDbu7MQcku54gg= +golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1230,8 +1293,8 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1281,6 +1344,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index d515b5f667d..740eea4ad6b 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -254,3 +254,7 @@ func (am AppModule) OnTimeoutPacket( // TODO return nil } + +func (am AppModule) NegotiateAppVersion(ctx sdk.Context, order channeltypes.Order, connectionID, portID string, counterparty channeltypes.Counterparty, proposedVersion string) (string, error) { + return "", nil +} diff --git a/modules/apps/transfer/keeper/MBT_README.md b/modules/apps/transfer/keeper/MBT_README.md index 8a5930f6d39..3cad1e58993 100644 --- a/modules/apps/transfer/keeper/MBT_README.md +++ b/modules/apps/transfer/keeper/MBT_README.md @@ -48,4 +48,4 @@ docker run --rm -v $(pwd):/var/apalache apalache/mc $@ ``` -In case of any questions please don't hesitate to contact Andrey Kuprianov (andrey@informal.systems). \ No newline at end of file +In case of any questions please don't hesitate to contact Andrey Kuprianov (andrey@informal.systems). diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 08c75a26a0e..1d505debdb9 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -7,13 +7,11 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/ibc-go/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/modules/core/24-host" ) @@ -69,17 +67,6 @@ func (k Keeper) GetTransferAccount(ctx sdk.Context) authtypes.ModuleAccountI { return k.authKeeper.GetModuleAccount(ctx, types.ModuleName) } -// ChanCloseInit defines a wrapper function for the channel Keeper's function -// in order to expose it to the ICS20 transfer handler. -func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { - capName := host.ChannelCapabilityPath(portID, channelID) - chanCap, ok := k.scopedKeeper.GetCapability(ctx, capName) - if !ok { - return sdkerrors.Wrapf(channeltypes.ErrChannelCapabilityNotFound, "could not retrieve channel capability at: %s", capName) - } - return k.channelKeeper.ChanCloseInit(ctx, portID, channelID, chanCap) -} - // IsBound checks if the transfer module is already bound to the desired port func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index db425f24507..31d6a3823a5 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -30,7 +30,7 @@ type TlaBalance struct { type TlaFungibleTokenPacketData struct { Sender string `json:"sender"` Receiver string `json:"receiver"` - Amount int `json:"amount"` + Amount string `json:"amount"` Denom []string `json:"denom"` } @@ -143,7 +143,7 @@ func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPack DestPort: packet.DestPort, Data: types.NewFungibleTokenPacketData( DenomFromTla(packet.Data.Denom), - uint64(packet.Data.Amount), + packet.Data.Amount, AddressFromString(packet.Data.Sender), AddressFromString(packet.Data.Receiver)), } @@ -333,11 +333,15 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { denom := denomTrace.IBCDenom() err = sdk.ValidateDenom(denom) if err == nil { + amount, ok := sdk.NewIntFromString(tc.packet.Data.Amount) + if !ok { + panic("MBT failed to parse amount from string") + } err = suite.chainB.GetSimApp().TransferKeeper.SendTransfer( suite.chainB.GetContext(), tc.packet.SourcePort, tc.packet.SourceChannel, - sdk.NewCoin(denom, sdk.NewIntFromUint64(tc.packet.Data.Amount)), + sdk.NewCoin(denom, amount), sender, tc.packet.Data.Receiver, clienttypes.NewHeight(0, 110), diff --git a/modules/apps/transfer/keeper/model_based_tests/Test5Packets.json b/modules/apps/transfer/keeper/model_based_tests/Test5Packets.json index 6ccdccc8aeb..5cb9e206ea5 100644 --- a/modules/apps/transfer/keeper/model_based_tests/Test5Packets.json +++ b/modules/apps/transfer/keeper/model_based_tests/Test5Packets.json @@ -8,7 +8,7 @@ "data": { "sender": "a3", "receiver": "a3", - "amount": 2, + "amount": "2", "denom": [ "", "", @@ -79,7 +79,7 @@ "data": { "sender": "a1", "receiver": "a3", - "amount": 1, + "amount": "1", "denom": [ "cosmos-hub", "", @@ -165,7 +165,7 @@ "data": { "sender": "a2", "receiver": "a2", - "amount": 4, + "amount": "4", "denom": [ "", "", @@ -266,7 +266,7 @@ "data": { "sender": "", "receiver": "a2", - "amount": 4, + "amount": "4", "denom": [ "", "", @@ -382,7 +382,7 @@ "data": { "sender": "a1", "receiver": "", - "amount": 1, + "amount": "1", "denom": [ "transfer", "channel-0", @@ -489,4 +489,4 @@ ], "error": true } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/Test5PacketsAllDifferentPass.json b/modules/apps/transfer/keeper/model_based_tests/Test5PacketsAllDifferentPass.json index 6a039f3eca4..80370205b15 100644 --- a/modules/apps/transfer/keeper/model_based_tests/Test5PacketsAllDifferentPass.json +++ b/modules/apps/transfer/keeper/model_based_tests/Test5PacketsAllDifferentPass.json @@ -8,7 +8,7 @@ "data": { "sender": "a3", "receiver": "a2", - "amount": 3, + "amount": "3", "denom": [ "", "", @@ -79,7 +79,7 @@ "data": { "sender": "a2", "receiver": "a1", - "amount": 3, + "amount": "3", "denom": [ "transfer", "channel-1", @@ -180,7 +180,7 @@ "data": { "sender": "a1", "receiver": "a2", - "amount": 3, + "amount": "3", "denom": [ "", "", @@ -311,7 +311,7 @@ "data": { "sender": "a1", "receiver": "", - "amount": 2, + "amount": "2", "denom": [ "", "channel-0", @@ -457,7 +457,7 @@ "data": { "sender": "a3", "receiver": "a3", - "amount": 1, + "amount": "1", "denom": [ "", "", @@ -609,4 +609,4 @@ ], "error": false } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementErrorFail.json b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementErrorFail.json index f1f553210b5..d5c89950e2f 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementErrorFail.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementErrorFail.json @@ -8,7 +8,7 @@ "data": { "sender": "a1", "receiver": "a2", - "amount": 1, + "amount": "1", "denom": [ "cosmos-hub", "transfer", @@ -55,4 +55,4 @@ ], "error": true } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementErrorPass.json b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementErrorPass.json index 3fbfe7fdf09..3aeb93ca214 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementErrorPass.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementErrorPass.json @@ -8,7 +8,7 @@ "data": { "sender": "", "receiver": "a1", - "amount": 1, + "amount": "1", "denom": [ "", "", @@ -79,7 +79,7 @@ "data": { "sender": "a1", "receiver": "a2", - "amount": 1, + "amount": "1", "denom": [ "transfer", "channel-1", @@ -156,4 +156,4 @@ ], "error": false } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementResultFail.json b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementResultFail.json index 9110a38ab65..b2424d3efc6 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementResultFail.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementResultFail.json @@ -8,7 +8,7 @@ "data": { "sender": "a1", "receiver": "a2", - "amount": 1, + "amount": "1", "denom": [ "cosmos-hub", "transfer", @@ -55,4 +55,4 @@ ], "error": true } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementResultPass.json b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementResultPass.json index 5215df7da33..1f1135a2d34 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementResultPass.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvAcknowledgementResultPass.json @@ -8,7 +8,7 @@ "data": { "sender": "a1", "receiver": "a2", - "amount": 1, + "amount": "1", "denom": [ "cosmos-hub", "transfer", @@ -55,4 +55,4 @@ ], "error": false } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvPacketFail.json b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvPacketFail.json index 9a7e8c406e7..f683c8fac8c 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvPacketFail.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvPacketFail.json @@ -8,7 +8,7 @@ "data": { "sender": "", "receiver": "", - "amount": 1, + "amount": "1", "denom": [ "", "", @@ -55,4 +55,4 @@ ], "error": true } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvPacketPass.json b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvPacketPass.json index 35f94c57208..6da859106d8 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestOnRecvPacketPass.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestOnRecvPacketPass.json @@ -8,7 +8,7 @@ "data": { "sender": "", "receiver": "a2", - "amount": 1, + "amount": "1", "denom": [ "", "", @@ -70,4 +70,4 @@ ], "error": false } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/TestOnTimeoutFail.json b/modules/apps/transfer/keeper/model_based_tests/TestOnTimeoutFail.json index a78ed85ca58..8b7c8228065 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestOnTimeoutFail.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestOnTimeoutFail.json @@ -8,7 +8,7 @@ "data": { "sender": "a1", "receiver": "a2", - "amount": 1, + "amount": "1", "denom": [ "cosmos-hub", "transfer", @@ -55,4 +55,4 @@ ], "error": true } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/TestOnTimeoutPass.json b/modules/apps/transfer/keeper/model_based_tests/TestOnTimeoutPass.json index 3136aace654..33d9c1a4e59 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestOnTimeoutPass.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestOnTimeoutPass.json @@ -8,7 +8,7 @@ "data": { "sender": "a3", "receiver": "a1", - "amount": 1, + "amount": "1", "denom": [ "", "", @@ -79,7 +79,7 @@ "data": { "sender": "a1", "receiver": "", - "amount": 1, + "amount": "1", "denom": [ "transfer", "channel-1", @@ -156,4 +156,4 @@ ], "error": false } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/TestSendTransferFail.json b/modules/apps/transfer/keeper/model_based_tests/TestSendTransferFail.json index 01d589d8677..4c3412e3ba8 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestSendTransferFail.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestSendTransferFail.json @@ -8,7 +8,7 @@ "data": { "sender": "", "receiver": "", - "amount": 1, + "amount": "1", "denom": [ "", "", @@ -55,4 +55,4 @@ ], "error": true } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/TestSendTransferPass.json b/modules/apps/transfer/keeper/model_based_tests/TestSendTransferPass.json index 452d2b3aa94..492b59ae969 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestSendTransferPass.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestSendTransferPass.json @@ -8,7 +8,7 @@ "data": { "sender": "a3", "receiver": "a2", - "amount": 1, + "amount": "1", "denom": [ "", "", @@ -79,7 +79,7 @@ "data": { "sender": "a2", "receiver": "a1", - "amount": 1, + "amount": "1", "denom": [ "transfer", "channel-0", @@ -171,4 +171,4 @@ ], "error": false } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json b/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json index 98552207047..b4ebe81c70d 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json @@ -8,7 +8,7 @@ "data": { "sender": "a1", "receiver": "a3", - "amount": 5, + "amount": "5", "denom": [ "", "", @@ -79,7 +79,7 @@ "data": { "sender": "a3", "receiver": "a1", - "amount": 3, + "amount": "3", "denom": [ "", "", @@ -180,7 +180,7 @@ "data": { "sender": "a1", "receiver": "a1", - "amount": 1, + "amount": "1", "denom": [ "transfer", "channel-0", @@ -302,4 +302,4 @@ ], "error": false } -] \ No newline at end of file +] diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 161295d0b70..5f9090a082b 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -5,10 +5,10 @@ import ( "strings" "github.com/armon/go-metrics" - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/ibc-go/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" @@ -144,7 +144,7 @@ func (k Keeper) SendTransfer( } packetData := types.NewFungibleTokenPacketData( - fullDenomPath, token.Amount.Uint64(), sender.String(), receiver, + fullDenomPath, token.Amount.String(), sender.String(), receiver, ) packet := channeltypes.NewPacket( @@ -163,11 +163,13 @@ func (k Keeper) SendTransfer( } defer func() { - telemetry.SetGaugeWithLabels( - []string{"tx", "msg", "ibc", "transfer"}, - float32(token.Amount.Int64()), - []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, fullDenomPath)}, - ) + if token.Amount.IsInt64() { + telemetry.SetGaugeWithLabels( + []string{"tx", "msg", "ibc", "transfer"}, + float32(token.Amount.Int64()), + []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, fullDenomPath)}, + ) + } telemetry.IncrCounterWithLabels( []string{"ibc", types.ModuleName, "send"}, @@ -200,6 +202,12 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t return err } + // parse the transfer amount + transferAmount, ok := sdk.NewIntFromString(data.Amount) + if !ok { + return sdkerrors.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into sdk.Int", data.Amount) + } + labels := []metrics.Label{ telemetry.NewLabel(coretypes.LabelSourcePort, packet.GetSourcePort()), telemetry.NewLabel(coretypes.LabelSourceChannel, packet.GetSourceChannel()), @@ -229,7 +237,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t if denomTrace.Path != "" { denom = denomTrace.IBCDenom() } - token := sdk.NewCoin(denom, sdk.NewIntFromUint64(data.Amount)) + token := sdk.NewCoin(denom, transferAmount) // unescrow tokens escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) @@ -242,11 +250,13 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t } defer func() { - telemetry.SetGaugeWithLabels( - []string{"ibc", types.ModuleName, "packet", "receive"}, - float32(data.Amount), - []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, unprefixedDenom)}, - ) + if transferAmount.IsInt64() { + telemetry.SetGaugeWithLabels( + []string{"ibc", types.ModuleName, "packet", "receive"}, + float32(transferAmount.Int64()), + []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, unprefixedDenom)}, + ) + } telemetry.IncrCounterWithLabels( []string{"ibc", types.ModuleName, "receive"}, @@ -283,8 +293,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t sdk.NewAttribute(types.AttributeKeyDenom, voucherDenom), ), ) - - voucher := sdk.NewCoin(voucherDenom, sdk.NewIntFromUint64(data.Amount)) + voucher := sdk.NewCoin(voucherDenom, transferAmount) // mint new tokens if the source of the transfer is the same chain if err := k.bankKeeper.MintCoins( @@ -301,11 +310,13 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t } defer func() { - telemetry.SetGaugeWithLabels( - []string{"ibc", types.ModuleName, "packet", "receive"}, - float32(data.Amount), - []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, data.Denom)}, - ) + if transferAmount.IsInt64() { + telemetry.SetGaugeWithLabels( + []string{"ibc", types.ModuleName, "packet", "receive"}, + float32(transferAmount.Int64()), + []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, data.Denom)}, + ) + } telemetry.IncrCounterWithLabels( []string{"ibc", types.ModuleName, "receive"}, @@ -350,7 +361,12 @@ func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, d // parse the denomination from the full denom path trace := types.ParseDenomTrace(data.Denom) - token := sdk.NewCoin(trace.IBCDenom(), sdk.NewIntFromUint64(data.Amount)) + // parse the transfer amount + transferAmount, ok := sdk.NewIntFromString(data.Amount) + if !ok { + return sdkerrors.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into sdk.Int", data.Amount) + } + token := sdk.NewCoin(trace.IBCDenom(), transferAmount) // decode the sender address sender, err := sdk.AccAddressFromBech32(data.Sender) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 4c383f0948f..02959303ab2 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -37,7 +37,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { func() { // send coin from chainA back to chainB suite.coordinator.CreateTransferChannels(path) - amount = types.GetTransferCoin(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom, 100) + amount = types.GetTransferCoin(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom, sdk.NewInt(100)) }, false, true}, {"source channel not found", func() { @@ -71,7 +71,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { {"send from module account failed", func() { suite.coordinator.CreateTransferChannels(path) - amount = types.GetTransferCoin(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, " randomdenom", 100) + amount = types.GetTransferCoin(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, " randomdenom", sdk.NewInt(100)) }, false, false}, {"channel capability not found", func() { @@ -102,7 +102,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { suite.Require().NoError(err) // message committed // receive coin on chainA from chainB - fungibleTokenPacket := types.NewFungibleTokenPacketData(coinFromBToA.Denom, coinFromBToA.Amount.Uint64(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String()) + fungibleTokenPacket := types.NewFungibleTokenPacketData(coinFromBToA.Denom, coinFromBToA.Amount.String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String()) packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, clienttypes.NewHeight(0, 110), 0) // get proof of packet commitment from chainB @@ -190,7 +190,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { suite.Require().NoError(err) // message committed // relay send packet - fungibleTokenPacket := types.NewFungibleTokenPacketData(coinFromBToA.Denom, coinFromBToA.Amount.Uint64(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String()) + fungibleTokenPacket := types.NewFungibleTokenPacketData(coinFromBToA.Denom, coinFromBToA.Amount.String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String()) packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, clienttypes.NewHeight(0, 110), 0) ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) err = path.RelayPacket(packet, ack.Acknowledgement()) @@ -211,7 +211,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { tc.malleate() - data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.Uint64(), suite.chainA.SenderAccount.GetAddress().String(), receiver) + data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.String(), suite.chainA.SenderAccount.GetAddress().String(), receiver) packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) @@ -280,7 +280,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { tc.malleate() - data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.Uint64(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String()) + data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String()) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom()) @@ -366,7 +366,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { tc.malleate() - data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.Uint64(), sender, suite.chainB.SenderAccount.GetAddress().String()) + data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.String(), sender, suite.chainB.SenderAccount.GetAddress().String()) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom()) diff --git a/modules/apps/transfer/module.go b/modules/apps/transfer/module.go index a9a1aa4f875..aa050055aa9 100644 --- a/modules/apps/transfer/module.go +++ b/modules/apps/transfer/module.go @@ -329,7 +329,7 @@ func (am AppModule) OnRecvPacket( var data types.FungibleTokenPacketData if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - ack = channeltypes.NewErrorAcknowledgement(fmt.Sprintf("cannot unmarshal ICS-20 transfer packet data: %s", err.Error())) + ack = channeltypes.NewErrorAcknowledgement("cannot unmarshal ICS-20 transfer packet data") } // only attempt the application logic if the packet data @@ -347,7 +347,7 @@ func (am AppModule) OnRecvPacket( sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), - sdk.NewAttribute(types.AttributeKeyAmount, fmt.Sprintf("%d", data.Amount)), + sdk.NewAttribute(types.AttributeKeyAmount, data.Amount), sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), ), ) @@ -382,7 +382,7 @@ func (am AppModule) OnAcknowledgementPacket( sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), - sdk.NewAttribute(types.AttributeKeyAmount, fmt.Sprintf("%d", data.Amount)), + sdk.NewAttribute(types.AttributeKeyAmount, data.Amount), sdk.NewAttribute(types.AttributeKeyAck, ack.String()), ), ) @@ -428,9 +428,25 @@ func (am AppModule) OnTimeoutPacket( sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), sdk.NewAttribute(types.AttributeKeyRefundReceiver, data.Sender), sdk.NewAttribute(types.AttributeKeyRefundDenom, data.Denom), - sdk.NewAttribute(types.AttributeKeyRefundAmount, fmt.Sprintf("%d", data.Amount)), + sdk.NewAttribute(types.AttributeKeyRefundAmount, data.Amount), ), ) return nil } + +// NegotiateAppVersion implements the IBCModule interface +func (am AppModule) NegotiateAppVersion( + ctx sdk.Context, + order channeltypes.Order, + connectionID string, + portID string, + counterparty channeltypes.Counterparty, + proposedVersion string, +) (string, error) { + if proposedVersion != types.Version { + return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "failed to negotiate app version: expected %s, got %s", types.Version, proposedVersion) + } + + return types.Version, nil +} diff --git a/modules/apps/transfer/transfer_test.go b/modules/apps/transfer/transfer_test.go index 030fb1bd14c..948a6b2cf4b 100644 --- a/modules/apps/transfer/transfer_test.go +++ b/modules/apps/transfer/transfer_test.go @@ -48,7 +48,9 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { // originalBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) timeoutHeight := clienttypes.NewHeight(0, 110) - coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) + amount, ok := sdk.NewIntFromString("9223372036854775808") // 2^63 (one above int64) + suite.Require().True(ok) + coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) // send from chainA to chainB msg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coinToSendToB, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0) @@ -57,7 +59,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { suite.Require().NoError(err) // message committed // relay send - fungibleTokenPacket := types.NewFungibleTokenPacketData(coinToSendToB.Denom, coinToSendToB.Amount.Uint64(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String()) + fungibleTokenPacket := types.NewFungibleTokenPacketData(coinToSendToB.Denom, coinToSendToB.Amount.String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String()) packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) err = path.RelayPacket(packet, ack.Acknowledgement()) @@ -67,7 +69,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { voucherDenomTrace := types.ParseDenomTrace(types.GetPrefixedDenom(packet.GetDestPort(), packet.GetDestChannel(), sdk.DefaultBondDenom)) balance := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom()) - coinSentFromAToB := types.GetTransferCoin(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.DefaultBondDenom, 100) + coinSentFromAToB := types.GetTransferCoin(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.DefaultBondDenom, amount) suite.Require().Equal(coinSentFromAToB, balance) // setup between chainB to chainC @@ -86,12 +88,12 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { // relay send // NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment fullDenomPath := types.GetPrefixedDenom(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, voucherDenomTrace.GetFullDenomPath()) - fungibleTokenPacket = types.NewFungibleTokenPacketData(voucherDenomTrace.GetFullDenomPath(), coinSentFromAToB.Amount.Uint64(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String()) + fungibleTokenPacket = types.NewFungibleTokenPacketData(voucherDenomTrace.GetFullDenomPath(), coinSentFromAToB.Amount.String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String()) packet = channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, timeoutHeight, 0) err = pathBtoC.RelayPacket(packet, ack.Acknowledgement()) suite.Require().NoError(err) // relay committed - coinSentFromBToC := sdk.NewInt64Coin(types.ParseDenomTrace(fullDenomPath).IBCDenom(), 100) + coinSentFromBToC := sdk.NewCoin(types.ParseDenomTrace(fullDenomPath).IBCDenom(), amount) balance = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccount.GetAddress(), coinSentFromBToC.Denom) // check that the balance is updated on chainC @@ -109,7 +111,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { // relay send // NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment - fungibleTokenPacket = types.NewFungibleTokenPacketData(fullDenomPath, coinSentFromBToC.Amount.Uint64(), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String()) + fungibleTokenPacket = types.NewFungibleTokenPacketData(fullDenomPath, coinSentFromBToC.Amount.String(), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String()) packet = channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, timeoutHeight, 0) err = pathBtoC.RelayPacket(packet, ack.Acknowledgement()) suite.Require().NoError(err) // relay committed diff --git a/modules/apps/transfer/types/coin.go b/modules/apps/transfer/types/coin.go index 08ae9a8d325..a3491e2bf09 100644 --- a/modules/apps/transfer/types/coin.go +++ b/modules/apps/transfer/types/coin.go @@ -42,7 +42,7 @@ func GetPrefixedDenom(portID, channelID, baseDenom string) string { // GetTransferCoin creates a transfer coin with the port ID and channel ID // prefixed to the base denom. -func GetTransferCoin(portID, channelID, baseDenom string, amount int64) sdk.Coin { +func GetTransferCoin(portID, channelID, baseDenom string, amount sdk.Int) sdk.Coin { denomTrace := ParseDenomTrace(GetPrefixedDenom(portID, channelID, baseDenom)) - return sdk.NewInt64Coin(denomTrace.IBCDenom(), amount) + return sdk.NewCoin(denomTrace.IBCDenom(), amount) } diff --git a/modules/apps/transfer/types/errors.go b/modules/apps/transfer/types/errors.go index 07cba194915..0f0cb7c42a4 100644 --- a/modules/apps/transfer/types/errors.go +++ b/modules/apps/transfer/types/errors.go @@ -4,7 +4,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// IBC channel sentinel errors +// IBC transfer sentinel errors var ( ErrInvalidPacketTimeout = sdkerrors.Register(ModuleName, 2, "invalid packet timeout") ErrInvalidDenomForTransfer = sdkerrors.Register(ModuleName, 3, "invalid denomination for cross-chain transfer") diff --git a/modules/apps/transfer/types/expected_keepers.go b/modules/apps/transfer/types/expected_keepers.go index df16f947c4b..d7881642c12 100644 --- a/modules/apps/transfer/types/expected_keepers.go +++ b/modules/apps/transfer/types/expected_keepers.go @@ -29,7 +29,6 @@ type ChannelKeeper interface { GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error - ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error } // ClientKeeper defines the expected IBC client keeper diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index 6e63b5ed30f..fa5e9f96db5 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -16,7 +16,8 @@ const ( validPort = "testportid" invalidPort = "(invalidport1)" invalidShortPort = "p" - invalidLongPort = "invalidlongportinvalidlongportinvalidlongportinvalidlongportinvalid" + // 195 characters + invalidLongPort = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eros neque, ultricies vel ligula ac, convallis porttitor elit. Maecenas tincidunt turpis elit, vel faucibus nisl pellentesque sodales" validChannel = "testchannel" invalidChannel = "(invalidchannel1)" diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index d726577f6f5..a7384c47486 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -23,7 +23,7 @@ var ( // NewFungibleTokenPacketData contructs a new FungibleTokenPacketData instance func NewFungibleTokenPacketData( - denom string, amount uint64, + denom string, amount string, sender, receiver string, ) FungibleTokenPacketData { return FungibleTokenPacketData{ @@ -38,8 +38,12 @@ func NewFungibleTokenPacketData( // NOTE: The addresses formats are not validated as the sender and recipient can have different // formats defined by their corresponding chains that are not known to IBC. func (ftpd FungibleTokenPacketData) ValidateBasic() error { - if ftpd.Amount == 0 { - return sdkerrors.Wrap(ErrInvalidAmount, "amount cannot be 0") + amount, ok := sdk.NewIntFromString(ftpd.Amount) + if !ok { + return sdkerrors.Wrapf(ErrInvalidAmount, "unable to parse transfer amount (%s) into sdk.Int", ftpd.Amount) + } + if !amount.IsPositive() { + return sdkerrors.Wrapf(ErrInvalidAmount, "amount must be strictly positive: got %d", amount) } if strings.TrimSpace(ftpd.Sender) == "" { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be blank") diff --git a/modules/apps/transfer/types/packet.pb.go b/modules/apps/transfer/types/packet.pb.go new file mode 100644 index 00000000000..486545b551f --- /dev/null +++ b/modules/apps/transfer/types/packet.pb.go @@ -0,0 +1,481 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/transfer/v2/packet.proto + +package types + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// FungibleTokenPacketData defines a struct for the packet payload +// See FungibleTokenPacketData spec: +// https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#data-structures +type FungibleTokenPacketData struct { + // the token denomination to be transferred + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + // the token amount to be transferred + Amount string `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"` + // the sender address + Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"` + // the recipient address on the destination chain + Receiver string `protobuf:"bytes,4,opt,name=receiver,proto3" json:"receiver,omitempty"` +} + +func (m *FungibleTokenPacketData) Reset() { *m = FungibleTokenPacketData{} } +func (m *FungibleTokenPacketData) String() string { return proto.CompactTextString(m) } +func (*FungibleTokenPacketData) ProtoMessage() {} +func (*FungibleTokenPacketData) Descriptor() ([]byte, []int) { + return fileDescriptor_653ca2ce9a5ca313, []int{0} +} +func (m *FungibleTokenPacketData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FungibleTokenPacketData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FungibleTokenPacketData.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *FungibleTokenPacketData) XXX_Merge(src proto.Message) { + xxx_messageInfo_FungibleTokenPacketData.Merge(m, src) +} +func (m *FungibleTokenPacketData) XXX_Size() int { + return m.Size() +} +func (m *FungibleTokenPacketData) XXX_DiscardUnknown() { + xxx_messageInfo_FungibleTokenPacketData.DiscardUnknown(m) +} + +var xxx_messageInfo_FungibleTokenPacketData proto.InternalMessageInfo + +func (m *FungibleTokenPacketData) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *FungibleTokenPacketData) GetAmount() string { + if m != nil { + return m.Amount + } + return "" +} + +func (m *FungibleTokenPacketData) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *FungibleTokenPacketData) GetReceiver() string { + if m != nil { + return m.Receiver + } + return "" +} + +func init() { + proto.RegisterType((*FungibleTokenPacketData)(nil), "ibc.applications.transfer.v2.FungibleTokenPacketData") +} + +func init() { + proto.RegisterFile("ibc/applications/transfer/v2/packet.proto", fileDescriptor_653ca2ce9a5ca313) +} + +var fileDescriptor_653ca2ce9a5ca313 = []byte{ + // 239 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x8f, 0xbf, 0x4a, 0xc5, 0x30, + 0x14, 0x87, 0x1b, 0xff, 0x5c, 0x34, 0x63, 0x11, 0x2d, 0x22, 0x41, 0x9c, 0x74, 0x30, 0x81, 0xab, + 0x4f, 0x20, 0xe2, 0x28, 0x22, 0x4e, 0x6e, 0x49, 0x7a, 0xac, 0xe1, 0x36, 0x39, 0x21, 0x49, 0x0b, + 0xe2, 0x4b, 0xf8, 0x58, 0x8e, 0x77, 0x74, 0x94, 0xf6, 0x45, 0xe4, 0xa6, 0x2a, 0x1d, 0xbf, 0xef, + 0xfc, 0xce, 0xf0, 0xd1, 0x0b, 0xa3, 0xb4, 0x90, 0xde, 0xb7, 0x46, 0xcb, 0x64, 0xd0, 0x45, 0x91, + 0x82, 0x74, 0xf1, 0x05, 0x82, 0xe8, 0x97, 0xc2, 0x4b, 0xbd, 0x82, 0xc4, 0x7d, 0xc0, 0x84, 0xe5, + 0x89, 0x51, 0x9a, 0xcf, 0xa7, 0xfc, 0x6f, 0xca, 0xfb, 0xe5, 0xd9, 0x3b, 0x3d, 0xba, 0xeb, 0x5c, + 0x63, 0x54, 0x0b, 0x4f, 0xb8, 0x02, 0xf7, 0x90, 0x5f, 0x6f, 0x65, 0x92, 0xe5, 0x01, 0xdd, 0xad, + 0xc1, 0xa1, 0xad, 0xc8, 0x29, 0x39, 0xdf, 0x7f, 0x9c, 0xa0, 0x3c, 0xa4, 0x0b, 0x69, 0xb1, 0x73, + 0xa9, 0xda, 0xca, 0xfa, 0x97, 0x36, 0x3e, 0x82, 0xab, 0x21, 0x54, 0xdb, 0x93, 0x9f, 0xa8, 0x3c, + 0xa6, 0x7b, 0x01, 0x34, 0x98, 0x1e, 0x42, 0xb5, 0x93, 0x2f, 0xff, 0x7c, 0x73, 0xff, 0x39, 0x30, + 0xb2, 0x1e, 0x18, 0xf9, 0x1e, 0x18, 0xf9, 0x18, 0x59, 0xb1, 0x1e, 0x59, 0xf1, 0x35, 0xb2, 0xe2, + 0xf9, 0xba, 0x31, 0xe9, 0xb5, 0x53, 0x5c, 0xa3, 0x15, 0x1a, 0xa3, 0xc5, 0x28, 0x8c, 0xd2, 0x97, + 0x0d, 0x0a, 0x8b, 0x75, 0xd7, 0x42, 0xdc, 0xc4, 0xcf, 0xa2, 0xd3, 0x9b, 0x87, 0xa8, 0x16, 0xb9, + 0xf8, 0xea, 0x27, 0x00, 0x00, 0xff, 0xff, 0x1f, 0x65, 0xe9, 0x98, 0x1e, 0x01, 0x00, 0x00, +} + +func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *FungibleTokenPacketData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FungibleTokenPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Receiver) > 0 { + i -= len(m.Receiver) + copy(dAtA[i:], m.Receiver) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Receiver))) + i-- + dAtA[i] = 0x22 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0x1a + } + if len(m.Amount) > 0 { + i -= len(m.Amount) + copy(dAtA[i:], m.Amount) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Amount))) + i-- + dAtA[i] = 0x12 + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintPacket(dAtA []byte, offset int, v uint64) int { + offset -= sovPacket(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *FungibleTokenPacketData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + l = len(m.Amount) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + l = len(m.Receiver) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + return n +} + +func sovPacket(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozPacket(x uint64) (n int) { + return sovPacket(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *FungibleTokenPacketData) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FungibleTokenPacketData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FungibleTokenPacketData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Receiver = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPacket(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPacket + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipPacket(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPacket + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPacket + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPacket + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthPacket + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupPacket + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthPacket + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthPacket = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowPacket = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupPacket = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 6b16095b0b5..e5d21d648d2 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -7,8 +7,10 @@ import ( ) const ( - denom = "transfer/gaiachannel/atom" - amount = uint64(100) + denom = "transfer/gaiachannel/atom" + amount = "100" + largeAmount = "18446744073709551616" // one greater than largest uint64 (^uint64(0)) + invalidLargeAmount = "115792089237316195423570985008687907853269984665640564039457584007913129639936" // 2^256 ) // TestFungibleTokenPacketDataValidateBasic tests ValidateBasic for FungibleTokenPacketData @@ -19,8 +21,12 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { expPass bool }{ {"valid packet", NewFungibleTokenPacketData(denom, amount, addr1, addr2), true}, + {"valid packet with large amount", NewFungibleTokenPacketData(denom, largeAmount, addr1, addr2), true}, {"invalid denom", NewFungibleTokenPacketData("", amount, addr1, addr2), false}, - {"invalid amount", NewFungibleTokenPacketData(denom, 0, addr1, addr2), false}, + {"invalid empty amount", NewFungibleTokenPacketData(denom, "", addr1, addr2), false}, + {"invalid zero amount", NewFungibleTokenPacketData(denom, "0", addr1, addr2), false}, + {"invalid negative amount", NewFungibleTokenPacketData(denom, "-1", addr1, addr2), false}, + {"invalid large amount", NewFungibleTokenPacketData(denom, invalidLargeAmount, addr1, addr2), false}, {"missing sender address", NewFungibleTokenPacketData(denom, amount, emptyAddr, addr2), false}, {"missing recipient address", NewFungibleTokenPacketData(denom, amount, addr1, emptyAddr), false}, } diff --git a/modules/apps/transfer/types/transfer.pb.go b/modules/apps/transfer/types/transfer.pb.go index f03b128f053..95df2214710 100644 --- a/modules/apps/transfer/types/transfer.pb.go +++ b/modules/apps/transfer/types/transfer.pb.go @@ -23,81 +23,6 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// FungibleTokenPacketData defines a struct for the packet payload -// See FungibleTokenPacketData spec: -// https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#data-structures -type FungibleTokenPacketData struct { - // the token denomination to be transferred - Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` - // the token amount to be transferred - Amount uint64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` - // the sender address - Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"` - // the recipient address on the destination chain - Receiver string `protobuf:"bytes,4,opt,name=receiver,proto3" json:"receiver,omitempty"` -} - -func (m *FungibleTokenPacketData) Reset() { *m = FungibleTokenPacketData{} } -func (m *FungibleTokenPacketData) String() string { return proto.CompactTextString(m) } -func (*FungibleTokenPacketData) ProtoMessage() {} -func (*FungibleTokenPacketData) Descriptor() ([]byte, []int) { - return fileDescriptor_5041673e96e97901, []int{0} -} -func (m *FungibleTokenPacketData) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *FungibleTokenPacketData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_FungibleTokenPacketData.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *FungibleTokenPacketData) XXX_Merge(src proto.Message) { - xxx_messageInfo_FungibleTokenPacketData.Merge(m, src) -} -func (m *FungibleTokenPacketData) XXX_Size() int { - return m.Size() -} -func (m *FungibleTokenPacketData) XXX_DiscardUnknown() { - xxx_messageInfo_FungibleTokenPacketData.DiscardUnknown(m) -} - -var xxx_messageInfo_FungibleTokenPacketData proto.InternalMessageInfo - -func (m *FungibleTokenPacketData) GetDenom() string { - if m != nil { - return m.Denom - } - return "" -} - -func (m *FungibleTokenPacketData) GetAmount() uint64 { - if m != nil { - return m.Amount - } - return 0 -} - -func (m *FungibleTokenPacketData) GetSender() string { - if m != nil { - return m.Sender - } - return "" -} - -func (m *FungibleTokenPacketData) GetReceiver() string { - if m != nil { - return m.Receiver - } - return "" -} - // DenomTrace contains the base denomination for ICS20 fungible tokens and the // source tracing information path. type DenomTrace struct { @@ -112,7 +37,7 @@ func (m *DenomTrace) Reset() { *m = DenomTrace{} } func (m *DenomTrace) String() string { return proto.CompactTextString(m) } func (*DenomTrace) ProtoMessage() {} func (*DenomTrace) Descriptor() ([]byte, []int) { - return fileDescriptor_5041673e96e97901, []int{1} + return fileDescriptor_5041673e96e97901, []int{0} } func (m *DenomTrace) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -172,7 +97,7 @@ func (m *Params) Reset() { *m = Params{} } func (m *Params) String() string { return proto.CompactTextString(m) } func (*Params) ProtoMessage() {} func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_5041673e96e97901, []int{2} + return fileDescriptor_5041673e96e97901, []int{1} } func (m *Params) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -216,7 +141,6 @@ func (m *Params) GetReceiveEnabled() bool { } func init() { - proto.RegisterType((*FungibleTokenPacketData)(nil), "ibc.applications.transfer.v1.FungibleTokenPacketData") proto.RegisterType((*DenomTrace)(nil), "ibc.applications.transfer.v1.DenomTrace") proto.RegisterType((*Params)(nil), "ibc.applications.transfer.v1.Params") } @@ -226,79 +150,26 @@ func init() { } var fileDescriptor_5041673e96e97901 = []byte{ - // 365 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x91, 0xc1, 0xaa, 0xda, 0x40, - 0x14, 0x86, 0x8d, 0xb5, 0xa2, 0xd3, 0xd2, 0xc2, 0x54, 0x34, 0x48, 0x1b, 0x25, 0x2b, 0xa1, 0x34, - 0x41, 0xda, 0x95, 0x9b, 0x82, 0xb5, 0x5d, 0x16, 0x09, 0xae, 0xba, 0x91, 0x99, 0xc9, 0x69, 0x1c, - 0x4c, 0x66, 0xc2, 0xcc, 0x44, 0x90, 0x3e, 0x41, 0x77, 0x7d, 0xac, 0x2e, 0x5d, 0xde, 0x95, 0x5c, - 0xf4, 0x0d, 0x7c, 0x82, 0x4b, 0x26, 0x21, 0xc8, 0xdd, 0x9d, 0xef, 0x9c, 0xff, 0x3f, 0xe7, 0xc0, - 0x8f, 0x3e, 0x72, 0xca, 0x42, 0x92, 0xe7, 0x29, 0x67, 0xc4, 0x70, 0x29, 0x74, 0x68, 0x14, 0x11, - 0xfa, 0x37, 0xa8, 0xf0, 0x30, 0x6f, 0xea, 0x20, 0x57, 0xd2, 0x48, 0xfc, 0x9e, 0x53, 0x16, 0xdc, - 0x8b, 0x83, 0x46, 0x70, 0x98, 0x8f, 0x07, 0x89, 0x4c, 0xa4, 0x15, 0x86, 0x65, 0x55, 0x79, 0xfc, - 0x3f, 0x68, 0xf4, 0xa3, 0x10, 0x09, 0xa7, 0x29, 0x6c, 0xe4, 0x1e, 0xc4, 0x9a, 0xb0, 0x3d, 0x98, - 0x15, 0x31, 0x04, 0x0f, 0xd0, 0xcb, 0x18, 0x84, 0xcc, 0x5c, 0x67, 0xea, 0xcc, 0xfa, 0x51, 0x05, - 0x78, 0x88, 0xba, 0x24, 0x93, 0x85, 0x30, 0x6e, 0x7b, 0xea, 0xcc, 0x3a, 0x51, 0x4d, 0x65, 0x5f, - 0x83, 0x88, 0x41, 0xb9, 0x2f, 0xac, 0xbc, 0x26, 0x3c, 0x46, 0x3d, 0x05, 0x0c, 0xf8, 0x01, 0x94, - 0xdb, 0xb1, 0x93, 0x86, 0xfd, 0xaf, 0x08, 0xad, 0xca, 0xa5, 0x1b, 0x45, 0x18, 0x60, 0x8c, 0x3a, - 0x39, 0x31, 0xbb, 0xfa, 0x9c, 0xad, 0xf1, 0x07, 0x84, 0x28, 0xd1, 0xb0, 0xad, 0x1e, 0x69, 0xdb, - 0x49, 0xbf, 0xec, 0x58, 0x9f, 0xff, 0xd7, 0x41, 0xdd, 0x35, 0x51, 0x24, 0xd3, 0x78, 0x81, 0x5e, - 0x97, 0x17, 0xb7, 0x20, 0x08, 0x4d, 0x21, 0xb6, 0x5b, 0x7a, 0xcb, 0xd1, 0xed, 0x3c, 0x79, 0x77, - 0x24, 0x59, 0xba, 0xf0, 0xef, 0xa7, 0x7e, 0xf4, 0xaa, 0xc4, 0xef, 0x15, 0xe1, 0x6f, 0xe8, 0x6d, - 0xfd, 0x53, 0x63, 0x6f, 0x5b, 0xfb, 0xf8, 0x76, 0x9e, 0x0c, 0x2b, 0xfb, 0x33, 0x81, 0x1f, 0xbd, - 0xa9, 0x3b, 0xf5, 0x92, 0xe5, 0xcf, 0xff, 0x17, 0xcf, 0x39, 0x5d, 0x3c, 0xe7, 0xf1, 0xe2, 0x39, - 0xff, 0xae, 0x5e, 0xeb, 0x74, 0xf5, 0x5a, 0x0f, 0x57, 0xaf, 0xf5, 0xeb, 0x4b, 0xc2, 0xcd, 0xae, - 0xa0, 0x01, 0x93, 0x59, 0xc8, 0xa4, 0xce, 0xa4, 0x0e, 0x39, 0x65, 0x9f, 0x12, 0x19, 0x66, 0x32, - 0x2e, 0x52, 0xd0, 0x65, 0xc2, 0x77, 0xc9, 0x9a, 0x63, 0x0e, 0x9a, 0x76, 0x6d, 0x40, 0x9f, 0x9f, - 0x02, 0x00, 0x00, 0xff, 0xff, 0xbd, 0xbc, 0x5f, 0xc9, 0x03, 0x02, 0x00, 0x00, -} - -func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *FungibleTokenPacketData) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *FungibleTokenPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Receiver) > 0 { - i -= len(m.Receiver) - copy(dAtA[i:], m.Receiver) - i = encodeVarintTransfer(dAtA, i, uint64(len(m.Receiver))) - i-- - dAtA[i] = 0x22 - } - if len(m.Sender) > 0 { - i -= len(m.Sender) - copy(dAtA[i:], m.Sender) - i = encodeVarintTransfer(dAtA, i, uint64(len(m.Sender))) - i-- - dAtA[i] = 0x1a - } - if m.Amount != 0 { - i = encodeVarintTransfer(dAtA, i, uint64(m.Amount)) - i-- - dAtA[i] = 0x10 - } - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintTransfer(dAtA, i, uint64(len(m.Denom))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil + // 296 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x90, 0xc1, 0x4a, 0x03, 0x31, + 0x10, 0x86, 0x9b, 0x22, 0xc5, 0x46, 0x51, 0x88, 0xa2, 0xa5, 0x68, 0x2a, 0x7b, 0x12, 0xc4, 0x0d, + 0x45, 0x4f, 0xbd, 0x08, 0x55, 0xaf, 0x22, 0xc5, 0x93, 0x97, 0x92, 0x64, 0xc7, 0x6d, 0x60, 0xb3, + 0x59, 0x92, 0xb4, 0xd0, 0x47, 0xf0, 0xe6, 0x63, 0x79, 0xec, 0xd1, 0x53, 0x91, 0xf6, 0x0d, 0xfa, + 0x04, 0xb2, 0x69, 0x59, 0x16, 0x6f, 0xff, 0xcc, 0x7c, 0xdf, 0x1c, 0x7e, 0x7c, 0xa3, 0x84, 0x64, + 0xbc, 0x28, 0x32, 0x25, 0xb9, 0x57, 0x26, 0x77, 0xcc, 0x5b, 0x9e, 0xbb, 0x0f, 0xb0, 0x6c, 0xd6, + 0xaf, 0x72, 0x5c, 0x58, 0xe3, 0x0d, 0xb9, 0x50, 0x42, 0xc6, 0x75, 0x38, 0xae, 0x80, 0x59, 0xbf, + 0x7b, 0x9a, 0x9a, 0xd4, 0x04, 0x90, 0x95, 0x69, 0xeb, 0x44, 0x0f, 0x18, 0x3f, 0x41, 0x6e, 0xf4, + 0x9b, 0xe5, 0x12, 0x08, 0xc1, 0x7b, 0x05, 0xf7, 0x93, 0x0e, 0xba, 0x42, 0xd7, 0xed, 0x51, 0xc8, + 0xe4, 0x12, 0x63, 0xc1, 0x1d, 0x8c, 0x93, 0x12, 0xeb, 0x34, 0xc3, 0xa5, 0x5d, 0x6e, 0x82, 0x17, + 0x7d, 0x22, 0xdc, 0x7a, 0xe5, 0x96, 0x6b, 0x47, 0x06, 0xf8, 0xd0, 0x41, 0x9e, 0x8c, 0x21, 0xe7, + 0x22, 0x83, 0x24, 0x7c, 0xd9, 0x1f, 0x9e, 0x6f, 0x96, 0xbd, 0x93, 0x39, 0xd7, 0xd9, 0x20, 0xaa, + 0x5f, 0xa3, 0xd1, 0x41, 0x39, 0x3e, 0x6f, 0x27, 0xf2, 0x88, 0x8f, 0x2d, 0x48, 0x50, 0x33, 0xa8, + 0xf4, 0x66, 0xd0, 0xbb, 0x9b, 0x65, 0xef, 0x6c, 0xab, 0xff, 0x03, 0xa2, 0xd1, 0xd1, 0x6e, 0xb3, + 0x7b, 0x32, 0x7c, 0xf9, 0x5e, 0x51, 0xb4, 0x58, 0x51, 0xf4, 0xbb, 0xa2, 0xe8, 0x6b, 0x4d, 0x1b, + 0x8b, 0x35, 0x6d, 0xfc, 0xac, 0x69, 0xe3, 0xfd, 0x3e, 0x55, 0x7e, 0x32, 0x15, 0xb1, 0x34, 0x9a, + 0x49, 0xe3, 0xb4, 0x71, 0x4c, 0x09, 0x79, 0x9b, 0x1a, 0xa6, 0x4d, 0x32, 0xcd, 0xc0, 0x95, 0x25, + 0xd7, 0xca, 0xf5, 0xf3, 0x02, 0x9c, 0x68, 0x85, 0x8e, 0xee, 0xfe, 0x02, 0x00, 0x00, 0xff, 0xff, + 0xac, 0xa4, 0x13, 0xf0, 0x86, 0x01, 0x00, 0x00, } func (m *DenomTrace) Marshal() (dAtA []byte, err error) { @@ -392,30 +263,6 @@ func encodeVarintTransfer(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *FungibleTokenPacketData) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Denom) - if l > 0 { - n += 1 + l + sovTransfer(uint64(l)) - } - if m.Amount != 0 { - n += 1 + sovTransfer(uint64(m.Amount)) - } - l = len(m.Sender) - if l > 0 { - n += 1 + l + sovTransfer(uint64(l)) - } - l = len(m.Receiver) - if l > 0 { - n += 1 + l + sovTransfer(uint64(l)) - } - return n -} - func (m *DenomTrace) Size() (n int) { if m == nil { return 0 @@ -454,171 +301,6 @@ func sovTransfer(x uint64) (n int) { func sozTransfer(x uint64) (n int) { return sovTransfer(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *FungibleTokenPacketData) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTransfer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: FungibleTokenPacketData: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: FungibleTokenPacketData: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTransfer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTransfer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTransfer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Denom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) - } - m.Amount = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTransfer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Amount |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTransfer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTransfer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTransfer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Sender = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTransfer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTransfer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTransfer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Receiver = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTransfer(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTransfer - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *DenomTrace) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/modules/core/02-client/client/cli/cli.go b/modules/core/02-client/client/cli/cli.go index eade59ba6f1..1b6572ebb75 100644 --- a/modules/core/02-client/client/cli/cli.go +++ b/modules/core/02-client/client/cli/cli.go @@ -20,6 +20,7 @@ func GetQueryCmd() *cobra.Command { queryCmd.AddCommand( GetCmdQueryClientStates(), GetCmdQueryClientState(), + GetCmdQueryClientStatus(), GetCmdQueryConsensusStates(), GetCmdQueryConsensusState(), GetCmdQueryHeader(), diff --git a/modules/core/02-client/client/cli/query.go b/modules/core/02-client/client/cli/query.go index 5ed7c049bed..8633b92a469 100644 --- a/modules/core/02-client/client/cli/query.go +++ b/modules/core/02-client/client/cli/query.go @@ -89,6 +89,39 @@ func GetCmdQueryClientState() *cobra.Command { return cmd } +// GetCmdQueryClientStatus defines the command to query the status of a client with a given id +func GetCmdQueryClientStatus() *cobra.Command { + cmd := &cobra.Command{ + Use: "status [client-id]", + Short: "Query client status", + Long: "Query client activity status. Any client without an 'Active' status is considered inactive", + Example: fmt.Sprintf("%s query %s %s status [client-id]", version.AppName, host.ModuleName, types.SubModuleName), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + clientID := args[0] + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryClientStatusRequest{ + ClientId: clientID, + } + + clientStatusRes, err := queryClient.ClientStatus(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(clientStatusRes) + }, + } + + return cmd +} + // GetCmdQueryConsensusStates defines the command to query all the consensus states from a given // client state. func GetCmdQueryConsensusStates() *cobra.Command { diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index 17c97a8d26d..f8719b38759 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -678,9 +678,8 @@ func (suite *KeeperTestSuite) TestUpdateClientEventEmission() { result, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) - // first event type is "message" - updateEvent := result.Events[1] - + // first event type is "message", followed by 3 "tx" events in ante + updateEvent := result.Events[4] suite.Require().Equal(clienttypes.EventTypeUpdateClient, updateEvent.Type) // use a boolean to ensure the update event contains the header diff --git a/modules/core/04-channel/keeper/events.go b/modules/core/04-channel/keeper/events.go new file mode 100644 index 00000000000..bfdf925f2e6 --- /dev/null +++ b/modules/core/04-channel/keeper/events.go @@ -0,0 +1,139 @@ +package keeper + +import ( + "encoding/hex" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/modules/core/exported" +) + +// EmitSendPacketEvent emits an event with packet data along with other packet information for relayer +// to pick up and relay to other chain +func EmitSendPacketEvent(ctx sdk.Context, packet exported.PacketI, channel types.Channel, timeoutHeight exported.Height) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeSendPacket, + sdk.NewAttribute(types.AttributeKeyData, string(packet.GetData())), // DEPRECATED + sdk.NewAttribute(types.AttributeKeyDataHex, hex.EncodeToString(packet.GetData())), + sdk.NewAttribute(types.AttributeKeyTimeoutHeight, timeoutHeight.String()), + sdk.NewAttribute(types.AttributeKeyTimeoutTimestamp, fmt.Sprintf("%d", packet.GetTimeoutTimestamp())), + sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), + sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), + sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), + sdk.NewAttribute(types.AttributeKeyChannelOrdering, channel.Ordering.String()), + // we only support 1-hop packets now, and that is the most important hop for a relayer + // (is it going to a chain I am connected to) + sdk.NewAttribute(types.AttributeKeyConnection, channel.ConnectionHops[0]), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// EmitRecvPacketEvent emits a receive packet event. It will be emitted both the first time a packet +// is received for a certain sequence and for all duplicate receives. +func EmitRecvPacketEvent(ctx sdk.Context, packet exported.PacketI, channel types.Channel) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeRecvPacket, + sdk.NewAttribute(types.AttributeKeyData, string(packet.GetData())), // DEPRECATED + sdk.NewAttribute(types.AttributeKeyDataHex, hex.EncodeToString(packet.GetData())), + sdk.NewAttribute(types.AttributeKeyTimeoutHeight, packet.GetTimeoutHeight().String()), + sdk.NewAttribute(types.AttributeKeyTimeoutTimestamp, fmt.Sprintf("%d", packet.GetTimeoutTimestamp())), + sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), + sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), + sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), + sdk.NewAttribute(types.AttributeKeyChannelOrdering, channel.Ordering.String()), + // we only support 1-hop packets now, and that is the most important hop for a relayer + // (is it going to a chain I am connected to) + sdk.NewAttribute(types.AttributeKeyConnection, channel.ConnectionHops[0]), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// EmitWriteAcknowledgementEvent emits an event that the relayer can query for +func EmitWriteAcknowledgementEvent(ctx sdk.Context, packet exported.PacketI, channel types.Channel, acknowledgement []byte) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeWriteAck, + sdk.NewAttribute(types.AttributeKeyData, string(packet.GetData())), // DEPRECATED + sdk.NewAttribute(types.AttributeKeyDataHex, hex.EncodeToString(packet.GetData())), + sdk.NewAttribute(types.AttributeKeyTimeoutHeight, packet.GetTimeoutHeight().String()), + sdk.NewAttribute(types.AttributeKeyTimeoutTimestamp, fmt.Sprintf("%d", packet.GetTimeoutTimestamp())), + sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), + sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), + sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), + sdk.NewAttribute(types.AttributeKeyAck, string(acknowledgement)), + sdk.NewAttribute(types.AttributeKeyAckHex, hex.EncodeToString(acknowledgement)), + // we only support 1-hop packets now, and that is the most important hop for a relayer + // (is it going to a chain I am connected to) + sdk.NewAttribute(types.AttributeKeyConnection, channel.ConnectionHops[0]), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// EmitAcknowledgePacketEvent emits an acknowledge packet event. It will be emitted both the first time +// a packet is acknowledged for a certain sequence and for all duplicate acknowledgements. +func EmitAcknowledgePacketEvent(ctx sdk.Context, packet exported.PacketI, channel types.Channel) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeAcknowledgePacket, + sdk.NewAttribute(types.AttributeKeyTimeoutHeight, packet.GetTimeoutHeight().String()), + sdk.NewAttribute(types.AttributeKeyTimeoutTimestamp, fmt.Sprintf("%d", packet.GetTimeoutTimestamp())), + sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), + sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), + sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), + sdk.NewAttribute(types.AttributeKeyChannelOrdering, channel.Ordering.String()), + // we only support 1-hop packets now, and that is the most important hop for a relayer + // (is it going to a chain I am connected to) + sdk.NewAttribute(types.AttributeKeyConnection, channel.ConnectionHops[0]), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + +// EmitTimeoutPacketEvent emits a timeout packet event. It will be emitted both the first time a packet +// is timed out for a certain sequence and for all duplicate timeouts. +func EmitTimeoutPacketEvent(ctx sdk.Context, packet exported.PacketI, channel types.Channel) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeTimeoutPacket, + sdk.NewAttribute(types.AttributeKeyTimeoutHeight, packet.GetTimeoutHeight().String()), + sdk.NewAttribute(types.AttributeKeyTimeoutTimestamp, fmt.Sprintf("%d", packet.GetTimeoutTimestamp())), + sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), + sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), + sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), + sdk.NewAttribute(types.AttributeKeyChannelOrdering, channel.Ordering.String()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} diff --git a/modules/core/04-channel/keeper/grpc_query.go b/modules/core/04-channel/keeper/grpc_query.go index 5f2155919aa..150d839b5f8 100644 --- a/modules/core/04-channel/keeper/grpc_query.go +++ b/modules/core/04-channel/keeper/grpc_query.go @@ -327,6 +327,27 @@ func (q Keeper) PacketAcknowledgements(c context.Context, req *types.QueryPacket acks := []*types.PacketState{} store := prefix.NewStore(ctx.KVStore(q.storeKey), []byte(host.PacketAcknowledgementPrefixPath(req.PortId, req.ChannelId))) + // if a list of packet sequences is provided then query for each specific ack and return a list <= len(req.PacketCommitmentSequences) + // otherwise, maintain previous behaviour and perform paginated query + for _, seq := range req.PacketCommitmentSequences { + acknowledgementBz, found := q.GetPacketAcknowledgement(ctx, req.PortId, req.ChannelId, seq) + if !found || len(acknowledgementBz) == 0 { + continue + } + + ack := types.NewPacketState(req.PortId, req.ChannelId, seq, acknowledgementBz) + acks = append(acks, &ack) + } + + if len(req.PacketCommitmentSequences) > 0 { + selfHeight := clienttypes.GetSelfHeight(ctx) + return &types.QueryPacketAcknowledgementsResponse{ + Acknowledgements: acks, + Pagination: nil, + Height: selfHeight, + }, nil + } + pageRes, err := query.Paginate(store, req.Pagination, func(key, value []byte) error { keySplit := strings.Split(string(key), "/") @@ -337,6 +358,7 @@ func (q Keeper) PacketAcknowledgements(c context.Context, req *types.QueryPacket ack := types.NewPacketState(req.PortId, req.ChannelId, sequence, value) acks = append(acks, &ack) + return nil }) diff --git a/modules/core/04-channel/keeper/grpc_query_test.go b/modules/core/04-channel/keeper/grpc_query_test.go index 88e3a717005..d803ae8b135 100644 --- a/modules/core/04-channel/keeper/grpc_query_test.go +++ b/modules/core/04-channel/keeper/grpc_query_test.go @@ -1025,6 +1025,33 @@ func (suite *KeeperTestSuite) TestQueryPacketAcknowledgements() { }, true, }, + { + "success, filtered res", + func() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + var commitments []uint64 + + for i := uint64(0); i < 100; i++ { + ack := types.NewPacketState(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, i, []byte(fmt.Sprintf("hash_%d", i))) + suite.chainA.App.GetIBCKeeper().ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), ack.PortId, ack.ChannelId, ack.Sequence, ack.Data) + + if i < 10 { // populate the store with 100 and query for 10 specific acks + expAcknowledgements = append(expAcknowledgements, &ack) + commitments = append(commitments, ack.Sequence) + } + } + + req = &types.QueryPacketAcknowledgementsRequest{ + PortId: path.EndpointA.ChannelConfig.PortID, + ChannelId: path.EndpointA.ChannelID, + PacketCommitmentSequences: commitments, + Pagination: nil, + } + }, + true, + }, { "success", func() { diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index 571b7ae3b53..38b40e5b795 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -2,7 +2,6 @@ package keeper import ( "bytes" - "encoding/hex" "fmt" "time" @@ -126,32 +125,16 @@ func (k Keeper) SendPacket( k.SetNextSequenceSend(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), nextSequenceSend) k.SetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), commitment) - // Emit Event with Packet data along with other packet information for relayer to pick up - // and relay to other chain - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeSendPacket, - sdk.NewAttribute(types.AttributeKeyData, string(packet.GetData())), // DEPRECATED - sdk.NewAttribute(types.AttributeKeyDataHex, hex.EncodeToString(packet.GetData())), - sdk.NewAttribute(types.AttributeKeyTimeoutHeight, timeoutHeight.String()), - sdk.NewAttribute(types.AttributeKeyTimeoutTimestamp, fmt.Sprintf("%d", packet.GetTimeoutTimestamp())), - sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), - sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), - sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), - sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), - sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), - sdk.NewAttribute(types.AttributeKeyChannelOrdering, channel.Ordering.String()), - // we only support 1-hop packets now, and that is the most important hop for a relayer - // (is it going to a chain I am connected to) - sdk.NewAttribute(types.AttributeKeyConnection, channel.ConnectionHops[0]), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - ), - }) - - k.Logger(ctx).Info("packet sent", "packet", fmt.Sprintf("%v", packet)) + EmitSendPacketEvent(ctx, packet, channel, timeoutHeight) + + k.Logger(ctx).Info( + "packet sent", + "sequence", packet.GetSequence(), + "src_port", packet.GetSourcePort(), + "src_channel", packet.GetSourceChannel(), + "dst_port", packet.GetDestPort(), + "dst_channel", packet.GetDestChannel(), + ) return nil } @@ -249,10 +232,11 @@ func (k Keeper) RecvPacket( // check if the packet receipt has been received already for unordered channels _, found := k.GetPacketReceipt(ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) if found { - return sdkerrors.Wrapf( - types.ErrPacketReceived, - "packet sequence (%d)", packet.GetSequence(), - ) + EmitRecvPacketEvent(ctx, packet, channel) + // This error indicates that the packet has already been relayed. Core IBC will + // treat this error as a no-op in order to prevent an entire relay transaction + // from failing and consuming unnecessary fees. + return types.ErrNoOpMsg } // All verification complete, update state @@ -271,12 +255,12 @@ func (k Keeper) RecvPacket( ) } - // helpful error message for relayers if packet.GetSequence() < nextSequenceRecv { - return sdkerrors.Wrapf( - types.ErrPacketReceived, - "packet sequence (%d), next sequence receive (%d)", packet.GetSequence(), nextSequenceRecv, - ) + EmitRecvPacketEvent(ctx, packet, channel) + // This error indicates that the packet has already been relayed. Core IBC will + // treat this error as a no-op in order to prevent an entire relay transaction + // from failing and consuming unnecessary fees. + return types.ErrNoOpMsg } if packet.GetSequence() != nextSequenceRecv { @@ -300,28 +284,7 @@ func (k Keeper) RecvPacket( k.Logger(ctx).Info("packet received", "packet", fmt.Sprintf("%v", packet)) // emit an event that the relayer can query for - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeRecvPacket, - sdk.NewAttribute(types.AttributeKeyData, string(packet.GetData())), // DEPRECATED - sdk.NewAttribute(types.AttributeKeyDataHex, hex.EncodeToString(packet.GetData())), - sdk.NewAttribute(types.AttributeKeyTimeoutHeight, packet.GetTimeoutHeight().String()), - sdk.NewAttribute(types.AttributeKeyTimeoutTimestamp, fmt.Sprintf("%d", packet.GetTimeoutTimestamp())), - sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), - sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), - sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), - sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), - sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), - sdk.NewAttribute(types.AttributeKeyChannelOrdering, channel.Ordering.String()), - // we only support 1-hop packets now, and that is the most important hop for a relayer - // (is it going to a chain I am connected to) - sdk.NewAttribute(types.AttributeKeyConnection, channel.ConnectionHops[0]), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - ), - }) + EmitRecvPacketEvent(ctx, packet, channel) return nil } @@ -384,30 +347,7 @@ func (k Keeper) WriteAcknowledgement( // log that a packet acknowledgement has been written k.Logger(ctx).Info("acknowledged written", "packet", fmt.Sprintf("%v", packet)) - // emit an event that the relayer can query for - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeWriteAck, - sdk.NewAttribute(types.AttributeKeyData, string(packet.GetData())), // DEPRECATED - sdk.NewAttribute(types.AttributeKeyDataHex, hex.EncodeToString(packet.GetData())), - sdk.NewAttribute(types.AttributeKeyTimeoutHeight, packet.GetTimeoutHeight().String()), - sdk.NewAttribute(types.AttributeKeyTimeoutTimestamp, fmt.Sprintf("%d", packet.GetTimeoutTimestamp())), - sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), - sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), - sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), - sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), - sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), - sdk.NewAttribute(types.AttributeKeyAck, string(acknowledgement)), - sdk.NewAttribute(types.AttributeKeyAckHex, hex.EncodeToString(acknowledgement)), - // we only support 1-hop packets now, and that is the most important hop for a relayer - // (is it going to a chain I am connected to) - sdk.NewAttribute(types.AttributeKeyConnection, channel.ConnectionHops[0]), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - ), - }) + EmitWriteAcknowledgementEvent(ctx, packet, channel, acknowledgement) return nil } @@ -480,7 +420,12 @@ func (k Keeper) AcknowledgePacket( commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) if len(commitment) == 0 { - return sdkerrors.Wrapf(types.ErrPacketCommitmentNotFound, "packet with sequence (%d) has been acknowledged, or timed out. In rare cases, the packet referenced was never sent, likely due to the relayer being misconfigured", packet.GetSequence()) + EmitAcknowledgePacketEvent(ctx, packet, channel) + // This error indicates that the acknowledgement has already been relayed + // or there is a misconfigured relayer attempting to prove an acknowledgement + // for a packet never sent. Core IBC will treat this error as a no-op in order to + // prevent an entire relay transaction from failing and consuming unnecessary fees. + return types.ErrNoOpMsg } packetCommitment := types.CommitPacket(k.cdc, packet) @@ -530,26 +475,7 @@ func (k Keeper) AcknowledgePacket( k.Logger(ctx).Info("packet acknowledged", "packet", fmt.Sprintf("%v", packet)) // emit an event marking that we have processed the acknowledgement - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeAcknowledgePacket, - sdk.NewAttribute(types.AttributeKeyTimeoutHeight, packet.GetTimeoutHeight().String()), - sdk.NewAttribute(types.AttributeKeyTimeoutTimestamp, fmt.Sprintf("%d", packet.GetTimeoutTimestamp())), - sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), - sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), - sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), - sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), - sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), - sdk.NewAttribute(types.AttributeKeyChannelOrdering, channel.Ordering.String()), - // we only support 1-hop packets now, and that is the most important hop for a relayer - // (is it going to a chain I am connected to) - sdk.NewAttribute(types.AttributeKeyConnection, channel.ConnectionHops[0]), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - ), - }) + EmitAcknowledgePacketEvent(ctx, packet, channel) return nil } diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index d1cb11370c3..9ef7798140d 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -267,8 +267,8 @@ func (suite *KeeperTestSuite) TestRecvPacket() { // attempts to receive packet 2 without receiving packet 1 channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, true}, - {"packet already relayed ORDERED channel", func() { - expError = types.ErrPacketReceived + {"packet already relayed ORDERED channel (no-op)", func() { + expError = types.ErrNoOpMsg path.SetChannelOrdered() suite.coordinator.Setup(path) @@ -281,8 +281,8 @@ func (suite *KeeperTestSuite) TestRecvPacket() { err = path.EndpointB.RecvPacket(packet.(types.Packet)) suite.Require().NoError(err) }, false}, - {"packet already relayed UNORDERED channel", func() { - expError = types.ErrPacketReceived + {"packet already relayed UNORDERED channel (no-op)", func() { + expError = types.ErrNoOpMsg // setup uses an UNORDERED channel suite.coordinator.Setup(path) @@ -428,7 +428,7 @@ func (suite *KeeperTestSuite) TestRecvPacket() { path.EndpointB.UpdateClient() }, false}, {"receipt already stored", func() { - expError = types.ErrPacketReceived + expError = types.ErrNoOpMsg suite.coordinator.Setup(path) packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp) @@ -617,8 +617,8 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, - {"packet already acknowledged ordered channel", func() { - expError = types.ErrPacketCommitmentNotFound + {"packet already acknowledged ordered channel (no-op)", func() { + expError = types.ErrNoOpMsg path.SetChannelOrdered() suite.coordinator.Setup(path) @@ -636,8 +636,8 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { err = path.EndpointA.AcknowledgePacket(packet, ack.Acknowledgement()) suite.Require().NoError(err) }, false}, - {"packet already acknowledged unordered channel", func() { - expError = types.ErrPacketCommitmentNotFound + {"packet already acknowledged unordered channel (no-op)", func() { + expError = types.ErrNoOpMsg // setup uses an UNORDERED channel suite.coordinator.Setup(path) @@ -738,7 +738,7 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"packet hasn't been sent", func() { - expError = types.ErrPacketCommitmentNotFound + expError = types.ErrNoOpMsg // packet commitment never written suite.coordinator.Setup(path) diff --git a/modules/core/04-channel/keeper/timeout.go b/modules/core/04-channel/keeper/timeout.go index caf4e037cf8..93fa9eca4fe 100644 --- a/modules/core/04-channel/keeper/timeout.go +++ b/modules/core/04-channel/keeper/timeout.go @@ -34,13 +34,6 @@ func (k Keeper) TimeoutPacket( ) } - if channel.State != types.OPEN { - return sdkerrors.Wrapf( - types.ErrInvalidChannelState, - "channel state is not OPEN (got %s)", channel.State.String(), - ) - } - // NOTE: TimeoutPacket is called by the AnteHandler which acts upon the packet.Route(), // so the capability authentication can be omitted here @@ -81,7 +74,19 @@ func (k Keeper) TimeoutPacket( commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) if len(commitment) == 0 { - return sdkerrors.Wrapf(types.ErrPacketCommitmentNotFound, "packet with sequence (%d) has been acknowledged or timed out. In rare cases, the packet referenced was never sent, likely due to the relayer being misconfigured", packet.GetSequence()) + EmitTimeoutPacketEvent(ctx, packet, channel) + // This error indicates that the timeout has already been relayed + // or there is a misconfigured relayer attempting to prove a timeout + // for a packet never sent. Core IBC will treat this error as a no-op in order to + // prevent an entire relay transaction from failing and consuming unnecessary fees. + return types.ErrNoOpMsg + } + + if channel.State != types.OPEN { + return sdkerrors.Wrapf( + types.ErrInvalidChannelState, + "channel state is not OPEN (got %s)", channel.State.String(), + ) } packetCommitment := types.CommitPacket(k.cdc, packet) @@ -155,23 +160,7 @@ func (k Keeper) TimeoutExecuted( k.Logger(ctx).Info("packet timed-out", "packet", fmt.Sprintf("%v", packet)) // emit an event marking that we have processed the timeout - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeTimeoutPacket, - sdk.NewAttribute(types.AttributeKeyTimeoutHeight, packet.GetTimeoutHeight().String()), - sdk.NewAttribute(types.AttributeKeyTimeoutTimestamp, fmt.Sprintf("%d", packet.GetTimeoutTimestamp())), - sdk.NewAttribute(types.AttributeKeySequence, fmt.Sprintf("%d", packet.GetSequence())), - sdk.NewAttribute(types.AttributeKeySrcPort, packet.GetSourcePort()), - sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()), - sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()), - sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()), - sdk.NewAttribute(types.AttributeKeyChannelOrdering, channel.Ordering.String()), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - ), - }) + EmitTimeoutPacketEvent(ctx, packet, channel) return nil } @@ -222,6 +211,15 @@ func (k Keeper) TimeoutOnClose( commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + if len(commitment) == 0 { + EmitTimeoutPacketEvent(ctx, packet, channel) + // This error indicates that the timeout has already been relayed + // or there is a misconfigured relayer attempting to prove a timeout + // for a packet never sent. Core IBC will treat this error as a no-op in order to + // prevent an entire relay transaction from failing and consuming unnecessary fees. + return types.ErrNoOpMsg + } + packetCommitment := types.CommitPacket(k.cdc, packet) // verify we sent the packet and haven't cleared it out yet diff --git a/modules/core/04-channel/keeper/timeout_test.go b/modules/core/04-channel/keeper/timeout_test.go index 460e6097632..7cdb88cdc05 100644 --- a/modules/core/04-channel/keeper/timeout_test.go +++ b/modules/core/04-channel/keeper/timeout_test.go @@ -48,7 +48,7 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { path.EndpointA.UpdateClient() }, true}, {"packet already timed out: ORDERED", func() { - expError = types.ErrInvalidChannelState + expError = types.ErrNoOpMsg ordered = true path.SetChannelOrdered() @@ -62,7 +62,7 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { suite.Require().NoError(err) }, false}, {"packet already timed out: UNORDERED", func() { - expError = types.ErrPacketCommitmentNotFound + expError = types.ErrNoOpMsg ordered = false suite.coordinator.Setup(path) @@ -83,9 +83,13 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { {"channel not open", func() { expError = types.ErrInvalidChannelState suite.coordinator.Setup(path) - packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp) + packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.GetClientState().GetLatestHeight().Increment().(clienttypes.Height), disabledTimeoutTimestamp) + err := path.EndpointA.SendPacket(packet) + suite.Require().NoError(err) + // need to update chainA's client representing chainB to prove missing ack + path.EndpointA.UpdateClient() - err := path.EndpointA.SetChannelClosed() + err = path.EndpointA.SetChannelClosed() suite.Require().NoError(err) }, false}, {"packet destination port ≠ channel counterparty port", func() { @@ -130,7 +134,7 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { path.EndpointA.UpdateClient() }, false}, {"packet hasn't been sent", func() { - expError = types.ErrPacketCommitmentNotFound + expError = types.ErrNoOpMsg ordered = true path.SetChannelOrdered() @@ -182,10 +186,12 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { orderedPacketKey := host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) unorderedPacketKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - if ordered { - proof, proofHeight = suite.chainB.QueryProof(orderedPacketKey) - } else { - proof, proofHeight = suite.chainB.QueryProof(unorderedPacketKey) + if path.EndpointB.ConnectionID != "" { + if ordered { + proof, proofHeight = path.EndpointB.QueryProof(orderedPacketKey) + } else { + proof, proofHeight = path.EndpointB.QueryProof(unorderedPacketKey) + } } err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.TimeoutPacket(suite.chainA.GetContext(), packet, proof, proofHeight, nextSeqRecv) diff --git a/modules/core/04-channel/types/errors.go b/modules/core/04-channel/types/errors.go index 6a6d608fb29..8c31cfbae18 100644 --- a/modules/core/04-channel/types/errors.go +++ b/modules/core/04-channel/types/errors.go @@ -31,5 +31,11 @@ var ( // ORDERED channel error ErrPacketSequenceOutOfOrder = sdkerrors.Register(SubModuleName, 21, "packet sequence is out of order") + // Antehandler error + ErrRedundantTx = sdkerrors.Register(SubModuleName, 22, "packet messages are redundant") + + // Perform a no-op on the current Msg + ErrNoOpMsg = sdkerrors.Register(SubModuleName, 23, "message is redundant, no-op will be performed") + ErrInvalidChannelVersion = sdkerrors.Register(SubModuleName, 24, "invalid channel version") ) diff --git a/modules/core/04-channel/types/msgs_test.go b/modules/core/04-channel/types/msgs_test.go index 10401ebcae7..9606b9357c1 100644 --- a/modules/core/04-channel/types/msgs_test.go +++ b/modules/core/04-channel/types/msgs_test.go @@ -32,7 +32,8 @@ const ( // invalid constants used for testing invalidPort = "(invalidport1)" invalidShortPort = "p" - invalidLongPort = "invalidlongportinvalidlongportinvalidlongportidinvalidlongportidinvalid" + // 195 characters + invalidLongPort = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eros neque, ultricies vel ligula ac, convallis porttitor elit. Maecenas tincidunt turpis elit, vel faucibus nisl pellentesque sodales" invalidChannel = "(invalidchannel1)" invalidShortChannel = "invalid" diff --git a/modules/core/04-channel/types/query.pb.go b/modules/core/04-channel/types/query.pb.go index a5e23569526..281e790ba6b 100644 --- a/modules/core/04-channel/types/query.pb.go +++ b/modules/core/04-channel/types/query.pb.go @@ -1184,6 +1184,8 @@ type QueryPacketAcknowledgementsRequest struct { ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` // pagination request Pagination *query.PageRequest `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` + // list of packet sequences + PacketCommitmentSequences []uint64 `protobuf:"varint,4,rep,packed,name=packet_commitment_sequences,json=packetCommitmentSequences,proto3" json:"packet_commitment_sequences,omitempty"` } func (m *QueryPacketAcknowledgementsRequest) Reset() { *m = QueryPacketAcknowledgementsRequest{} } @@ -1240,6 +1242,13 @@ func (m *QueryPacketAcknowledgementsRequest) GetPagination() *query.PageRequest return nil } +func (m *QueryPacketAcknowledgementsRequest) GetPacketCommitmentSequences() []uint64 { + if m != nil { + return m.PacketCommitmentSequences + } + return nil +} + // QueryPacketAcknowledgemetsResponse is the request type for the // Query/QueryPacketAcknowledgements RPC method type QueryPacketAcknowledgementsResponse struct { @@ -1699,100 +1708,100 @@ func init() { func init() { proto.RegisterFile("ibc/core/channel/v1/query.proto", fileDescriptor_1034a1e9abc4cca1) } var fileDescriptor_1034a1e9abc4cca1 = []byte{ - // 1481 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x59, 0xdf, 0x6f, 0x14, 0x55, - 0x14, 0xee, 0xdd, 0x16, 0x68, 0x0f, 0xc8, 0x8f, 0xdb, 0x16, 0xca, 0x50, 0xb6, 0x65, 0x8d, 0x52, - 0x48, 0x98, 0x4b, 0x0b, 0x56, 0x62, 0x94, 0x84, 0x36, 0x11, 0x6a, 0x04, 0xca, 0x20, 0x11, 0x48, - 0x74, 0x9d, 0x9d, 0xbd, 0x6c, 0x27, 0xed, 0xce, 0x0c, 0x3b, 0xb3, 0x0b, 0xa4, 0xae, 0x31, 0x3e, - 0x20, 0x89, 0x2f, 0x46, 0x1e, 0x4c, 0x7c, 0x31, 0x31, 0xbe, 0xf0, 0xe0, 0x83, 0x7f, 0x81, 0xaf, - 0xbc, 0x49, 0x82, 0x0f, 0x26, 0x24, 0x68, 0xa8, 0x09, 0xbe, 0xfa, 0xe2, 0xb3, 0x99, 0xfb, 0x63, - 0x76, 0x66, 0x77, 0x66, 0xba, 0xdb, 0xed, 0x26, 0x8d, 0x6f, 0x33, 0x77, 0xee, 0x39, 0xf7, 0xfb, - 0xbe, 0x73, 0xcf, 0xe9, 0x39, 0x5b, 0x98, 0x30, 0x0b, 0x06, 0x31, 0xec, 0x0a, 0x25, 0xc6, 0x92, - 0x6e, 0x59, 0x74, 0x85, 0xd4, 0xa6, 0xc9, 0xed, 0x2a, 0xad, 0xdc, 0x53, 0x9d, 0x8a, 0xed, 0xd9, - 0x78, 0xd8, 0x2c, 0x18, 0xaa, 0xbf, 0x41, 0x15, 0x1b, 0xd4, 0xda, 0xb4, 0x12, 0xb2, 0x5a, 0x31, - 0xa9, 0xe5, 0xf9, 0x46, 0xfc, 0x89, 0x5b, 0x29, 0xc7, 0x0d, 0xdb, 0x2d, 0xdb, 0x2e, 0x29, 0xe8, - 0x2e, 0xe5, 0xee, 0x48, 0x6d, 0xba, 0x40, 0x3d, 0x7d, 0x9a, 0x38, 0x7a, 0xc9, 0xb4, 0x74, 0xcf, - 0xb4, 0x2d, 0xb1, 0xf7, 0x48, 0x1c, 0x04, 0x79, 0x18, 0xdf, 0x32, 0x5e, 0xb2, 0xed, 0xd2, 0x0a, - 0x25, 0xba, 0x63, 0x12, 0xdd, 0xb2, 0x6c, 0x8f, 0xd9, 0xbb, 0xe2, 0xeb, 0x41, 0xf1, 0x95, 0xbd, - 0x15, 0xaa, 0xb7, 0x88, 0x6e, 0x09, 0xf4, 0xca, 0x48, 0xc9, 0x2e, 0xd9, 0xec, 0x91, 0xf8, 0x4f, - 0x7c, 0x35, 0x77, 0x11, 0x86, 0xaf, 0xf8, 0x98, 0xe6, 0xf9, 0x21, 0x1a, 0xbd, 0x5d, 0xa5, 0xae, - 0x87, 0x0f, 0xc0, 0x0e, 0xc7, 0xae, 0x78, 0x79, 0xb3, 0x38, 0x86, 0x26, 0xd1, 0xd4, 0x90, 0xb6, - 0xdd, 0x7f, 0x5d, 0x28, 0xe2, 0xc3, 0x00, 0x02, 0x8f, 0xff, 0x2d, 0xc3, 0xbe, 0x0d, 0x89, 0x95, - 0x85, 0x62, 0xee, 0x11, 0x82, 0x91, 0xa8, 0x3f, 0xd7, 0xb1, 0x2d, 0x97, 0xe2, 0x59, 0xd8, 0x21, - 0x76, 0x31, 0x87, 0x3b, 0x67, 0xc6, 0xd5, 0x18, 0x35, 0x55, 0x69, 0x26, 0x37, 0xe3, 0x11, 0xd8, - 0xe6, 0x54, 0x6c, 0xfb, 0x16, 0x3b, 0x6a, 0x97, 0xc6, 0x5f, 0xf0, 0x3c, 0xec, 0x62, 0x0f, 0xf9, - 0x25, 0x6a, 0x96, 0x96, 0xbc, 0xb1, 0x7e, 0xe6, 0x52, 0x09, 0xb9, 0xe4, 0x11, 0xa8, 0x4d, 0xab, - 0x17, 0xd8, 0x8e, 0xb9, 0x81, 0xc7, 0xcf, 0x27, 0xfa, 0xb4, 0x9d, 0xcc, 0x8a, 0x2f, 0xe5, 0x3e, - 0x8e, 0x42, 0x75, 0x25, 0xf7, 0x77, 0x01, 0x1a, 0x81, 0x11, 0x68, 0x5f, 0x57, 0x79, 0x14, 0x55, - 0x3f, 0x8a, 0x2a, 0xbf, 0x14, 0x22, 0x8a, 0xea, 0xa2, 0x5e, 0xa2, 0xc2, 0x56, 0x0b, 0x59, 0xe6, - 0x9e, 0x23, 0x18, 0x6d, 0x3a, 0x40, 0x88, 0x31, 0x07, 0x83, 0x82, 0x9f, 0x3b, 0x86, 0x26, 0xfb, - 0x99, 0xff, 0x38, 0x35, 0x16, 0x8a, 0xd4, 0xf2, 0xcc, 0x5b, 0x26, 0x2d, 0x4a, 0x5d, 0x02, 0x3b, - 0x7c, 0x3e, 0x82, 0x32, 0xc3, 0x50, 0x1e, 0x5d, 0x17, 0x25, 0x07, 0x10, 0x86, 0x89, 0xcf, 0xc0, - 0xf6, 0x0e, 0x55, 0x14, 0xfb, 0x73, 0x0f, 0x10, 0x64, 0x39, 0x41, 0xdb, 0xb2, 0xa8, 0xe1, 0x7b, - 0x6b, 0xd6, 0x32, 0x0b, 0x60, 0x04, 0x1f, 0xc5, 0x55, 0x0a, 0xad, 0x34, 0x69, 0x9d, 0xd9, 0xb0, - 0xd6, 0x7f, 0x23, 0x98, 0x48, 0x84, 0xf2, 0xff, 0x52, 0xfd, 0xba, 0x14, 0x9d, 0x63, 0x9a, 0x67, - 0xbb, 0xaf, 0x7a, 0xba, 0x47, 0xbb, 0x4d, 0xde, 0x3f, 0x02, 0x11, 0x63, 0x5c, 0x0b, 0x11, 0x75, - 0x38, 0x60, 0x06, 0xfa, 0xe4, 0x39, 0xd4, 0xbc, 0xeb, 0x6f, 0x11, 0x99, 0x72, 0x2c, 0x8e, 0x48, - 0x48, 0xd2, 0x90, 0xcf, 0x51, 0x33, 0x6e, 0xb9, 0x97, 0x29, 0xff, 0x13, 0x82, 0x23, 0x11, 0x86, - 0x3e, 0x27, 0xcb, 0xad, 0xba, 0x9b, 0xa1, 0x1f, 0x3e, 0x0a, 0x7b, 0x2a, 0xb4, 0x66, 0xba, 0xa6, - 0x6d, 0xe5, 0xad, 0x6a, 0xb9, 0x40, 0x2b, 0x0c, 0xe5, 0x80, 0xb6, 0x5b, 0x2e, 0x5f, 0x62, 0xab, - 0x91, 0x8d, 0x82, 0xce, 0x40, 0x74, 0xa3, 0xc0, 0xfb, 0x0c, 0x41, 0x2e, 0x0d, 0xaf, 0x08, 0xca, - 0x3b, 0xb0, 0xc7, 0x90, 0x5f, 0x22, 0xc1, 0x18, 0x51, 0xf9, 0xdf, 0x03, 0x55, 0xfe, 0x3d, 0x50, - 0xcf, 0x59, 0xf7, 0xb4, 0xdd, 0x46, 0xc4, 0x0d, 0x3e, 0x04, 0x43, 0x22, 0x90, 0x01, 0xab, 0x41, - 0xbe, 0xb0, 0x50, 0x6c, 0x44, 0xa3, 0x3f, 0x2d, 0x1a, 0x03, 0x1b, 0x89, 0x46, 0x05, 0xc6, 0x19, - 0xb9, 0x45, 0xdd, 0x58, 0xa6, 0xde, 0xbc, 0x5d, 0x2e, 0x9b, 0x5e, 0x99, 0x5a, 0x5e, 0xb7, 0x71, - 0x50, 0x60, 0xd0, 0xf5, 0x5d, 0x58, 0x06, 0x15, 0x01, 0x08, 0xde, 0x73, 0xdf, 0x21, 0x38, 0x9c, - 0x70, 0xa8, 0x10, 0x93, 0x95, 0x2c, 0xb9, 0xca, 0x0e, 0xde, 0xa5, 0x85, 0x56, 0x7a, 0x79, 0x3d, - 0xbf, 0x4f, 0x02, 0xe7, 0x76, 0x2b, 0x49, 0xb4, 0xce, 0xf6, 0x6f, 0xb8, 0xce, 0xbe, 0x94, 0x25, - 0x3f, 0x06, 0x61, 0x50, 0x66, 0x77, 0x36, 0xd4, 0x92, 0x95, 0x76, 0x32, 0xb6, 0xd2, 0x72, 0x27, - 0xfc, 0x2e, 0x87, 0x8d, 0xb6, 0x42, 0x99, 0xb5, 0xe1, 0x60, 0x88, 0xa8, 0x46, 0x0d, 0x6a, 0x3a, - 0x3d, 0xbd, 0x99, 0x0f, 0x11, 0x28, 0x71, 0x27, 0x0a, 0x59, 0x15, 0x18, 0xac, 0xf8, 0x4b, 0x35, - 0xca, 0xfd, 0x0e, 0x6a, 0xc1, 0x7b, 0x2f, 0x73, 0xf4, 0x8e, 0x28, 0x98, 0x1c, 0xd4, 0x39, 0x63, - 0xd9, 0xb2, 0xef, 0xac, 0xd0, 0x62, 0x89, 0xf6, 0x3a, 0x51, 0x1f, 0xc9, 0xd2, 0x97, 0x70, 0xb2, - 0x90, 0x65, 0x0a, 0xf6, 0xe8, 0xd1, 0x4f, 0x22, 0x65, 0x9b, 0x97, 0x7b, 0x99, 0xb7, 0x3f, 0xa6, - 0x62, 0xdd, 0x32, 0xc9, 0xfb, 0x2f, 0x82, 0x57, 0x53, 0x61, 0x0a, 0x4d, 0xdf, 0x87, 0xbd, 0x4d, - 0xe2, 0xb5, 0x9f, 0xc6, 0x2d, 0x96, 0x5b, 0x21, 0x97, 0xbf, 0x95, 0x75, 0xf5, 0x9a, 0x25, 0x73, - 0x86, 0x63, 0xee, 0x3a, 0x34, 0x67, 0xe1, 0x90, 0xc3, 0x3c, 0xe5, 0x1b, 0xe5, 0x2b, 0x2f, 0xef, - 0xb0, 0x3b, 0xd6, 0x3f, 0xd9, 0x3f, 0x35, 0xa0, 0x1d, 0x74, 0x9a, 0x8a, 0xe5, 0x55, 0xb9, 0x21, - 0x77, 0x57, 0x94, 0xd3, 0x18, 0x60, 0x22, 0x18, 0xe3, 0x30, 0xd4, 0xf0, 0x87, 0x98, 0xbf, 0xc6, - 0x42, 0x48, 0x93, 0x4c, 0x87, 0x9a, 0xdc, 0x97, 0xe5, 0xa6, 0x71, 0xf4, 0x39, 0x63, 0xb9, 0x6b, - 0x41, 0x4e, 0xc2, 0x88, 0x10, 0x44, 0x37, 0x96, 0x5b, 0x94, 0xc0, 0x8e, 0xbc, 0x79, 0x0d, 0x09, - 0xaa, 0x70, 0x28, 0x16, 0x47, 0x8f, 0xf9, 0xdf, 0x10, 0xbd, 0xee, 0x25, 0x7a, 0x37, 0x88, 0x87, - 0xc6, 0x01, 0x74, 0xdb, 0x47, 0xff, 0x8c, 0x60, 0x32, 0xd9, 0xb7, 0xe0, 0x35, 0x03, 0xa3, 0x16, - 0xbd, 0xdb, 0xb8, 0x2c, 0x79, 0xc1, 0x9e, 0x1d, 0x35, 0xa0, 0x0d, 0x5b, 0xad, 0xb6, 0x3d, 0x2c, - 0x61, 0x33, 0x5f, 0xed, 0x87, 0x6d, 0x0c, 0x33, 0xfe, 0x01, 0xc1, 0x0e, 0xd1, 0x6e, 0xe2, 0xa9, - 0xd8, 0x7c, 0x8f, 0xf9, 0xc1, 0x40, 0x39, 0xd6, 0xc6, 0x4e, 0xce, 0x3c, 0x37, 0xf7, 0xc5, 0xd3, - 0xbf, 0x1e, 0x66, 0xde, 0xc6, 0x6f, 0x91, 0x94, 0x5f, 0x3b, 0x5c, 0xb2, 0xda, 0x90, 0xb8, 0x4e, - 0x7c, 0xe1, 0x5d, 0xb2, 0x2a, 0xc2, 0x51, 0xc7, 0x0f, 0x10, 0x0c, 0xca, 0x01, 0x0f, 0xaf, 0x7f, - 0xb6, 0xbc, 0xd6, 0xca, 0xf1, 0x76, 0xb6, 0x0a, 0x9c, 0xaf, 0x31, 0x9c, 0x13, 0xf8, 0x70, 0x2a, - 0x4e, 0xfc, 0x0b, 0x02, 0xdc, 0x3a, 0x75, 0xe2, 0x53, 0x29, 0x27, 0x25, 0x8d, 0xcb, 0xca, 0xe9, - 0xce, 0x8c, 0x04, 0xd0, 0xb3, 0x0c, 0xe8, 0x19, 0x3c, 0x1b, 0x0f, 0x34, 0x30, 0xf4, 0x35, 0x0d, - 0x5e, 0xea, 0x0d, 0x06, 0x4f, 0x7c, 0x06, 0x2d, 0x23, 0x5f, 0x2a, 0x83, 0xa4, 0xd9, 0x33, 0x95, - 0x41, 0xe2, 0x54, 0x99, 0xbb, 0xcc, 0x18, 0x2c, 0xe0, 0xf3, 0x1b, 0xbf, 0x12, 0x24, 0x3c, 0x8b, - 0xe2, 0x6f, 0x32, 0x30, 0x1a, 0x3b, 0x33, 0xe1, 0xd9, 0xf5, 0x01, 0xc6, 0x0d, 0x85, 0xca, 0x9b, - 0x1d, 0xdb, 0x09, 0x6e, 0x5f, 0x22, 0x46, 0xee, 0x73, 0x84, 0x3f, 0xeb, 0x86, 0x5d, 0x74, 0xbe, - 0x23, 0x72, 0x50, 0x24, 0xab, 0x4d, 0x23, 0x67, 0x9d, 0xf0, 0x32, 0x10, 0xfa, 0xc0, 0x17, 0xea, - 0xf8, 0x19, 0x82, 0xbd, 0xcd, 0x7d, 0x3b, 0x9e, 0x4e, 0xe6, 0x95, 0x30, 0x97, 0x29, 0x33, 0x9d, - 0x98, 0x08, 0x15, 0x3e, 0x61, 0x22, 0xdc, 0xc4, 0xd7, 0xbb, 0xd0, 0xa0, 0xe5, 0x2f, 0xad, 0x4b, - 0x56, 0x65, 0xf9, 0xac, 0xe3, 0xa7, 0x08, 0xf6, 0xb5, 0x4c, 0x25, 0xb8, 0x03, 0xac, 0x41, 0x16, - 0x9e, 0xea, 0xc8, 0x46, 0x10, 0xbc, 0xc6, 0x08, 0x5e, 0xc6, 0x17, 0x37, 0x95, 0x20, 0xfe, 0x15, - 0xc1, 0x2b, 0x91, 0x81, 0x00, 0xab, 0xeb, 0xa1, 0x8b, 0xce, 0x2a, 0x0a, 0x69, 0x7b, 0xbf, 0x60, - 0xf2, 0x11, 0x63, 0xf2, 0x21, 0xbe, 0xd6, 0x3d, 0x93, 0x0a, 0x77, 0x1d, 0x89, 0xd3, 0x1a, 0x82, - 0xd1, 0xd8, 0x06, 0x34, 0x2d, 0x35, 0xd3, 0xc6, 0x8f, 0xb4, 0xd4, 0x4c, 0x1d, 0x1e, 0x72, 0x37, - 0x18, 0xd3, 0xab, 0xf8, 0x4a, 0xf7, 0x4c, 0x75, 0x63, 0x39, 0xc2, 0xf2, 0x25, 0x82, 0xfd, 0xf1, - 0x6d, 0x36, 0xee, 0x14, 0x6e, 0x70, 0x2f, 0xcf, 0x74, 0x6e, 0x28, 0x88, 0xde, 0x64, 0x44, 0x3f, - 0xc0, 0xda, 0xa6, 0x10, 0x8d, 0xd2, 0xb9, 0x9f, 0x81, 0x7d, 0x2d, 0xed, 0x6b, 0x5a, 0xde, 0x25, - 0x35, 0xe1, 0x69, 0x79, 0x97, 0xd8, 0x1f, 0x6f, 0x52, 0x79, 0x8d, 0x2b, 0x2d, 0x29, 0x8d, 0x7d, - 0x9d, 0x54, 0x03, 0x40, 0x79, 0x47, 0x50, 0xfe, 0x07, 0xc1, 0xee, 0x68, 0x13, 0x8b, 0x49, 0x3b, - 0x8c, 0x42, 0x6d, 0xb7, 0x72, 0xb2, 0x7d, 0x03, 0xc1, 0xff, 0x53, 0x46, 0xbf, 0x86, 0xbd, 0xde, - 0xb0, 0x8f, 0x74, 0xf1, 0x11, 0xda, 0xfe, 0x8d, 0xc7, 0xbf, 0x21, 0x18, 0x8e, 0xe9, 0x72, 0x71, - 0x4a, 0x1b, 0x90, 0xdc, 0x70, 0x2b, 0x6f, 0x74, 0x68, 0x25, 0x24, 0x58, 0x64, 0x12, 0xbc, 0x87, - 0x2f, 0x74, 0x21, 0x41, 0xa4, 0x17, 0x9f, 0x5b, 0x7c, 0xfc, 0x22, 0x8b, 0x9e, 0xbc, 0xc8, 0xa2, - 0x3f, 0x5f, 0x64, 0xd1, 0xd7, 0x6b, 0xd9, 0xbe, 0x27, 0x6b, 0xd9, 0xbe, 0xdf, 0xd7, 0xb2, 0x7d, - 0x37, 0x67, 0x4b, 0xa6, 0xb7, 0x54, 0x2d, 0xa8, 0x86, 0x5d, 0x26, 0xe2, 0x1f, 0x7b, 0x66, 0xc1, - 0x38, 0x51, 0xb2, 0x49, 0xd9, 0x2e, 0x56, 0x57, 0xa8, 0xcb, 0xcf, 0x3f, 0x79, 0xfa, 0x84, 0x84, - 0xe0, 0xdd, 0x73, 0xa8, 0x5b, 0xd8, 0xce, 0x7e, 0x81, 0x3d, 0xf5, 0x5f, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x90, 0x44, 0xdb, 0xbc, 0x65, 0x1c, 0x00, 0x00, + // 1486 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x59, 0xcf, 0x6f, 0xd4, 0x46, + 0x14, 0xce, 0x6c, 0x16, 0x48, 0x1e, 0x94, 0x1f, 0x93, 0x04, 0x82, 0x09, 0x9b, 0xb0, 0x55, 0x4b, + 0x40, 0xc2, 0x43, 0x02, 0x4d, 0x51, 0xd5, 0x22, 0x91, 0x48, 0x85, 0x54, 0x05, 0x82, 0x29, 0x2a, + 0x20, 0xb5, 0x5b, 0xaf, 0x77, 0xd8, 0x58, 0xc9, 0xda, 0x66, 0xed, 0x5d, 0x40, 0xe9, 0x56, 0x55, + 0x0f, 0x14, 0xa9, 0x97, 0xaa, 0x1c, 0x2a, 0xf5, 0x52, 0xa9, 0x37, 0x0e, 0x3d, 0xf4, 0x2f, 0xe8, + 0x95, 0x5b, 0x91, 0xe8, 0xa1, 0x12, 0x12, 0xad, 0x08, 0x12, 0xbd, 0xf6, 0xd2, 0x73, 0xe5, 0xf9, + 0xe1, 0xb5, 0x77, 0x6d, 0x27, 0x9b, 0xcd, 0x4a, 0x51, 0x6f, 0xf6, 0x78, 0xde, 0x9b, 0xef, 0xfb, + 0xde, 0xbc, 0x97, 0xf7, 0x36, 0x30, 0x6e, 0x16, 0x0d, 0x62, 0xd8, 0x55, 0x4a, 0x8c, 0x45, 0xdd, + 0xb2, 0xe8, 0x32, 0xa9, 0x4f, 0x91, 0xdb, 0x35, 0x5a, 0xbd, 0xa7, 0x3a, 0x55, 0xdb, 0xb3, 0xf1, + 0x90, 0x59, 0x34, 0x54, 0x7f, 0x83, 0x2a, 0x36, 0xa8, 0xf5, 0x29, 0x25, 0x64, 0xb5, 0x6c, 0x52, + 0xcb, 0xf3, 0x8d, 0xf8, 0x13, 0xb7, 0x52, 0x8e, 0x1b, 0xb6, 0x5b, 0xb1, 0x5d, 0x52, 0xd4, 0x5d, + 0xca, 0xdd, 0x91, 0xfa, 0x54, 0x91, 0x7a, 0xfa, 0x14, 0x71, 0xf4, 0xb2, 0x69, 0xe9, 0x9e, 0x69, + 0x5b, 0x62, 0xef, 0x91, 0x38, 0x08, 0xf2, 0x30, 0xbe, 0x65, 0xac, 0x6c, 0xdb, 0xe5, 0x65, 0x4a, + 0x74, 0xc7, 0x24, 0xba, 0x65, 0xd9, 0x1e, 0xb3, 0x77, 0xc5, 0xd7, 0x83, 0xe2, 0x2b, 0x7b, 0x2b, + 0xd6, 0x6e, 0x11, 0xdd, 0x12, 0xe8, 0x95, 0xe1, 0xb2, 0x5d, 0xb6, 0xd9, 0x23, 0xf1, 0x9f, 0xf8, + 0x6a, 0xfe, 0x22, 0x0c, 0x5d, 0xf1, 0x31, 0xcd, 0xf1, 0x43, 0x34, 0x7a, 0xbb, 0x46, 0x5d, 0x0f, + 0x1f, 0x80, 0x1d, 0x8e, 0x5d, 0xf5, 0x0a, 0x66, 0x69, 0x14, 0x4d, 0xa0, 0xc9, 0x41, 0x6d, 0xbb, + 0xff, 0x3a, 0x5f, 0xc2, 0x87, 0x01, 0x04, 0x1e, 0xff, 0x5b, 0x86, 0x7d, 0x1b, 0x14, 0x2b, 0xf3, + 0xa5, 0xfc, 0x23, 0x04, 0xc3, 0x51, 0x7f, 0xae, 0x63, 0x5b, 0x2e, 0xc5, 0x33, 0xb0, 0x43, 0xec, + 0x62, 0x0e, 0x77, 0x4e, 0x8f, 0xa9, 0x31, 0x6a, 0xaa, 0xd2, 0x4c, 0x6e, 0xc6, 0xc3, 0xb0, 0xcd, + 0xa9, 0xda, 0xf6, 0x2d, 0x76, 0xd4, 0x2e, 0x8d, 0xbf, 0xe0, 0x39, 0xd8, 0xc5, 0x1e, 0x0a, 0x8b, + 0xd4, 0x2c, 0x2f, 0x7a, 0xa3, 0xfd, 0xcc, 0xa5, 0x12, 0x72, 0xc9, 0x23, 0x50, 0x9f, 0x52, 0x2f, + 0xb0, 0x1d, 0xb3, 0xd9, 0xc7, 0xcf, 0xc7, 0xfb, 0xb4, 0x9d, 0xcc, 0x8a, 0x2f, 0xe5, 0x3f, 0x8d, + 0x42, 0x75, 0x25, 0xf7, 0xf7, 0x01, 0x9a, 0x81, 0x11, 0x68, 0xdf, 0x54, 0x79, 0x14, 0x55, 0x3f, + 0x8a, 0x2a, 0xbf, 0x14, 0x22, 0x8a, 0xea, 0x82, 0x5e, 0xa6, 0xc2, 0x56, 0x0b, 0x59, 0xe6, 0x9f, + 0x23, 0x18, 0x69, 0x39, 0x40, 0x88, 0x31, 0x0b, 0x03, 0x82, 0x9f, 0x3b, 0x8a, 0x26, 0xfa, 0x99, + 0xff, 0x38, 0x35, 0xe6, 0x4b, 0xd4, 0xf2, 0xcc, 0x5b, 0x26, 0x2d, 0x49, 0x5d, 0x02, 0x3b, 0x7c, + 0x3e, 0x82, 0x32, 0xc3, 0x50, 0x1e, 0x5d, 0x13, 0x25, 0x07, 0x10, 0x86, 0x89, 0xcf, 0xc0, 0xf6, + 0x0e, 0x55, 0x14, 0xfb, 0xf3, 0x0f, 0x10, 0xe4, 0x38, 0x41, 0xdb, 0xb2, 0xa8, 0xe1, 0x7b, 0x6b, + 0xd5, 0x32, 0x07, 0x60, 0x04, 0x1f, 0xc5, 0x55, 0x0a, 0xad, 0xb4, 0x68, 0x9d, 0xd9, 0xb0, 0xd6, + 0x7f, 0x23, 0x18, 0x4f, 0x84, 0xf2, 0xff, 0x52, 0xfd, 0xba, 0x14, 0x9d, 0x63, 0x9a, 0x63, 0xbb, + 0xaf, 0x7a, 0xba, 0x47, 0xbb, 0x4d, 0xde, 0x3f, 0x03, 0x11, 0x63, 0x5c, 0x0b, 0x11, 0x75, 0x38, + 0x60, 0x06, 0xfa, 0x14, 0x38, 0xd4, 0x82, 0xeb, 0x6f, 0x11, 0x99, 0x72, 0x2c, 0x8e, 0x48, 0x48, + 0xd2, 0x90, 0xcf, 0x11, 0x33, 0x6e, 0xb9, 0x97, 0x29, 0xff, 0x33, 0x82, 0x23, 0x11, 0x86, 0x3e, + 0x27, 0xcb, 0xad, 0xb9, 0x9b, 0xa1, 0x1f, 0x3e, 0x0a, 0x7b, 0xaa, 0xb4, 0x6e, 0xba, 0xa6, 0x6d, + 0x15, 0xac, 0x5a, 0xa5, 0x48, 0xab, 0x0c, 0x65, 0x56, 0xdb, 0x2d, 0x97, 0x2f, 0xb1, 0xd5, 0xc8, + 0x46, 0x41, 0x27, 0x1b, 0xdd, 0x28, 0xf0, 0x3e, 0x43, 0x90, 0x4f, 0xc3, 0x2b, 0x82, 0xf2, 0x1e, + 0xec, 0x31, 0xe4, 0x97, 0x48, 0x30, 0x86, 0x55, 0xfe, 0xf7, 0x40, 0x95, 0x7f, 0x0f, 0xd4, 0x73, + 0xd6, 0x3d, 0x6d, 0xb7, 0x11, 0x71, 0x83, 0x0f, 0xc1, 0xa0, 0x08, 0x64, 0xc0, 0x6a, 0x80, 0x2f, + 0xcc, 0x97, 0x9a, 0xd1, 0xe8, 0x4f, 0x8b, 0x46, 0x76, 0x23, 0xd1, 0xa8, 0xc2, 0x18, 0x23, 0xb7, + 0xa0, 0x1b, 0x4b, 0xd4, 0x9b, 0xb3, 0x2b, 0x15, 0xd3, 0xab, 0x50, 0xcb, 0xeb, 0x36, 0x0e, 0x0a, + 0x0c, 0xb8, 0xbe, 0x0b, 0xcb, 0xa0, 0x22, 0x00, 0xc1, 0x7b, 0xfe, 0x07, 0x04, 0x87, 0x13, 0x0e, + 0x15, 0x62, 0xb2, 0x92, 0x25, 0x57, 0xd9, 0xc1, 0xbb, 0xb4, 0xd0, 0x4a, 0x2f, 0xaf, 0xe7, 0x8f, + 0x49, 0xe0, 0xdc, 0x6e, 0x25, 0x89, 0xd6, 0xd9, 0xfe, 0x0d, 0xd7, 0xd9, 0x57, 0xb2, 0xe4, 0xc7, + 0x20, 0x0c, 0xca, 0xec, 0xce, 0xa6, 0x5a, 0xb2, 0xd2, 0x4e, 0xc4, 0x56, 0x5a, 0xee, 0x84, 0xdf, + 0xe5, 0xb0, 0xd1, 0x56, 0x28, 0xb3, 0x36, 0x1c, 0x0c, 0x11, 0xd5, 0xa8, 0x41, 0x4d, 0xa7, 0xa7, + 0x37, 0xf3, 0x21, 0x02, 0x25, 0xee, 0x44, 0x21, 0xab, 0x02, 0x03, 0x55, 0x7f, 0xa9, 0x4e, 0xb9, + 0xdf, 0x01, 0x2d, 0x78, 0xef, 0x65, 0x8e, 0xde, 0x11, 0x05, 0x93, 0x83, 0x3a, 0x67, 0x2c, 0x59, + 0xf6, 0x9d, 0x65, 0x5a, 0x2a, 0xd3, 0x5e, 0x27, 0xea, 0x23, 0x59, 0xfa, 0x12, 0x4e, 0x16, 0xb2, + 0x4c, 0xc2, 0x1e, 0x3d, 0xfa, 0x49, 0xa4, 0x6c, 0xeb, 0x72, 0x2f, 0xf3, 0xf6, 0x65, 0x2a, 0xd6, + 0xad, 0x92, 0xbc, 0xf8, 0x2c, 0x1c, 0x72, 0x18, 0xc0, 0x42, 0x33, 0xd7, 0x0a, 0x52, 0x70, 0x77, + 0x34, 0x3b, 0xd1, 0x3f, 0x99, 0xd5, 0x0e, 0x3a, 0x2d, 0x99, 0x7d, 0x55, 0x6e, 0xc8, 0xff, 0x8b, + 0xe0, 0xf5, 0x54, 0x9a, 0x22, 0x26, 0x1f, 0xc2, 0xde, 0x16, 0xf1, 0xd7, 0x5f, 0x06, 0xda, 0x2c, + 0xb7, 0x42, 0x2d, 0xf8, 0x5e, 0xd6, 0xe5, 0x6b, 0x96, 0xcc, 0x39, 0x8e, 0xb9, 0xeb, 0xd0, 0xae, + 0x11, 0x92, 0xfe, 0xb5, 0x42, 0x72, 0x57, 0x94, 0xe3, 0x18, 0x60, 0x22, 0x18, 0x63, 0x30, 0xd8, + 0xf4, 0x87, 0x98, 0xbf, 0xe6, 0x42, 0x48, 0x93, 0x4c, 0x87, 0x9a, 0xdc, 0x97, 0xe5, 0xaa, 0x79, + 0xf4, 0x39, 0x63, 0xa9, 0x6b, 0x41, 0x4e, 0xc2, 0xb0, 0x10, 0x44, 0x37, 0x96, 0xda, 0x94, 0xc0, + 0x8e, 0xbc, 0x79, 0x4d, 0x09, 0x6a, 0x70, 0x28, 0x16, 0x47, 0x8f, 0xf9, 0xdf, 0x10, 0xbd, 0xf2, + 0x25, 0x7a, 0x37, 0x88, 0x87, 0xc6, 0x01, 0x74, 0xdb, 0x87, 0xff, 0x82, 0x60, 0x22, 0xd9, 0xb7, + 0xe0, 0x35, 0x0d, 0x23, 0x16, 0xbd, 0xdb, 0xbc, 0x2c, 0x05, 0xc1, 0x9e, 0x1d, 0x95, 0xd5, 0x86, + 0xac, 0x76, 0xdb, 0x1e, 0x96, 0xc0, 0xe9, 0x6f, 0xf6, 0xc3, 0x36, 0x86, 0x19, 0xff, 0x84, 0x60, + 0x87, 0x68, 0x57, 0xf1, 0x64, 0x6c, 0xbe, 0xc7, 0xfc, 0xe0, 0xa0, 0x1c, 0x5b, 0xc7, 0x4e, 0xce, + 0x3c, 0x3f, 0xfb, 0xd5, 0xd3, 0x97, 0x0f, 0x33, 0xef, 0xe2, 0x77, 0x48, 0xca, 0xaf, 0x25, 0x2e, + 0x59, 0x69, 0x4a, 0xdc, 0x20, 0xbe, 0xf0, 0x2e, 0x59, 0x11, 0xe1, 0x68, 0xe0, 0x07, 0x08, 0x06, + 0xe4, 0x80, 0x88, 0xd7, 0x3e, 0x5b, 0x5e, 0x6b, 0xe5, 0xf8, 0x7a, 0xb6, 0x0a, 0x9c, 0x6f, 0x30, + 0x9c, 0xe3, 0xf8, 0x70, 0x2a, 0x4e, 0xfc, 0x2b, 0x02, 0xdc, 0x3e, 0xb5, 0xe2, 0x53, 0x29, 0x27, + 0x25, 0x8d, 0xdb, 0xca, 0xe9, 0xce, 0x8c, 0x04, 0xd0, 0xb3, 0x0c, 0xe8, 0x19, 0x3c, 0x13, 0x0f, + 0x34, 0x30, 0xf4, 0x35, 0x0d, 0x5e, 0x1a, 0x4d, 0x06, 0x4f, 0x7c, 0x06, 0x6d, 0x23, 0x63, 0x2a, + 0x83, 0xa4, 0xd9, 0x35, 0x95, 0x41, 0xe2, 0x54, 0x9a, 0xbf, 0xcc, 0x18, 0xcc, 0xe3, 0xf3, 0x1b, + 0xbf, 0x12, 0x24, 0x3c, 0xcb, 0xe2, 0xef, 0x32, 0x30, 0x12, 0x3b, 0x73, 0xe1, 0x99, 0xb5, 0x01, + 0xc6, 0x0d, 0x95, 0xca, 0xdb, 0x1d, 0xdb, 0x09, 0x6e, 0x5f, 0x23, 0x46, 0xee, 0x4b, 0x84, 0xbf, + 0xe8, 0x86, 0x5d, 0x74, 0x3e, 0x24, 0x72, 0xd0, 0x24, 0x2b, 0x2d, 0x23, 0x6b, 0x83, 0xf0, 0x32, + 0x10, 0xfa, 0xc0, 0x17, 0x1a, 0xf8, 0x19, 0x82, 0xbd, 0xad, 0x7d, 0x3f, 0x9e, 0x4a, 0xe6, 0x95, + 0x30, 0xd7, 0x29, 0xd3, 0x9d, 0x98, 0x08, 0x15, 0x3e, 0x63, 0x22, 0xdc, 0xc4, 0xd7, 0xbb, 0xd0, + 0xa0, 0xed, 0x2f, 0xad, 0x4b, 0x56, 0x64, 0xf9, 0x6c, 0xe0, 0xa7, 0x08, 0xf6, 0xb5, 0x4d, 0x35, + 0xb8, 0x03, 0xac, 0x41, 0x16, 0x9e, 0xea, 0xc8, 0x46, 0x10, 0xbc, 0xc6, 0x08, 0x5e, 0xc6, 0x17, + 0x37, 0x95, 0x20, 0xfe, 0x0d, 0xc1, 0x6b, 0x91, 0x81, 0x02, 0xab, 0x6b, 0xa1, 0x8b, 0xce, 0x3a, + 0x0a, 0x59, 0xf7, 0x7e, 0xc1, 0xe4, 0x13, 0xc6, 0xe4, 0x63, 0x7c, 0xad, 0x7b, 0x26, 0x55, 0xee, + 0x3a, 0x12, 0xa7, 0x55, 0x04, 0x23, 0xb1, 0x0d, 0x68, 0x5a, 0x6a, 0xa6, 0x8d, 0x2f, 0x69, 0xa9, + 0x99, 0x3a, 0x7c, 0xe4, 0x6f, 0x30, 0xa6, 0x57, 0xf1, 0x95, 0xee, 0x99, 0xea, 0xc6, 0x52, 0x84, + 0xe5, 0x2b, 0x04, 0xfb, 0xe3, 0xdb, 0x6c, 0xdc, 0x29, 0xdc, 0xe0, 0x5e, 0x9e, 0xe9, 0xdc, 0x50, + 0x10, 0xbd, 0xc9, 0x88, 0x7e, 0x84, 0xb5, 0x4d, 0x21, 0x1a, 0xa5, 0x73, 0x3f, 0x03, 0xfb, 0xda, + 0xda, 0xd7, 0xb4, 0xbc, 0x4b, 0x6a, 0xc2, 0xd3, 0xf2, 0x2e, 0xb1, 0x3f, 0xde, 0xa4, 0xf2, 0x1a, + 0x57, 0x5a, 0x52, 0x1a, 0xfb, 0x06, 0xa9, 0x05, 0x80, 0x0a, 0x8e, 0xa0, 0xfc, 0x0f, 0x82, 0xdd, + 0xd1, 0x26, 0x16, 0x93, 0xf5, 0x30, 0x0a, 0xb5, 0xdd, 0xca, 0xc9, 0xf5, 0x1b, 0x08, 0xfe, 0x9f, + 0x33, 0xfa, 0x75, 0xec, 0xf5, 0x86, 0x7d, 0xa4, 0x8b, 0x8f, 0xd0, 0xf6, 0x6f, 0x3c, 0xfe, 0x1d, + 0xc1, 0x50, 0x4c, 0x97, 0x8b, 0x53, 0xda, 0x80, 0xe4, 0x86, 0x5b, 0x79, 0xab, 0x43, 0x2b, 0x21, + 0xc1, 0x02, 0x93, 0xe0, 0x03, 0x7c, 0xa1, 0x0b, 0x09, 0x22, 0xbd, 0xf8, 0xec, 0xc2, 0xe3, 0x17, + 0x39, 0xf4, 0xe4, 0x45, 0x0e, 0xfd, 0xf5, 0x22, 0x87, 0xbe, 0x5d, 0xcd, 0xf5, 0x3d, 0x59, 0xcd, + 0xf5, 0xfd, 0xb1, 0x9a, 0xeb, 0xbb, 0x39, 0x53, 0x36, 0xbd, 0xc5, 0x5a, 0x51, 0x35, 0xec, 0x0a, + 0x11, 0xff, 0x18, 0x34, 0x8b, 0xc6, 0x89, 0xb2, 0x4d, 0x2a, 0x76, 0xa9, 0xb6, 0x4c, 0x5d, 0x7e, + 0xfe, 0xc9, 0xd3, 0x27, 0x24, 0x04, 0xef, 0x9e, 0x43, 0xdd, 0xe2, 0x76, 0xf6, 0x0b, 0xee, 0xa9, + 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x53, 0x37, 0x2a, 0x8c, 0xa5, 0x1c, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3226,6 +3235,24 @@ func (m *QueryPacketAcknowledgementsRequest) MarshalToSizedBuffer(dAtA []byte) ( _ = i var l int _ = l + if len(m.PacketCommitmentSequences) > 0 { + dAtA20 := make([]byte, len(m.PacketCommitmentSequences)*10) + var j19 int + for _, num := range m.PacketCommitmentSequences { + for num >= 1<<7 { + dAtA20[j19] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j19++ + } + dAtA20[j19] = uint8(num) + j19++ + } + i -= j19 + copy(dAtA[i:], dAtA20[:j19]) + i = encodeVarintQuery(dAtA, i, uint64(j19)) + i-- + dAtA[i] = 0x22 + } if m.Pagination != nil { { size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) @@ -3335,20 +3362,20 @@ func (m *QueryUnreceivedPacketsRequest) MarshalToSizedBuffer(dAtA []byte) (int, var l int _ = l if len(m.PacketCommitmentSequences) > 0 { - dAtA23 := make([]byte, len(m.PacketCommitmentSequences)*10) - var j22 int + dAtA25 := make([]byte, len(m.PacketCommitmentSequences)*10) + var j24 int for _, num := range m.PacketCommitmentSequences { for num >= 1<<7 { - dAtA23[j22] = uint8(uint64(num)&0x7f | 0x80) + dAtA25[j24] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j22++ + j24++ } - dAtA23[j22] = uint8(num) - j22++ + dAtA25[j24] = uint8(num) + j24++ } - i -= j22 - copy(dAtA[i:], dAtA23[:j22]) - i = encodeVarintQuery(dAtA, i, uint64(j22)) + i -= j24 + copy(dAtA[i:], dAtA25[:j24]) + i = encodeVarintQuery(dAtA, i, uint64(j24)) i-- dAtA[i] = 0x1a } @@ -3400,20 +3427,20 @@ func (m *QueryUnreceivedPacketsResponse) MarshalToSizedBuffer(dAtA []byte) (int, i-- dAtA[i] = 0x12 if len(m.Sequences) > 0 { - dAtA26 := make([]byte, len(m.Sequences)*10) - var j25 int + dAtA28 := make([]byte, len(m.Sequences)*10) + var j27 int for _, num := range m.Sequences { for num >= 1<<7 { - dAtA26[j25] = uint8(uint64(num)&0x7f | 0x80) + dAtA28[j27] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j25++ + j27++ } - dAtA26[j25] = uint8(num) - j25++ + dAtA28[j27] = uint8(num) + j27++ } - i -= j25 - copy(dAtA[i:], dAtA26[:j25]) - i = encodeVarintQuery(dAtA, i, uint64(j25)) + i -= j27 + copy(dAtA[i:], dAtA28[:j27]) + i = encodeVarintQuery(dAtA, i, uint64(j27)) i-- dAtA[i] = 0xa } @@ -3441,20 +3468,20 @@ func (m *QueryUnreceivedAcksRequest) MarshalToSizedBuffer(dAtA []byte) (int, err var l int _ = l if len(m.PacketAckSequences) > 0 { - dAtA28 := make([]byte, len(m.PacketAckSequences)*10) - var j27 int + dAtA30 := make([]byte, len(m.PacketAckSequences)*10) + var j29 int for _, num := range m.PacketAckSequences { for num >= 1<<7 { - dAtA28[j27] = uint8(uint64(num)&0x7f | 0x80) + dAtA30[j29] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j27++ + j29++ } - dAtA28[j27] = uint8(num) - j27++ + dAtA30[j29] = uint8(num) + j29++ } - i -= j27 - copy(dAtA[i:], dAtA28[:j27]) - i = encodeVarintQuery(dAtA, i, uint64(j27)) + i -= j29 + copy(dAtA[i:], dAtA30[:j29]) + i = encodeVarintQuery(dAtA, i, uint64(j29)) i-- dAtA[i] = 0x1a } @@ -3506,20 +3533,20 @@ func (m *QueryUnreceivedAcksResponse) MarshalToSizedBuffer(dAtA []byte) (int, er i-- dAtA[i] = 0x12 if len(m.Sequences) > 0 { - dAtA31 := make([]byte, len(m.Sequences)*10) - var j30 int + dAtA33 := make([]byte, len(m.Sequences)*10) + var j32 int for _, num := range m.Sequences { for num >= 1<<7 { - dAtA31[j30] = uint8(uint64(num)&0x7f | 0x80) + dAtA33[j32] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j30++ + j32++ } - dAtA31[j30] = uint8(num) - j30++ + dAtA33[j32] = uint8(num) + j32++ } - i -= j30 - copy(dAtA[i:], dAtA31[:j30]) - i = encodeVarintQuery(dAtA, i, uint64(j30)) + i -= j32 + copy(dAtA[i:], dAtA33[:j32]) + i = encodeVarintQuery(dAtA, i, uint64(j32)) i-- dAtA[i] = 0xa } @@ -3985,6 +4012,13 @@ func (m *QueryPacketAcknowledgementsRequest) Size() (n int) { l = m.Pagination.Size() n += 1 + l + sovQuery(uint64(l)) } + if len(m.PacketCommitmentSequences) > 0 { + l = 0 + for _, e := range m.PacketCommitmentSequences { + l += sovQuery(uint64(e)) + } + n += 1 + sovQuery(uint64(l)) + l + } return n } @@ -6785,6 +6819,82 @@ func (m *QueryPacketAcknowledgementsRequest) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 4: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.PacketCommitmentSequences = append(m.PacketCommitmentSequences, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.PacketCommitmentSequences) == 0 { + m.PacketCommitmentSequences = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.PacketCommitmentSequences = append(m.PacketCommitmentSequences, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field PacketCommitmentSequences", wireType) + } default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/modules/core/05-port/keeper/grpc_query.go b/modules/core/05-port/keeper/grpc_query.go new file mode 100644 index 00000000000..a665b0cee75 --- /dev/null +++ b/modules/core/05-port/keeper/grpc_query.go @@ -0,0 +1,52 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/cosmos/ibc-go/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/modules/core/24-host" +) + +var _ types.QueryServer = (*Keeper)(nil) + +// AppVersion implements the Query/AppVersion gRPC method +func (q Keeper) AppVersion(c context.Context, req *types.QueryAppVersionRequest) (*types.QueryAppVersionResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + if err := validategRPCRequest(req.PortId); err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(c) + module, _, err := q.LookupModuleByPort(ctx, req.PortId) + if err != nil { + return nil, status.Errorf(codes.NotFound, sdkerrors.Wrap(err, "could not retrieve module from port-id").Error()) + } + + ibcModule, found := q.Router.GetRoute(module) + if !found { + return nil, status.Errorf(codes.NotFound, sdkerrors.Wrapf(types.ErrInvalidRoute, "route not found to module: %s", module).Error()) + } + + version, err := ibcModule.NegotiateAppVersion(ctx, req.Ordering, req.ConnectionId, req.PortId, *req.Counterparty, req.ProposedVersion) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, sdkerrors.Wrap(err, "version negotation failed").Error()) + } + + return types.NewQueryAppVersionResponse(req.PortId, version), nil +} + +func validategRPCRequest(portID string) error { + if err := host.PortIdentifierValidator(portID); err != nil { + return status.Error(codes.InvalidArgument, err.Error()) + } + + return nil +} diff --git a/modules/core/05-port/keeper/grpc_query_test.go b/modules/core/05-port/keeper/grpc_query_test.go new file mode 100644 index 00000000000..716727ece68 --- /dev/null +++ b/modules/core/05-port/keeper/grpc_query_test.go @@ -0,0 +1,103 @@ +package keeper_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/modules/core/05-port/types" + "github.com/cosmos/ibc-go/testing/mock" +) + +func (suite *KeeperTestSuite) TestAppVersion() { + var ( + req *types.QueryAppVersionRequest + expVersion string + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = nil + }, + false, + }, + { + "invalid port ID", + func() { + req = &types.QueryAppVersionRequest{ + PortId: "", + } + }, + false, + }, + { + "module not found", + func() { + req = &types.QueryAppVersionRequest{ + PortId: "mock-port-id", + } + }, + false, + }, + { + "version negotiation failure", + func() { + + expVersion = mock.Version + + req = &types.QueryAppVersionRequest{ + PortId: "mock", // retrieves the mock testing module + Counterparty: &channeltypes.Counterparty{ + PortId: "mock-port-id", + ChannelId: "mock-channel-id", + }, + ProposedVersion: "invalid-proposed-version", + } + }, + false, + }, + { + "success", + func() { + + expVersion = mock.Version + + req = &types.QueryAppVersionRequest{ + PortId: "mock", // retrieves the mock testing module + Counterparty: &channeltypes.Counterparty{ + PortId: "mock-port-id", + ChannelId: "mock-channel-id", + }, + ProposedVersion: mock.Version, + } + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + + ctx := sdk.WrapSDKContext(suite.ctx) + res, err := suite.keeper.AppVersion(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(expVersion, res.Version) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/modules/core/05-port/keeper/keeper.go b/modules/core/05-port/keeper/keeper.go index 1bac7622b85..dd5f17a24fe 100644 --- a/modules/core/05-port/keeper/keeper.go +++ b/modules/core/05-port/keeper/keeper.go @@ -14,6 +14,8 @@ import ( // Keeper defines the IBC connection keeper type Keeper struct { + Router *types.Router + scopedKeeper capabilitykeeper.ScopedKeeper } diff --git a/modules/core/05-port/module.go b/modules/core/05-port/module.go new file mode 100644 index 00000000000..7dfefb140e2 --- /dev/null +++ b/modules/core/05-port/module.go @@ -0,0 +1,24 @@ +package port + +import ( + "github.com/gogo/protobuf/grpc" + "github.com/spf13/cobra" + + "github.com/cosmos/ibc-go/modules/core/05-port/types" + "github.com/cosmos/ibc-go/modules/core/client/cli" +) + +// Name returns the IBC port ICS name. +func Name() string { + return types.SubModuleName +} + +// GetQueryCmd returns the root query command for IBC ports. +func GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// RegisterQueryService registers the gRPC query service for IBC ports. +func RegisterQueryService(server grpc.Server, queryServer types.QueryServer) { + types.RegisterQueryServer(server, queryServer) +} diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 9c0885c0cf1..d80ad851071 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -82,4 +82,16 @@ type IBCModule interface { packet channeltypes.Packet, relayer sdk.AccAddress, ) error + + // NegotiateAppVersion performs application version negotiation given the provided channel ordering, connectionID, portID, counterparty and proposed version. + // An error is returned if version negotiation cannot be performed. For example, an application module implementing this interface + // may decide to return an error in the event of the proposed version being incompatible with it's own + NegotiateAppVersion( + ctx sdk.Context, + order channeltypes.Order, + connectionID string, + portID string, + counterparty channeltypes.Counterparty, + proposedVersion string, + ) (version string, err error) } diff --git a/modules/core/05-port/types/query.go b/modules/core/05-port/types/query.go new file mode 100644 index 00000000000..7da3fe678af --- /dev/null +++ b/modules/core/05-port/types/query.go @@ -0,0 +1,9 @@ +package types + +// NewQueryAppVersionResponse creates a new QueryAppVersionResponse instance +func NewQueryAppVersionResponse(portID, version string) *QueryAppVersionResponse { + return &QueryAppVersionResponse{ + PortId: portID, + Version: version, + } +} diff --git a/modules/core/05-port/types/query.pb.go b/modules/core/05-port/types/query.pb.go new file mode 100644 index 00000000000..5c80d520815 --- /dev/null +++ b/modules/core/05-port/types/query.pb.go @@ -0,0 +1,843 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/core/port/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + types "github.com/cosmos/ibc-go/modules/core/04-channel/types" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryAppVersionRequest is the request type for the Query/AppVersion RPC method +type QueryAppVersionRequest struct { + // port unique identifier + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + // connection unique identifier + ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` + // whether the channel is ordered or unordered + Ordering types.Order `protobuf:"varint,3,opt,name=ordering,proto3,enum=ibc.core.channel.v1.Order" json:"ordering,omitempty"` + // counterparty channel end + Counterparty *types.Counterparty `protobuf:"bytes,4,opt,name=counterparty,proto3" json:"counterparty,omitempty"` + // proposed version + ProposedVersion string `protobuf:"bytes,5,opt,name=proposed_version,json=proposedVersion,proto3" json:"proposed_version,omitempty"` +} + +func (m *QueryAppVersionRequest) Reset() { *m = QueryAppVersionRequest{} } +func (m *QueryAppVersionRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAppVersionRequest) ProtoMessage() {} +func (*QueryAppVersionRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9a256596009a8334, []int{0} +} +func (m *QueryAppVersionRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAppVersionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAppVersionRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAppVersionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAppVersionRequest.Merge(m, src) +} +func (m *QueryAppVersionRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAppVersionRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAppVersionRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAppVersionRequest proto.InternalMessageInfo + +func (m *QueryAppVersionRequest) GetPortId() string { + if m != nil { + return m.PortId + } + return "" +} + +func (m *QueryAppVersionRequest) GetConnectionId() string { + if m != nil { + return m.ConnectionId + } + return "" +} + +func (m *QueryAppVersionRequest) GetOrdering() types.Order { + if m != nil { + return m.Ordering + } + return types.NONE +} + +func (m *QueryAppVersionRequest) GetCounterparty() *types.Counterparty { + if m != nil { + return m.Counterparty + } + return nil +} + +func (m *QueryAppVersionRequest) GetProposedVersion() string { + if m != nil { + return m.ProposedVersion + } + return "" +} + +// QueryAppVersionResponse is the response type for the Query/AppVersion RPC method. +type QueryAppVersionResponse struct { + // port id associated with the request identifiers + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + // supported app version + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` +} + +func (m *QueryAppVersionResponse) Reset() { *m = QueryAppVersionResponse{} } +func (m *QueryAppVersionResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAppVersionResponse) ProtoMessage() {} +func (*QueryAppVersionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9a256596009a8334, []int{1} +} +func (m *QueryAppVersionResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAppVersionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAppVersionResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAppVersionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAppVersionResponse.Merge(m, src) +} +func (m *QueryAppVersionResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAppVersionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAppVersionResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAppVersionResponse proto.InternalMessageInfo + +func (m *QueryAppVersionResponse) GetPortId() string { + if m != nil { + return m.PortId + } + return "" +} + +func (m *QueryAppVersionResponse) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func init() { + proto.RegisterType((*QueryAppVersionRequest)(nil), "ibc.core.port.v1.QueryAppVersionRequest") + proto.RegisterType((*QueryAppVersionResponse)(nil), "ibc.core.port.v1.QueryAppVersionResponse") +} + +func init() { proto.RegisterFile("ibc/core/port/v1/query.proto", fileDescriptor_9a256596009a8334) } + +var fileDescriptor_9a256596009a8334 = []byte{ + // 371 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x3f, 0x8f, 0xda, 0x30, + 0x14, 0x4f, 0x68, 0x81, 0xd6, 0xa5, 0x2d, 0xf2, 0x50, 0x22, 0x54, 0x45, 0x40, 0x97, 0x30, 0xe0, + 0x14, 0x50, 0xbb, 0xb7, 0x55, 0x07, 0xa4, 0x56, 0x55, 0x33, 0x74, 0xe8, 0x82, 0x88, 0x63, 0x81, + 0x25, 0xf0, 0x33, 0xb6, 0x13, 0x89, 0xed, 0x3e, 0xc2, 0x7d, 0xac, 0x1b, 0x19, 0x6f, 0x3c, 0xc1, + 0x17, 0x39, 0x39, 0x21, 0x70, 0x7f, 0x38, 0xe9, 0x36, 0xbf, 0xf7, 0xfb, 0xa3, 0xdf, 0x7b, 0x7e, + 0xe8, 0x23, 0x8f, 0x69, 0x48, 0x41, 0xb1, 0x50, 0x82, 0x32, 0x61, 0x36, 0x0c, 0xd7, 0x29, 0x53, + 0x1b, 0x22, 0x15, 0x18, 0xc0, 0x4d, 0x1e, 0x53, 0x62, 0x51, 0x62, 0x51, 0x92, 0x0d, 0xdb, 0xdd, + 0x23, 0x9f, 0x2e, 0x66, 0x42, 0xb0, 0xa5, 0x95, 0x1c, 0x9e, 0x85, 0xa8, 0x77, 0x51, 0x41, 0x1f, + 0xfe, 0x5a, 0x93, 0x6f, 0x52, 0xfe, 0x63, 0x4a, 0x73, 0x10, 0x11, 0x5b, 0xa7, 0x4c, 0x1b, 0xdc, + 0x42, 0x75, 0x6b, 0x34, 0xe5, 0x89, 0xe7, 0x76, 0xdc, 0xe0, 0x75, 0x54, 0xb3, 0xe5, 0x24, 0xc1, + 0x9f, 0xd0, 0x5b, 0x0a, 0x42, 0x30, 0x6a, 0x38, 0x08, 0x0b, 0x57, 0x72, 0xb8, 0x71, 0x6a, 0x4e, + 0x12, 0xfc, 0x15, 0xbd, 0x02, 0x95, 0x30, 0xc5, 0xc5, 0xdc, 0x7b, 0xd1, 0x71, 0x83, 0x77, 0xa3, + 0x36, 0x39, 0x06, 0x2c, 0x33, 0x64, 0x43, 0xf2, 0xc7, 0x92, 0xa2, 0x23, 0x17, 0xff, 0x44, 0x0d, + 0x0a, 0xa9, 0x30, 0x4c, 0xc9, 0x99, 0x32, 0x1b, 0xef, 0x65, 0xc7, 0x0d, 0xde, 0x8c, 0xba, 0x67, + 0xb5, 0x3f, 0xee, 0x10, 0xa3, 0x7b, 0x32, 0xdc, 0x47, 0x4d, 0xa9, 0x40, 0x82, 0x66, 0xc9, 0x34, + 0x2b, 0xe6, 0xf2, 0xaa, 0x79, 0xcc, 0xf7, 0x65, 0xff, 0x30, 0x6e, 0xef, 0x17, 0x6a, 0x3d, 0xda, + 0x80, 0x96, 0x20, 0x34, 0x7b, 0x7a, 0x05, 0x1e, 0xaa, 0x97, 0xae, 0xc5, 0xf0, 0x65, 0x39, 0x5a, + 0xa2, 0x6a, 0xee, 0x86, 0x29, 0x42, 0x27, 0x47, 0x1c, 0x90, 0x87, 0xbf, 0x43, 0xce, 0xaf, 0xbd, + 0xdd, 0x7f, 0x06, 0xb3, 0x88, 0xd7, 0x73, 0xbe, 0xff, 0xbe, 0xda, 0xf9, 0xee, 0x76, 0xe7, 0xbb, + 0x37, 0x3b, 0xdf, 0xbd, 0xdc, 0xfb, 0xce, 0x76, 0xef, 0x3b, 0xd7, 0x7b, 0xdf, 0xf9, 0x3f, 0x9e, + 0x73, 0xb3, 0x48, 0x63, 0x42, 0x61, 0x15, 0x52, 0xd0, 0x2b, 0xd0, 0x21, 0x8f, 0xe9, 0x60, 0x0e, + 0xe1, 0x0a, 0x92, 0x74, 0xc9, 0x74, 0x71, 0x18, 0x9f, 0xbf, 0x0c, 0xf2, 0x5b, 0x32, 0x1b, 0xc9, + 0x74, 0x5c, 0xcb, 0x8f, 0x62, 0x7c, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x19, 0xf0, 0xfb, 0x67, 0x69, + 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // AppVersion queries an IBC Port and determines the appropriate application version to be used + AppVersion(ctx context.Context, in *QueryAppVersionRequest, opts ...grpc.CallOption) (*QueryAppVersionResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) AppVersion(ctx context.Context, in *QueryAppVersionRequest, opts ...grpc.CallOption) (*QueryAppVersionResponse, error) { + out := new(QueryAppVersionResponse) + err := c.cc.Invoke(ctx, "/ibc.core.port.v1.Query/AppVersion", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // AppVersion queries an IBC Port and determines the appropriate application version to be used + AppVersion(context.Context, *QueryAppVersionRequest) (*QueryAppVersionResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) AppVersion(ctx context.Context, req *QueryAppVersionRequest) (*QueryAppVersionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AppVersion not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_AppVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAppVersionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AppVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.port.v1.Query/AppVersion", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AppVersion(ctx, req.(*QueryAppVersionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ibc.core.port.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AppVersion", + Handler: _Query_AppVersion_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ibc/core/port/v1/query.proto", +} + +func (m *QueryAppVersionRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAppVersionRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAppVersionRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ProposedVersion) > 0 { + i -= len(m.ProposedVersion) + copy(dAtA[i:], m.ProposedVersion) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ProposedVersion))) + i-- + dAtA[i] = 0x2a + } + if m.Counterparty != nil { + { + size, err := m.Counterparty.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.Ordering != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Ordering)) + i-- + dAtA[i] = 0x18 + } + if len(m.ConnectionId) > 0 { + i -= len(m.ConnectionId) + copy(dAtA[i:], m.ConnectionId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ConnectionId))) + i-- + dAtA[i] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryAppVersionResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAppVersionResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAppVersionResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryAppVersionRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ConnectionId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Ordering != 0 { + n += 1 + sovQuery(uint64(m.Ordering)) + } + if m.Counterparty != nil { + l = m.Counterparty.Size() + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ProposedVersion) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAppVersionResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Version) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryAppVersionRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAppVersionRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAppVersionRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnectionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Ordering", wireType) + } + m.Ordering = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Ordering |= types.Order(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Counterparty", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Counterparty == nil { + m.Counterparty = &types.Counterparty{} + } + if err := m.Counterparty.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposedVersion", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProposedVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAppVersionResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAppVersionResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAppVersionResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/core/24-host/validate.go b/modules/core/24-host/validate.go index 10458e8d3a7..2bc7e18132c 100644 --- a/modules/core/24-host/validate.go +++ b/modules/core/24-host/validate.go @@ -16,6 +16,10 @@ import ( // adjusting this restriction. const DefaultMaxCharacterLength = 64 +// DefaultMaxPortCharacterLength defines the default maximum character length used +// in validation of port identifiers. +var DefaultMaxPortCharacterLength = 128 + // IsValidID defines regular expression to check if the string consist of // characters in one of the following categories only: // - Alphanumeric @@ -80,7 +84,7 @@ func ChannelIdentifierValidator(id string) error { // A valid Identifier must be between 2-64 characters and only contain alphanumeric and some allowed // special characters (see IsValidID). func PortIdentifierValidator(id string) error { - return defaultIdentifierValidator(id, 2, DefaultMaxCharacterLength) + return defaultIdentifierValidator(id, 2, DefaultMaxPortCharacterLength) } // NewPathValidator takes in a Identifier Validator function and returns diff --git a/modules/core/24-host/validate_test.go b/modules/core/24-host/validate_test.go index 40987bd1571..fe5c290ba40 100644 --- a/modules/core/24-host/validate_test.go +++ b/modules/core/24-host/validate_test.go @@ -8,6 +8,9 @@ import ( "github.com/stretchr/testify/require" ) +// 195 characters +var longId = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eros neque, ultricies vel ligula ac, convallis porttitor elit. Maecenas tincidunt turpis elit, vel faucibus nisl pellentesque sodales" + type testCase struct { msg string id string @@ -50,6 +53,33 @@ func TestDefaultIdentifierValidator(t *testing.T) { } } +func TestPortIdentifierValidator(t *testing.T) { + testCases := []testCase{ + {"valid lowercase", "transfer", true}, + {"valid id special chars", "._+-#[]<>._+-#[]<>", true}, + {"valid id lower and special chars", "lower._+-#[]<>", true}, + {"numeric id", "1234567890", true}, + {"uppercase id", "NOTLOWERCASE", true}, + {"numeric id", "1234567890", true}, + {"blank id", " ", false}, + {"id length out of range", "1", false}, + {"id is too long", longId, false}, + {"path-like id", "lower/case/id", false}, + {"invalid id", "(clientid)", false}, + {"empty string", "", false}, + } + + for _, tc := range testCases { + + err := PortIdentifierValidator(tc.id) + if tc.expPass { + require.NoError(t, err, tc.msg) + } else { + require.Error(t, err, tc.msg) + } + } +} + func TestPathValidator(t *testing.T) { testCases := []testCase{ {"valid lowercase", "p/lowercaseid", true}, diff --git a/modules/core/ante/ante.go b/modules/core/ante/ante.go new file mode 100644 index 00000000000..aa579027d7f --- /dev/null +++ b/modules/core/ante/ante.go @@ -0,0 +1,72 @@ +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" + channelkeeper "github.com/cosmos/ibc-go/modules/core/04-channel/keeper" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" +) + +type AnteDecorator struct { + k channelkeeper.Keeper +} + +func NewAnteDecorator(k channelkeeper.Keeper) AnteDecorator { + return AnteDecorator{k: k} +} + +// AnteDecorator returns an error if a multiMsg tx only contains packet messages (Recv, Ack, Timeout) and additional update messages and all packet messages +// are redundant. If the transaction is just a single UpdateClient message, or the multimsg transaction contains some other message type, then the antedecorator returns no error +// and continues processing to ensure these transactions are included. +// This will ensure that relayers do not waste fees on multiMsg transactions when another relayer has already submitted all packets, by rejecting the tx at the mempool layer. +func (ad AnteDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + // do not run redundancy check on DeliverTx or simulate + if (ctx.IsCheckTx() || ctx.IsReCheckTx()) && !simulate { + // keep track of total packet messages and number of redundancies across `RecvPacket`, `AcknowledgePacket`, and `TimeoutPacket/OnClose` + redundancies := 0 + packetMsgs := 0 + for _, m := range tx.GetMsgs() { + switch msg := m.(type) { + case *channeltypes.MsgRecvPacket: + if _, found := ad.k.GetPacketReceipt(ctx, msg.Packet.GetDestPort(), msg.Packet.GetDestChannel(), msg.Packet.GetSequence()); found { + redundancies += 1 + } + packetMsgs += 1 + + case *channeltypes.MsgAcknowledgement: + if commitment := ad.k.GetPacketCommitment(ctx, msg.Packet.GetSourcePort(), msg.Packet.GetSourceChannel(), msg.Packet.GetSequence()); len(commitment) == 0 { + redundancies += 1 + } + packetMsgs += 1 + + case *channeltypes.MsgTimeout: + if commitment := ad.k.GetPacketCommitment(ctx, msg.Packet.GetSourcePort(), msg.Packet.GetSourceChannel(), msg.Packet.GetSequence()); len(commitment) == 0 { + redundancies += 1 + } + packetMsgs += 1 + + case *channeltypes.MsgTimeoutOnClose: + if commitment := ad.k.GetPacketCommitment(ctx, msg.Packet.GetSourcePort(), msg.Packet.GetSourceChannel(), msg.Packet.GetSequence()); len(commitment) == 0 { + redundancies += 1 + } + packetMsgs += 1 + + case *clienttypes.MsgUpdateClient: + // do nothing here, as we want to avoid updating clients if it is batched with only redundant messages + + default: + // if the multiMsg tx has a msg that is not a packet msg or update msg, then we will not return error + // regardless of if all packet messages are redundant. This ensures that non-packet messages get processed + // even if they get batched with redundant packet messages. + return next(ctx, tx, simulate) + } + + } + + // only return error if all packet messages are redundant + if redundancies == packetMsgs && packetMsgs > 0 { + return ctx, channeltypes.ErrRedundantTx + } + } + return next(ctx, tx, simulate) +} diff --git a/modules/core/ante/ante_test.go b/modules/core/ante/ante_test.go new file mode 100644 index 00000000000..0b997685285 --- /dev/null +++ b/modules/core/ante/ante_test.go @@ -0,0 +1,485 @@ +package ante_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/modules/core/ante" + ibctesting "github.com/cosmos/ibc-go/testing" + "github.com/cosmos/ibc-go/testing/mock" + "github.com/stretchr/testify/suite" +) + +type AnteTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + // testing chains used for convenience and readability + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain + + path *ibctesting.Path +} + +// SetupTest creates a coordinator with 2 test chains. +func (suite *AnteTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + // commit some blocks so that QueryProof returns valid proof (cannot return valid query if height <= 1) + suite.coordinator.CommitNBlocks(suite.chainA, 2) + suite.coordinator.CommitNBlocks(suite.chainB, 2) + suite.path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(suite.path) +} + +// TestAnteTestSuite runs all the tests within this package. +func TestAnteTestSuite(t *testing.T) { + suite.Run(t, new(AnteTestSuite)) +} + +func (suite *AnteTestSuite) TestAnteDecorator() { + testCases := []struct { + name string + malleate func(suite *AnteTestSuite) []sdk.Msg + expPass bool + }{ + { + "success on single msg", + func(suite *AnteTestSuite) []sdk.Msg { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), 1, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + return []sdk.Msg{channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")} + }, + true, + }, + { + "success on multiple msgs", + func(suite *AnteTestSuite) []sdk.Msg { + var msgs []sdk.Msg + + for i := 1; i <= 5; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + return msgs + }, + true, + }, + { + "success on multiple msgs: 1 fresh recv packet", + func(suite *AnteTestSuite) []sdk.Msg { + var msgs []sdk.Msg + + for i := 1; i <= 5; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + err := suite.path.EndpointA.SendPacket(packet) + suite.Require().NoError(err) + + // receive all sequences except packet 3 + if i != 3 { + err = suite.path.EndpointB.RecvPacket(packet) + suite.Require().NoError(err) + } + + msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + + return msgs + }, + true, + }, + { + "success on multiple mixed msgs", + func(suite *AnteTestSuite) []sdk.Msg { + var msgs []sdk.Msg + + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + err := suite.path.EndpointA.SendPacket(packet) + suite.Require().NoError(err) + + msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + clienttypes.NewHeight(1, 0), 0) + err := suite.path.EndpointB.SendPacket(packet) + suite.Require().NoError(err) + + msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 4; i <= 6; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + clienttypes.NewHeight(1, 0), 0) + err := suite.path.EndpointB.SendPacket(packet) + suite.Require().NoError(err) + + msgs = append(msgs, channeltypes.NewMsgTimeout(packet, uint64(i), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + return msgs + }, + true, + }, + { + "success on multiple mixed msgs: 1 fresh packet of each type", + func(suite *AnteTestSuite) []sdk.Msg { + var msgs []sdk.Msg + + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + err := suite.path.EndpointA.SendPacket(packet) + suite.Require().NoError(err) + + // receive all sequences except packet 3 + if i != 3 { + + err := suite.path.EndpointB.RecvPacket(packet) + suite.Require().NoError(err) + } + + msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + clienttypes.NewHeight(1, 0), 0) + err := suite.path.EndpointB.SendPacket(packet) + suite.Require().NoError(err) + + // receive all acks except ack 2 + if i != 2 { + err = suite.path.EndpointA.RecvPacket(packet) + suite.Require().NoError(err) + err = suite.path.EndpointB.AcknowledgePacket(packet, mock.MockAcknowledgement.Acknowledgement()) + suite.Require().NoError(err) + } + + msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 4; i <= 6; i++ { + height := suite.chainA.LastHeader.GetHeight() + timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + timeoutHeight, 0) + err := suite.path.EndpointB.SendPacket(packet) + suite.Require().NoError(err) + + // timeout packet + suite.coordinator.CommitNBlocks(suite.chainA, 3) + + // timeout packets except sequence 5 + if i != 5 { + suite.path.EndpointB.UpdateClient() + err = suite.path.EndpointB.TimeoutPacket(packet) + suite.Require().NoError(err) + } + + msgs = append(msgs, channeltypes.NewMsgTimeout(packet, uint64(i), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + return msgs + }, + true, + }, + { + "success on multiple mixed msgs: only 1 fresh msg in total", + func(suite *AnteTestSuite) []sdk.Msg { + var msgs []sdk.Msg + + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + // receive all packets + suite.path.EndpointA.SendPacket(packet) + suite.path.EndpointB.RecvPacket(packet) + + msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + // receive all acks + suite.path.EndpointB.SendPacket(packet) + suite.path.EndpointA.RecvPacket(packet) + suite.path.EndpointB.AcknowledgePacket(packet, mock.MockAcknowledgement.Acknowledgement()) + + msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 4; i < 5; i++ { + height := suite.chainA.LastHeader.GetHeight() + timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + timeoutHeight, 0) + + // do not timeout packet, timeout msg is fresh + suite.path.EndpointB.SendPacket(packet) + + msgs = append(msgs, channeltypes.NewMsgTimeout(packet, uint64(i), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + return msgs + }, + true, + }, + { + "success on single update client msg", + func(suite *AnteTestSuite) []sdk.Msg { + return []sdk.Msg{&clienttypes.MsgUpdateClient{}} + }, + true, + }, + { + "success on multiple update clients", + func(suite *AnteTestSuite) []sdk.Msg { + return []sdk.Msg{&clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}} + }, + true, + }, + { + "success on multiple update clients and fresh packet message", + func(suite *AnteTestSuite) []sdk.Msg { + msgs := []sdk.Msg{&clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}} + + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), 1, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + return append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + }, + true, + }, + { + "success of tx with different msg type even if all packet messages are redundant", + func(suite *AnteTestSuite) []sdk.Msg { + msgs := []sdk.Msg{&clienttypes.MsgUpdateClient{}} + + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + // receive all packets + suite.path.EndpointA.SendPacket(packet) + suite.path.EndpointB.RecvPacket(packet) + + msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + // receive all acks + suite.path.EndpointB.SendPacket(packet) + suite.path.EndpointA.RecvPacket(packet) + suite.path.EndpointB.AcknowledgePacket(packet, mock.MockAcknowledgement.Acknowledgement()) + + msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 4; i < 6; i++ { + height := suite.chainA.LastHeader.GetHeight() + timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + timeoutHeight, 0) + + err := suite.path.EndpointB.SendPacket(packet) + suite.Require().NoError(err) + + // timeout packet + suite.coordinator.CommitNBlocks(suite.chainA, 3) + + suite.path.EndpointB.UpdateClient() + suite.path.EndpointB.TimeoutPacket(packet) + + msgs = append(msgs, channeltypes.NewMsgTimeoutOnClose(packet, uint64(i), []byte("proof"), []byte("channelProof"), clienttypes.NewHeight(0, 1), "signer")) + } + + // append non packet and update message to msgs to ensure multimsg tx should pass + msgs = append(msgs, &clienttypes.MsgSubmitMisbehaviour{}) + + return msgs + }, + true, + }, + { + "no success on multiple mixed message: all are redundant", + func(suite *AnteTestSuite) []sdk.Msg { + var msgs []sdk.Msg + + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + // receive all packets + suite.path.EndpointA.SendPacket(packet) + suite.path.EndpointB.RecvPacket(packet) + + msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + // receive all acks + suite.path.EndpointB.SendPacket(packet) + suite.path.EndpointA.RecvPacket(packet) + suite.path.EndpointB.AcknowledgePacket(packet, mock.MockAcknowledgement.Acknowledgement()) + + msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 4; i < 6; i++ { + height := suite.chainA.LastHeader.GetHeight() + timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + timeoutHeight, 0) + + err := suite.path.EndpointB.SendPacket(packet) + suite.Require().NoError(err) + + // timeout packet + suite.coordinator.CommitNBlocks(suite.chainA, 3) + + suite.path.EndpointB.UpdateClient() + suite.path.EndpointB.TimeoutPacket(packet) + + msgs = append(msgs, channeltypes.NewMsgTimeoutOnClose(packet, uint64(i), []byte("proof"), []byte("channelProof"), clienttypes.NewHeight(0, 1), "signer")) + } + return msgs + }, + false, + }, + { + "no success if msgs contain update clients and redundant packet messages", + func(suite *AnteTestSuite) []sdk.Msg { + msgs := []sdk.Msg{&clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}} + + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + // receive all packets + suite.path.EndpointA.SendPacket(packet) + suite.path.EndpointB.RecvPacket(packet) + + msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 1; i <= 3; i++ { + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + // receive all acks + suite.path.EndpointB.SendPacket(packet) + suite.path.EndpointA.RecvPacket(packet) + suite.path.EndpointB.AcknowledgePacket(packet, mock.MockAcknowledgement.Acknowledgement()) + + msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + } + for i := 4; i < 6; i++ { + height := suite.chainA.LastHeader.GetHeight() + timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) + packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + timeoutHeight, 0) + + err := suite.path.EndpointB.SendPacket(packet) + suite.Require().NoError(err) + + // timeout packet + suite.coordinator.CommitNBlocks(suite.chainA, 3) + + suite.path.EndpointB.UpdateClient() + suite.path.EndpointB.TimeoutPacket(packet) + + msgs = append(msgs, channeltypes.NewMsgTimeoutOnClose(packet, uint64(i), []byte("proof"), []byte("channelProof"), clienttypes.NewHeight(0, 1), "signer")) + } + return msgs + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + // reset suite + suite.SetupTest() + + k := suite.chainB.App.GetIBCKeeper().ChannelKeeper + decorator := ante.NewAnteDecorator(k) + + msgs := tc.malleate(suite) + + deliverCtx := suite.chainB.GetContext().WithIsCheckTx(false) + checkCtx := suite.chainB.GetContext().WithIsCheckTx(true) + + // create multimsg tx + txBuilder := suite.chainB.TxConfig.NewTxBuilder() + err := txBuilder.SetMsgs(msgs...) + suite.Require().NoError(err) + tx := txBuilder.GetTx() + + next := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { return ctx, nil } + + _, err = decorator.AnteHandle(deliverCtx, tx, false, next) + suite.Require().NoError(err, "antedecorator should not error on DeliverTx") + + _, err = decorator.AnteHandle(checkCtx, tx, false, next) + if tc.expPass { + suite.Require().NoError(err, "non-strict decorator did not pass as expected") + } else { + suite.Require().Error(err, "non-strict antehandler did not return error as expected") + } + }) + } +} diff --git a/modules/core/keeper/grpc_query.go b/modules/core/keeper/grpc_query.go index f647ab5aceb..7d5e1336054 100644 --- a/modules/core/keeper/grpc_query.go +++ b/modules/core/keeper/grpc_query.go @@ -6,6 +6,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types" ) // ClientState implements the IBC QueryServer interface @@ -132,3 +133,8 @@ func (q Keeper) UnreceivedAcks(c context.Context, req *channeltypes.QueryUnrecei func (q Keeper) NextSequenceReceive(c context.Context, req *channeltypes.QueryNextSequenceReceiveRequest) (*channeltypes.QueryNextSequenceReceiveResponse, error) { return q.ChannelKeeper.NextSequenceReceive(c, req) } + +// AppVersion implements the IBC QueryServer interface +func (q Keeper) AppVersion(c context.Context, req *porttypes.QueryAppVersionRequest) (*porttypes.QueryAppVersionResponse, error) { + return q.PortKeeper.AppVersion(c, req) +} diff --git a/modules/core/keeper/keeper.go b/modules/core/keeper/keeper.go index 164fecfcd23..b04e6ffe732 100644 --- a/modules/core/keeper/keeper.go +++ b/modules/core/keeper/keeper.go @@ -70,6 +70,8 @@ func (k *Keeper) SetRouter(rtr *porttypes.Router) { if k.Router != nil && k.Router.Sealed() { panic("cannot reset a sealed router") } + + k.PortKeeper.Router = rtr k.Router = rtr k.Router.Seal() } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index ab9e583385c..69bde98b687 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -492,15 +492,29 @@ func (k Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPacke } // Perform TAO verification - if err := k.ChannelKeeper.RecvPacket(ctx, cap, msg.Packet, msg.ProofCommitment, msg.ProofHeight); err != nil { + // + // If the packet was already received, perform a no-op + // Use a cached context to prevent accidental state changes + cacheCtx, writeFn := ctx.CacheContext() + err = k.ChannelKeeper.RecvPacket(cacheCtx, cap, msg.Packet, msg.ProofCommitment, msg.ProofHeight) + + // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + + switch err { + case nil: + writeFn() + case channeltypes.ErrNoOpMsg: + return &channeltypes.MsgRecvPacketResponse{}, nil // no-op + default: return nil, sdkerrors.Wrap(err, "receive packet verification failed") } // Perform application logic callback + // // Cache context so that we may discard state changes from callback if the acknowledgement is unsuccessful. - cacheCtx, writeFn := ctx.CacheContext() + cacheCtx, writeFn = ctx.CacheContext() ack := cbs.OnRecvPacket(cacheCtx, msg.Packet, relayer) - // This doesn't cause duplicate events to be emitted. // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. // Events from callback are emitted regardless of acknowledgement success ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) @@ -556,7 +570,21 @@ func (k Keeper) Timeout(goCtx context.Context, msg *channeltypes.MsgTimeout) (*c } // Perform TAO verification - if err := k.ChannelKeeper.TimeoutPacket(ctx, msg.Packet, msg.ProofUnreceived, msg.ProofHeight, msg.NextSequenceRecv); err != nil { + // + // If the timeout was already received, perform a no-op + // Use a cached context to prevent accidental state changes + cacheCtx, writeFn := ctx.CacheContext() + err = k.ChannelKeeper.TimeoutPacket(cacheCtx, msg.Packet, msg.ProofUnreceived, msg.ProofHeight, msg.NextSequenceRecv) + + // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + + switch err { + case nil: + writeFn() + case channeltypes.ErrNoOpMsg: + return &channeltypes.MsgTimeoutResponse{}, nil // no-op + default: return nil, sdkerrors.Wrap(err, "timeout packet verification failed") } @@ -610,11 +638,26 @@ func (k Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTimeo } // Perform TAO verification - if err := k.ChannelKeeper.TimeoutOnClose(ctx, cap, msg.Packet, msg.ProofUnreceived, msg.ProofClose, msg.ProofHeight, msg.NextSequenceRecv); err != nil { + // + // If the timeout was already received, perform a no-op + // Use a cached context to prevent accidental state changes + cacheCtx, writeFn := ctx.CacheContext() + err = k.ChannelKeeper.TimeoutOnClose(cacheCtx, cap, msg.Packet, msg.ProofUnreceived, msg.ProofClose, msg.ProofHeight, msg.NextSequenceRecv) + + // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + + switch err { + case nil: + writeFn() + case channeltypes.ErrNoOpMsg: + return &channeltypes.MsgTimeoutOnCloseResponse{}, nil // no-op + default: return nil, sdkerrors.Wrap(err, "timeout on close packet verification failed") } // Perform application logic callback + // // NOTE: MsgTimeout and MsgTimeoutOnClose use the same "OnTimeoutPacket" // application logic callback. err = cbs.OnTimeoutPacket(ctx, msg.Packet, relayer) @@ -666,7 +709,21 @@ func (k Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAckn } // Perform TAO verification - if err := k.ChannelKeeper.AcknowledgePacket(ctx, cap, msg.Packet, msg.Acknowledgement, msg.ProofAcked, msg.ProofHeight); err != nil { + // + // If the acknowledgement was already received, perform a no-op + // Use a cached context to prevent accidental state changes + cacheCtx, writeFn := ctx.CacheContext() + err = k.ChannelKeeper.AcknowledgePacket(cacheCtx, cap, msg.Packet, msg.Acknowledgement, msg.ProofAcked, msg.ProofHeight) + + // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + + switch err { + case nil: + writeFn() + case channeltypes.ErrNoOpMsg: + return &channeltypes.MsgAcknowledgementResponse{}, nil // no-op + default: return nil, sdkerrors.Wrap(err, "acknowledge packet verification failed") } diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index a337c1fb323..b28dc263689 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -141,7 +141,8 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { suite.coordinator.Setup(path) packet = channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) }, false, false}, - {"ORDERED: packet already received (replay)", func() { + {"successful no-op: ORDERED - packet already received (replay)", func() { + // mock will panic if application callback is called twice on the same packet path.SetChannelOrdered() suite.coordinator.Setup(path) packet = channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) @@ -151,8 +152,9 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - }, false, false}, - {"UNORDERED: packet already received (replay)", func() { + }, true, false}, + {"successful no-op: UNORDERED - packet already received (replay)", func() { + // mock will panic if application callback is called twice on the same packet suite.coordinator.Setup(path) packet = channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) @@ -161,7 +163,7 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - }, false, false}, + }, true, false}, } for _, tc := range testCases { @@ -174,9 +176,16 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { tc.malleate() + var ( + proof []byte + proofHeight clienttypes.Height + ) + // get proof of packet commitment from chainA packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - proof, proofHeight := suite.chainA.QueryProof(packetKey) + if path.EndpointA.ChannelID != "" { + proof, proofHeight = path.EndpointA.QueryProof(packetKey) + } msg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, suite.chainB.SenderAccount.GetAddress().String()) @@ -185,12 +194,12 @@ func (suite *KeeperTestSuite) TestHandleRecvPacket() { if tc.expPass { suite.Require().NoError(err) - // replay should fail since state changes occur + // replay should not fail since it will be treated as a no-op _, err := keeper.Keeper.RecvPacket(*suite.chainB.App.GetIBCKeeper(), sdk.WrapSDKContext(suite.chainB.GetContext()), msg) - suite.Require().Error(err) + suite.Require().NoError(err) // check that callback state was handled correctly - _, exists := suite.chainB.GetSimApp().ScopedIBCMockKeeper.GetCapability(suite.chainB.GetContext(), ibctesting.MockCanaryCapabilityName) + _, exists := suite.chainB.GetSimApp().ScopedIBCMockKeeper.GetCapability(suite.chainB.GetContext(), ibctesting.GetMockRecvCanaryCapabilityName(packet)) if tc.expRevert { suite.Require().False(exists, "capability exists in store even after callback reverted") } else { @@ -293,7 +302,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { err := path.EndpointA.SendPacket(packet) suite.Require().NoError(err) }, false}, - {"ORDERED: packet already acknowledged (replay)", func() { + {"successful no-op: ORDERED - packet already acknowledged (replay)", func() { suite.coordinator.Setup(path) packet = channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) @@ -305,8 +314,8 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { err = path.EndpointA.AcknowledgePacket(packet, ibctesting.MockAcknowledgement) suite.Require().NoError(err) - }, false}, - {"UNORDERED: packet already acknowledged (replay)", func() { + }, true}, + {"successful no-op: UNORDERED - packet already acknowledged (replay)", func() { suite.coordinator.Setup(path) packet = channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) @@ -319,7 +328,7 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { err = path.EndpointA.AcknowledgePacket(packet, ibctesting.MockAcknowledgement) suite.Require().NoError(err) - }, false}, + }, true}, } for _, tc := range testCases { @@ -331,8 +340,14 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { tc.malleate() + var ( + proof []byte + proofHeight clienttypes.Height + ) packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - proof, proofHeight := suite.chainB.QueryProof(packetKey) + if path.EndpointB.ChannelID != "" { + proof, proofHeight = path.EndpointB.QueryProof(packetKey) + } msg := channeltypes.NewMsgAcknowledgement(packet, ibcmock.MockAcknowledgement.Acknowledgement(), proof, proofHeight, suite.chainA.SenderAccount.GetAddress().String()) @@ -341,14 +356,13 @@ func (suite *KeeperTestSuite) TestHandleAcknowledgePacket() { if tc.expPass { suite.Require().NoError(err) - // replay should an error - _, err := keeper.Keeper.Acknowledgement(*suite.chainA.App.GetIBCKeeper(), sdk.WrapSDKContext(suite.chainA.GetContext()), msg) - suite.Require().Error(err) - // verify packet commitment was deleted on source chain has := suite.chainA.App.GetIBCKeeper().ChannelKeeper.HasPacketCommitment(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) suite.Require().False(has) + // replay should not error as it is treated as a no-op + _, err := keeper.Keeper.Acknowledgement(*suite.chainA.App.GetIBCKeeper(), sdk.WrapSDKContext(suite.chainA.GetContext()), msg) + suite.Require().NoError(err) } else { suite.Require().Error(err) } @@ -441,11 +455,11 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) }, false}, - {"UNORDERED: packet not sent", func() { + {"successful no-op: UNORDERED - packet not sent", func() { suite.coordinator.Setup(path) - packet = channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) + packet = channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 1), 0) packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - }, false}, + }, true}, } for _, tc := range testCases { @@ -457,7 +471,13 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { tc.malleate() - proof, proofHeight := suite.chainB.QueryProof(packetKey) + var ( + proof []byte + proofHeight clienttypes.Height + ) + if path.EndpointB.ChannelID != "" { + proof, proofHeight = path.EndpointB.QueryProof(packetKey) + } msg := channeltypes.NewMsgTimeout(packet, 1, proof, proofHeight, suite.chainA.SenderAccount.GetAddress().String()) @@ -466,9 +486,9 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { if tc.expPass { suite.Require().NoError(err) - // replay should return an error + // replay should not return an error as it is treated as a no-op _, err := keeper.Keeper.Timeout(*suite.chainA.App.GetIBCKeeper(), sdk.WrapSDKContext(suite.chainA.GetContext()), msg) - suite.Require().Error(err) + suite.Require().NoError(err) // verify packet commitment was deleted on source chain has := suite.chainA.App.GetIBCKeeper().ChannelKeeper.HasPacketCommitment(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) @@ -577,14 +597,14 @@ func (suite *KeeperTestSuite) TestHandleTimeoutOnClosePacket() { packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) }, false}, - {"UNORDERED: packet not sent", func() { + {"successful no-op: UNORDERED - packet not sent", func() { suite.coordinator.Setup(path) - packet = channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) + packet = channeltypes.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 1), 0) packetKey = host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) // close counterparty channel path.EndpointB.SetChannelClosed() - }, false}, + }, true}, {"ORDERED: channel not closed", func() { path.SetChannelOrdered() suite.coordinator.Setup(path) @@ -622,9 +642,9 @@ func (suite *KeeperTestSuite) TestHandleTimeoutOnClosePacket() { if tc.expPass { suite.Require().NoError(err) - // replay should return an error + // replay should not return an error as it will be treated as a no-op _, err := keeper.Keeper.TimeoutOnClose(*suite.chainA.App.GetIBCKeeper(), sdk.WrapSDKContext(suite.chainA.GetContext()), msg) - suite.Require().Error(err) + suite.Require().NoError(err) // verify packet commitment was deleted on source chain has := suite.chainA.App.GetIBCKeeper().ChannelKeeper.HasPacketCommitment(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) diff --git a/modules/core/types/query.go b/modules/core/types/query.go index a4a4bd5448c..f7559c8bf56 100644 --- a/modules/core/types/query.go +++ b/modules/core/types/query.go @@ -9,6 +9,8 @@ import ( connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types" channel "github.com/cosmos/ibc-go/modules/core/04-channel" channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + port "github.com/cosmos/ibc-go/modules/core/05-port" + porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types" ) // QueryServer defines the IBC interfaces that the gRPC query server must implement @@ -16,6 +18,7 @@ type QueryServer interface { clienttypes.QueryServer connectiontypes.QueryServer channeltypes.QueryServer + porttypes.QueryServer } // RegisterQueryService registers each individual IBC submodule query service @@ -23,4 +26,5 @@ func RegisterQueryService(server grpc.Server, queryService QueryServer) { client.RegisterQueryService(server, queryService) connection.RegisterQueryService(server, queryService) channel.RegisterQueryService(server, queryService) + port.RegisterQueryService(server, queryService) } diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index b1c41f6a511..69c0486c088 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -6,19 +6,6 @@ option go_package = "github.com/cosmos/ibc-go/modules/apps/transfer/types"; import "gogoproto/gogo.proto"; -// FungibleTokenPacketData defines a struct for the packet payload -// See FungibleTokenPacketData spec: -// https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#data-structures -message FungibleTokenPacketData { - // the token denomination to be transferred - string denom = 1; - // the token amount to be transferred - uint64 amount = 2; - // the sender address - string sender = 3; - // the recipient address on the destination chain - string receiver = 4; -} // DenomTrace contains the base denomination for ICS20 fungible tokens and the // source tracing information path. diff --git a/proto/ibc/applications/transfer/v2/packet.proto b/proto/ibc/applications/transfer/v2/packet.proto new file mode 100644 index 00000000000..d7caa354106 --- /dev/null +++ b/proto/ibc/applications/transfer/v2/packet.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package ibc.applications.transfer.v2; + +option go_package = "github.com/cosmos/ibc-go/modules/apps/transfer/types"; + +// FungibleTokenPacketData defines a struct for the packet payload +// See FungibleTokenPacketData spec: +// https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#data-structures +message FungibleTokenPacketData { + // the token denomination to be transferred + string denom = 1; + // the token amount to be transferred + string amount = 2; + // the sender address + string sender = 3; + // the recipient address on the destination chain + string receiver = 4; +} + diff --git a/proto/ibc/core/channel/v1/query.proto b/proto/ibc/core/channel/v1/query.proto index 194fe86777f..9690e24edfc 100644 --- a/proto/ibc/core/channel/v1/query.proto +++ b/proto/ibc/core/channel/v1/query.proto @@ -301,6 +301,8 @@ message QueryPacketAcknowledgementsRequest { string channel_id = 2; // pagination request cosmos.base.query.v1beta1.PageRequest pagination = 3; + // list of packet sequences + repeated uint64 packet_commitment_sequences = 4; } // QueryPacketAcknowledgemetsResponse is the request type for the diff --git a/proto/ibc/core/port/v1/query.proto b/proto/ibc/core/port/v1/query.proto new file mode 100644 index 00000000000..ed61b14e3af --- /dev/null +++ b/proto/ibc/core/port/v1/query.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; + +package ibc.core.port.v1; + +option go_package = "github.com/cosmos/ibc-go/modules/core/05-port/types"; + +import "ibc/core/channel/v1/channel.proto"; + +// Query defines the gRPC querier service +service Query { + // AppVersion queries an IBC Port and determines the appropriate application version to be used + rpc AppVersion(QueryAppVersionRequest) returns (QueryAppVersionResponse) {} +} + +// QueryAppVersionRequest is the request type for the Query/AppVersion RPC method +message QueryAppVersionRequest { + // port unique identifier + string port_id = 1; + // connection unique identifier + string connection_id = 2; + // whether the channel is ordered or unordered + ibc.core.channel.v1.Order ordering = 3; + // counterparty channel end + ibc.core.channel.v1.Counterparty counterparty = 4; + // proposed version + string proposed_version = 5; +} + +// QueryAppVersionResponse is the response type for the Query/AppVersion RPC method. +message QueryAppVersionResponse { + // port id associated with the request identifiers + string port_id = 1; + // supported app version + string version = 2; +} diff --git a/scripts/protoc-swagger-gen.sh b/scripts/protoc-swagger-gen.sh index 30cf44bcc08..aab3e65f6f4 100755 --- a/scripts/protoc-swagger-gen.sh +++ b/scripts/protoc-swagger-gen.sh @@ -21,7 +21,7 @@ done # combine swagger files # uses nodejs package `swagger-combine`. # all the individual swagger files need to be configured in `config.json` for merging -# swagger-combine ./client/docs/config.json -o ./client/docs/swagger-ui/swagger.yaml -f yaml --continueOnConflictingPaths true --includeDefinitions true +swagger-combine ./docs/client/config.json -o ./docs/client/swagger-ui/swagger.yaml -f yaml --continueOnConflictingPaths true --includeDefinitions true # clean swagger files rm -rf ./tmp-swagger-gen diff --git a/testing/chain.go b/testing/chain.go index c012f383767..e9b2a38241a 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -82,9 +82,12 @@ func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain { // generate genesis account senderPrivKey := secp256k1.GenPrivKey() acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) + amount, ok := sdk.NewIntFromString("10000000000000000000") + require.True(t, ok) + balance := banktypes.Balance{ Address: acc.GetAddress().String(), - Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))), + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)), } app := SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, balance) diff --git a/testing/mock/mock.go b/testing/mock/mock.go index 9edf5d3536a..75de08c3d4b 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -3,6 +3,8 @@ package mock import ( "bytes" "encoding/json" + "errors" + "strconv" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" @@ -24,15 +26,19 @@ import ( const ( ModuleName = "mock" + + Version = "mock-version" ) var ( - MockAcknowledgement = channeltypes.NewResultAcknowledgement([]byte("mock acknowledgement")) - MockFailAcknowledgement = channeltypes.NewErrorAcknowledgement("mock failed acknowledgement") - MockPacketData = []byte("mock packet data") - MockFailPacketData = []byte("mock failed packet data") - MockAsyncPacketData = []byte("mock async packet data") - MockCanaryCapabilityName = "mock canary capability name" + MockAcknowledgement = channeltypes.NewResultAcknowledgement([]byte("mock acknowledgement")) + MockFailAcknowledgement = channeltypes.NewErrorAcknowledgement("mock failed acknowledgement") + MockPacketData = []byte("mock packet data") + MockFailPacketData = []byte("mock failed packet data") + MockAsyncPacketData = []byte("mock async packet data") + MockRecvCanaryCapabilityName = "mock receive canary capability name" + MockAckCanaryCapabilityName = "mock acknowledgement canary capability name" + MockTimeoutCanaryCapabilityName = "mock timeout canary capability name" ) var _ porttypes.IBCModule = AppModule{} @@ -194,7 +200,12 @@ func (am AppModule) OnChanCloseConfirm(sdk.Context, string, string) error { // OnRecvPacket implements the IBCModule interface. func (am AppModule) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) exported.Acknowledgement { // set state by claiming capability to check if revert happens return - am.scopedKeeper.NewCapability(ctx, MockCanaryCapabilityName) + _, err := am.scopedKeeper.NewCapability(ctx, MockRecvCanaryCapabilityName+strconv.Itoa(int(packet.GetSequence()))) + if err != nil { + // application callback called twice on same packet sequence + // must never occur + panic(err) + } if bytes.Equal(MockPacketData, packet.GetData()) { return MockAcknowledgement } else if bytes.Equal(MockAsyncPacketData, packet.GetData()) { @@ -205,11 +216,41 @@ func (am AppModule) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, re } // OnAcknowledgementPacket implements the IBCModule interface. -func (am AppModule) OnAcknowledgementPacket(sdk.Context, channeltypes.Packet, []byte, sdk.AccAddress) error { +func (am AppModule) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, _ []byte, _ sdk.AccAddress) error { + _, err := am.scopedKeeper.NewCapability(ctx, MockAckCanaryCapabilityName+strconv.Itoa(int(packet.GetSequence()))) + if err != nil { + // application callback called twice on same packet sequence + // must never occur + panic(err) + } + return nil } // OnTimeoutPacket implements the IBCModule interface. -func (am AppModule) OnTimeoutPacket(sdk.Context, channeltypes.Packet, sdk.AccAddress) error { +func (am AppModule) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, _ sdk.AccAddress) error { + _, err := am.scopedKeeper.NewCapability(ctx, MockTimeoutCanaryCapabilityName+strconv.Itoa(int(packet.GetSequence()))) + if err != nil { + // application callback called twice on same packet sequence + // must never occur + panic(err) + } + return nil } + +// NegotiateAppVersion implements the IBCModule interface. +func (am AppModule) NegotiateAppVersion( + ctx sdk.Context, + order channeltypes.Order, + connectionID string, + portID string, + counterparty channeltypes.Counterparty, + proposedVersion string, +) (string, error) { + if proposedVersion != Version { // allow testing of error scenarios + return "", errors.New("failed to negotiate app version") + } + + return Version, nil +} diff --git a/testing/sdk_test.go b/testing/sdk_test.go index b7b63b1a1c1..4d41e96dac9 100644 --- a/testing/sdk_test.go +++ b/testing/sdk_test.go @@ -126,65 +126,6 @@ func (s *IntegrationTestSuite) TearDownSuite() { s.network.Cleanup() } -// Create an IBC tx that's encoded as amino-JSON. Since we can't amino-marshal -// a tx with "cosmos-sdk/MsgTransfer" using the SDK, we just hardcode the tx -// here. But external clients might, see https://github.com/cosmos/cosmos-sdk/issues/8022. -func mkIBCStdTx() []byte { - ibcTx := `{ - "account_number": "68", - "chain_id": "stargate-4", - "fee": { - "amount": [ - { - "amount": "3500", - "denom": "umuon" - } - ], - "gas": "350000" - }, - "memo": "", - "msg": [ - { - "type": "cosmos-sdk/MsgTransfer", - "value": { - "receiver": "cosmos1q9wtnlwdjrhwtcjmt2uq77jrgx7z3usrq2yz7z", - "sender": "cosmos1q9wtnlwdjrhwtcjmt2uq77jrgx7z3usrq2yz7z", - "source_channel": "channel-0", - "source_port": "transfer", - "token": { - "amount": "1000000", - "denom": "umuon" - } - } - } - ], - "sequence": "24" - }` - req := fmt.Sprintf(`{"tx":%s,"mode":"async"}`, ibcTx) - - return []byte(req) -} - -func (s *IntegrationTestSuite) TestEncodeIBCTx() { - val := s.network.Validators[0] - - req := mkIBCStdTx() - res, err := rest.PostRequest(fmt.Sprintf("%s/txs/encode", val.APIAddress), "application/json", []byte(req)) - s.Require().NoError(err) - - s.Require().Contains(string(res), authrest.ErrEncodeDecode.Error()) -} - -func (s *IntegrationTestSuite) TestBroadcastIBCTxRequest() { - val := s.network.Validators[0] - - req := mkIBCStdTx() - res, err := rest.PostRequest(fmt.Sprintf("%s/txs", val.APIAddress), "application/json", []byte(req)) - s.Require().NoError(err) - - s.Require().NotContains(string(res), "this transaction cannot be broadcasted via legacy REST endpoints", string(res)) -} - // TestLegacyRestErrMessages creates two IBC txs, one that fails, one that // succeeds, and make sure we cannot query any of them (with pretty error msg). // Our intension is to test the error message of querying a message which is diff --git a/testing/simapp/app.go b/testing/simapp/app.go index e84e96bdf9e..6592c6ed424 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -13,7 +13,6 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmos "github.com/tendermint/tendermint/libs/os" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/baseapp" @@ -268,6 +267,9 @@ func NewSimApp( // note replicate if you do not need to test core IBC or light clients. scopedIBCMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName) + // seal capability keeper after scoping modules + app.CapabilityKeeper.Seal() + // add keepers app.AccountKeeper = authkeeper.NewAccountKeeper( appCodec, keys[authtypes.StoreKey], app.GetSubspace(authtypes.ModuleName), authtypes.ProtoBaseAccount, maccPerms, @@ -392,8 +394,9 @@ func NewSimApp( // there is nothing left over in the validator fee pool, so as to keep the // CanWithdrawInvariant invariant. // NOTE: staking module is required if HistoricalEntries param > 0 + // NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC) app.mm.SetOrderBeginBlockers( - upgradetypes.ModuleName, minttypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName, + upgradetypes.ModuleName, capabilitytypes.ModuleName, minttypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName, evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName, ) app.mm.SetOrderEndBlockers(crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName) @@ -470,16 +473,6 @@ func NewSimApp( if err := app.LoadLatestVersion(); err != nil { tmos.Exit(err.Error()) } - - // Initialize and seal the capability keeper so all persistent capabilities - // are loaded in-memory and prevent any further modules from creating scoped - // sub-keepers. - // This must be done during creation of baseapp rather than in InitChain so - // that in-memory capabilities get regenerated on app restart. - // Note that since this reads from the store, we can only perform it when - // `loadLatest` is set to true. - ctx := app.BaseApp.NewUncachedContext(true, tmproto.Header{}) - app.CapabilityKeeper.InitializeAndSeal(ctx) } app.ScopedIBCKeeper = scopedIBCKeeper diff --git a/testing/values.go b/testing/values.go index 5ba3ab1dd29..7a66b683826 100644 --- a/testing/values.go +++ b/testing/values.go @@ -5,12 +5,14 @@ package ibctesting import ( + "strconv" "time" sdk "github.com/cosmos/cosmos-sdk/types" ibctransfertypes "github.com/cosmos/ibc-go/modules/apps/transfer/types" connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" commitmenttypes "github.com/cosmos/ibc-go/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/modules/light-clients/07-tendermint/types" "github.com/cosmos/ibc-go/testing/mock" @@ -50,10 +52,14 @@ var ( ConnectionVersion = connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions())[0] - MockAcknowledgement = mock.MockAcknowledgement.Acknowledgement() - MockPacketData = mock.MockPacketData - MockFailPacketData = mock.MockFailPacketData - MockCanaryCapabilityName = mock.MockCanaryCapabilityName + MockAcknowledgement = mock.MockAcknowledgement.Acknowledgement() + MockPacketData = mock.MockPacketData + MockFailPacketData = mock.MockFailPacketData + MockRecvCanaryCapabilityName = mock.MockRecvCanaryCapabilityName prefix = commitmenttypes.NewMerklePrefix([]byte("ibc")) ) + +func GetMockRecvCanaryCapabilityName(packet channeltypes.Packet) string { + return MockRecvCanaryCapabilityName + strconv.Itoa(int(packet.GetSequence())) +} From 3517def446bae59acb4a09a1e1dbb04e52cf2a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 20 Sep 2021 12:54:20 +0200 Subject: [PATCH 22/66] fix err message (#419) --- modules/apps/27-interchain-accounts/keeper/relay.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index baf6009b2e1..15ddfdf7bd3 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -202,7 +202,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error var data types.IBCAccountPacketData if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal interchain account packet data: %s", err.Error()) + return sdkerrors.Wrapf(types.ErrUnknownPacketData, "cannot unmarshal ICS-27 interchain account packet data") } switch data.Type { From e7cf4d31da685e38ae63c97eb07d6c1c3470fb1b Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 20 Sep 2021 16:56:33 +0200 Subject: [PATCH 23/66] feat: ica app version negotiation (#410) * adding NegotiateAppVersion implementation and tests * updating GenerateAddress to return sdk.AccAddress, fixing tests * updating ica handshake flow to parse address from version string, fixing associated tests * updating module_tests * derive ica addresses from module account addr * removing unused keys * adding improved version validation, updating tests * removing redundant local var - owner * updating Delimiter godoc * updating validation logic * adding test cases for ValidateVersion * adding additional validation testcase, updating godocs * updating Version -> VersionPrefix, error msgs, validation tests * updating NewAppVersion func sig and usage * updating NewAppVersion args and returning more appropriate errors for handshake * Update modules/apps/27-interchain-accounts/keeper/handshake.go Co-authored-by: Sean King * updating ValidateVersion godoc Co-authored-by: Sean King --- .../27-interchain-accounts/keeper/account.go | 14 ++- .../keeper/account_test.go | 4 +- .../keeper/handshake.go | 36 ++++++-- .../keeper/handshake_test.go | 24 ++--- .../keeper/keeper_test.go | 16 +++- .../keeper/relay_test.go | 2 +- modules/apps/27-interchain-accounts/module.go | 16 +++- .../27-interchain-accounts/module_test.go | 80 ++++++++++++++++ .../27-interchain-accounts/types/account.go | 24 +++-- .../types/account_test.go | 91 ++++++++++++------- .../27-interchain-accounts/types/errors.go | 6 +- .../apps/27-interchain-accounts/types/keys.go | 45 +++++---- .../27-interchain-accounts/types/validate.go | 44 +++++++++ .../types/validate_test.go | 61 +++++++++++++ 14 files changed, 364 insertions(+), 99 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/module_test.go create mode 100644 modules/apps/27-interchain-accounts/types/validate.go create mode 100644 modules/apps/27-interchain-accounts/types/validate_test.go diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index 43e3bc4b143..814e96d6dad 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -31,7 +31,7 @@ func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpart return sdkerrors.Wrap(err, "unable to bind to newly generated portID") } - msg := channeltypes.NewMsgChannelOpenInit(portID, types.Version, channeltypes.ORDERED, []string{connectionID}, types.PortID, types.ModuleName) + msg := channeltypes.NewMsgChannelOpenInit(portID, types.VersionPrefix, channeltypes.ORDERED, []string{connectionID}, types.PortID, types.ModuleName) handler := k.msgRouter.Handler(msg) if _, err := handler(ctx, msg); err != nil { return err @@ -40,17 +40,15 @@ func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpart return nil } -// Register interchain account if it has not already been created -func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, portID string) { - address := types.GenerateAddress(portID) - - account := k.accountKeeper.GetAccount(ctx, address) - if account != nil { +// RegisterInterchainAccount attempts to create a new account using the provided address and stores it in state keyed by the provided port identifier +// If an account for the provided address already exists this function returns early (no-op) +func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, accAddr sdk.AccAddress, portID string) { + if acc := k.accountKeeper.GetAccount(ctx, accAddr); acc != nil { return } interchainAccount := types.NewInterchainAccount( - authtypes.NewBaseAccountWithAddress(address), + authtypes.NewBaseAccountWithAddress(accAddr), portID, ) diff --git a/modules/apps/27-interchain-accounts/keeper/account_test.go b/modules/apps/27-interchain-accounts/keeper/account_test.go index 3d9cd9bae49..69ac5a5dc87 100644 --- a/modules/apps/27-interchain-accounts/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/keeper/account_test.go @@ -44,8 +44,8 @@ func (suite *KeeperTestSuite) TestInitInterchainAccount() { tc := tc suite.Run(tc.name, func() { - suite.SetupTest() // reset - owner = "owner" // must be explicitly changed + suite.SetupTest() // reset + owner = TestOwnerAddress // must be explicitly changed path = NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index e4677b72188..bccd1be1a16 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -36,8 +36,9 @@ func (k Keeper) OnChanOpenInit( if counterparty.PortId != types.PortID { return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "counterparty port-id must be '%s', (%s != %s)", types.PortID, counterparty.PortId, types.PortID) } - if version != types.Version { - return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "channel version must be '%s' (%s != %s)", types.Version, version, types.Version) + + if err := types.ValidateVersion(version); err != nil { + return sdkerrors.Wrap(err, "version validation failed") } existingChannelID, found := k.GetActiveChannel(ctx, portID) @@ -71,11 +72,13 @@ func (k Keeper) OnChanOpenTry( if order != channeltypes.ORDERED { return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "invalid channel ordering: %s, expected %s", order.String(), channeltypes.ORDERED.String()) } - if version != types.Version { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "got: %s, expected %s", version, types.Version) + + if err := types.ValidateVersion(version); err != nil { + return sdkerrors.Wrap(err, "version validation failed") } - if counterpartyVersion != types.Version { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) + + if err := types.ValidateVersion(counterpartyVersion); err != nil { + return sdkerrors.Wrap(err, "counterparty version validation failed") } // On the host chain the capability may only be claimed during the OnChanOpenTry @@ -84,23 +87,38 @@ func (k Keeper) OnChanOpenTry( return err } + // Check to ensure that the version string contains the expected address generated from the Counterparty portID + accAddr := types.GenerateAddress(counterparty.PortId) + parsedAddr := types.ParseAddressFromVersion(version) + if parsedAddr != accAddr.String() { + return sdkerrors.Wrapf(types.ErrInvalidAccountAddress, "version contains invalid account address: expected %s, got %s", parsedAddr, accAddr) + } + // Register interchain account if it does not already exist - k.RegisterInterchainAccount(ctx, counterparty.PortId) + k.RegisterInterchainAccount(ctx, accAddr, counterparty.PortId) + return nil } +// OnChanOpenAck sets the active channel for the interchain account/owner pair +// and stores the associated interchain account address in state keyed by it's corresponding port identifier +// +// Controller Chain func (k Keeper) OnChanOpenAck( ctx sdk.Context, portID, channelID string, counterpartyVersion string, ) error { - if counterpartyVersion != types.Version { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) + if err := types.ValidateVersion(counterpartyVersion); err != nil { + return sdkerrors.Wrap(err, "counterparty version validation failed") } k.SetActiveChannel(ctx, portID, channelID) + accAddr := types.ParseAddressFromVersion(counterpartyVersion) + k.SetInterchainAccountAddress(ctx, portID, accAddr) + return nil } diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index 35f09372f76..d3ba9b20a31 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -62,7 +62,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { suite.coordinator.SetupConnections(path) // mock init interchain account - portID, err := types.GeneratePortID("owner", path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + portID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) suite.Require().NoError(err) portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) suite.chainA.GetSimApp().ICAKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) @@ -75,7 +75,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { Ordering: channeltypes.ORDERED, Counterparty: counterparty, ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: types.Version, + Version: types.VersionPrefix, } chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(portID, path.EndpointA.ChannelID)) @@ -136,6 +136,11 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { suite.Require().NoError(err) }, false, }, + { + "invalid account address", func() { + channel.Counterparty.PortId = "invalid-port-id" + }, false, + }, } for _, tc := range testCases { @@ -144,11 +149,10 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { suite.Run(tc.name, func() { suite.SetupTest() // reset path = NewICAPath(suite.chainA, suite.chainB) - owner := "owner" - counterpartyVersion = types.Version + counterpartyVersion = types.VersionPrefix suite.coordinator.SetupConnections(path) - err := InitInterchainAccount(path.EndpointA, owner) + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) suite.Require().NoError(err) // default values @@ -158,7 +162,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { Ordering: channeltypes.ORDERED, Counterparty: counterparty, ConnectionHops: []string{path.EndpointB.ConnectionID}, - Version: types.Version, + Version: TestVersion, } chanCap, err = suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) @@ -211,11 +215,10 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { suite.Run(tc.name, func() { suite.SetupTest() // reset path = NewICAPath(suite.chainA, suite.chainB) - owner := "owner" - counterpartyVersion = types.Version + counterpartyVersion = TestVersion suite.coordinator.SetupConnections(path) - err := InitInterchainAccount(path.EndpointA, owner) + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) suite.Require().NoError(err) err = path.EndpointB.ChanOpenTry() @@ -264,10 +267,9 @@ func (suite *KeeperTestSuite) TestOnChanOpenConfirm() { suite.Run(tc.name, func() { suite.SetupTest() // reset path = NewICAPath(suite.chainA, suite.chainB) - owner := "owner" suite.coordinator.SetupConnections(path) - err := InitInterchainAccount(path.EndpointA, owner) + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) suite.Require().NoError(err) err = path.EndpointB.ChanOpenTry() diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index 7064d6ebc07..0f7c12d8189 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "fmt" "testing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -11,6 +12,15 @@ import ( ibctesting "github.com/cosmos/ibc-go/testing" ) +var ( + // TestOwnerAddress defines a reusable bech32 address for testing purposes + TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + // TestPortID defines a resuable port identifier for testing purposes + TestPortID = fmt.Sprintf("ics-27-0-0-%s", TestOwnerAddress) + // TestVersion defines a resuable interchainaccounts version string for testing purposes + TestVersion = types.NewAppVersion(types.VersionPrefix, types.GenerateAddress(TestPortID).String()) +) + type KeeperTestSuite struct { suite.Suite @@ -35,8 +45,8 @@ func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { path.EndpointB.ChannelConfig.PortID = types.PortID path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointA.ChannelConfig.Version = types.Version - path.EndpointB.ChannelConfig.Version = types.Version + path.EndpointA.ChannelConfig.Version = types.VersionPrefix + path.EndpointB.ChannelConfig.Version = TestVersion return path } @@ -104,7 +114,7 @@ func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { path := NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) - err := SetupICAPath(path, "testing") + err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) counterpartyPortID := path.EndpointA.ChannelConfig.PortID diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index 66c3b22d51a..ea836fb8c05 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -74,7 +74,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() { suite.Run(tc.name, func() { suite.SetupTest() // reset path = NewICAPath(suite.chainA, suite.chainB) - owner := "owner" + owner := TestOwnerAddress suite.coordinator.SetupConnections(path) err := suite.SetupICAPath(path, owner) diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 740eea4ad6b..efa808f8d01 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -255,6 +255,18 @@ func (am AppModule) OnTimeoutPacket( return nil } -func (am AppModule) NegotiateAppVersion(ctx sdk.Context, order channeltypes.Order, connectionID, portID string, counterparty channeltypes.Counterparty, proposedVersion string) (string, error) { - return "", nil +// NegotiateAppVersion implements the IBCModule interface +func (am AppModule) NegotiateAppVersion( + ctx sdk.Context, + order channeltypes.Order, + connectionID string, + portID string, + counterparty channeltypes.Counterparty, + proposedVersion string, +) (string, error) { + if proposedVersion != types.VersionPrefix { + return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "failed to negotiate app version: expected %s, got %s", types.VersionPrefix, proposedVersion) + } + + return types.NewAppVersion(types.VersionPrefix, types.GenerateAddress(counterparty.PortId).String()), nil } diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go new file mode 100644 index 00000000000..fbfea84a189 --- /dev/null +++ b/modules/apps/27-interchain-accounts/module_test.go @@ -0,0 +1,80 @@ +package interchain_accounts_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/testing" +) + +var ( + // TestOwnerAddress defines a reusable bech32 address for testing purposes + TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + // TestPortID defines a resuable port identifier for testing purposes + TestPortID = fmt.Sprintf("ics-27-0-0-%s", TestOwnerAddress) + // TestVersion defines a resuable interchainaccounts version string for testing purposes + TestVersion = types.NewAppVersion(types.VersionPrefix, types.GenerateAddress(TestPortID).String()) +) + +type InterchainAccountsTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + // testing chains used for convenience and readability + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain + chainC *ibctesting.TestChain +} + +func (suite *InterchainAccountsTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2)) +} + +func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { + path := ibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig.PortID = types.PortID + path.EndpointB.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointA.ChannelConfig.Version = types.VersionPrefix + path.EndpointB.ChannelConfig.Version = TestVersion + + return path +} + +func TestICATestSuite(t *testing.T) { + suite.Run(t, new(InterchainAccountsTestSuite)) +} + +func (suite *InterchainAccountsTestSuite) TestNegotiateAppVersion() { + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + module, _, err := suite.chainA.GetSimApp().GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.GetSimApp().GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + counterpartyPortID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + suite.Require().NoError(err) + + counterparty := &channeltypes.Counterparty{ + PortId: counterpartyPortID, + ChannelId: path.EndpointB.ChannelID, + } + + version, err := cbs.NegotiateAppVersion(suite.chainA.GetContext(), channeltypes.ORDERED, path.EndpointA.ConnectionID, types.PortID, *counterparty, types.VersionPrefix) + suite.Require().NoError(err) + suite.Require().NoError(types.ValidateVersion(version)) + suite.Require().Equal(TestVersion, version) +} diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index 93f8b18e9a4..7948e2e6afa 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -5,13 +5,12 @@ import ( "fmt" "strings" - yaml "gopkg.in/yaml.v2" - crypto "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/tendermint/tendermint/crypto/tmhash" + yaml "gopkg.in/yaml.v2" connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types" ) @@ -20,9 +19,14 @@ const ( ICAPrefix string = "ics-27" ) -// GenerateAddress returns a truncated SHA256 hash using the provided port string -func GenerateAddress(port string) []byte { - return tmhash.SumTruncated([]byte(port)) +// GenerateAddress returns an sdk.AccAddress using the provided port identifier +func GenerateAddress(portID string) sdk.AccAddress { + return sdk.AccAddress(tmhash.SumTruncated([]byte(portID))) +} + +// ParseAddressFromVersion trims the interchainaccounts version prefix and returns the associated account address +func ParseAddressFromVersion(version string) string { + return strings.TrimPrefix(version, fmt.Sprint(VersionPrefix, Delimiter)) } // GeneratePortID generates the portID for a specific owner @@ -32,21 +36,21 @@ func GenerateAddress(port string) []byte { // https://github.com/seantking/ibc/tree/sean/ics-27-updates/spec/app/ics-027-interchain-accounts#registering--controlling-flows // TODO: update link to spec func GeneratePortID(owner, connectionID, counterpartyConnectionID string) (string, error) { - ownerID := strings.TrimSpace(owner) - if ownerID == "" { - return "", sdkerrors.Wrap(ErrInvalidOwnerAddress, "owner address cannot be empty") + if strings.TrimSpace(owner) == "" { + return "", sdkerrors.Wrap(ErrInvalidAccountAddress, "owner address cannot be empty") } + connectionSeq, err := connectiontypes.ParseConnectionSequence(connectionID) if err != nil { return "", sdkerrors.Wrap(err, "invalid connection identifier") } + counterpartyConnectionSeq, err := connectiontypes.ParseConnectionSequence(counterpartyConnectionID) if err != nil { return "", sdkerrors.Wrap(err, "invalid counterparty connection identifier") } - portID := fmt.Sprintf("%s-%d-%d-%s", ICAPrefix, connectionSeq, counterpartyConnectionSeq, ownerID) - return portID, nil + return fmt.Sprintf("%s-%d-%d-%s", ICAPrefix, connectionSeq, counterpartyConnectionSeq, owner), nil } type InterchainAccountI interface { diff --git a/modules/apps/27-interchain-accounts/types/account_test.go b/modules/apps/27-interchain-accounts/types/account_test.go index 15bc23eb3e8..8f3bbc1126b 100644 --- a/modules/apps/27-interchain-accounts/types/account_test.go +++ b/modules/apps/27-interchain-accounts/types/account_test.go @@ -1,12 +1,19 @@ package types_test import ( + "fmt" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/testing" - "github.com/stretchr/testify/suite" +) + +var ( + // TestOwnerAddress defines a reusable bech32 address for testing purposes + TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" ) type TypesTestSuite struct { @@ -25,59 +32,81 @@ func (suite *TypesTestSuite) SetupTest() { suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) } -func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { - path := ibctesting.NewPath(chainA, chainB) - path.EndpointA.ChannelConfig.PortID = types.PortID - path.EndpointB.ChannelConfig.PortID = types.PortID - path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointA.ChannelConfig.Version = types.Version - path.EndpointB.ChannelConfig.Version = types.Version - - return path -} - func TestTypesTestSuite(t *testing.T) { suite.Run(t, new(TypesTestSuite)) } +func (suite *TypesTestSuite) TestGenerateAddress() { + addr := types.GenerateAddress("test-port-id") + accAddr, err := sdk.AccAddressFromBech32(addr.String()) + + suite.Require().NoError(err, "TestGenerateAddress failed") + suite.Require().NotEmpty(accAddr) +} + func (suite *TypesTestSuite) TestGeneratePortID() { var ( path *ibctesting.Path - owner string + owner = TestOwnerAddress ) - var testCases = []struct { + + testCases := []struct { name string malleate func() expValue string expPass bool }{ - {"success", func() {}, "ics-27-0-0-owner123", true}, - {"success with non matching connection sequences", func() { - path.EndpointA.ConnectionID = "connection-1" - }, "ics-27-1-0-owner123", true}, - {"invalid owner address", func() { - owner = " " - }, "", false}, - {"invalid connectionID", func() { - path.EndpointA.ConnectionID = "connection" - }, "", false}, - {"invalid counterparty connectionID", func() { - path.EndpointB.ConnectionID = "connection" - }, "", false}, + { + "success", + func() {}, + fmt.Sprintf("ics-27-0-0-%s", TestOwnerAddress), + true, + }, + { + "success with non matching connection sequences", + func() { + path.EndpointA.ConnectionID = "connection-1" + }, + fmt.Sprintf("ics-27-1-0-%s", TestOwnerAddress), + true, + }, + { + "invalid owner address", + func() { + owner = " " + }, + "", + false, + }, + { + "invalid connectionID", + func() { + path.EndpointA.ConnectionID = "connection" + }, + "", + false, + }, + { + "invalid counterparty connectionID", + func() { + path.EndpointB.ConnectionID = "connection" + }, + "", + false, + }, } for _, tc := range testCases { tc := tc suite.Run(tc.name, func() { suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB) + path = ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.Setup(path) - owner = "owner123" // must be explicitly changed tc.malleate() portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + if tc.expPass { suite.Require().NoError(err, tc.name) suite.Require().Equal(tc.expValue, portID) diff --git a/modules/apps/27-interchain-accounts/types/errors.go b/modules/apps/27-interchain-accounts/types/errors.go index 32425a81071..5c5bf3fed44 100644 --- a/modules/apps/27-interchain-accounts/types/errors.go +++ b/modules/apps/27-interchain-accounts/types/errors.go @@ -11,9 +11,9 @@ var ( ErrUnsupportedChain = sdkerrors.Register(ModuleName, 5, "unsupported chain") ErrInvalidOutgoingData = sdkerrors.Register(ModuleName, 6, "invalid outgoing data") ErrInvalidRoute = sdkerrors.Register(ModuleName, 7, "invalid route") - ErrInterchainAccountNotFound = sdkerrors.Register(ModuleName, 8, "Interchain Account not found") - ErrInterchainAccountAlreadySet = sdkerrors.Register(ModuleName, 9, "Interchain Account is already set") + ErrInterchainAccountNotFound = sdkerrors.Register(ModuleName, 8, "interchain account not found") + ErrInterchainAccountAlreadySet = sdkerrors.Register(ModuleName, 9, "interchain account is already set") ErrActiveChannelNotFound = sdkerrors.Register(ModuleName, 10, "no active channel for this owner") ErrInvalidVersion = sdkerrors.Register(ModuleName, 11, "invalid interchain accounts version") - ErrInvalidOwnerAddress = sdkerrors.Register(ModuleName, 12, "invalid owner address") + ErrInvalidAccountAddress = sdkerrors.Register(ModuleName, 12, "invalid account address") ) diff --git a/modules/apps/27-interchain-accounts/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go index 909813ec46d..51841d0de0b 100644 --- a/modules/apps/27-interchain-accounts/types/keys.go +++ b/modules/apps/27-interchain-accounts/types/keys.go @@ -1,41 +1,48 @@ package types -import "fmt" +import ( + "fmt" +) const ( - // ModuleName defines the Interchain Account module name + // ModuleName defines the interchain accounts module name ModuleName = "interchainaccounts" - // Version defines the current version the IBC tranfer - // module supports - Version = "ics27-1" + // VersionPrefix defines the current version for interchain accounts + VersionPrefix = "ics27-1" + // PortID is the default port id that the interchain accounts module binds to PortID = "ibcaccount" - StoreKey = ModuleName - RouterKey = ModuleName + // StoreKey is the store key string for interchain accounts + StoreKey = ModuleName - // Key to store portID in our store - PortKey = "portID" + // RouterKey is the message route for interchain accounts + RouterKey = ModuleName + // QuerierRoute is the querier route for interchain accounts QuerierRoute = ModuleName - // MemStoreKey defines the in-memory store key - MemStoreKey = "mem_capability" + // Delimiter is the delimiter used for the interchain accounts version string + Delimiter = "|" ) +var ( + // PortKey defines the key to store the port ID in store + PortKey = []byte{0x01} +) + +// NewVersion returns a complete version string in the format: VersionPrefix + Delimter + AccAddress +func NewAppVersion(versionPrefix, accAddr string) string { + return fmt.Sprint(versionPrefix, Delimiter, accAddr) +} + +// KeyActiveChannel creates and returns a new key used for active channels store operations func KeyActiveChannel(portId string) []byte { return []byte(fmt.Sprintf("activeChannel/%s", portId)) } +// KeyOwnerAccount creates and returns a new key used for owner account store operations func KeyOwnerAccount(portId string) []byte { return []byte(fmt.Sprintf("owner/%s", portId)) } - -var ( - KeyPrefixRegisteredAccount = []byte("register") -) - -func GetIdentifier(portID, channelID string) string { - return fmt.Sprintf("%s/%s/", portID, channelID) -} diff --git a/modules/apps/27-interchain-accounts/types/validate.go b/modules/apps/27-interchain-accounts/types/validate.go new file mode 100644 index 00000000000..691eb369e41 --- /dev/null +++ b/modules/apps/27-interchain-accounts/types/validate.go @@ -0,0 +1,44 @@ +package types + +import ( + "regexp" + "strings" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// DefaultMaxAddrLength defines the default maximum character length used in validation of addresses +var DefaultMaxAddrLength = 128 + +// IsValidAddr defines a regular expression to check if the provided string consists of +// strictly alphanumeric characters +var IsValidAddr = regexp.MustCompile("^[a-zA-Z0-9]*$").MatchString + +// ValidateVersion performs basic validation of the provided ics27 version string. +// An ics27 version string may include an optional account address as per [TODO: Add spec when available] +// ValidateVersion first attempts to split the version string using the standard delimiter, then asserts a supported +// version prefix is included, followed by additional checks which enforce constraints on the optional account address. +// When no delimiter is present, only the version prefix is validated +func ValidateVersion(version string) error { + s := strings.Split(version, Delimiter) + + if s[0] != VersionPrefix { + return sdkerrors.Wrapf(ErrInvalidVersion, "expected %s, got %s", VersionPrefix, s[0]) + } + + if len(s) > 1 { + if len(s) != 2 { + return sdkerrors.Wrap(ErrInvalidAccountAddress, "unexpected address format") + } + + if !IsValidAddr(s[1]) || len(s[1]) == 0 || len(s[1]) > DefaultMaxAddrLength { + return sdkerrors.Wrapf( + ErrInvalidAccountAddress, + "address must contain strictly alphanumeric characters, not exceeding %d characters in length", + DefaultMaxAddrLength, + ) + } + } + + return nil +} diff --git a/modules/apps/27-interchain-accounts/types/validate_test.go b/modules/apps/27-interchain-accounts/types/validate_test.go new file mode 100644 index 00000000000..aa1bb33c8ae --- /dev/null +++ b/modules/apps/27-interchain-accounts/types/validate_test.go @@ -0,0 +1,61 @@ +package types_test + +import ( + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" +) + +func (suite *TypesTestSuite) TestValidateVersion() { + testCases := []struct { + name string + version string + expPass bool + }{ + { + "success", + types.NewAppVersion(types.VersionPrefix, TestOwnerAddress), + true, + }, + { + "success - version prefix only", + types.VersionPrefix, + true, + }, + { + "invalid version", + types.NewAppVersion("ics27-5", TestOwnerAddress), + false, + }, + { + "invalid account address - empty", + types.NewAppVersion(types.VersionPrefix, ""), + false, + }, + { + "invalid account address - exceeded character length", + types.NewAppVersion(types.VersionPrefix, "ofwafxhdmqcdbpzvrccxkidbunrwyyoboyctignpvthxbwxtmnzyfwhhywobaatltfwafxhdmqcdbpzvrccxkidbunrwyyoboyctignpvthxbwxtmnzyfwhhywobaatlt"), + false, + }, + { + "invalid account address - non alphanumeric characters", + types.NewAppVersion(types.VersionPrefix, "-_-"), + false, + }, + { + "invalid account address - address contains additional delimiter", + types.NewAppVersion(types.VersionPrefix, "cosmos17dtl0mjt3t77kpu|hg2edqzjpszulwhgzuj9ljs"), + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + err := types.ValidateVersion(tc.version) + + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + }) + } +} From e64fb254f6303760ab093cc68f8b6248baeb8408 Mon Sep 17 00:00:00 2001 From: Sean King Date: Thu, 23 Sep 2021 09:43:06 +0200 Subject: [PATCH 24/66] test: adding tests for OnRecvPacket (#412) * test: adding tests for OnRecvPacket * test: adding further test cases for onRecvPacket --- .../27-interchain-accounts/keeper/relay.go | 13 +- .../keeper/relay_test.go | 138 +++++++++++++++++- 2 files changed, 137 insertions(+), 14 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 15ddfdf7bd3..6884a026dba 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -44,18 +44,7 @@ func (k Keeper) createOutgoingPacket( return []byte{}, types.ErrInvalidOutgoingData } - var msgs []sdk.Msg - - switch data := data.(type) { - case []sdk.Msg: - msgs = data - case sdk.Msg: - msgs = []sdk.Msg{data} - default: - return []byte{}, types.ErrInvalidOutgoingData - } - - txBytes, err := k.SerializeCosmosTx(k.cdc, msgs) + txBytes, err := k.SerializeCosmosTx(k.cdc, data) if err != nil { return []byte{}, sdkerrors.Wrap(err, "invalid packet data or codec") } diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index ea836fb8c05..6fd53d7b888 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -1,9 +1,15 @@ package keeper_test import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/testing" ) @@ -74,13 +80,15 @@ func (suite *KeeperTestSuite) TestTrySendTx() { suite.Run(tc.name, func() { suite.SetupTest() // reset path = NewICAPath(suite.chainA, suite.chainB) - owner := TestOwnerAddress suite.coordinator.SetupConnections(path) - err := suite.SetupICAPath(path, owner) + err := suite.SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) + portID = path.EndpointA.ChannelConfig.PortID + tc.malleate() + _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), portID, msg) if tc.expPass { @@ -91,3 +99,129 @@ func (suite *KeeperTestSuite) TestTrySendTx() { }) } } + +func (suite *KeeperTestSuite) TestOnRecvPacket() { + var ( + path *ibctesting.Path + msg sdk.Msg + txBytes []byte + packetData []byte + sourcePort string + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "Interchain account successfully executes banktypes.MsgSend", func() { + // build MsgSend + amount, _ := sdk.ParseCoinsNormalized("100stake") + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + // build packet data + txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, msg) + suite.Require().NoError(err) + + data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, + Data: txBytes} + packetData = data.GetBytes() + }, true, + }, + { + "Cannot deserialize txBytes", func() { + txBytes = []byte("invalid tx bytes") + data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, + Data: txBytes} + packetData = data.GetBytes() + }, false, + }, + { + "Cannot deserialize txBytes: invalid IBCTxRaw", func() { + txBody := []byte("invalid tx body") + txRaw := &types.IBCTxRaw{ + BodyBytes: txBody, + } + + txBytes = suite.chainB.Codec.MustMarshal(txRaw) + data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, + Data: txBytes} + packetData = data.GetBytes() + }, false, + }, + { + "Invalid packet type", func() { + txBytes = []byte{} + // Type here is an ENUM + // Valid type is types.EXECUTE_TX + data := types.IBCAccountPacketData{Type: 100, + Data: txBytes} + packetData = data.GetBytes() + }, false, + }, + { + "Cannot unmarshal interchain account packet data into types.IBCAccountPacketData", func() { + packetData = []byte{} + }, false, + }, + { + "Unauthorised: Interchain account not found for given source portID", func() { + sourcePort = "invalid-port-id" + }, false, + }, + { + "Unauthorised: Signer of message is not the interchain account associated with sourcePortID", func() { + // build MsgSend + amount, _ := sdk.ParseCoinsNormalized("100stake") + // Incorrect FromAddress + msg = &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + // build packet data + txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, msg) + suite.Require().NoError(err) + data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, + Data: txBytes} + packetData = data.GetBytes() + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + err := suite.SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + // send 100stake to interchain account wallet + amount, _ := sdk.ParseCoinsNormalized("100stake") + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + bankMsg := &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: interchainAccountAddr, Amount: amount} + + _, err = suite.chainB.SendMsgs(bankMsg) + suite.Require().NoError(err) + + // valid source port + sourcePort = path.EndpointA.ChannelConfig.PortID + + // malleate packetData for test cases + tc.malleate() + + seq := uint64(1) + packet := channeltypes.NewPacket(packetData, seq, sourcePort, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) + + // Pass it in here + err = suite.chainB.GetSimApp().ICAKeeper.OnRecvPacket(suite.chainB.GetContext(), packet) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} From 7fb133e365ed532c13a6acd088f0e8acce338f5f Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 23 Sep 2021 15:50:34 +0200 Subject: [PATCH 25/66] chore: merge latest main to interchain-accounts (#435) --- .../client/cli/query.go | 2 +- .../apps/27-interchain-accounts/genesis.go | 6 +-- .../27-interchain-accounts/keeper/account.go | 6 +-- .../keeper/account_test.go | 4 +- .../keeper/grpc_query.go | 2 +- .../keeper/grpc_query_test.go | 2 +- .../keeper/handshake.go | 10 ++-- .../keeper/handshake_test.go | 8 +-- .../27-interchain-accounts/keeper/keeper.go | 4 +- .../keeper/keeper_test.go | 6 +-- .../27-interchain-accounts/keeper/relay.go | 9 ++-- .../keeper/relay_test.go | 8 +-- modules/apps/27-interchain-accounts/module.go | 12 ++--- .../27-interchain-accounts/module_test.go | 6 +-- .../27-interchain-accounts/types/account.go | 2 +- .../types/account.pb.go | 14 +++--- .../types/account_test.go | 4 +- .../types/expected_keepers.go | 7 +-- .../types/genesis.pb.go | 14 +++--- .../27-interchain-accounts/types/query.pb.go | 46 ++++++++--------- .../27-interchain-accounts/types/types.pb.go | 50 +++++++++---------- .../types/validate_test.go | 2 +- .../interchain_accounts/v1/account.proto | 2 +- .../interchain_accounts/v1/genesis.proto | 2 +- .../interchain_accounts/v1/query.proto | 2 +- .../interchain_accounts/v1/types.proto | 2 +- testing/simapp/app.go | 7 ++- 27 files changed, 120 insertions(+), 119 deletions(-) diff --git a/modules/apps/27-interchain-accounts/client/cli/query.go b/modules/apps/27-interchain-accounts/client/cli/query.go index 55149f2b0fd..70137749561 100644 --- a/modules/apps/27-interchain-accounts/client/cli/query.go +++ b/modules/apps/27-interchain-accounts/client/cli/query.go @@ -7,7 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ) func GetQueryCmd() *cobra.Command { diff --git a/modules/apps/27-interchain-accounts/genesis.go b/modules/apps/27-interchain-accounts/genesis.go index 7f225f54150..0fd975ace00 100644 --- a/modules/apps/27-interchain-accounts/genesis.go +++ b/modules/apps/27-interchain-accounts/genesis.go @@ -4,10 +4,10 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/keeper" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - host "github.com/cosmos/ibc-go/modules/core/24-host" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) // InitGenesis initializes the interchain accounts application state from a provided genesis state diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index 814e96d6dad..069ec805b85 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -5,9 +5,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/modules/core/24-host" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) // InitInterchainAccount is the entry point to registering an interchain account. diff --git a/modules/apps/27-interchain-accounts/keeper/account_test.go b/modules/apps/27-interchain-accounts/keeper/account_test.go index 69ac5a5dc87..78a35eafaef 100644 --- a/modules/apps/27-interchain-accounts/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/keeper/account_test.go @@ -1,8 +1,8 @@ package keeper_test import ( - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - ibctesting "github.com/cosmos/ibc-go/testing" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v2/testing" ) func (suite *KeeperTestSuite) TestInitInterchainAccount() { diff --git a/modules/apps/27-interchain-accounts/keeper/grpc_query.go b/modules/apps/27-interchain-accounts/keeper/grpc_query.go index dacf55efeb1..1d110916202 100644 --- a/modules/apps/27-interchain-accounts/keeper/grpc_query.go +++ b/modules/apps/27-interchain-accounts/keeper/grpc_query.go @@ -10,7 +10,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ) var _ types.QueryServer = Keeper{} diff --git a/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go b/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go index c5ea7a3cd84..1beed47d7e1 100644 --- a/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go +++ b/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ) func (suite *KeeperTestSuite) TestQueryInterchainAccountAddress() { diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index bccd1be1a16..ea1015eaefa 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -5,10 +5,10 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/modules/core/24-host" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) // OnChanOpenInit performs basic validation of channel initialization. @@ -87,7 +87,7 @@ func (k Keeper) OnChanOpenTry( return err } - // Check to ensure that the version string contains the expected address generated from the Counterparty portID + // Check to ensure that the version string contains the expected address generated from the Counterparty portID accAddr := types.GenerateAddress(counterparty.PortId) parsedAddr := types.ParseAddressFromVersion(version) if parsedAddr != accAddr.String() { diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index d3ba9b20a31..ba2a1eea9ca 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -3,10 +3,10 @@ package keeper_test import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/modules/core/24-host" - ibctesting "github.com/cosmos/ibc-go/testing" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v2/testing" ) func (suite *KeeperTestSuite) TestOnChanOpenInit() { diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index d45fd9037aa..93fe12ba9ac 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -11,8 +11,8 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - host "github.com/cosmos/ibc-go/modules/core/24-host" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) // Keeper defines the IBC transfer keeper diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index 0f7c12d8189..cf3aca35f96 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -7,9 +7,9 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/testing" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v2/testing" ) var ( diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 6884a026dba..09175043dec 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -5,11 +5,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/modules/core/24-host" "github.com/tendermint/tendermint/crypto/tmhash" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) // TODO: implement middleware functionality, this will allow us to use capabilities to diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index 6fd53d7b888..78d407934d8 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -6,11 +6,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/testing" + ibctesting "github.com/cosmos/ibc-go/v2/testing" ) func (suite *KeeperTestSuite) TestTrySendTx() { diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index efa808f8d01..99bbf2d1bd8 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -17,12 +17,12 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/runtime" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/client/cli" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/keeper" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types" - ibcexported "github.com/cosmos/ibc-go/modules/core/exported" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/client/cli" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" ) var ( diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go index fbfea84a189..af5ea30eb7b 100644 --- a/modules/apps/27-interchain-accounts/module_test.go +++ b/modules/apps/27-interchain-accounts/module_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/testing" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v2/testing" ) var ( diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index 7948e2e6afa..db44d4acf14 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -12,7 +12,7 @@ import ( "github.com/tendermint/tendermint/crypto/tmhash" yaml "gopkg.in/yaml.v2" - connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types" + connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" ) const ( diff --git a/modules/apps/27-interchain-accounts/types/account.pb.go b/modules/apps/27-interchain-accounts/types/account.pb.go index 4518d7581a9..d645d28b72c 100644 --- a/modules/apps/27-interchain-accounts/types/account.pb.go +++ b/modules/apps/27-interchain-accounts/types/account.pb.go @@ -72,7 +72,7 @@ func init() { } var fileDescriptor_5561bd92625bf7da = []byte{ - // 338 bytes of a gzipped FileDescriptorProto + // 341 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0xcd, 0x4c, 0x4a, 0xd6, 0x4f, 0x2c, 0x28, 0xc8, 0xc9, 0x4c, 0x4e, 0x2c, 0xc9, 0xcc, 0xcf, 0x2b, 0xd6, 0xcf, 0xcc, 0x2b, 0x49, 0x2d, 0x4a, 0xce, 0x48, 0xcc, 0xcc, 0x8b, 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0x29, @@ -88,13 +88,13 @@ var fileDescriptor_5561bd92625bf7da = []byte{ 0x5c, 0xbc, 0x50, 0x89, 0xf8, 0xfc, 0xf2, 0xbc, 0xd4, 0x22, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0x89, 0x4f, 0xf7, 0xe4, 0x45, 0x20, 0x9a, 0x51, 0xa4, 0x95, 0x82, 0x78, 0xa0, 0x7c, 0x7f, 0x10, 0xd7, 0x4a, 0xae, 0x63, 0x81, 0x3c, 0xc3, 0x8c, 0x05, 0xf2, 0x0c, 0x97, 0xb6, 0xe8, 0x0a, - 0x61, 0xb8, 0xdf, 0xd3, 0x29, 0xe6, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, + 0x61, 0xb8, 0xdf, 0xd3, 0x29, 0xfe, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, - 0x9c, 0xd2, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xa1, 0xe1, 0xa7, 0x9f, 0x99, - 0x94, 0xac, 0x9b, 0x9e, 0xaf, 0x9f, 0x9b, 0x9f, 0x52, 0x9a, 0x93, 0x5a, 0x0c, 0x8a, 0xbe, 0x62, - 0x7d, 0x23, 0x73, 0x5d, 0x44, 0x14, 0xe8, 0xc2, 0x63, 0xae, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, - 0x0d, 0x1c, 0x76, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x46, 0x61, 0xdb, 0x7e, 0xee, 0x01, - 0x00, 0x00, + 0x5c, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xa1, 0xe1, 0xa7, 0x9f, 0x99, + 0x94, 0xac, 0x9b, 0x9e, 0xaf, 0x5f, 0x66, 0xa4, 0x9f, 0x9b, 0x9f, 0x52, 0x9a, 0x93, 0x5a, 0x0c, + 0x8a, 0xc1, 0x62, 0x7d, 0x23, 0x73, 0x5d, 0x44, 0x2c, 0xe8, 0xc2, 0x23, 0xaf, 0xa4, 0xb2, 0x20, + 0xb5, 0x38, 0x89, 0x0d, 0x1c, 0x7c, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe7, 0xf4, 0x36, + 0xc4, 0xf1, 0x01, 0x00, 0x00, } func (m *InterchainAccount) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/27-interchain-accounts/types/account_test.go b/modules/apps/27-interchain-accounts/types/account_test.go index 8f3bbc1126b..54a42759b26 100644 --- a/modules/apps/27-interchain-accounts/types/account_test.go +++ b/modules/apps/27-interchain-accounts/types/account_test.go @@ -7,8 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" - ibctesting "github.com/cosmos/ibc-go/testing" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v2/testing" ) var ( diff --git a/modules/apps/27-interchain-accounts/types/expected_keepers.go b/modules/apps/27-interchain-accounts/types/expected_keepers.go index 448a0b3fcaa..4a3aa86d55b 100644 --- a/modules/apps/27-interchain-accounts/types/expected_keepers.go +++ b/modules/apps/27-interchain-accounts/types/expected_keepers.go @@ -4,9 +4,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/modules/core/exported" + + connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" ) type Router interface { diff --git a/modules/apps/27-interchain-accounts/types/genesis.pb.go b/modules/apps/27-interchain-accounts/types/genesis.pb.go index 9e32a1c8abc..44661c274c4 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.pb.go +++ b/modules/apps/27-interchain-accounts/types/genesis.pb.go @@ -77,7 +77,7 @@ func init() { } var fileDescriptor_629b3ced0911516b = []byte{ - // 241 bytes of a gzipped FileDescriptorProto + // 244 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0xcd, 0x4c, 0x4a, 0xd6, 0x4f, 0x2c, 0x28, 0xc8, 0xc9, 0x4c, 0x4e, 0x2c, 0xc9, 0xcc, 0xcf, 0x2b, 0xd6, 0xcf, 0xcc, 0x2b, 0x49, 0x2d, 0x4a, 0xce, 0x48, 0xcc, 0xcc, 0x8b, 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0x29, @@ -87,13 +87,13 @@ var fileDescriptor_629b3ced0911516b = []byte{ 0xe3, 0x0e, 0x31, 0x2f, 0xb8, 0x24, 0xb1, 0x24, 0x55, 0x48, 0x9b, 0x8b, 0xbd, 0x20, 0xbf, 0xa8, 0x24, 0x3e, 0x33, 0x45, 0x82, 0x51, 0x81, 0x51, 0x83, 0xd3, 0x49, 0xe8, 0xd3, 0x3d, 0x79, 0xbe, 0xca, 0xc4, 0xdc, 0x1c, 0x2b, 0x25, 0xa8, 0x84, 0x52, 0x10, 0x1b, 0x88, 0xe5, 0x99, 0xe2, 0x14, - 0x73, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, - 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x4e, 0xe9, 0x99, 0x25, 0x19, + 0x7f, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, + 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0xae, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0x99, 0x49, - 0xc9, 0xba, 0xe9, 0xf9, 0xfa, 0xb9, 0xf9, 0x29, 0xa5, 0x39, 0xa9, 0xc5, 0x20, 0x9f, 0x16, 0xeb, - 0x1b, 0x99, 0xeb, 0x22, 0x5c, 0xab, 0x0b, 0xf7, 0x64, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, - 0xd8, 0x85, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x89, 0x2b, 0x4e, 0x7c, 0x19, 0x01, 0x00, - 0x00, + 0xc9, 0xba, 0xe9, 0xf9, 0xfa, 0x65, 0x46, 0xfa, 0xb9, 0xf9, 0x29, 0xa5, 0x39, 0xa9, 0xc5, 0x20, + 0xcf, 0x16, 0xeb, 0x1b, 0x99, 0xeb, 0x22, 0x1c, 0xac, 0x0b, 0xf7, 0x67, 0x49, 0x65, 0x41, 0x6a, + 0x71, 0x12, 0x1b, 0xd8, 0x91, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0xe5, 0x36, 0xd4, + 0x1c, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/27-interchain-accounts/types/query.pb.go b/modules/apps/27-interchain-accounts/types/query.pb.go index 271ba3b4827..29557f53dca 100644 --- a/modules/apps/27-interchain-accounts/types/query.pb.go +++ b/modules/apps/27-interchain-accounts/types/query.pb.go @@ -124,29 +124,29 @@ func init() { } var fileDescriptor_72a16b57c3343764 = []byte{ - // 347 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x3f, 0x4b, 0x3b, 0x31, - 0x18, 0xbe, 0x0c, 0xbf, 0x1f, 0x9a, 0xf1, 0xe8, 0x50, 0x0e, 0xb9, 0x4a, 0x51, 0x74, 0x69, 0x62, - 0x5b, 0x44, 0x10, 0x97, 0x76, 0xeb, 0xa0, 0x68, 0x47, 0x11, 0x8e, 0x5c, 0x2e, 0x5c, 0x03, 0x6d, - 0xde, 0x34, 0xc9, 0x15, 0xfa, 0x0d, 0x1c, 0xfd, 0x08, 0xfd, 0x1e, 0xce, 0x82, 0x63, 0x47, 0x47, - 0x69, 0x17, 0x3f, 0x86, 0xf4, 0xae, 0xd4, 0x82, 0x16, 0x6f, 0x70, 0x7b, 0xc9, 0xf3, 0x3e, 0x7f, - 0x78, 0x9f, 0xe0, 0xb6, 0x8c, 0x39, 0x65, 0x5a, 0x0f, 0x25, 0x67, 0x4e, 0x82, 0xb2, 0x54, 0x2a, - 0x27, 0x0c, 0x1f, 0x30, 0xa9, 0x22, 0xc6, 0x39, 0x64, 0xca, 0x59, 0x3a, 0x69, 0xd2, 0x71, 0x26, - 0xcc, 0x94, 0x68, 0x03, 0x0e, 0xfc, 0x13, 0x19, 0x73, 0xb2, 0x4d, 0x22, 0x3f, 0x90, 0xc8, 0xa4, - 0x19, 0x54, 0x52, 0x48, 0x21, 0xe7, 0xd0, 0xd5, 0x54, 0xd0, 0x83, 0x83, 0x14, 0x20, 0x1d, 0x0a, - 0xca, 0xb4, 0xa4, 0x4c, 0x29, 0x70, 0x6b, 0x91, 0x02, 0x3d, 0x2f, 0x9b, 0x68, 0x3d, 0x17, 0xb4, - 0x7a, 0x8c, 0x8f, 0xee, 0x56, 0x11, 0x7b, 0x9b, 0xe5, 0x4e, 0x81, 0x77, 0x92, 0xc4, 0x08, 0x6b, - 0xfb, 0x62, 0x9c, 0x09, 0xeb, 0xfc, 0x33, 0x5c, 0xc9, 0x9f, 0x85, 0xd1, 0xcc, 0xb8, 0x69, 0xa4, - 0xc1, 0xb8, 0x48, 0x26, 0x55, 0x74, 0x88, 0x4e, 0xf7, 0xfb, 0xfe, 0x36, 0x76, 0x0b, 0xc6, 0xf5, - 0x92, 0xcb, 0xbd, 0xc7, 0x59, 0xcd, 0xfb, 0x98, 0xd5, 0xbc, 0xba, 0xc0, 0xc7, 0xbf, 0x78, 0x58, - 0x0d, 0xca, 0x0a, 0xff, 0x0a, 0x07, 0xdf, 0x43, 0x47, 0xac, 0xd8, 0x5a, 0x5b, 0x55, 0xe5, 0x0e, - 0x95, 0xd6, 0x0b, 0xc2, 0xff, 0x72, 0x1f, 0xff, 0x19, 0xe1, 0xea, 0x2e, 0x33, 0xff, 0x9a, 0x94, - 0xac, 0x81, 0x94, 0x39, 0x4c, 0x70, 0xf3, 0x57, 0x72, 0xc5, 0x0d, 0xea, 0x5e, 0xf7, 0xe1, 0x75, - 0x11, 0xa2, 0xf9, 0x22, 0x44, 0xef, 0x8b, 0x10, 0x3d, 0x2d, 0x43, 0x6f, 0xbe, 0x0c, 0xbd, 0xb7, - 0x65, 0xe8, 0xdd, 0x77, 0x53, 0xe9, 0x06, 0x59, 0x4c, 0x38, 0x8c, 0x28, 0x07, 0x3b, 0x02, 0x4b, - 0x65, 0xcc, 0x1b, 0x29, 0xd0, 0x11, 0x24, 0xd9, 0x50, 0xd8, 0xd5, 0x07, 0xb0, 0xb4, 0x75, 0xd1, - 0xf8, 0x8a, 0xd0, 0xd8, 0x74, 0xef, 0xa6, 0x5a, 0xd8, 0xf8, 0x7f, 0xde, 0x7b, 0xfb, 0x33, 0x00, - 0x00, 0xff, 0xff, 0x2e, 0x9f, 0x3c, 0xd1, 0xc2, 0x02, 0x00, 0x00, + // 349 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0xbf, 0x4a, 0x03, 0x31, + 0x18, 0xbf, 0x0c, 0x8a, 0x66, 0x3c, 0x3a, 0x94, 0x43, 0xae, 0x52, 0x14, 0x5d, 0x9a, 0xd8, 0x16, + 0x11, 0xc4, 0xa5, 0x82, 0x43, 0x07, 0x45, 0x3b, 0xba, 0x1c, 0xb9, 0x5c, 0xb8, 0x06, 0xda, 0x7c, + 0x69, 0x92, 0x2b, 0xf4, 0x0d, 0x1c, 0x7d, 0x84, 0xbe, 0x87, 0xb3, 0xe0, 0xd8, 0xd1, 0x51, 0xda, + 0xc5, 0xc7, 0x90, 0xde, 0x95, 0x5a, 0xd0, 0xe2, 0x0d, 0x6e, 0x1f, 0xf9, 0x7d, 0xbf, 0x3f, 0x7c, + 0xbf, 0xe0, 0xb6, 0x8c, 0x39, 0x65, 0x5a, 0x0f, 0x24, 0x67, 0x4e, 0x82, 0xb2, 0x54, 0x2a, 0x27, + 0x0c, 0xef, 0x33, 0xa9, 0x22, 0xc6, 0x39, 0x64, 0xca, 0x59, 0x3a, 0x6e, 0xd2, 0x51, 0x26, 0xcc, + 0x84, 0x68, 0x03, 0x0e, 0xfc, 0x13, 0x19, 0x73, 0xb2, 0x49, 0x22, 0xbf, 0x90, 0xc8, 0xb8, 0x19, + 0x54, 0x52, 0x48, 0x21, 0xe7, 0xd0, 0xe5, 0x54, 0xd0, 0x83, 0x83, 0x14, 0x20, 0x1d, 0x08, 0xca, + 0xb4, 0xa4, 0x4c, 0x29, 0x70, 0x2b, 0x91, 0x02, 0x3d, 0x2f, 0x9b, 0x68, 0x35, 0x17, 0xb4, 0x7a, + 0x8c, 0x8f, 0x1e, 0x96, 0x11, 0xbb, 0xeb, 0xe5, 0x4e, 0x81, 0x77, 0x92, 0xc4, 0x08, 0x6b, 0x7b, + 0x62, 0x94, 0x09, 0xeb, 0xfc, 0x33, 0x5c, 0xc9, 0x9f, 0x85, 0xd1, 0xcc, 0xb8, 0x49, 0xa4, 0xc1, + 0xb8, 0x48, 0x26, 0x55, 0x74, 0x88, 0x4e, 0xf7, 0x7b, 0xfe, 0x26, 0x76, 0x0f, 0xc6, 0x75, 0x93, + 0xcb, 0xbd, 0xa7, 0x69, 0xcd, 0xfb, 0x9c, 0xd6, 0xbc, 0xba, 0xc0, 0xc7, 0x7f, 0x78, 0x58, 0x0d, + 0xca, 0x0a, 0xff, 0x0a, 0x07, 0x3f, 0x43, 0x47, 0xac, 0xd8, 0x5a, 0x59, 0x55, 0xe5, 0x16, 0x95, + 0xd6, 0x2b, 0xc2, 0x3b, 0xb9, 0x8f, 0xff, 0x82, 0x70, 0x75, 0x9b, 0x99, 0x7f, 0x4b, 0x4a, 0xd6, + 0x40, 0xca, 0x1c, 0x26, 0xb8, 0xfb, 0x2f, 0xb9, 0xe2, 0x06, 0x75, 0xef, 0x3a, 0x7a, 0x9b, 0x87, + 0x68, 0x36, 0x0f, 0xd1, 0xc7, 0x3c, 0x44, 0xcf, 0x8b, 0xd0, 0x9b, 0x2d, 0x42, 0xef, 0x7d, 0x11, + 0x7a, 0x8f, 0x37, 0xa9, 0x74, 0xfd, 0x2c, 0x26, 0x1c, 0x86, 0x94, 0x83, 0x1d, 0x82, 0xa5, 0x32, + 0xe6, 0x8d, 0x14, 0xe8, 0xb8, 0x45, 0x87, 0x90, 0x64, 0x03, 0x61, 0x97, 0x7f, 0xc0, 0xd2, 0xd6, + 0x45, 0xe3, 0x3b, 0x45, 0x63, 0x5d, 0xbf, 0x9b, 0x68, 0x61, 0xe3, 0xdd, 0xbc, 0xfa, 0xf6, 0x57, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x38, 0xd5, 0xa3, 0x36, 0xc5, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/apps/27-interchain-accounts/types/types.pb.go b/modules/apps/27-interchain-accounts/types/types.pb.go index 62324b0be0a..6233fa0eb26 100644 --- a/modules/apps/27-interchain-accounts/types/types.pb.go +++ b/modules/apps/27-interchain-accounts/types/types.pb.go @@ -205,33 +205,33 @@ func init() { } var fileDescriptor_39bab93e18d89799 = []byte{ - // 405 bytes of a gzipped FileDescriptorProto + // 407 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x51, 0x41, 0x6b, 0xd4, 0x40, 0x18, 0x4d, 0x34, 0x48, 0x3b, 0x4a, 0xd1, 0xb0, 0x42, 0x8d, 0x10, 0x4b, 0x2e, 0x16, 0x21, 0x33, - 0x76, 0x2b, 0x08, 0x42, 0xc1, 0x4d, 0x1a, 0x21, 0x17, 0x59, 0x62, 0x0a, 0x55, 0x84, 0x30, 0x33, - 0x19, 0xd3, 0xc1, 0x24, 0x13, 0x3a, 0x93, 0xd5, 0xf9, 0x07, 0xe2, 0xc9, 0x3f, 0xe0, 0xc9, 0x3f, - 0xe3, 0x71, 0x8f, 0x9e, 0x44, 0x76, 0xff, 0x81, 0xbf, 0x40, 0x32, 0xc1, 0x5d, 0x0f, 0x1e, 0x7a, - 0x7b, 0x33, 0xdf, 0xf7, 0x1e, 0xef, 0x7b, 0x0f, 0x1c, 0x73, 0x42, 0x11, 0xee, 0xba, 0x9a, 0x53, - 0xac, 0xb8, 0x68, 0x25, 0xe2, 0xad, 0x62, 0x97, 0xf4, 0x02, 0xf3, 0xb6, 0xc0, 0x94, 0x8a, 0xbe, - 0x55, 0x12, 0x2d, 0x8e, 0x90, 0xd2, 0x1d, 0x93, 0xb0, 0xbb, 0x14, 0x4a, 0xb8, 0x0f, 0x39, 0xa1, - 0xf0, 0x5f, 0x12, 0xfc, 0x0f, 0x09, 0x2e, 0x8e, 0xbc, 0x7b, 0x95, 0x10, 0x55, 0xcd, 0x90, 0xa1, - 0x91, 0xfe, 0x1d, 0xc2, 0xad, 0x1e, 0x35, 0xbc, 0x49, 0x25, 0x2a, 0x61, 0x20, 0x1a, 0xd0, 0xf8, - 0x1b, 0x3c, 0x07, 0x3b, 0x69, 0x14, 0xe7, 0x1f, 0x33, 0xfc, 0xc1, 0x7d, 0x02, 0x00, 0x11, 0xa5, - 0x2e, 0x88, 0x56, 0x4c, 0xee, 0xdb, 0x07, 0xf6, 0xe1, 0xad, 0xe8, 0xee, 0xef, 0x9f, 0x0f, 0xee, - 0x68, 0xdc, 0xd4, 0xcf, 0x82, 0xed, 0x2c, 0xc8, 0x76, 0x87, 0x47, 0x64, 0xf0, 0x09, 0xd8, 0x35, - 0x0a, 0x91, 0x28, 0xb5, 0xfb, 0x18, 0xec, 0x34, 0x4c, 0x4a, 0x5c, 0x19, 0x81, 0xeb, 0x87, 0x37, - 0xa7, 0x13, 0x38, 0x5a, 0x82, 0x7f, 0x2d, 0xc1, 0x59, 0xab, 0xb3, 0xcd, 0x56, 0xd0, 0x80, 0x49, - 0x1a, 0xc5, 0xb3, 0xf1, 0x86, 0x39, 0xa6, 0xef, 0x99, 0x3a, 0xc5, 0x0a, 0xbb, 0x33, 0xe0, 0x0c, - 0x09, 0x18, 0x1b, 0x7b, 0xd3, 0x10, 0x5e, 0x31, 0x01, 0x98, 0xeb, 0x8e, 0x65, 0x86, 0xea, 0xba, - 0xc0, 0x29, 0xb1, 0xc2, 0xfb, 0xd7, 0x86, 0x4b, 0x32, 0x83, 0x1f, 0x9d, 0x00, 0x67, 0xd8, 0x70, - 0x11, 0xb8, 0x9f, 0xbf, 0x9e, 0x27, 0x45, 0x72, 0x9e, 0xc4, 0x67, 0x79, 0x52, 0xe4, 0xe7, 0xc5, - 0xd9, 0xcb, 0x57, 0xf3, 0x24, 0x4e, 0x5f, 0xa4, 0xc9, 0xe9, 0x6d, 0xcb, 0xdb, 0xfb, 0xfc, 0xf5, - 0x00, 0x6c, 0xa7, 0x9e, 0xf3, 0xe9, 0x9b, 0x6f, 0x45, 0x6f, 0xbf, 0xaf, 0x7c, 0x7b, 0xb9, 0xf2, - 0xed, 0x5f, 0x2b, 0xdf, 0xfe, 0xb2, 0xf6, 0xad, 0xe5, 0xda, 0xb7, 0x7e, 0xac, 0x7d, 0xeb, 0x4d, - 0x54, 0x71, 0x75, 0xd1, 0x13, 0x48, 0x45, 0x83, 0xa8, 0x90, 0x8d, 0x90, 0x88, 0x13, 0x1a, 0x56, - 0x02, 0x35, 0xa2, 0xec, 0x6b, 0x26, 0x87, 0xd2, 0x25, 0x9a, 0x3e, 0x0d, 0xb7, 0xc6, 0xc3, 0x4d, - 0xdf, 0xa6, 0x6c, 0x72, 0xc3, 0x64, 0x74, 0xfc, 0x27, 0x00, 0x00, 0xff, 0xff, 0x70, 0xa3, 0x00, - 0x15, 0x24, 0x02, 0x00, 0x00, + 0x36, 0x15, 0x04, 0xa1, 0xe0, 0x26, 0x8d, 0x90, 0x8b, 0x2c, 0x31, 0x85, 0xea, 0x25, 0xcc, 0x4c, + 0xc6, 0x74, 0x30, 0xc9, 0x84, 0xce, 0x64, 0x75, 0xfe, 0x81, 0x78, 0xf2, 0x0f, 0x78, 0xf2, 0xcf, + 0x78, 0xec, 0xd1, 0x93, 0xc8, 0xee, 0x3f, 0xf0, 0x17, 0x48, 0x26, 0xb8, 0xeb, 0xc1, 0x83, 0xb7, + 0x37, 0xf3, 0x7d, 0xef, 0xf1, 0xbe, 0xf7, 0xc0, 0x31, 0x27, 0x14, 0xe1, 0xbe, 0x6f, 0x38, 0xc5, + 0x8a, 0x8b, 0x4e, 0x22, 0xde, 0x29, 0x76, 0x49, 0x2f, 0x30, 0xef, 0x4a, 0x4c, 0xa9, 0x18, 0x3a, + 0x25, 0xd1, 0xf2, 0x08, 0x29, 0xdd, 0x33, 0x09, 0xfb, 0x4b, 0xa1, 0x84, 0xfb, 0x90, 0x13, 0x0a, + 0xff, 0x26, 0xc1, 0x7f, 0x90, 0xe0, 0xf2, 0xc8, 0xbb, 0x57, 0x0b, 0x51, 0x37, 0x0c, 0x19, 0x1a, + 0x19, 0xde, 0x22, 0xdc, 0xe9, 0x49, 0xc3, 0x9b, 0xd5, 0xa2, 0x16, 0x06, 0xa2, 0x11, 0x4d, 0xbf, + 0xc1, 0x73, 0xb0, 0x93, 0xc5, 0x49, 0xf1, 0x21, 0xc7, 0xef, 0xdd, 0x27, 0x00, 0x10, 0x51, 0xe9, + 0x92, 0x68, 0xc5, 0xe4, 0xbe, 0x7d, 0x60, 0x1f, 0xde, 0x8a, 0xef, 0xfe, 0xfa, 0xf1, 0xe0, 0x8e, + 0xc6, 0x6d, 0xf3, 0x2c, 0xd8, 0xce, 0x82, 0x7c, 0x77, 0x7c, 0xc4, 0x06, 0x9f, 0x80, 0x5d, 0xa3, + 0x10, 0x8b, 0x4a, 0xbb, 0x8f, 0xc1, 0x4e, 0xcb, 0xa4, 0xc4, 0xb5, 0x11, 0xb8, 0x7e, 0x78, 0x33, + 0x9a, 0xc1, 0xc9, 0x12, 0xfc, 0x63, 0x09, 0xce, 0x3b, 0x9d, 0x6f, 0xb6, 0x82, 0x16, 0xcc, 0xb2, + 0x38, 0x99, 0x4f, 0x37, 0x2c, 0x30, 0x7d, 0xc7, 0xd4, 0x29, 0x56, 0xd8, 0x9d, 0x03, 0x67, 0x4c, + 0xc0, 0xd8, 0xd8, 0x8b, 0x42, 0xf8, 0x9f, 0x09, 0xc0, 0x42, 0xf7, 0x2c, 0x37, 0x54, 0xd7, 0x05, + 0x4e, 0x85, 0x15, 0xde, 0xbf, 0x36, 0x5e, 0x92, 0x1b, 0xfc, 0xe8, 0x04, 0x38, 0xe3, 0x86, 0x8b, + 0xc0, 0xfd, 0xe2, 0xf5, 0x22, 0x2d, 0xd3, 0xf3, 0x34, 0x39, 0x2b, 0xd2, 0xb2, 0x38, 0x2f, 0xcf, + 0x5e, 0xbe, 0x5a, 0xa4, 0x49, 0xf6, 0x22, 0x4b, 0x4f, 0x6f, 0x5b, 0xde, 0xde, 0xa7, 0x2f, 0x07, + 0x60, 0x3b, 0xf5, 0x9c, 0x8f, 0x5f, 0x7d, 0x2b, 0x2e, 0xbf, 0xad, 0x7c, 0xfb, 0x6a, 0xe5, 0xdb, + 0x3f, 0x57, 0xbe, 0xfd, 0x79, 0xed, 0x5b, 0x57, 0x6b, 0xdf, 0xfa, 0xbe, 0xf6, 0xad, 0x37, 0x69, + 0xcd, 0xd5, 0xc5, 0x40, 0x20, 0x15, 0x2d, 0xa2, 0x42, 0xb6, 0x42, 0x22, 0x4e, 0x68, 0x58, 0x0b, + 0xb4, 0x8c, 0x50, 0x2b, 0xaa, 0xa1, 0x61, 0x72, 0xec, 0x5d, 0xa2, 0xe8, 0x69, 0xb8, 0xf5, 0x1e, + 0x6e, 0x2a, 0x37, 0x7d, 0x93, 0x1b, 0x26, 0xa6, 0xe3, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x3e, + 0xd3, 0x1d, 0x0c, 0x27, 0x02, 0x00, 0x00, } func (m *IBCTxRaw) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/27-interchain-accounts/types/validate_test.go b/modules/apps/27-interchain-accounts/types/validate_test.go index aa1bb33c8ae..bca182a78b5 100644 --- a/modules/apps/27-interchain-accounts/types/validate_test.go +++ b/modules/apps/27-interchain-accounts/types/validate_test.go @@ -1,7 +1,7 @@ package types_test import ( - "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ) func (suite *TypesTestSuite) TestValidateVersion() { diff --git a/proto/ibc/applications/interchain_accounts/v1/account.proto b/proto/ibc/applications/interchain_accounts/v1/account.proto index b63aec16133..a94519cd6ac 100644 --- a/proto/ibc/applications/interchain_accounts/v1/account.proto +++ b/proto/ibc/applications/interchain_accounts/v1/account.proto @@ -5,7 +5,7 @@ import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; import "cosmos/auth/v1beta1/auth.proto"; -option go_package = "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"; +option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; // An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain message InterchainAccount { diff --git a/proto/ibc/applications/interchain_accounts/v1/genesis.proto b/proto/ibc/applications/interchain_accounts/v1/genesis.proto index 3afb804eb69..001eeb00a6c 100644 --- a/proto/ibc/applications/interchain_accounts/v1/genesis.proto +++ b/proto/ibc/applications/interchain_accounts/v1/genesis.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package ibc.applications.interchain_accounts.v1; -option go_package = "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"; +option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/applications/interchain_accounts/v1/query.proto b/proto/ibc/applications/interchain_accounts/v1/query.proto index 96232982f09..160912b0610 100644 --- a/proto/ibc/applications/interchain_accounts/v1/query.proto +++ b/proto/ibc/applications/interchain_accounts/v1/query.proto @@ -5,7 +5,7 @@ import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; import "ibc/applications/interchain_accounts/v1/account.proto"; -option go_package = "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"; +option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; // Query defines the gRPC querier service. service Query { diff --git a/proto/ibc/applications/interchain_accounts/v1/types.proto b/proto/ibc/applications/interchain_accounts/v1/types.proto index dc817a44963..c60b65bdd33 100644 --- a/proto/ibc/applications/interchain_accounts/v1/types.proto +++ b/proto/ibc/applications/interchain_accounts/v1/types.proto @@ -3,7 +3,7 @@ package ibc.applications.interchain_accounts.v1; import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; -option go_package = "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"; +option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; // Raw tx body message IBCTxRaw { diff --git a/testing/simapp/app.go b/testing/simapp/app.go index e5c30f3f11f..e5943e1a410 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -80,9 +80,9 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - ica "github.com/cosmos/ibc-go/modules/v2/apps/27-interchain-accounts" - icakeeper "github.com/cosmos/ibc-go/modules/v2/apps/27-interchain-accounts/keeper" - icatypes "github.com/cosmos/ibc-go/modules/v2/apps/27-interchain-accounts/types" + ica "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts" + icakeeper "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/keeper" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" transfer "github.com/cosmos/ibc-go/v2/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v2/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v2/modules/apps/transfer/types" @@ -95,7 +95,6 @@ import ( ibckeeper "github.com/cosmos/ibc-go/v2/modules/core/keeper" ibcmock "github.com/cosmos/ibc-go/v2/testing/mock" - authz "github.com/cosmos/cosmos-sdk/x/authz" authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" From c14931780abaa45248e93b90675177bf495dd613 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 23 Sep 2021 19:44:42 +0200 Subject: [PATCH 26/66] chore: update ica prefix for port identifiers (#434) * removing ICAPrefix const in favour of VersionPrefix * updating tests --- modules/apps/27-interchain-accounts/keeper/keeper_test.go | 2 +- modules/apps/27-interchain-accounts/module_test.go | 2 +- modules/apps/27-interchain-accounts/types/account.go | 6 +----- modules/apps/27-interchain-accounts/types/account_test.go | 4 ++-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index cf3aca35f96..118d38a7f9a 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -16,7 +16,7 @@ var ( // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes - TestPortID = fmt.Sprintf("ics-27-0-0-%s", TestOwnerAddress) + TestPortID = fmt.Sprintf("%s-0-0-%s", types.VersionPrefix, TestOwnerAddress) // TestVersion defines a resuable interchainaccounts version string for testing purposes TestVersion = types.NewAppVersion(types.VersionPrefix, types.GenerateAddress(TestPortID).String()) ) diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go index af5ea30eb7b..7539d216f70 100644 --- a/modules/apps/27-interchain-accounts/module_test.go +++ b/modules/apps/27-interchain-accounts/module_test.go @@ -15,7 +15,7 @@ var ( // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes - TestPortID = fmt.Sprintf("ics-27-0-0-%s", TestOwnerAddress) + TestPortID = fmt.Sprintf("%s-0-0-%s", types.VersionPrefix, TestOwnerAddress) // TestVersion defines a resuable interchainaccounts version string for testing purposes TestVersion = types.NewAppVersion(types.VersionPrefix, types.GenerateAddress(TestPortID).String()) ) diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index db44d4acf14..9a3c0acf29c 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -15,10 +15,6 @@ import ( connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" ) -const ( - ICAPrefix string = "ics-27" -) - // GenerateAddress returns an sdk.AccAddress using the provided port identifier func GenerateAddress(portID string) sdk.AccAddress { return sdk.AccAddress(tmhash.SumTruncated([]byte(portID))) @@ -50,7 +46,7 @@ func GeneratePortID(owner, connectionID, counterpartyConnectionID string) (strin return "", sdkerrors.Wrap(err, "invalid counterparty connection identifier") } - return fmt.Sprintf("%s-%d-%d-%s", ICAPrefix, connectionSeq, counterpartyConnectionSeq, owner), nil + return fmt.Sprintf("%s-%d-%d-%s", VersionPrefix, connectionSeq, counterpartyConnectionSeq, owner), nil } type InterchainAccountI interface { diff --git a/modules/apps/27-interchain-accounts/types/account_test.go b/modules/apps/27-interchain-accounts/types/account_test.go index 54a42759b26..6baa602edc2 100644 --- a/modules/apps/27-interchain-accounts/types/account_test.go +++ b/modules/apps/27-interchain-accounts/types/account_test.go @@ -59,7 +59,7 @@ func (suite *TypesTestSuite) TestGeneratePortID() { { "success", func() {}, - fmt.Sprintf("ics-27-0-0-%s", TestOwnerAddress), + fmt.Sprintf("%s-0-0-%s", types.VersionPrefix, TestOwnerAddress), true, }, { @@ -67,7 +67,7 @@ func (suite *TypesTestSuite) TestGeneratePortID() { func() { path.EndpointA.ConnectionID = "connection-1" }, - fmt.Sprintf("ics-27-1-0-%s", TestOwnerAddress), + fmt.Sprintf("%s-1-0-%s", types.VersionPrefix, TestOwnerAddress), true, }, { From 581ca296c54da007901955d17782a3dd159a14af Mon Sep 17 00:00:00 2001 From: Sean King Date: Fri, 24 Sep 2021 13:36:45 +0200 Subject: [PATCH 27/66] test: account/keeper tests for ICA (#420) * test: adding tests for account type * tests: adding test for keeper & account * fix: updating channel closing capabilities * fix: updating to use test library instead of hardcoded values * fix: updating error handling for account * test: adding test for account string comparison * fix: updating marshal yaml --- .../27-interchain-accounts/keeper/account.go | 13 --- .../keeper/account_test.go | 6 +- .../keeper/handshake.go | 20 ----- .../keeper/keeper_test.go | 14 +++ modules/apps/27-interchain-accounts/module.go | 4 +- .../27-interchain-accounts/types/account.go | 40 +++++---- .../types/account_test.go | 88 +++++++++++++++++++ .../27-interchain-accounts/types/errors.go | 1 + 8 files changed, 135 insertions(+), 51 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index 069ec805b85..d66c15ddab9 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -56,16 +56,3 @@ func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, accAddr sdk.AccAddres k.accountKeeper.SetAccount(ctx, interchainAccount) k.SetInterchainAccountAddress(ctx, portID, interchainAccount.Address) } - -func (k Keeper) GetInterchainAccount(ctx sdk.Context, addr sdk.AccAddress) (types.InterchainAccount, error) { - acc := k.accountKeeper.GetAccount(ctx, addr) - if acc == nil { - return types.InterchainAccount{}, sdkerrors.Wrap(types.ErrInterchainAccountNotFound, "there is no account") - } - - interchainAccount, ok := acc.(*types.InterchainAccount) - if !ok { - return types.InterchainAccount{}, sdkerrors.Wrap(types.ErrInterchainAccountNotFound, "account is not an interchain account") - } - return *interchainAccount, nil -} diff --git a/modules/apps/27-interchain-accounts/keeper/account_test.go b/modules/apps/27-interchain-accounts/keeper/account_test.go index 78a35eafaef..87630e29d91 100644 --- a/modules/apps/27-interchain-accounts/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/keeper/account_test.go @@ -17,7 +17,6 @@ func (suite *KeeperTestSuite) TestInitInterchainAccount() { malleate func() expPass bool }{ - { "success", func() {}, true, }, @@ -31,6 +30,11 @@ func (suite *KeeperTestSuite) TestInitInterchainAccount() { }, false, }, */ + { + "fails to generate port-id", func() { + owner = "" + }, false, + }, { "MsgChanOpenInit fails - channel is already active", func() { portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index ea1015eaefa..ce426c6a920 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -130,23 +130,3 @@ func (k Keeper) OnChanOpenConfirm( ) error { return nil } - -// May want to use these for re-opening a channel when it is closed -//// OnChanCloseInit implements the IBCModule interface -//func (am AppModule) OnChanCloseInit( -// ctx sdk.Context, -// portID, -// channelID string, -//) error { -// // Disallow user-initiated channel closing for transfer channels -// return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") -//} - -//// OnChanCloseConfirm implements the IBCModule interface -//func (am AppModule) OnChanCloseConfirm( -// ctx sdk.Context, -// portID, -// channelID string, -//) error { -// return nil -//} diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index 118d38a7f9a..cee2c5e4143 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -129,6 +129,20 @@ func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { suite.Require().Empty(retrievedAddr) } +func (suite *KeeperTestSuite) TestIsActiveChannel() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + owner := TestOwnerAddress + suite.coordinator.SetupConnections(path) + + err := suite.SetupICAPath(path, owner) + suite.Require().NoError(err) + portID := path.EndpointA.ChannelConfig.PortID + + isActive := suite.chainA.GetSimApp().ICAKeeper.IsActiveChannel(suite.chainA.GetContext(), portID) + suite.Require().Equal(isActive, true) +} + func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() { expectedAddr, portID := "address", "port" suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), portID, expectedAddr) diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 99bbf2d1bd8..59b4c71618a 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -187,7 +187,7 @@ func (am AppModule) OnChanCloseInit( channelID string, ) error { // Disallow user-initiated channel closing for interchain account channels - return nil + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") } func (am AppModule) OnChanCloseConfirm( @@ -195,7 +195,7 @@ func (am AppModule) OnChanCloseConfirm( portID, channelID string, ) error { - return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") + return nil } func (am AppModule) OnRecvPacket( diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index 9a3c0acf29c..a46390c3005 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -10,7 +10,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/tendermint/tendermint/crypto/tmhash" - yaml "gopkg.in/yaml.v2" + "gopkg.in/yaml.v2" connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" ) @@ -66,40 +66,44 @@ func NewInterchainAccount(ba *authtypes.BaseAccount, accountOwner string) *Inter } // SetPubKey - Implements AccountI -func (InterchainAccount) SetPubKey(pubKey crypto.PubKey) error { - return fmt.Errorf("not supported for interchain accounts") +func (ia InterchainAccount) SetPubKey(pubKey crypto.PubKey) error { + return sdkerrors.Wrap(ErrUnsupported, "cannot set public key for interchain account") } // SetSequence - Implements AccountI -func (InterchainAccount) SetSequence(seq uint64) error { - return fmt.Errorf("not supported for interchain accounts") +func (ia InterchainAccount) SetSequence(seq uint64) error { + return sdkerrors.Wrap(ErrUnsupported, "cannot set sequence number for interchain account") } func (ia InterchainAccount) Validate() error { + if strings.TrimSpace(ia.AccountOwner) == "" { + return sdkerrors.Wrap(ErrInvalidAccountAddress, "AccountOwner cannot be empty") + } + return ia.BaseAccount.Validate() } -type ibcAccountPretty struct { +type InterchainAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` Sequence uint64 `json:"sequence" yaml:"sequence"` - AccountOwner string `json:"address" yaml:"account_owner"` + AccountOwner string `json:"account_owner" yaml:"account_owner"` } func (ia InterchainAccount) String() string { out, _ := ia.MarshalYAML() - return out.(string) + return string(out) } -// MarshalYAML returns the YAML representation of a InterchainAccount. -func (ia InterchainAccount) MarshalYAML() (interface{}, error) { +// MarshalYAML returns the YAML representation of an InterchainAccount +func (ia InterchainAccount) MarshalYAML() ([]byte, error) { accAddr, err := sdk.AccAddressFromBech32(ia.Address) if err != nil { return nil, err } - bs, err := yaml.Marshal(ibcAccountPretty{ + bz, err := yaml.Marshal(InterchainAccountPretty{ Address: accAddr, PubKey: "", AccountNumber: ia.AccountNumber, @@ -111,28 +115,34 @@ func (ia InterchainAccount) MarshalYAML() (interface{}, error) { return nil, err } - return string(bs), nil + return bz, nil } -// MarshalJSON returns the JSON representation of a InterchainAccount. +// MarshalJSON returns the JSON representation of an InterchainAccount. func (ia InterchainAccount) MarshalJSON() ([]byte, error) { accAddr, err := sdk.AccAddressFromBech32(ia.Address) if err != nil { return nil, err } - return json.Marshal(ibcAccountPretty{ + bz, err := json.Marshal(InterchainAccountPretty{ Address: accAddr, PubKey: "", AccountNumber: ia.AccountNumber, Sequence: ia.Sequence, AccountOwner: ia.AccountOwner, }) + + if err != nil { + return nil, err + } + + return bz, nil } // UnmarshalJSON unmarshals raw JSON bytes into a ModuleAccount. func (ia *InterchainAccount) UnmarshalJSON(bz []byte) error { - var alias ibcAccountPretty + var alias InterchainAccountPretty if err := json.Unmarshal(bz, &alias); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/types/account_test.go b/modules/apps/27-interchain-accounts/types/account_test.go index 6baa602edc2..fb3f3126c55 100644 --- a/modules/apps/27-interchain-accounts/types/account_test.go +++ b/modules/apps/27-interchain-accounts/types/account_test.go @@ -1,11 +1,15 @@ package types_test import ( + "encoding/json" "fmt" "testing" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/suite" + "gopkg.in/yaml.v2" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/v2/testing" @@ -117,3 +121,87 @@ func (suite *TypesTestSuite) TestGeneratePortID() { }) } } + +func (suite *TypesTestSuite) TestInterchainAccount() { + pubkey := secp256k1.GenPrivKey().PubKey() + addr := sdk.AccAddress(pubkey.Address()) + baseAcc := authtypes.NewBaseAccountWithAddress(addr) + interchainAcc := types.NewInterchainAccount(baseAcc, TestOwnerAddress) + + // should fail when trying to set the public key or sequence of an interchain account + err := interchainAcc.SetPubKey(pubkey) + suite.Require().Error(err) + err = interchainAcc.SetSequence(1) + suite.Require().Error(err) +} + +func (suite *TypesTestSuite) TestGenesisAccountValidate() { + pubkey := secp256k1.GenPrivKey().PubKey() + addr := sdk.AccAddress(pubkey.Address()) + baseAcc := authtypes.NewBaseAccountWithAddress(addr) + pubkey = secp256k1.GenPrivKey().PubKey() + ownerAddr := sdk.AccAddress(pubkey.Address()) + + testCases := []struct { + name string + acc authtypes.GenesisAccount + expPass bool + }{ + { + "success", + types.NewInterchainAccount(baseAcc, ownerAddr.String()), + true, + }, + { + "interchain account with empty AccountOwner field", + types.NewInterchainAccount(baseAcc, ""), + false, + }, + } + + for _, tc := range testCases { + err := tc.acc.Validate() + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + } +} + +func (suite *TypesTestSuite) TestInterchainAccountMarshalYAML() { + addr := suite.chainA.SenderAccount.GetAddress() + ba := authtypes.NewBaseAccountWithAddress(addr) + + interchainAcc := types.NewInterchainAccount(ba, suite.chainB.SenderAccount.GetAddress().String()) + bz, err := yaml.Marshal(types.InterchainAccountPretty{ + Address: addr, + PubKey: "", + AccountNumber: interchainAcc.AccountNumber, + Sequence: interchainAcc.Sequence, + AccountOwner: interchainAcc.AccountOwner, + }) + suite.Require().NoError(err) + + bz1, err := interchainAcc.MarshalYAML() + suite.Require().Equal(string(bz), string(bz1)) +} + +func (suite *TypesTestSuite) TestInterchainAccountJSON() { + addr := suite.chainA.SenderAccount.GetAddress() + ba := authtypes.NewBaseAccountWithAddress(addr) + + interchainAcc := types.NewInterchainAccount(ba, suite.chainB.SenderAccount.GetAddress().String()) + + bz, err := json.Marshal(interchainAcc) + suite.Require().NoError(err) + + bz1, err := interchainAcc.MarshalJSON() + suite.Require().NoError(err) + suite.Require().Equal(string(bz), string(bz1)) + + var a types.InterchainAccount + suite.Require().NoError(json.Unmarshal(bz, &a)) + suite.Require().Equal(a.String(), interchainAcc.String()) +} diff --git a/modules/apps/27-interchain-accounts/types/errors.go b/modules/apps/27-interchain-accounts/types/errors.go index 5c5bf3fed44..6b05a626a82 100644 --- a/modules/apps/27-interchain-accounts/types/errors.go +++ b/modules/apps/27-interchain-accounts/types/errors.go @@ -16,4 +16,5 @@ var ( ErrActiveChannelNotFound = sdkerrors.Register(ModuleName, 10, "no active channel for this owner") ErrInvalidVersion = sdkerrors.Register(ModuleName, 11, "invalid interchain accounts version") ErrInvalidAccountAddress = sdkerrors.Register(ModuleName, 12, "invalid account address") + ErrUnsupported = sdkerrors.Register(ModuleName, 13, "interchain account does not support this action") ) From c4fcc0e00397549fa730b34458e1396366c079ee Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Fri, 24 Sep 2021 13:50:22 +0200 Subject: [PATCH 28/66] feat: module account address derivation (#428) * adding module account to interchain-accounts with associated changes * configuring ica module account in simapp * Update modules/apps/27-interchain-accounts/keeper/keeper.go Co-authored-by: Sean King * updating godoc and import alias Co-authored-by: Sean King --- .../keeper/grpc_query_test.go | 6 ++--- .../keeper/handshake.go | 2 +- .../27-interchain-accounts/keeper/keeper.go | 27 +++++++++++++++++++ .../keeper/keeper_test.go | 9 +++++-- modules/apps/27-interchain-accounts/module.go | 6 +---- .../27-interchain-accounts/module_test.go | 7 ++++- .../27-interchain-accounts/types/account.go | 11 ++++---- .../types/account_test.go | 2 +- .../types/expected_keepers.go | 6 +++-- testing/simapp/app.go | 1 + 10 files changed, 57 insertions(+), 20 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go b/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go index 1beed47d7e1..d514d6bbc34 100644 --- a/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go +++ b/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go @@ -48,12 +48,12 @@ func (suite *KeeperTestSuite) TestQueryInterchainAccountAddress() { { "success", func() { - expAddr = authtypes.NewBaseAccountWithAddress(types.GenerateAddress("ics-27")).GetAddress().String() + expAddr = authtypes.NewBaseAccountWithAddress(types.GenerateAddress(TestAccAddress, TestPortID)).GetAddress().String() req = &types.QueryInterchainAccountAddressRequest{ - CounterpartyPortId: "ics-27", + CounterpartyPortId: TestPortID, } - suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), "ics-27", expAddr) + suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), TestPortID, expAddr) }, true, }, diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index ce426c6a920..6b929f547d9 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -88,7 +88,7 @@ func (k Keeper) OnChanOpenTry( } // Check to ensure that the version string contains the expected address generated from the Counterparty portID - accAddr := types.GenerateAddress(counterparty.PortId) + accAddr := types.GenerateAddress(k.accountKeeper.GetModuleAddress(types.ModuleName), counterparty.PortId) parsedAddr := types.ParseAddressFromVersion(version) if parsedAddr != accAddr.String() { return sdkerrors.Wrapf(types.ErrInvalidAccountAddress, "version contains invalid account address: expected %s, got %s", parsedAddr, accAddr) diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index 93fe12ba9ac..832755817b5 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -7,11 +7,13 @@ import ( "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" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) @@ -37,6 +39,12 @@ func NewKeeper( channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, accountKeeper types.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, hook types.IBCAccountHooks, ) Keeper { + + // ensure ibc interchain accounts module account is set + if addr := accountKeeper.GetModuleAddress(types.ModuleName); addr == nil { + panic("the Interchain Accounts module account has not been set") + } + return Keeper{ storeKey: key, cdc: cdc, @@ -163,3 +171,22 @@ func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portID string, addr store := ctx.KVStore(k.storeKey) store.Set(types.KeyOwnerAccount(portID), []byte(address)) } + +// NegotiateAppVersion handles application version negotation for the IBC interchain accounts module +func (k Keeper) NegotiateAppVersion( + ctx sdk.Context, + order channeltypes.Order, + connectionID string, + portID string, + counterparty channeltypes.Counterparty, + proposedVersion string, +) (string, error) { + if proposedVersion != types.VersionPrefix { + return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "failed to negotiate app version: expected %s, got %s", types.VersionPrefix, proposedVersion) + } + + moduleAccAddr := k.accountKeeper.GetModuleAddress(types.ModuleName) + accAddr := types.GenerateAddress(moduleAccAddr, counterparty.PortId) + + return types.NewAppVersion(types.VersionPrefix, accAddr.String()), nil +} diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index cee2c5e4143..1930f327bd9 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -4,8 +4,10 @@ import ( "fmt" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/crypto" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" @@ -13,12 +15,15 @@ import ( ) var ( + // TestAccAddress defines a resuable bech32 address for testing purposes + // TODO: update crypto.AddressHash() when sdk uses address.Module() + TestAccAddress = types.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))), TestPortID) // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes TestPortID = fmt.Sprintf("%s-0-0-%s", types.VersionPrefix, TestOwnerAddress) // TestVersion defines a resuable interchainaccounts version string for testing purposes - TestVersion = types.NewAppVersion(types.VersionPrefix, types.GenerateAddress(TestPortID).String()) + TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) ) type KeeperTestSuite struct { @@ -118,7 +123,7 @@ func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { suite.Require().NoError(err) counterpartyPortID := path.EndpointA.ChannelConfig.PortID - expectedAddr := authtypes.NewBaseAccountWithAddress(types.GenerateAddress(counterpartyPortID)).GetAddress() + expectedAddr := authtypes.NewBaseAccountWithAddress(types.GenerateAddress(suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName), counterpartyPortID)).GetAddress() retrievedAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), counterpartyPortID) suite.Require().True(found) diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 59b4c71618a..59a02825112 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -264,9 +264,5 @@ func (am AppModule) NegotiateAppVersion( counterparty channeltypes.Counterparty, proposedVersion string, ) (string, error) { - if proposedVersion != types.VersionPrefix { - return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "failed to negotiate app version: expected %s, got %s", types.VersionPrefix, proposedVersion) - } - - return types.NewAppVersion(types.VersionPrefix, types.GenerateAddress(counterparty.PortId).String()), nil + return am.keeper.NegotiateAppVersion(ctx, order, connectionID, portID, counterparty, proposedVersion) } diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go index 7539d216f70..c3c3a30f2b1 100644 --- a/modules/apps/27-interchain-accounts/module_test.go +++ b/modules/apps/27-interchain-accounts/module_test.go @@ -4,7 +4,9 @@ import ( "fmt" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/crypto" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" @@ -12,12 +14,15 @@ import ( ) var ( + // TestAccAddress defines a resuable bech32 address for testing purposes + // TODO: update crypto.AddressHash() when sdk uses address.Module() + TestAccAddress = types.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))), TestPortID) // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes TestPortID = fmt.Sprintf("%s-0-0-%s", types.VersionPrefix, TestOwnerAddress) // TestVersion defines a resuable interchainaccounts version string for testing purposes - TestVersion = types.NewAppVersion(types.VersionPrefix, types.GenerateAddress(TestPortID).String()) + TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) ) type InterchainAccountsTestSuite struct { diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index a46390c3005..f664bc1186d 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -7,17 +7,18 @@ import ( crypto "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkaddress "github.com/cosmos/cosmos-sdk/types/address" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/tendermint/tendermint/crypto/tmhash" - "gopkg.in/yaml.v2" + yaml "gopkg.in/yaml.v2" connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" ) -// GenerateAddress returns an sdk.AccAddress using the provided port identifier -func GenerateAddress(portID string) sdk.AccAddress { - return sdk.AccAddress(tmhash.SumTruncated([]byte(portID))) +// GenerateAddress returns an sdk.AccAddress derived using the provided module account address and port identifier. +// The sdk.AccAddress returned is a sub-address of the module account, using the controller chain's port identifier as the derivation key +func GenerateAddress(moduleAccAddr sdk.AccAddress, portID string) sdk.AccAddress { + return sdk.AccAddress(sdkaddress.Derive(moduleAccAddr, []byte(portID))) } // ParseAddressFromVersion trims the interchainaccounts version prefix and returns the associated account address diff --git a/modules/apps/27-interchain-accounts/types/account_test.go b/modules/apps/27-interchain-accounts/types/account_test.go index fb3f3126c55..644121a6652 100644 --- a/modules/apps/27-interchain-accounts/types/account_test.go +++ b/modules/apps/27-interchain-accounts/types/account_test.go @@ -41,7 +41,7 @@ func TestTypesTestSuite(t *testing.T) { } func (suite *TypesTestSuite) TestGenerateAddress() { - addr := types.GenerateAddress("test-port-id") + addr := types.GenerateAddress([]byte{}, "test-port-id") accAddr, err := sdk.AccAddressFromBech32(addr.String()) suite.Require().NoError(err, "TestGenerateAddress failed") diff --git a/modules/apps/27-interchain-accounts/types/expected_keepers.go b/modules/apps/27-interchain-accounts/types/expected_keepers.go index 4a3aa86d55b..add14e17b0b 100644 --- a/modules/apps/27-interchain-accounts/types/expected_keepers.go +++ b/modules/apps/27-interchain-accounts/types/expected_keepers.go @@ -16,10 +16,12 @@ type Router interface { // AccountKeeper defines the contract required for account APIs. type AccountKeeper interface { - SetAccount(ctx sdk.Context, acc authtypes.AccountI) - GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI NewAccount(ctx sdk.Context, acc authtypes.AccountI) authtypes.AccountI NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI + GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI + SetAccount(ctx sdk.Context, acc authtypes.AccountI) + GetModuleAccount(ctx sdk.Context, name string) authtypes.ModuleAccountI + GetModuleAddress(name string) sdk.AccAddress } // ChannelKeeper defines the expected IBC channel keeper diff --git a/testing/simapp/app.go b/testing/simapp/app.go index e5943e1a410..211fe55c212 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -147,6 +147,7 @@ var ( stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, govtypes.ModuleName: {authtypes.Burner}, ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + icatypes.ModuleName: nil, } ) From df1aa03af1900f7cbf11f1daa79da6c726bc691e Mon Sep 17 00:00:00 2001 From: Sean King Date: Fri, 24 Sep 2021 14:36:22 +0200 Subject: [PATCH 29/66] ICA: tests for module.go (#424) * test * test: adding module.go test with handshake callback tests * tests: adding key tests --- .../27-interchain-accounts/module_test.go | 163 +++++++++++++++++- .../27-interchain-accounts/types/keys_test.go | 14 ++ 2 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/types/keys_test.go diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go index c3c3a30f2b1..778a676f20b 100644 --- a/modules/apps/27-interchain-accounts/module_test.go +++ b/modules/apps/27-interchain-accounts/module_test.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) @@ -36,6 +37,10 @@ type InterchainAccountsTestSuite struct { chainC *ibctesting.TestChain } +func TestICATestSuite(t *testing.T) { + suite.Run(t, new(InterchainAccountsTestSuite)) +} + func (suite *InterchainAccountsTestSuite) SetupTest() { suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) @@ -55,8 +60,162 @@ func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { return path } -func TestICATestSuite(t *testing.T) { - suite.Run(t, new(InterchainAccountsTestSuite)) +func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { + portID, err := types.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) + if err != nil { + return err + } + channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) + + if err := endpoint.Chain.GetSimApp().ICAKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, owner); err != nil { + return err + } + + // commit state changes for proof verification + endpoint.Chain.App.Commit() + endpoint.Chain.NextBlock() + + // update port/channel ids + endpoint.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + endpoint.ChannelConfig.PortID = portID + return nil +} + +// SetupICAPath invokes the InterchainAccounts entrypoint and subsequent channel handshake handlers +func SetupICAPath(path *ibctesting.Path, owner string) error { + if err := InitInterchainAccount(path.EndpointA, owner); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenTry(); err != nil { + return err + } + + if err := path.EndpointA.ChanOpenAck(); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenConfirm(); err != nil { + return err + } + + return nil +} + +func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + // mock init interchain account + portID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + suite.Require().NoError(err) + portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) + suite.chainA.GetSimApp().ICAKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) + path.EndpointA.ChannelConfig.PortID = portID + + // default values + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + channel := &channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: channeltypes.ORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: types.VersionPrefix, + } + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) + suite.Require().NoError(err) + + chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(ibctesting.TransferPort, path.EndpointA.ChannelID)) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), + ) + suite.Require().NoError(err) +} + +func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + counterpartyVersion := types.VersionPrefix + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + // default values + counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channel := &channeltypes.Channel{ + State: channeltypes.TRYOPEN, + Ordering: channeltypes.ORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointB.ConnectionID}, + Version: types.VersionPrefix, + } + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) + suite.Require().NoError(err) + + chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(ibctesting.TransferPort, path.EndpointA.ChannelID)) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenTry(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), counterpartyVersion, + ) +} + +func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + counterpartyVersion := types.VersionPrefix + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyVersion) + suite.Require().NoError(err) +} + +func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanOpenAck() + suite.Require().NoError(err) + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenConfirm(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().NoError(err) } func (suite *InterchainAccountsTestSuite) TestNegotiateAppVersion() { diff --git a/modules/apps/27-interchain-accounts/types/keys_test.go b/modules/apps/27-interchain-accounts/types/keys_test.go new file mode 100644 index 00000000000..43db0bf8a13 --- /dev/null +++ b/modules/apps/27-interchain-accounts/types/keys_test.go @@ -0,0 +1,14 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" +) + +func TestKeyActiveChannel(t *testing.T) { + key := types.KeyActiveChannel("owner") + require.Equal(t, string(key), "activeChannel/owner") +} From 77b786938aa4ba5ea755d64a0b972ee65dd14a61 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 27 Sep 2021 13:06:04 +0200 Subject: [PATCH 30/66] additional code cov and clean up (#440) --- .../27-interchain-accounts/keeper/account.go | 2 +- .../keeper/account_test.go | 29 +++++++-------- .../27-interchain-accounts/types/account.go | 8 ++--- .../types/account_test.go | 36 +++++++++---------- .../27-interchain-accounts/types/codec.go | 8 ++--- .../types/expected_keepers.go | 1 + .../apps/27-interchain-accounts/types/keys.go | 8 ++--- .../27-interchain-accounts/types/keys_test.go | 15 ++++---- .../27-interchain-accounts/types/querier.go | 7 ---- 9 files changed, 55 insertions(+), 59 deletions(-) delete mode 100644 modules/apps/27-interchain-accounts/types/querier.go diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index d66c15ddab9..f10bd73e005 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -22,7 +22,7 @@ func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpart return err } - if k.IsBound(ctx, portID) { + if k.portKeeper.IsBound(ctx, portID) { return sdkerrors.Wrap(types.ErrPortAlreadyBound, portID) } diff --git a/modules/apps/27-interchain-accounts/keeper/account_test.go b/modules/apps/27-interchain-accounts/keeper/account_test.go index 87630e29d91..3d5a1bb31af 100644 --- a/modules/apps/27-interchain-accounts/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/keeper/account_test.go @@ -20,27 +20,28 @@ func (suite *KeeperTestSuite) TestInitInterchainAccount() { { "success", func() {}, true, }, - /* - // TODO: https://github.com/cosmos/ibc-go/issues/288 - { - "port is already bound", func() { - // mock init interchain account - portID := suite.chainA.GetSimApp().ICAKeeper.GeneratePortId(owner, path.EndpointA.ConnectionID) - suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) - }, false, - }, - */ { - "fails to generate port-id", func() { + "port is already bound", + func() { + suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), TestPortID) + }, + false, + }, + { + "fails to generate port-id", + func() { owner = "" - }, false, + }, + false, }, { - "MsgChanOpenInit fails - channel is already active", func() { + "MsgChanOpenInit fails - channel is already active", + func() { portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) suite.Require().NoError(err) suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID) - }, false, + }, + false, }, } diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index f664bc1186d..a9f1fdcde1a 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -84,7 +84,7 @@ func (ia InterchainAccount) Validate() error { return ia.BaseAccount.Validate() } -type InterchainAccountPretty struct { +type interchainAccountPretty struct { Address sdk.AccAddress `json:"address" yaml:"address"` PubKey string `json:"public_key" yaml:"public_key"` AccountNumber uint64 `json:"account_number" yaml:"account_number"` @@ -104,7 +104,7 @@ func (ia InterchainAccount) MarshalYAML() ([]byte, error) { return nil, err } - bz, err := yaml.Marshal(InterchainAccountPretty{ + bz, err := yaml.Marshal(interchainAccountPretty{ Address: accAddr, PubKey: "", AccountNumber: ia.AccountNumber, @@ -126,7 +126,7 @@ func (ia InterchainAccount) MarshalJSON() ([]byte, error) { return nil, err } - bz, err := json.Marshal(InterchainAccountPretty{ + bz, err := json.Marshal(interchainAccountPretty{ Address: accAddr, PubKey: "", AccountNumber: ia.AccountNumber, @@ -143,7 +143,7 @@ func (ia InterchainAccount) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals raw JSON bytes into a ModuleAccount. func (ia *InterchainAccount) UnmarshalJSON(bz []byte) error { - var alias InterchainAccountPretty + var alias interchainAccountPretty if err := json.Unmarshal(bz, &alias); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/types/account_test.go b/modules/apps/27-interchain-accounts/types/account_test.go index 644121a6652..acca53e39c4 100644 --- a/modules/apps/27-interchain-accounts/types/account_test.go +++ b/modules/apps/27-interchain-accounts/types/account_test.go @@ -9,7 +9,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/suite" - "gopkg.in/yaml.v2" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/v2/testing" @@ -48,6 +47,13 @@ func (suite *TypesTestSuite) TestGenerateAddress() { suite.Require().NotEmpty(accAddr) } +func (suite *TypesTestSuite) TestParseAddressFromVersion() { + version := types.NewAppVersion(types.VersionPrefix, TestOwnerAddress) + + addr := types.ParseAddressFromVersion(version) + suite.Require().Equal(TestOwnerAddress, addr) +} + func (suite *TypesTestSuite) TestGeneratePortID() { var ( path *ibctesting.Path @@ -75,25 +81,25 @@ func (suite *TypesTestSuite) TestGeneratePortID() { true, }, { - "invalid owner address", + "invalid connectionID", func() { - owner = " " + path.EndpointA.ConnectionID = "connection" }, "", false, }, { - "invalid connectionID", + "invalid counterparty connectionID", func() { - path.EndpointA.ConnectionID = "connection" + path.EndpointB.ConnectionID = "connection" }, "", false, }, { - "invalid counterparty connectionID", + "invalid owner address", func() { - path.EndpointB.ConnectionID = "connection" + owner = " " }, "", false, @@ -172,20 +178,14 @@ func (suite *TypesTestSuite) TestGenesisAccountValidate() { func (suite *TypesTestSuite) TestInterchainAccountMarshalYAML() { addr := suite.chainA.SenderAccount.GetAddress() - ba := authtypes.NewBaseAccountWithAddress(addr) + baseAcc := authtypes.NewBaseAccountWithAddress(addr) - interchainAcc := types.NewInterchainAccount(ba, suite.chainB.SenderAccount.GetAddress().String()) - bz, err := yaml.Marshal(types.InterchainAccountPretty{ - Address: addr, - PubKey: "", - AccountNumber: interchainAcc.AccountNumber, - Sequence: interchainAcc.Sequence, - AccountOwner: interchainAcc.AccountOwner, - }) + interchainAcc := types.NewInterchainAccount(baseAcc, suite.chainB.SenderAccount.GetAddress().String()) + bz, err := interchainAcc.MarshalYAML() suite.Require().NoError(err) - bz1, err := interchainAcc.MarshalYAML() - suite.Require().Equal(string(bz), string(bz1)) + expected := fmt.Sprintf("address: %s\npublic_key: \"\"\naccount_number: 0\nsequence: 0\naccount_owner: %s\n", suite.chainA.SenderAccount.GetAddress(), suite.chainB.SenderAccount.GetAddress()) + suite.Require().Equal(expected, string(bz)) } func (suite *TypesTestSuite) TestInterchainAccountJSON() { diff --git a/modules/apps/27-interchain-accounts/types/codec.go b/modules/apps/27-interchain-accounts/types/codec.go index c46946deaa2..bfa8cde043c 100644 --- a/modules/apps/27-interchain-accounts/types/codec.go +++ b/modules/apps/27-interchain-accounts/types/codec.go @@ -6,6 +6,10 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) +var ( + ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) +) + // RegisterLegacyAminoCodec registers the account interfaces and concrete types on the // provided LegacyAmino codec. These types are used for Amino JSON serialization func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { @@ -18,7 +22,3 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations((*authtypes.AccountI)(nil), &InterchainAccount{}) } - -var ( - ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) -) diff --git a/modules/apps/27-interchain-accounts/types/expected_keepers.go b/modules/apps/27-interchain-accounts/types/expected_keepers.go index add14e17b0b..8b355e504a0 100644 --- a/modules/apps/27-interchain-accounts/types/expected_keepers.go +++ b/modules/apps/27-interchain-accounts/types/expected_keepers.go @@ -46,5 +46,6 @@ type ConnectionKeeper interface { // PortKeeper defines the expected IBC port keeper type PortKeeper interface { BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability + IsBound(ctx sdk.Context, portID string) bool LookupModuleByPort(ctx sdk.Context, portID string) (string, *capabilitytypes.Capability, error) } diff --git a/modules/apps/27-interchain-accounts/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go index 51841d0de0b..8640226191f 100644 --- a/modules/apps/27-interchain-accounts/types/keys.go +++ b/modules/apps/27-interchain-accounts/types/keys.go @@ -38,11 +38,11 @@ func NewAppVersion(versionPrefix, accAddr string) string { } // KeyActiveChannel creates and returns a new key used for active channels store operations -func KeyActiveChannel(portId string) []byte { - return []byte(fmt.Sprintf("activeChannel/%s", portId)) +func KeyActiveChannel(portID string) []byte { + return []byte(fmt.Sprintf("activeChannel/%s", portID)) } // KeyOwnerAccount creates and returns a new key used for owner account store operations -func KeyOwnerAccount(portId string) []byte { - return []byte(fmt.Sprintf("owner/%s", portId)) +func KeyOwnerAccount(portID string) []byte { + return []byte(fmt.Sprintf("owner/%s", portID)) } diff --git a/modules/apps/27-interchain-accounts/types/keys_test.go b/modules/apps/27-interchain-accounts/types/keys_test.go index 43db0bf8a13..037061a3d3e 100644 --- a/modules/apps/27-interchain-accounts/types/keys_test.go +++ b/modules/apps/27-interchain-accounts/types/keys_test.go @@ -1,14 +1,15 @@ package types_test import ( - "testing" - - "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ) -func TestKeyActiveChannel(t *testing.T) { - key := types.KeyActiveChannel("owner") - require.Equal(t, string(key), "activeChannel/owner") +func (suite *TypesTestSuite) TestKeyActiveChannel() { + key := types.KeyActiveChannel("port-id") + suite.Require().Equal("activeChannel/port-id", string(key)) +} + +func (suite *TypesTestSuite) TestKeyOwnerAccount() { + key := types.KeyOwnerAccount("port-id") + suite.Require().Equal("owner/port-id", string(key)) } diff --git a/modules/apps/27-interchain-accounts/types/querier.go b/modules/apps/27-interchain-accounts/types/querier.go deleted file mode 100644 index 34faaba304b..00000000000 --- a/modules/apps/27-interchain-accounts/types/querier.go +++ /dev/null @@ -1,7 +0,0 @@ -package types - -// query endpoints supported by the auth Querier -const ( - QueryIBCAccount = "ibcaccount" - QueryIBCAccountFromData = "ibcaccount-from-data" -) From 0db5c95d46a78fe03322d7b5664075ff1b56e869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 29 Sep 2021 13:03:59 +0200 Subject: [PATCH 31/66] split ica module.go into ibc_module.go (#453) Splits IBCModule logic into separate ibc_module.go file and updates app.go registration --- .../apps/27-interchain-accounts/ibc_module.go | 161 ++++++++++++++++++ modules/apps/27-interchain-accounts/module.go | 138 +-------------- testing/simapp/app.go | 3 +- 3 files changed, 164 insertions(+), 138 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/ibc_module.go diff --git a/modules/apps/27-interchain-accounts/ibc_module.go b/modules/apps/27-interchain-accounts/ibc_module.go new file mode 100644 index 00000000000..80e798af826 --- /dev/null +++ b/modules/apps/27-interchain-accounts/ibc_module.go @@ -0,0 +1,161 @@ +package interchain_accounts + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" +) + +// IBCModule implements the ICS26 callbacks for interchain accounts given the +// interchain account keeper and underlying application. +type IBCModule struct { + keeper keeper.Keeper + app porttypes.IBCModule +} + +// NewIBCModule creates a new IBCModule given the keeper and underlying application +func NewIBCModule(k keeper.Keeper, app porttypes.IBCModule) IBCModule { + return IBCModule{ + keeper: k, + app: app, + } +} + +// Implement IBCModule callbacks +func (im IBCModule) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) error { + return im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) +} + +func (im IBCModule) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version, + counterpartyVersion string, +) error { + return im.keeper.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version, counterpartyVersion) +} + +func (im IBCModule) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyVersion string, +) error { + return im.keeper.OnChanOpenAck(ctx, portID, channelID, counterpartyVersion) +} + +func (im IBCModule) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return im.keeper.OnChanOpenConfirm(ctx, portID, channelID) +} + +func (im IBCModule) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + // Disallow user-initiated channel closing for interchain account channels + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") +} + +func (im IBCModule) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +func (im IBCModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + _ sdk.AccAddress, +) ibcexported.Acknowledgement { + ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + + var data types.IBCAccountPacketData + if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + ack = channeltypes.NewErrorAcknowledgement(fmt.Sprintf("cannot unmarshal ICS-27 interchain account packet data: %s", err.Error())) + } + + // only attempt the application logic if the packet data + // was successfully decoded + if ack.Success() { + err := im.keeper.OnRecvPacket(ctx, packet) + if err != nil { + ack = channeltypes.NewErrorAcknowledgement(err.Error()) + } + } + + // NOTE: acknowledgement will be written synchronously during IBC handler execution. + return ack +} + +func (im IBCModule) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + _ sdk.AccAddress, +) error { + var ack channeltypes.Acknowledgement + + if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-27 interchain account packet acknowledgment: %v", err) + } + var data types.IBCAccountPacketData + if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-27 interchain account packet data: %s", err.Error()) + } + + if err := im.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil { + return err + } + + return nil +} + +func (im IBCModule) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, + _ sdk.AccAddress, +) error { + // TODO + return nil +} + +// NegotiateAppVersion implements the IBCModule interface +func (im IBCModule) NegotiateAppVersion( + ctx sdk.Context, + order channeltypes.Order, + connectionID string, + portID string, + counterparty channeltypes.Counterparty, + proposedVersion string, +) (string, error) { + return im.keeper.NegotiateAppVersion(ctx, order, connectionID, portID, counterparty, proposedVersion) +} diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 59a02825112..ab085b886dc 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -2,7 +2,6 @@ package interchain_accounts import ( "encoding/json" - "fmt" "github.com/gorilla/mux" "github.com/spf13/cobra" @@ -11,23 +10,19 @@ import ( "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/types/module" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/grpc-ecosystem/grpc-gateway/runtime" abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/client/cli" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/keeper" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" - ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" ) var ( _ module.AppModule = AppModule{} - _ porttypes.IBCModule = AppModule{} + _ porttypes.IBCModule = IBCModule{} _ module.AppModuleBasic = AppModuleBasic{} ) @@ -135,134 +130,3 @@ func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } - -// Implement IBCModule callbacks -func (am AppModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) error { - return am.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) -} - -func (am AppModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version, - counterpartyVersion string, -) error { - return am.keeper.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version, counterpartyVersion) -} - -func (am AppModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - return am.keeper.OnChanOpenAck(ctx, portID, channelID, counterpartyVersion) -} - -func (am AppModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - return am.keeper.OnChanOpenConfirm(ctx, portID, channelID) -} - -func (am AppModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - // Disallow user-initiated channel closing for interchain account channels - return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") -} - -func (am AppModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - return nil -} - -func (am AppModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - _ sdk.AccAddress, -) ibcexported.Acknowledgement { - ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - - var data types.IBCAccountPacketData - if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - ack = channeltypes.NewErrorAcknowledgement(fmt.Sprintf("cannot unmarshal ICS-27 interchain account packet data: %s", err.Error())) - } - - // only attempt the application logic if the packet data - // was successfully decoded - if ack.Success() { - err := am.keeper.OnRecvPacket(ctx, packet) - if err != nil { - ack = channeltypes.NewErrorAcknowledgement(err.Error()) - } - } - - // NOTE: acknowledgement will be written synchronously during IBC handler execution. - return ack -} - -func (am AppModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - _ sdk.AccAddress, -) error { - var ack channeltypes.Acknowledgement - - if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-27 interchain account packet acknowledgment: %v", err) - } - var data types.IBCAccountPacketData - if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-27 interchain account packet data: %s", err.Error()) - } - - if err := am.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil { - return err - } - - return nil -} - -func (am AppModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - _ sdk.AccAddress, -) error { - // TODO - return nil -} - -// NegotiateAppVersion implements the IBCModule interface -func (am AppModule) NegotiateAppVersion( - ctx sdk.Context, - order channeltypes.Order, - connectionID string, - portID string, - counterparty channeltypes.Counterparty, - proposedVersion string, -) (string, error) { - return am.keeper.NegotiateAppVersion(ctx, order, connectionID, portID, counterparty, proposedVersion) -} diff --git a/testing/simapp/app.go b/testing/simapp/app.go index fcc3d6546d6..c158e3fead7 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -338,6 +338,7 @@ func NewSimApp( app.AccountKeeper, scopedICAKeeper, app.MsgServiceRouter(), app, ) icaModule := ica.NewAppModule(app.ICAKeeper) + icaIBCModule := ica.NewIBCModule(app.ICAKeeper, nil) // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // note replicate if you do not need to test core IBC or light clients. @@ -346,7 +347,7 @@ func NewSimApp( // Create static IBC router, add transfer route, then set and seal it ibcRouter := porttypes.NewRouter() ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) - ibcRouter.AddRoute(icatypes.ModuleName, icaModule) + ibcRouter.AddRoute(icatypes.ModuleName, icaIBCModule) ibcRouter.AddRoute(ibcmock.ModuleName, mockModule) app.IBCKeeper.SetRouter(ibcRouter) From e24294cc8982dcb25950ebcaee8f0caa4fbb7557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 4 Oct 2021 11:57:24 +0200 Subject: [PATCH 32/66] Rename IBCAccountPacketData, Remove TxRaw (#456) * rename IBCAccountPacketData, remove txRaw type * Update proto/ibc/applications/interchain_accounts/v1/types.proto --- docs/ibc/proto-docs.md | 29 +- .../apps/27-interchain-accounts/ibc_module.go | 4 +- .../27-interchain-accounts/keeper/keeper.go | 6 +- .../27-interchain-accounts/keeper/relay.go | 24 +- .../keeper/relay_test.go | 26 +- .../27-interchain-accounts/types/packet.go | 2 +- .../27-interchain-accounts/types/types.pb.go | 330 ++++++------------ .../interchain_accounts/v1/types.proto | 10 +- 8 files changed, 133 insertions(+), 298 deletions(-) diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 020332c0aa3..986ffd334f8 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -17,9 +17,8 @@ - [Query](#ibc.applications.interchain_accounts.v1.Query) - [ibc/applications/interchain_accounts/v1/types.proto](#ibc/applications/interchain_accounts/v1/types.proto) - - [IBCAccountPacketData](#ibc.applications.interchain_accounts.v1.IBCAccountPacketData) - [IBCTxBody](#ibc.applications.interchain_accounts.v1.IBCTxBody) - - [IBCTxRaw](#ibc.applications.interchain_accounts.v1.IBCTxRaw) + - [InterchainAccountPacketData](#ibc.applications.interchain_accounts.v1.InterchainAccountPacketData) - [Type](#ibc.applications.interchain_accounts.v1.Type) @@ -399,22 +398,6 @@ Query defines the gRPC querier service. - - -### IBCAccountPacketData -Packet data is comprised of raw transaction & type of transaction - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `type` | [Type](#ibc.applications.interchain_accounts.v1.Type) | | | -| `data` | [bytes](#bytes) | | | - - - - - - ### IBCTxBody @@ -430,15 +413,17 @@ Body of a tx for an ics27 IBC packet - + -### IBCTxRaw -Raw tx body +### InterchainAccountPacketData +InterchainAccountPacketData is comprised of araw transaction,type of transaction and optional memo field. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `body_bytes` | [bytes](#bytes) | | | +| `type` | [Type](#ibc.applications.interchain_accounts.v1.Type) | | | +| `data` | [bytes](#bytes) | | | +| `memo` | [string](#string) | | | diff --git a/modules/apps/27-interchain-accounts/ibc_module.go b/modules/apps/27-interchain-accounts/ibc_module.go index 80e798af826..99451e7876a 100644 --- a/modules/apps/27-interchain-accounts/ibc_module.go +++ b/modules/apps/27-interchain-accounts/ibc_module.go @@ -98,7 +98,7 @@ func (im IBCModule) OnRecvPacket( ) ibcexported.Acknowledgement { ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - var data types.IBCAccountPacketData + var data types.InterchainAccountPacketData if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { ack = channeltypes.NewErrorAcknowledgement(fmt.Sprintf("cannot unmarshal ICS-27 interchain account packet data: %s", err.Error())) } @@ -127,7 +127,7 @@ func (im IBCModule) OnAcknowledgementPacket( if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-27 interchain account packet acknowledgment: %v", err) } - var data types.IBCAccountPacketData + var data types.InterchainAccountPacketData if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-27 interchain account packet data: %s", err.Error()) } diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index 832755817b5..a68bdb338f1 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -83,11 +83,7 @@ func (k Keeper) SerializeCosmosTx(cdc codec.BinaryCodec, data interface{}) ([]by Messages: msgAnys, } - txRaw := &types.IBCTxRaw{ - BodyBytes: cdc.MustMarshal(txBody), - } - - bz, err := cdc.Marshal(txRaw) + bz, err := cdc.Marshal(txBody) if err != nil { return nil, err } diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 09175043dec..20d5e0a3150 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -15,7 +15,7 @@ import ( // TODO: implement middleware functionality, this will allow us to use capabilities to // manage helper module access to owner addresses they do not have capabilities for -func (k Keeper) TrySendTx(ctx sdk.Context, portID string, data interface{}) ([]byte, error) { +func (k Keeper) TrySendTx(ctx sdk.Context, portID string, data interface{}, memo string) ([]byte, error) { // Check for the active channel activeChannelId, found := k.GetActiveChannel(ctx, portID) if !found { @@ -30,7 +30,7 @@ func (k Keeper) TrySendTx(ctx sdk.Context, portID string, data interface{}) ([]b destinationPort := sourceChannelEnd.GetCounterparty().GetPortID() destinationChannel := sourceChannelEnd.GetCounterparty().GetChannelID() - return k.createOutgoingPacket(ctx, portID, activeChannelId, destinationPort, destinationChannel, data) + return k.createOutgoingPacket(ctx, portID, activeChannelId, destinationPort, destinationChannel, data, memo) } func (k Keeper) createOutgoingPacket( @@ -40,6 +40,7 @@ func (k Keeper) createOutgoingPacket( destinationPort, destinationChannel string, data interface{}, + memo string, ) ([]byte, error) { if data == nil { return []byte{}, types.ErrInvalidOutgoingData @@ -61,9 +62,10 @@ func (k Keeper) createOutgoingPacket( return []byte{}, channeltypes.ErrSequenceSendNotFound } - packetData := types.IBCAccountPacketData{ + packetData := types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: txBytes, + Memo: memo, } // timeoutTimestamp is set to be a max number here so that we never recieve a timeout @@ -85,17 +87,9 @@ func (k Keeper) createOutgoingPacket( } func (k Keeper) DeserializeTx(_ sdk.Context, txBytes []byte) ([]sdk.Msg, error) { - var txRaw types.IBCTxRaw - - err := k.cdc.Unmarshal(txBytes, &txRaw) - if err != nil { - return nil, err - } - var txBody types.IBCTxBody - err = k.cdc.Unmarshal(txRaw.BodyBytes, &txBody) - if err != nil { + if err := k.cdc.Unmarshal(txBytes, &txBody); err != nil { return nil, err } @@ -189,7 +183,7 @@ func (k Keeper) ComputeVirtualTxHash(txBytes []byte, seq uint64) []byte { } func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error { - var data types.IBCAccountPacketData + var data types.InterchainAccountPacketData if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { return sdkerrors.Wrapf(types.ErrUnknownPacketData, "cannot unmarshal ICS-27 interchain account packet data") @@ -213,7 +207,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error } } -func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.IBCAccountPacketData, ack channeltypes.Acknowledgement) error { +func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.InterchainAccountPacketData, ack channeltypes.Acknowledgement) error { switch ack.Response.(type) { case *channeltypes.Acknowledgement_Error: if k.hook != nil { @@ -232,7 +226,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac } } -func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.IBCAccountPacketData) error { +func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.InterchainAccountPacketData) error { if k.hook != nil { k.hook.OnTxFailed(ctx, packet.SourcePort, packet.SourceChannel, k.ComputeVirtualTxHash(data.Data, packet.Sequence), data.Data) } diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index 78d407934d8..e6df1ce44db 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -81,6 +81,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() { suite.SetupTest() // reset path = NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) + memo := "memo" err := suite.SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) @@ -89,7 +90,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() { tc.malleate() - _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), portID, msg) + _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), portID, msg, memo) if tc.expPass { suite.Require().NoError(err) @@ -124,7 +125,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, msg) suite.Require().NoError(err) - data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, + data := types.InterchainAccountPacketData{Type: types.EXECUTE_TX, Data: txBytes} packetData = data.GetBytes() }, true, @@ -132,20 +133,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "Cannot deserialize txBytes", func() { txBytes = []byte("invalid tx bytes") - data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, - Data: txBytes} - packetData = data.GetBytes() - }, false, - }, - { - "Cannot deserialize txBytes: invalid IBCTxRaw", func() { - txBody := []byte("invalid tx body") - txRaw := &types.IBCTxRaw{ - BodyBytes: txBody, - } - - txBytes = suite.chainB.Codec.MustMarshal(txRaw) - data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, + data := types.InterchainAccountPacketData{Type: types.EXECUTE_TX, Data: txBytes} packetData = data.GetBytes() }, false, @@ -155,13 +143,13 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { txBytes = []byte{} // Type here is an ENUM // Valid type is types.EXECUTE_TX - data := types.IBCAccountPacketData{Type: 100, + data := types.InterchainAccountPacketData{Type: 100, Data: txBytes} packetData = data.GetBytes() }, false, }, { - "Cannot unmarshal interchain account packet data into types.IBCAccountPacketData", func() { + "Cannot unmarshal interchain account packet data into types.InterchainAccountPacketData", func() { packetData = []byte{} }, false, }, @@ -179,7 +167,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // build packet data txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, msg) suite.Require().NoError(err) - data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, + data := types.InterchainAccountPacketData{Type: types.EXECUTE_TX, Data: txBytes} packetData = data.GetBytes() }, false, diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 9863fca3914..1c64054b3ee 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -4,6 +4,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -func (packet IBCAccountPacketData) GetBytes() []byte { +func (packet InterchainAccountPacketData) GetBytes() []byte { return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&packet)) } diff --git a/modules/apps/27-interchain-accounts/types/types.pb.go b/modules/apps/27-interchain-accounts/types/types.pb.go index 6233fa0eb26..38aa8249c28 100644 --- a/modules/apps/27-interchain-accounts/types/types.pb.go +++ b/modules/apps/27-interchain-accounts/types/types.pb.go @@ -50,51 +50,6 @@ func (Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor_39bab93e18d89799, []int{0} } -// Raw tx body -type IBCTxRaw struct { - BodyBytes []byte `protobuf:"bytes,1,opt,name=body_bytes,json=bodyBytes,proto3" json:"body_bytes,omitempty" yaml:"body_bytes"` -} - -func (m *IBCTxRaw) Reset() { *m = IBCTxRaw{} } -func (m *IBCTxRaw) String() string { return proto.CompactTextString(m) } -func (*IBCTxRaw) ProtoMessage() {} -func (*IBCTxRaw) Descriptor() ([]byte, []int) { - return fileDescriptor_39bab93e18d89799, []int{0} -} -func (m *IBCTxRaw) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *IBCTxRaw) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_IBCTxRaw.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *IBCTxRaw) XXX_Merge(src proto.Message) { - xxx_messageInfo_IBCTxRaw.Merge(m, src) -} -func (m *IBCTxRaw) XXX_Size() int { - return m.Size() -} -func (m *IBCTxRaw) XXX_DiscardUnknown() { - xxx_messageInfo_IBCTxRaw.DiscardUnknown(m) -} - -var xxx_messageInfo_IBCTxRaw proto.InternalMessageInfo - -func (m *IBCTxRaw) GetBodyBytes() []byte { - if m != nil { - return m.BodyBytes - } - return nil -} - // Body of a tx for an ics27 IBC packet type IBCTxBody struct { Messages []*types.Any `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` @@ -104,7 +59,7 @@ func (m *IBCTxBody) Reset() { *m = IBCTxBody{} } func (m *IBCTxBody) String() string { return proto.CompactTextString(m) } func (*IBCTxBody) ProtoMessage() {} func (*IBCTxBody) Descriptor() ([]byte, []int) { - return fileDescriptor_39bab93e18d89799, []int{1} + return fileDescriptor_39bab93e18d89799, []int{0} } func (m *IBCTxBody) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -140,24 +95,25 @@ func (m *IBCTxBody) GetMessages() []*types.Any { return nil } -// Packet data is comprised of raw transaction & type of transaction -type IBCAccountPacketData struct { +// InterchainAccountPacketData is comprised of araw transaction,type of transaction and optional memo field. +type InterchainAccountPacketData struct { Type Type `protobuf:"varint,1,opt,name=type,proto3,enum=ibc.applications.interchain_accounts.v1.Type" json:"type,omitempty"` Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + Memo string `protobuf:"bytes,3,opt,name=memo,proto3" json:"memo,omitempty"` } -func (m *IBCAccountPacketData) Reset() { *m = IBCAccountPacketData{} } -func (m *IBCAccountPacketData) String() string { return proto.CompactTextString(m) } -func (*IBCAccountPacketData) ProtoMessage() {} -func (*IBCAccountPacketData) Descriptor() ([]byte, []int) { - return fileDescriptor_39bab93e18d89799, []int{2} +func (m *InterchainAccountPacketData) Reset() { *m = InterchainAccountPacketData{} } +func (m *InterchainAccountPacketData) String() string { return proto.CompactTextString(m) } +func (*InterchainAccountPacketData) ProtoMessage() {} +func (*InterchainAccountPacketData) Descriptor() ([]byte, []int) { + return fileDescriptor_39bab93e18d89799, []int{1} } -func (m *IBCAccountPacketData) XXX_Unmarshal(b []byte) error { +func (m *InterchainAccountPacketData) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *IBCAccountPacketData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *InterchainAccountPacketData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_IBCAccountPacketData.Marshal(b, m, deterministic) + return xxx_messageInfo_InterchainAccountPacketData.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -167,37 +123,43 @@ func (m *IBCAccountPacketData) XXX_Marshal(b []byte, deterministic bool) ([]byte return b[:n], nil } } -func (m *IBCAccountPacketData) XXX_Merge(src proto.Message) { - xxx_messageInfo_IBCAccountPacketData.Merge(m, src) +func (m *InterchainAccountPacketData) XXX_Merge(src proto.Message) { + xxx_messageInfo_InterchainAccountPacketData.Merge(m, src) } -func (m *IBCAccountPacketData) XXX_Size() int { +func (m *InterchainAccountPacketData) XXX_Size() int { return m.Size() } -func (m *IBCAccountPacketData) XXX_DiscardUnknown() { - xxx_messageInfo_IBCAccountPacketData.DiscardUnknown(m) +func (m *InterchainAccountPacketData) XXX_DiscardUnknown() { + xxx_messageInfo_InterchainAccountPacketData.DiscardUnknown(m) } -var xxx_messageInfo_IBCAccountPacketData proto.InternalMessageInfo +var xxx_messageInfo_InterchainAccountPacketData proto.InternalMessageInfo -func (m *IBCAccountPacketData) GetType() Type { +func (m *InterchainAccountPacketData) GetType() Type { if m != nil { return m.Type } return EXECUTE_TX } -func (m *IBCAccountPacketData) GetData() []byte { +func (m *InterchainAccountPacketData) GetData() []byte { if m != nil { return m.Data } return nil } +func (m *InterchainAccountPacketData) GetMemo() string { + if m != nil { + return m.Memo + } + return "" +} + func init() { proto.RegisterEnum("ibc.applications.interchain_accounts.v1.Type", Type_name, Type_value) - proto.RegisterType((*IBCTxRaw)(nil), "ibc.applications.interchain_accounts.v1.IBCTxRaw") proto.RegisterType((*IBCTxBody)(nil), "ibc.applications.interchain_accounts.v1.IBCTxBody") - proto.RegisterType((*IBCAccountPacketData)(nil), "ibc.applications.interchain_accounts.v1.IBCAccountPacketData") + proto.RegisterType((*InterchainAccountPacketData)(nil), "ibc.applications.interchain_accounts.v1.InterchainAccountPacketData") } func init() { @@ -205,63 +167,31 @@ func init() { } var fileDescriptor_39bab93e18d89799 = []byte{ - // 407 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x51, 0x41, 0x6b, 0xd4, 0x40, - 0x18, 0x4d, 0x34, 0x48, 0x3b, 0x4a, 0xd1, 0xb0, 0x42, 0x8d, 0x10, 0x4b, 0x2e, 0x16, 0x21, 0x33, - 0x36, 0x15, 0x04, 0xa1, 0xe0, 0x26, 0x8d, 0x90, 0x8b, 0x2c, 0x31, 0x85, 0xea, 0x25, 0xcc, 0x4c, - 0xc6, 0x74, 0x30, 0xc9, 0x84, 0xce, 0x64, 0x75, 0xfe, 0x81, 0x78, 0xf2, 0x0f, 0x78, 0xf2, 0xcf, - 0x78, 0xec, 0xd1, 0x93, 0xc8, 0xee, 0x3f, 0xf0, 0x17, 0x48, 0x26, 0xb8, 0xeb, 0xc1, 0x83, 0xb7, - 0x37, 0xf3, 0x7d, 0xef, 0xf1, 0xbe, 0xf7, 0xc0, 0x31, 0x27, 0x14, 0xe1, 0xbe, 0x6f, 0x38, 0xc5, - 0x8a, 0x8b, 0x4e, 0x22, 0xde, 0x29, 0x76, 0x49, 0x2f, 0x30, 0xef, 0x4a, 0x4c, 0xa9, 0x18, 0x3a, - 0x25, 0xd1, 0xf2, 0x08, 0x29, 0xdd, 0x33, 0x09, 0xfb, 0x4b, 0xa1, 0x84, 0xfb, 0x90, 0x13, 0x0a, - 0xff, 0x26, 0xc1, 0x7f, 0x90, 0xe0, 0xf2, 0xc8, 0xbb, 0x57, 0x0b, 0x51, 0x37, 0x0c, 0x19, 0x1a, - 0x19, 0xde, 0x22, 0xdc, 0xe9, 0x49, 0xc3, 0x9b, 0xd5, 0xa2, 0x16, 0x06, 0xa2, 0x11, 0x4d, 0xbf, - 0xc1, 0x73, 0xb0, 0x93, 0xc5, 0x49, 0xf1, 0x21, 0xc7, 0xef, 0xdd, 0x27, 0x00, 0x10, 0x51, 0xe9, - 0x92, 0x68, 0xc5, 0xe4, 0xbe, 0x7d, 0x60, 0x1f, 0xde, 0x8a, 0xef, 0xfe, 0xfa, 0xf1, 0xe0, 0x8e, - 0xc6, 0x6d, 0xf3, 0x2c, 0xd8, 0xce, 0x82, 0x7c, 0x77, 0x7c, 0xc4, 0x06, 0x9f, 0x80, 0x5d, 0xa3, - 0x10, 0x8b, 0x4a, 0xbb, 0x8f, 0xc1, 0x4e, 0xcb, 0xa4, 0xc4, 0xb5, 0x11, 0xb8, 0x7e, 0x78, 0x33, - 0x9a, 0xc1, 0xc9, 0x12, 0xfc, 0x63, 0x09, 0xce, 0x3b, 0x9d, 0x6f, 0xb6, 0x82, 0x16, 0xcc, 0xb2, - 0x38, 0x99, 0x4f, 0x37, 0x2c, 0x30, 0x7d, 0xc7, 0xd4, 0x29, 0x56, 0xd8, 0x9d, 0x03, 0x67, 0x4c, - 0xc0, 0xd8, 0xd8, 0x8b, 0x42, 0xf8, 0x9f, 0x09, 0xc0, 0x42, 0xf7, 0x2c, 0x37, 0x54, 0xd7, 0x05, - 0x4e, 0x85, 0x15, 0xde, 0xbf, 0x36, 0x5e, 0x92, 0x1b, 0xfc, 0xe8, 0x04, 0x38, 0xe3, 0x86, 0x8b, - 0xc0, 0xfd, 0xe2, 0xf5, 0x22, 0x2d, 0xd3, 0xf3, 0x34, 0x39, 0x2b, 0xd2, 0xb2, 0x38, 0x2f, 0xcf, - 0x5e, 0xbe, 0x5a, 0xa4, 0x49, 0xf6, 0x22, 0x4b, 0x4f, 0x6f, 0x5b, 0xde, 0xde, 0xa7, 0x2f, 0x07, - 0x60, 0x3b, 0xf5, 0x9c, 0x8f, 0x5f, 0x7d, 0x2b, 0x2e, 0xbf, 0xad, 0x7c, 0xfb, 0x6a, 0xe5, 0xdb, - 0x3f, 0x57, 0xbe, 0xfd, 0x79, 0xed, 0x5b, 0x57, 0x6b, 0xdf, 0xfa, 0xbe, 0xf6, 0xad, 0x37, 0x69, - 0xcd, 0xd5, 0xc5, 0x40, 0x20, 0x15, 0x2d, 0xa2, 0x42, 0xb6, 0x42, 0x22, 0x4e, 0x68, 0x58, 0x0b, - 0xb4, 0x8c, 0x50, 0x2b, 0xaa, 0xa1, 0x61, 0x72, 0xec, 0x5d, 0xa2, 0xe8, 0x69, 0xb8, 0xf5, 0x1e, - 0x6e, 0x2a, 0x37, 0x7d, 0x93, 0x1b, 0x26, 0xa6, 0xe3, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x3e, - 0xd3, 0x1d, 0x0c, 0x27, 0x02, 0x00, 0x00, -} - -func (m *IBCTxRaw) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *IBCTxRaw) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *IBCTxRaw) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.BodyBytes) > 0 { - i -= len(m.BodyBytes) - copy(dAtA[i:], m.BodyBytes) - i = encodeVarintTypes(dAtA, i, uint64(len(m.BodyBytes))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil + // 380 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0xcf, 0xaa, 0xd3, 0x40, + 0x18, 0xc5, 0x33, 0xde, 0x20, 0xde, 0x51, 0x8a, 0x84, 0x2e, 0x62, 0x0a, 0x21, 0x74, 0x63, 0x10, + 0x32, 0x63, 0xd3, 0x85, 0xab, 0x2e, 0xfa, 0x27, 0x42, 0x36, 0x52, 0x62, 0x0a, 0xd5, 0x4d, 0x98, + 0x4c, 0xc7, 0x74, 0xb0, 0xc9, 0x84, 0xce, 0xa4, 0x98, 0x37, 0x28, 0xae, 0x7c, 0x01, 0x57, 0xbe, + 0x8c, 0xcb, 0x2e, 0x5d, 0x4a, 0xfb, 0x22, 0x92, 0x04, 0x5b, 0x17, 0x2e, 0xee, 0xee, 0xf0, 0xcd, + 0xfc, 0x0e, 0xdf, 0xf9, 0x0e, 0x1c, 0xf3, 0x94, 0x62, 0x52, 0x96, 0x3b, 0x4e, 0x89, 0xe2, 0xa2, + 0x90, 0x98, 0x17, 0x8a, 0xed, 0xe9, 0x96, 0xf0, 0x22, 0x21, 0x94, 0x8a, 0xaa, 0x50, 0x12, 0x1f, + 0x46, 0x58, 0xd5, 0x25, 0x93, 0xa8, 0xdc, 0x0b, 0x25, 0x8c, 0x97, 0x3c, 0xa5, 0xe8, 0x5f, 0x08, + 0xfd, 0x07, 0x42, 0x87, 0x91, 0xf5, 0x22, 0x13, 0x22, 0xdb, 0x31, 0xdc, 0x62, 0x69, 0xf5, 0x09, + 0x93, 0xa2, 0xee, 0x3c, 0xac, 0x7e, 0x26, 0x32, 0xd1, 0x4a, 0xdc, 0xa8, 0x6e, 0x3a, 0x9c, 0xc0, + 0xfb, 0x70, 0x36, 0x8f, 0xbf, 0xcc, 0xc4, 0xa6, 0x36, 0x5e, 0xc3, 0x27, 0x39, 0x93, 0x92, 0x64, + 0x4c, 0x9a, 0xc0, 0xb9, 0x73, 0x9f, 0xfa, 0x7d, 0xd4, 0x19, 0xa2, 0xbf, 0x86, 0x68, 0x5a, 0xd4, + 0xd1, 0xf5, 0xd7, 0xf0, 0x08, 0xe0, 0x20, 0xbc, 0xae, 0x32, 0xed, 0x36, 0x59, 0x12, 0xfa, 0x99, + 0xa9, 0x05, 0x51, 0xc4, 0x98, 0x42, 0xbd, 0xc9, 0x61, 0x02, 0x07, 0xb8, 0x3d, 0xdf, 0x43, 0x0f, + 0xcc, 0x81, 0xe2, 0xba, 0x64, 0x51, 0x8b, 0x1a, 0x06, 0xd4, 0x37, 0x44, 0x11, 0xf3, 0x91, 0x03, + 0xdc, 0x67, 0x51, 0xab, 0x9b, 0x59, 0xce, 0x72, 0x61, 0xde, 0x39, 0xc0, 0xbd, 0x8f, 0x5a, 0xfd, + 0x6a, 0x02, 0xf5, 0x86, 0x32, 0x30, 0x1c, 0xc4, 0x1f, 0x96, 0x41, 0x12, 0xac, 0x83, 0xf9, 0x2a, + 0x0e, 0x92, 0x78, 0x9d, 0xac, 0xde, 0xbd, 0x5f, 0x06, 0xf3, 0xf0, 0x6d, 0x18, 0x2c, 0x9e, 0x6b, + 0x56, 0xef, 0xeb, 0x77, 0x07, 0xde, 0x5e, 0x2d, 0xfd, 0xf8, 0xc3, 0xd6, 0x66, 0xc9, 0xcf, 0xb3, + 0x0d, 0x4e, 0x67, 0x1b, 0xfc, 0x3e, 0xdb, 0xe0, 0xdb, 0xc5, 0xd6, 0x4e, 0x17, 0x5b, 0xfb, 0x75, + 0xb1, 0xb5, 0x8f, 0x41, 0xc6, 0xd5, 0xb6, 0x4a, 0x11, 0x15, 0x39, 0xa6, 0x42, 0xe6, 0x42, 0x62, + 0x9e, 0x52, 0x2f, 0x13, 0xf8, 0xe0, 0xe3, 0x5c, 0x6c, 0xaa, 0x1d, 0x93, 0x4d, 0xa3, 0x12, 0xfb, + 0x6f, 0xbc, 0x5b, 0x1e, 0xef, 0x5a, 0x66, 0xdb, 0x64, 0xfa, 0xb8, 0x3d, 0xe1, 0xf8, 0x4f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x69, 0x0c, 0xd9, 0x88, 0x01, 0x02, 0x00, 0x00, } func (m *IBCTxBody) Marshal() (dAtA []byte, err error) { @@ -301,7 +231,7 @@ func (m *IBCTxBody) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *IBCAccountPacketData) Marshal() (dAtA []byte, err error) { +func (m *InterchainAccountPacketData) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -311,16 +241,23 @@ func (m *IBCAccountPacketData) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *IBCAccountPacketData) MarshalTo(dAtA []byte) (int, error) { +func (m *InterchainAccountPacketData) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *IBCAccountPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *InterchainAccountPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l + if len(m.Memo) > 0 { + i -= len(m.Memo) + copy(dAtA[i:], m.Memo) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Memo))) + i-- + dAtA[i] = 0x1a + } if len(m.Data) > 0 { i -= len(m.Data) copy(dAtA[i:], m.Data) @@ -347,19 +284,6 @@ func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *IBCTxRaw) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.BodyBytes) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - return n -} - func (m *IBCTxBody) Size() (n int) { if m == nil { return 0 @@ -375,7 +299,7 @@ func (m *IBCTxBody) Size() (n int) { return n } -func (m *IBCAccountPacketData) Size() (n int) { +func (m *InterchainAccountPacketData) Size() (n int) { if m == nil { return 0 } @@ -388,6 +312,10 @@ func (m *IBCAccountPacketData) Size() (n int) { if l > 0 { n += 1 + l + sovTypes(uint64(l)) } + l = len(m.Memo) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } return n } @@ -397,90 +325,6 @@ func sovTypes(x uint64) (n int) { func sozTypes(x uint64) (n int) { return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *IBCTxRaw) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: IBCTxRaw: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: IBCTxRaw: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BodyBytes", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.BodyBytes = append(m.BodyBytes[:0], dAtA[iNdEx:postIndex]...) - if m.BodyBytes == nil { - m.BodyBytes = []byte{} - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *IBCTxBody) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -565,7 +409,7 @@ func (m *IBCTxBody) Unmarshal(dAtA []byte) error { } return nil } -func (m *IBCAccountPacketData) Unmarshal(dAtA []byte) error { +func (m *InterchainAccountPacketData) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -588,10 +432,10 @@ func (m *IBCAccountPacketData) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: IBCAccountPacketData: wiretype end group for non-group") + return fmt.Errorf("proto: InterchainAccountPacketData: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: IBCAccountPacketData: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: InterchainAccountPacketData: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -647,6 +491,38 @@ func (m *IBCAccountPacketData) Unmarshal(dAtA []byte) error { m.Data = []byte{} } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Memo", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Memo = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/proto/ibc/applications/interchain_accounts/v1/types.proto b/proto/ibc/applications/interchain_accounts/v1/types.proto index c60b65bdd33..758c2539072 100644 --- a/proto/ibc/applications/interchain_accounts/v1/types.proto +++ b/proto/ibc/applications/interchain_accounts/v1/types.proto @@ -5,11 +5,6 @@ import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; -// Raw tx body -message IBCTxRaw { - bytes body_bytes = 1 [(gogoproto.moretags) = "yaml:\"body_bytes\""]; -} - // Body of a tx for an ics27 IBC packet message IBCTxBody { repeated google.protobuf.Any messages = 1; @@ -24,8 +19,9 @@ enum Type { TYPE_EXECUTE_TX_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "EXECUTE_TX"]; } -// Packet data is comprised of raw transaction & type of transaction -message IBCAccountPacketData { +// InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. +message InterchainAccountPacketData { Type type = 1; bytes data = 2; + string memo = 3; } From 064aa4245eb086c8ed1bd9de129ca00792a5df79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 6 Oct 2021 17:23:28 +0200 Subject: [PATCH 33/66] Rename DeserializeTx, enforce []sdk.Msg usage in SerializeCosmosTx (#457) * rename DeserializeTx to DeserializeCosmosTx, simply serialization logic * improve godoc wording --- .../27-interchain-accounts/keeper/keeper.go | 12 +---------- .../27-interchain-accounts/keeper/relay.go | 21 +++++++++++++++---- .../keeper/relay_test.go | 15 +++++++++---- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index a68bdb338f1..9730f5a9da7 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -58,17 +58,7 @@ func NewKeeper( } // SerializeCosmosTx marshals data to bytes using the provided codec -func (k Keeper) SerializeCosmosTx(cdc codec.BinaryCodec, data interface{}) ([]byte, error) { - msgs := make([]sdk.Msg, 0) - switch data := data.(type) { - case sdk.Msg: - msgs = append(msgs, data) - case []sdk.Msg: - msgs = append(msgs, data...) - default: - return nil, types.ErrInvalidOutgoingData - } - +func (k Keeper) SerializeCosmosTx(cdc codec.BinaryCodec, msgs []sdk.Msg) ([]byte, error) { msgAnys := make([]*codectypes.Any, len(msgs)) for i, msg := range msgs { diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 20d5e0a3150..964bfb5cd20 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -46,9 +46,20 @@ func (k Keeper) createOutgoingPacket( return []byte{}, types.ErrInvalidOutgoingData } - txBytes, err := k.SerializeCosmosTx(k.cdc, data) + var ( + txBytes []byte + err error + ) + + switch data := data.(type) { + case []sdk.Msg: + txBytes, err = k.SerializeCosmosTx(k.cdc, data) + default: + return nil, sdkerrors.Wrapf(types.ErrInvalidOutgoingData, "message type %T is not supported", data) + } + if err != nil { - return []byte{}, sdkerrors.Wrap(err, "invalid packet data or codec") + return nil, sdkerrors.Wrap(err, "serialization of transaction data failed") } channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(sourcePort, sourceChannel)) @@ -86,7 +97,9 @@ func (k Keeper) createOutgoingPacket( return k.ComputeVirtualTxHash(packetData.Data, packet.Sequence), k.channelKeeper.SendPacket(ctx, channelCap, packet) } -func (k Keeper) DeserializeTx(_ sdk.Context, txBytes []byte) ([]sdk.Msg, error) { +// DeserializeCosmosTx unmarshals and unpacks a slice of transaction bytes +// into a slice of sdk.Msg's. +func (k Keeper) DeserializeCosmosTx(_ sdk.Context, txBytes []byte) ([]sdk.Msg, error) { var txBody types.IBCTxBody if err := k.cdc.Unmarshal(txBytes, &txBody); err != nil { @@ -191,7 +204,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error switch data.Type { case types.EXECUTE_TX: - msgs, err := k.DeserializeTx(ctx, data.Data) + msgs, err := k.DeserializeCosmosTx(ctx, data.Data) if err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index e6df1ce44db..2609f59545c 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -29,11 +29,11 @@ func (suite *KeeperTestSuite) TestTrySendTx() { "success", func() { amount, _ := sdk.ParseCoinsNormalized("100stake") interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) - msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + msg = []sdk.Msg{&banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount}} }, true, }, { - "success with []sdk.Message", func() { + "success with multiple sdk.Msg", func() { amount, _ := sdk.ParseCoinsNormalized("100stake") interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) msg1 := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} @@ -46,6 +46,13 @@ func (suite *KeeperTestSuite) TestTrySendTx() { msg = []byte{} }, false, }, + { + "incorrect outgoing data - []sdk.Msg is not used", func() { + amount, _ := sdk.ParseCoinsNormalized("100stake") + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + }, false, + }, { "active channel not found", func() { amount, _ := sdk.ParseCoinsNormalized("100stake") @@ -122,7 +129,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} // build packet data - txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, msg) + txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) suite.Require().NoError(err) data := types.InterchainAccountPacketData{Type: types.EXECUTE_TX, @@ -165,7 +172,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // Incorrect FromAddress msg = &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} // build packet data - txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, msg) + txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) suite.Require().NoError(err) data := types.InterchainAccountPacketData{Type: types.EXECUTE_TX, Data: txBytes} From 1f87f2ea10a0a253d40e5d68abd56be76dddb1d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:09:20 +0200 Subject: [PATCH 34/66] remove computeVirtualTxHash (#473) --- .../27-interchain-accounts/keeper/relay.go | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 964bfb5cd20..18e6d552eff 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -1,11 +1,8 @@ package keeper import ( - "encoding/binary" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/tendermint/tendermint/crypto/tmhash" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" @@ -15,16 +12,16 @@ import ( // TODO: implement middleware functionality, this will allow us to use capabilities to // manage helper module access to owner addresses they do not have capabilities for -func (k Keeper) TrySendTx(ctx sdk.Context, portID string, data interface{}, memo string) ([]byte, error) { +func (k Keeper) TrySendTx(ctx sdk.Context, portID string, data interface{}, memo string) (uint64, error) { // Check for the active channel activeChannelId, found := k.GetActiveChannel(ctx, portID) if !found { - return nil, types.ErrActiveChannelNotFound + return 0, types.ErrActiveChannelNotFound } sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, portID, activeChannelId) if !found { - return []byte{}, sdkerrors.Wrap(channeltypes.ErrChannelNotFound, activeChannelId) + return 0, sdkerrors.Wrap(channeltypes.ErrChannelNotFound, activeChannelId) } destinationPort := sourceChannelEnd.GetCounterparty().GetPortID() @@ -41,9 +38,9 @@ func (k Keeper) createOutgoingPacket( destinationChannel string, data interface{}, memo string, -) ([]byte, error) { +) (uint64, error) { if data == nil { - return []byte{}, types.ErrInvalidOutgoingData + return 0, types.ErrInvalidOutgoingData } var ( @@ -55,22 +52,22 @@ func (k Keeper) createOutgoingPacket( case []sdk.Msg: txBytes, err = k.SerializeCosmosTx(k.cdc, data) default: - return nil, sdkerrors.Wrapf(types.ErrInvalidOutgoingData, "message type %T is not supported", data) + return 0, sdkerrors.Wrapf(types.ErrInvalidOutgoingData, "message type %T is not supported", data) } if err != nil { - return nil, sdkerrors.Wrap(err, "serialization of transaction data failed") + return 0, sdkerrors.Wrap(err, "serialization of transaction data failed") } channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(sourcePort, sourceChannel)) if !ok { - return []byte{}, sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + return 0, sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } // get the next sequence sequence, found := k.channelKeeper.GetNextSequenceSend(ctx, sourcePort, sourceChannel) if !found { - return []byte{}, channeltypes.ErrSequenceSendNotFound + return 0, channeltypes.ErrSequenceSendNotFound } packetData := types.InterchainAccountPacketData{ @@ -94,7 +91,11 @@ func (k Keeper) createOutgoingPacket( timeoutTimestamp, ) - return k.ComputeVirtualTxHash(packetData.Data, packet.Sequence), k.channelKeeper.SendPacket(ctx, channelCap, packet) + if err := k.channelKeeper.SendPacket(ctx, channelCap, packet); err != nil { + return 0, err + } + + return packet.Sequence, nil } // DeserializeCosmosTx unmarshals and unpacks a slice of transaction bytes @@ -188,13 +189,6 @@ func (k Keeper) executeMsg(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { return handler(ctx, msg) } -// Compute the virtual tx hash that is used only internally. -func (k Keeper) ComputeVirtualTxHash(txBytes []byte, seq uint64) []byte { - bz := make([]byte, 8) - binary.LittleEndian.PutUint64(bz, seq) - return tmhash.SumTruncated(append(txBytes, bz...)) -} - func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error { var data types.InterchainAccountPacketData @@ -224,12 +218,12 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac switch ack.Response.(type) { case *channeltypes.Acknowledgement_Error: if k.hook != nil { - k.hook.OnTxFailed(ctx, packet.SourcePort, packet.SourceChannel, k.ComputeVirtualTxHash(data.Data, packet.Sequence), data.Data) + k.hook.OnTxFailed(ctx, packet.SourcePort, packet.SourceChannel, packet.Data, data.Data) } return nil case *channeltypes.Acknowledgement_Result: if k.hook != nil { - k.hook.OnTxSucceeded(ctx, packet.SourcePort, packet.SourceChannel, k.ComputeVirtualTxHash(data.Data, packet.Sequence), data.Data) + k.hook.OnTxSucceeded(ctx, packet.SourcePort, packet.SourceChannel, packet.Data, data.Data) } return nil default: @@ -241,7 +235,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.InterchainAccountPacketData) error { if k.hook != nil { - k.hook.OnTxFailed(ctx, packet.SourcePort, packet.SourceChannel, k.ComputeVirtualTxHash(data.Data, packet.Sequence), data.Data) + k.hook.OnTxFailed(ctx, packet.SourcePort, packet.SourceChannel, packet.Data, data.Data) } return nil From f1293763fba549f38c986fe557bb80f084f92e24 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 7 Oct 2021 11:18:21 +0200 Subject: [PATCH 35/66] chore: ctrl port connection id validation (#454) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * adding pipe char | to identifier regex * updating GeneratePortID to use pipe delimiter in favour of dash, ParseAddressFromVersion to use Split in favour of TrimPrefix * adding CounterpartyHops method to expected channel keeper interface * updating tests to satisy delimiter updates * adding connection seq validation of ctrl port id and updating tests * cleanup * adding defensive check for ParseAddressFromVersion * adding conn sequence parsing funcs to pkg types * moving conn sequence validation to reusable func * updating error msgs, adding tests for conn seq parsers * adding expected sequence to error msgs * updating ParseCtrlConnSequence to ParseControllerConnSequence * fixing counterparty port error * Update modules/apps/27-interchain-accounts/keeper/handshake.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/27-interchain-accounts/keeper/handshake.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/27-interchain-accounts/types/account.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * removing pipe from valid identifier regex * adding error returns to parsing funcs, updating tests, error messages * separting imports in keys.go * updating handshake tests * Update modules/apps/27-interchain-accounts/types/keys.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * renaming validation func, removing parenthesis in error msgs * renaming func validateControllerPort -> validateControllerPortParams Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- .../keeper/handshake.go | 88 ++++++++- .../keeper/handshake_test.go | 186 +++++++++++++++--- .../keeper/keeper_test.go | 3 +- .../27-interchain-accounts/module_test.go | 26 ++- .../27-interchain-accounts/types/account.go | 12 +- .../types/account_test.go | 13 +- .../types/expected_keepers.go | 1 + .../apps/27-interchain-accounts/types/keys.go | 54 ++++- .../27-interchain-accounts/types/keys_test.go | 131 ++++++++++++ 9 files changed, 455 insertions(+), 59 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index 6b929f547d9..607f9524256 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -6,6 +6,7 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" @@ -31,10 +32,25 @@ func (k Keeper) OnChanOpenInit( version string, ) error { if order != channeltypes.ORDERED { - return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "invalid channel ordering: %s, expected %s", order.String(), channeltypes.ORDERED.String()) + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order) } + + connSequence, err := types.ParseControllerConnSequence(portID) + if err != nil { + return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, portID) + } + + counterpartyConnSequence, err := types.ParseHostConnSequence(portID) + if err != nil { + return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, portID) + } + + if err := k.validateControllerPortParams(ctx, channelID, portID, connSequence, counterpartyConnSequence); err != nil { + return sdkerrors.Wrapf(err, "failed to validate controller port %s", portID) + } + if counterparty.PortId != types.PortID { - return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "counterparty port-id must be '%s', (%s != %s)", types.PortID, counterparty.PortId, types.PortID) + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "expected %s, got %s", types.PortID, counterparty.PortId) } if err := types.ValidateVersion(version); err != nil { @@ -43,7 +59,7 @@ func (k Keeper) OnChanOpenInit( existingChannelID, found := k.GetActiveChannel(ctx, portID) if found { - return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel (%s) for portID (%s)", existingChannelID, portID) + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel %s for portID %s", existingChannelID, portID) } // Claim channel capability passed back by IBC module @@ -70,7 +86,25 @@ func (k Keeper) OnChanOpenTry( counterpartyVersion string, ) error { if order != channeltypes.ORDERED { - return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "invalid channel ordering: %s, expected %s", order.String(), channeltypes.ORDERED.String()) + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order) + } + + if portID != types.PortID { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "expected %s, got %s", types.PortID, portID) + } + + connSequence, err := types.ParseHostConnSequence(counterparty.PortId) + if err != nil { + return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, counterparty.PortId) + } + + counterpartyConnSequence, err := types.ParseControllerConnSequence(counterparty.PortId) + if err != nil { + return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, counterparty.PortId) + } + + if err := k.validateControllerPortParams(ctx, channelID, portID, connSequence, counterpartyConnSequence); err != nil { + return sdkerrors.Wrapf(err, "failed to validate controller port %s", counterparty.PortId) } if err := types.ValidateVersion(version); err != nil { @@ -89,7 +123,11 @@ func (k Keeper) OnChanOpenTry( // Check to ensure that the version string contains the expected address generated from the Counterparty portID accAddr := types.GenerateAddress(k.accountKeeper.GetModuleAddress(types.ModuleName), counterparty.PortId) - parsedAddr := types.ParseAddressFromVersion(version) + parsedAddr, err := types.ParseAddressFromVersion(version) + if err != nil { + return sdkerrors.Wrapf(err, "expected format , got %s", types.Delimiter, version) + } + if parsedAddr != accAddr.String() { return sdkerrors.Wrapf(types.ErrInvalidAccountAddress, "version contains invalid account address: expected %s, got %s", parsedAddr, accAddr) } @@ -116,7 +154,11 @@ func (k Keeper) OnChanOpenAck( k.SetActiveChannel(ctx, portID, channelID) - accAddr := types.ParseAddressFromVersion(counterpartyVersion) + accAddr, err := types.ParseAddressFromVersion(counterpartyVersion) + if err != nil { + return sdkerrors.Wrapf(err, "expected format , got %s", types.Delimiter, counterpartyVersion) + } + k.SetInterchainAccountAddress(ctx, portID, accAddr) return nil @@ -130,3 +172,37 @@ func (k Keeper) OnChanOpenConfirm( ) error { return nil } + +// validateControllerPortParams asserts the provided connection sequence and counterparty connection sequence +// match that of the associated connection stored in state +func (k Keeper) validateControllerPortParams(ctx sdk.Context, channelID, portID string, connectionSeq, counterpartyConnectionSeq uint64) error { + channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID) + if !found { + return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID %s channel ID %s", portID, channelID) + } + + counterpartyHops, found := k.channelKeeper.CounterpartyHops(ctx, channel) + if !found { + return sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + connSeq, err := connectiontypes.ParseConnectionSequence(channel.ConnectionHops[0]) + if err != nil { + return sdkerrors.Wrapf(err, "failed to parse connection sequence %s", channel.ConnectionHops[0]) + } + + counterpartyConnSeq, err := connectiontypes.ParseConnectionSequence(counterpartyHops[0]) + if err != nil { + return sdkerrors.Wrapf(err, "failed to parse counterparty connection sequence %s", counterpartyHops[0]) + } + + if connSeq != connectionSeq { + return sdkerrors.Wrapf(connectiontypes.ErrInvalidConnection, "sequence mismatch, expected %d, got %d", connSeq, connectionSeq) + } + + if counterpartyConnSeq != counterpartyConnectionSeq { + return sdkerrors.Wrapf(connectiontypes.ErrInvalidConnection, "counterparty sequence mismatch, expected %d, got %d", counterpartyConnSeq, counterpartyConnectionSeq) + } + + return nil +} diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index ba2a1eea9ca..63afb203f11 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -23,33 +23,94 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { }{ { - "success", func() {}, true, + "success", + func() { + path.EndpointA.SetChannel(*channel) + }, + true, }, { - "invalid order - UNORDERED", func() { + "invalid order - UNORDERED", + func() { channel.Ordering = channeltypes.UNORDERED - }, false, + }, + false, }, { - "invalid counterparty port ID", func() { - channel.Counterparty.PortId = ibctesting.MockPort - }, false, + "invalid port ID", + func() { + path.EndpointA.ChannelConfig.PortID = "invalid-port-id" + }, + false, }, { - "invalid version", func() { + "invalid counterparty port ID", + func() { + path.EndpointA.SetChannel(*channel) + channel.Counterparty.PortId = "invalid-port-id" + }, + false, + }, + { + "invalid version", + func() { + path.EndpointA.SetChannel(*channel) channel.Version = "version" - }, false, + }, + false, }, { - "channel is already active", func() { + "channel not found", + func() { + path.EndpointA.ChannelID = "invalid-channel-id" + }, + false, + }, + { + "connection not found", + func() { + channel.ConnectionHops = []string{"invalid-connnection-id"} + path.EndpointA.SetChannel(*channel) + }, + false, + }, + { + "invalid connection sequence", + func() { + portID, err := types.GeneratePortID(TestOwnerAddress, "connection-1", "connection-0") + suite.Require().NoError(err) + + path.EndpointA.ChannelConfig.PortID = portID + path.EndpointA.SetChannel(*channel) + }, + false, + }, + { + "invalid counterparty connection sequence", + func() { + portID, err := types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-1") + suite.Require().NoError(err) + + path.EndpointA.ChannelConfig.PortID = portID + path.EndpointA.SetChannel(*channel) + }, + false, + }, + { + "channel is already active", + func() { suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - }, false, + }, + false, }, { - "capability already claimed", func() { + "capability already claimed", + func() { + path.EndpointA.SetChannel(*channel) err := suite.chainA.GetSimApp().ScopedICAKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) suite.Require().NoError(err) - }, false, + }, + false, }, } @@ -97,7 +158,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { } } -// ChainA is controller, ChainB is host chain func (suite *KeeperTestSuite) TestOnChanOpenTry() { var ( channel *channeltypes.Channel @@ -113,33 +173,105 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { }{ { - "success", func() {}, true, + "success", + func() { + path.EndpointB.SetChannel(*channel) + }, + true, }, { - "invalid order - UNORDERED", func() { + "invalid order - UNORDERED", + func() { channel.Ordering = channeltypes.UNORDERED - }, false, + }, + false, + }, + { + "invalid port", + func() { + path.EndpointB.ChannelConfig.PortID = "invalid-port-id" + }, + false, + }, + { + "invalid counterparty port", + func() { + channel.Counterparty.PortId = "invalid-port-id" + }, + false, }, { - "invalid version", func() { + "channel not found", + func() { + path.EndpointB.ChannelID = "invalid-channel-id" + }, + false, + }, + { + "connection not found", + func() { + channel.ConnectionHops = []string{"invalid-connnection-id"} + path.EndpointB.SetChannel(*channel) + }, + false, + }, + { + "invalid connection sequence", + func() { + portID, err := types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-1") + suite.Require().NoError(err) + + channel.Counterparty.PortId = portID + path.EndpointB.SetChannel(*channel) + }, + false, + }, + { + "invalid counterparty connection sequence", + func() { + portID, err := types.GeneratePortID(TestOwnerAddress, "connection-1", "connection-0") + suite.Require().NoError(err) + + channel.Counterparty.PortId = portID + path.EndpointB.SetChannel(*channel) + }, + false, + }, + { + "invalid version", + func() { channel.Version = "version" - }, false, + path.EndpointB.SetChannel(*channel) + }, + false, }, { - "invalid counterparty version", func() { + "invalid counterparty version", + func() { counterpartyVersion = "version" - }, false, + path.EndpointB.SetChannel(*channel) + }, + false, }, { - "capability already claimed", func() { + "capability already claimed", + func() { + path.EndpointB.SetChannel(*channel) err := suite.chainB.GetSimApp().ScopedICAKeeper.ClaimCapability(suite.chainB.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) suite.Require().NoError(err) - }, false, + }, + false, }, { - "invalid account address", func() { - channel.Counterparty.PortId = "invalid-port-id" - }, false, + "invalid account address", + func() { + portID, err := types.GeneratePortID("invalid-owner-addr", "connection-0", "connection-0") + suite.Require().NoError(err) + + channel.Counterparty.PortId = portID + path.EndpointB.SetChannel(*channel) + }, + false, }, } @@ -155,6 +287,10 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) suite.Require().NoError(err) + // set the channel id on host + channelSequence := path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(path.EndpointB.Chain.GetContext()) + path.EndpointB.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + // default values counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) channel = &channeltypes.Channel{ diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index 1930f327bd9..35d61cb0295 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -1,7 +1,6 @@ package keeper_test import ( - "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -21,7 +20,7 @@ var ( // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes - TestPortID = fmt.Sprintf("%s-0-0-%s", types.VersionPrefix, TestOwnerAddress) + TestPortID, _ = types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-0") // TestVersion defines a resuable interchainaccounts version string for testing purposes TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) ) diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go index 778a676f20b..a2ff103d3eb 100644 --- a/modules/apps/27-interchain-accounts/module_test.go +++ b/modules/apps/27-interchain-accounts/module_test.go @@ -1,7 +1,6 @@ package interchain_accounts_test import ( - "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -21,7 +20,7 @@ var ( // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes - TestPortID = fmt.Sprintf("%s-0-0-%s", types.VersionPrefix, TestOwnerAddress) + TestPortID, _ = types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-0") // TestVersion defines a resuable interchainaccounts version string for testing purposes TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) ) @@ -124,6 +123,9 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { Version: types.VersionPrefix, } + // set channel + path.EndpointA.SetChannel(*channel) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) suite.Require().NoError(err) @@ -142,7 +144,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { suite.SetupTest() // reset path := NewICAPath(suite.chainA, suite.chainB) - counterpartyVersion := types.VersionPrefix suite.coordinator.SetupConnections(path) err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) @@ -158,24 +159,29 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { Version: types.VersionPrefix, } - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) + // set channel + channelSequence := path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(path.EndpointB.Chain.GetContext()) + path.EndpointB.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + path.EndpointB.SetChannel(*channel) + + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), types.PortID) suite.Require().NoError(err) - chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(ibctesting.TransferPort, path.EndpointA.ChannelID)) + chanCap, err := suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(ibctesting.TransferPort, path.EndpointB.ChannelID)) suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - err = cbs.OnChanOpenTry(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), counterpartyVersion, + err = cbs.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.GetConnectionHops(), + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, TestVersion, types.VersionPrefix, ) + suite.Require().NoError(err) } func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { suite.SetupTest() // reset path := NewICAPath(suite.chainA, suite.chainB) - counterpartyVersion := types.VersionPrefix suite.coordinator.SetupConnections(path) err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) @@ -190,7 +196,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyVersion) + err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, TestVersion) suite.Require().NoError(err) } diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index a9f1fdcde1a..87cd0634900 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -21,11 +21,6 @@ func GenerateAddress(moduleAccAddr sdk.AccAddress, portID string) sdk.AccAddress return sdk.AccAddress(sdkaddress.Derive(moduleAccAddr, []byte(portID))) } -// ParseAddressFromVersion trims the interchainaccounts version prefix and returns the associated account address -func ParseAddressFromVersion(version string) string { - return strings.TrimPrefix(version, fmt.Sprint(VersionPrefix, Delimiter)) -} - // GeneratePortID generates the portID for a specific owner // on the controller chain in the format: // @@ -47,7 +42,12 @@ func GeneratePortID(owner, connectionID, counterpartyConnectionID string) (strin return "", sdkerrors.Wrap(err, "invalid counterparty connection identifier") } - return fmt.Sprintf("%s-%d-%d-%s", VersionPrefix, connectionSeq, counterpartyConnectionSeq, owner), nil + return fmt.Sprint( + VersionPrefix, Delimiter, + connectionSeq, Delimiter, + counterpartyConnectionSeq, Delimiter, + owner, + ), nil } type InterchainAccountI interface { diff --git a/modules/apps/27-interchain-accounts/types/account_test.go b/modules/apps/27-interchain-accounts/types/account_test.go index acca53e39c4..751bc0f0fa6 100644 --- a/modules/apps/27-interchain-accounts/types/account_test.go +++ b/modules/apps/27-interchain-accounts/types/account_test.go @@ -17,6 +17,8 @@ import ( var ( // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + // TestPortID defines a resuable port identifier for testing purposes + TestPortID, _ = types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-0") ) type TypesTestSuite struct { @@ -47,13 +49,6 @@ func (suite *TypesTestSuite) TestGenerateAddress() { suite.Require().NotEmpty(accAddr) } -func (suite *TypesTestSuite) TestParseAddressFromVersion() { - version := types.NewAppVersion(types.VersionPrefix, TestOwnerAddress) - - addr := types.ParseAddressFromVersion(version) - suite.Require().Equal(TestOwnerAddress, addr) -} - func (suite *TypesTestSuite) TestGeneratePortID() { var ( path *ibctesting.Path @@ -69,7 +64,7 @@ func (suite *TypesTestSuite) TestGeneratePortID() { { "success", func() {}, - fmt.Sprintf("%s-0-0-%s", types.VersionPrefix, TestOwnerAddress), + fmt.Sprint(types.VersionPrefix, types.Delimiter, "0", types.Delimiter, "0", types.Delimiter, TestOwnerAddress), true, }, { @@ -77,7 +72,7 @@ func (suite *TypesTestSuite) TestGeneratePortID() { func() { path.EndpointA.ConnectionID = "connection-1" }, - fmt.Sprintf("%s-1-0-%s", types.VersionPrefix, TestOwnerAddress), + fmt.Sprint(types.VersionPrefix, types.Delimiter, "1", types.Delimiter, "0", types.Delimiter, TestOwnerAddress), true, }, { diff --git a/modules/apps/27-interchain-accounts/types/expected_keepers.go b/modules/apps/27-interchain-accounts/types/expected_keepers.go index 8b355e504a0..73a9b2ffe85 100644 --- a/modules/apps/27-interchain-accounts/types/expected_keepers.go +++ b/modules/apps/27-interchain-accounts/types/expected_keepers.go @@ -31,6 +31,7 @@ type ChannelKeeper interface { SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error ChanOpenInit(ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, portCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string) (string, *capabilitytypes.Capability, error) + CounterpartyHops(ctx sdk.Context, channel channeltypes.Channel) ([]string, bool) } // ClientKeeper defines the expected IBC client keeper diff --git a/modules/apps/27-interchain-accounts/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go index 8640226191f..d8e3e1c1ec4 100644 --- a/modules/apps/27-interchain-accounts/types/keys.go +++ b/modules/apps/27-interchain-accounts/types/keys.go @@ -2,6 +2,12 @@ package types import ( "fmt" + "strconv" + "strings" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" ) const ( @@ -24,7 +30,11 @@ const ( QuerierRoute = ModuleName // Delimiter is the delimiter used for the interchain accounts version string - Delimiter = "|" + Delimiter = "." + + // ControllerPortFormat is the expected port identifier format to which controller chains must conform + // See (TODO: Link to spec when updated) + ControllerPortFormat = "..." ) var ( @@ -46,3 +56,45 @@ func KeyActiveChannel(portID string) []byte { func KeyOwnerAccount(portID string) []byte { return []byte(fmt.Sprintf("owner/%s", portID)) } + +// ParseControllerConnSequence attempts to parse the controller connection sequence from the provided port identifier +// The port identifier must match the controller chain format outlined in (TODO: link spec), otherwise an empty string is returned +func ParseControllerConnSequence(portID string) (uint64, error) { + s := strings.Split(portID, Delimiter) + if len(s) != 4 { + return 0, sdkerrors.Wrap(porttypes.ErrInvalidPort, "failed to parse port identifier") + } + + seq, err := strconv.ParseUint(s[1], 10, 64) + if err != nil { + return 0, sdkerrors.Wrapf(err, "failed to parse connection sequence (%s)", s[1]) + } + + return seq, nil +} + +// ParseHostConnSequence attempts to parse the host connection sequence from the provided port identifier +// The port identifier must match the controller chain format outlined in (TODO: link spec), otherwise an empty string is returned +func ParseHostConnSequence(portID string) (uint64, error) { + s := strings.Split(portID, Delimiter) + if len(s) != 4 { + return 0, sdkerrors.Wrap(porttypes.ErrInvalidPort, "failed to parse port identifier") + } + + seq, err := strconv.ParseUint(s[2], 10, 64) + if err != nil { + return 0, sdkerrors.Wrapf(err, "failed to parse connection sequence (%s)", s[2]) + } + + return seq, nil +} + +// ParseAddressFromVersion attempts to extract the associated account address from the provided version string +func ParseAddressFromVersion(version string) (string, error) { + s := strings.Split(version, Delimiter) + if len(s) != 2 { + return "", sdkerrors.Wrap(ErrInvalidVersion, "failed to parse version") + } + + return s[1], nil +} diff --git a/modules/apps/27-interchain-accounts/types/keys_test.go b/modules/apps/27-interchain-accounts/types/keys_test.go index 037061a3d3e..0bb4c7cea84 100644 --- a/modules/apps/27-interchain-accounts/types/keys_test.go +++ b/modules/apps/27-interchain-accounts/types/keys_test.go @@ -1,6 +1,8 @@ package types_test import ( + "fmt" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ) @@ -13,3 +15,132 @@ func (suite *TypesTestSuite) TestKeyOwnerAccount() { key := types.KeyOwnerAccount("port-id") suite.Require().Equal("owner/port-id", string(key)) } + +func (suite *TypesTestSuite) TestParseControllerConnSequence() { + + testCases := []struct { + name string + portID string + expValue uint64 + expPass bool + }{ + { + "success", + TestPortID, + 0, + true, + }, + { + "failed to parse port identifier", + "invalid-port-id", + 0, + false, + }, + { + "failed to parse connection sequence", + "ics27-1.x.y.cosmos1", + 0, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + connSeq, err := types.ParseControllerConnSequence(tc.portID) + + if tc.expPass { + suite.Require().Equal(tc.expValue, connSeq) + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Zero(connSeq) + suite.Require().Error(err, tc.name) + } + }) + } +} + +func (suite *TypesTestSuite) TestParseHostConnSequence() { + + testCases := []struct { + name string + portID string + expValue uint64 + expPass bool + }{ + { + "success", + TestPortID, + 0, + true, + }, + { + "failed to parse port identifier", + "invalid-port-id", + 0, + false, + }, + { + "failed to parse connection sequence", + "ics27-1.x.y.cosmos1", + 0, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + connSeq, err := types.ParseHostConnSequence(tc.portID) + + if tc.expPass { + suite.Require().Equal(tc.expValue, connSeq) + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Zero(connSeq) + suite.Require().Error(err, tc.name) + } + }) + } +} + +func (suite *TypesTestSuite) TestParseAddressFromVersion() { + + testCases := []struct { + name string + version string + expValue string + expPass bool + }{ + { + "success", + types.NewAppVersion(types.VersionPrefix, TestOwnerAddress), + TestOwnerAddress, + true, + }, + { + "failed to parse address from version", + "invalid-version-string", + "", + false, + }, + { + "failure with multiple delimiters", + fmt.Sprint(types.NewAppVersion(types.VersionPrefix, TestOwnerAddress), types.Delimiter, types.NewAppVersion(types.VersionPrefix, TestOwnerAddress)), + "", + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + addr, err := types.ParseAddressFromVersion(tc.version) + + if tc.expPass { + suite.Require().Equal(tc.expValue, addr) + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Empty(addr) + suite.Require().Error(err, tc.name) + } + }) + } +} From e072e6724ef2e98aaba7e0ae3946bd93a7547ed3 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 7 Oct 2021 11:32:24 +0200 Subject: [PATCH 36/66] chore: correctly set/delete active channels (#463) * correctly set active channels, implement delete OnChanCloseConfirm callback * removing active channel on packet timeout --- .../apps/27-interchain-accounts/ibc_module.go | 15 +++++-- .../keeper/handshake.go | 19 +++++++- .../keeper/handshake_test.go | 44 +++++++++++++++++++ .../27-interchain-accounts/keeper/keeper.go | 6 +++ .../keeper/keeper_test.go | 3 +- .../27-interchain-accounts/keeper/relay.go | 8 ++-- .../keeper/relay_test.go | 42 ++++++++++++++++++ 7 files changed, 126 insertions(+), 11 deletions(-) diff --git a/modules/apps/27-interchain-accounts/ibc_module.go b/modules/apps/27-interchain-accounts/ibc_module.go index 99451e7876a..abc488af67a 100644 --- a/modules/apps/27-interchain-accounts/ibc_module.go +++ b/modules/apps/27-interchain-accounts/ibc_module.go @@ -29,7 +29,7 @@ func NewIBCModule(k keeper.Keeper, app porttypes.IBCModule) IBCModule { } } -// Implement IBCModule callbacks +// OnChanOpenInit implements the IBCModule interface func (im IBCModule) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, @@ -43,6 +43,7 @@ func (im IBCModule) OnChanOpenInit( return im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) } +// OnChanOpenTry implements the IBCModule interface func (im IBCModule) OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, @@ -57,6 +58,7 @@ func (im IBCModule) OnChanOpenTry( return im.keeper.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version, counterpartyVersion) } +// OnChanOpenAck implements the IBCModule interface func (im IBCModule) OnChanOpenAck( ctx sdk.Context, portID, @@ -66,6 +68,7 @@ func (im IBCModule) OnChanOpenAck( return im.keeper.OnChanOpenAck(ctx, portID, channelID, counterpartyVersion) } +// OnChanOpenConfirm implements the IBCModule interface func (im IBCModule) OnChanOpenConfirm( ctx sdk.Context, portID, @@ -74,6 +77,7 @@ func (im IBCModule) OnChanOpenConfirm( return im.keeper.OnChanOpenConfirm(ctx, portID, channelID) } +// OnChanCloseInit implements the IBCModule interface func (im IBCModule) OnChanCloseInit( ctx sdk.Context, portID, @@ -83,14 +87,16 @@ func (im IBCModule) OnChanCloseInit( return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") } +// OnChanCloseConfirm implements the IBCModule interface func (im IBCModule) OnChanCloseConfirm( ctx sdk.Context, portID, channelID string, ) error { - return nil + return im.keeper.OnChanCloseConfirm(ctx, portID, channelID) } +// OnRecvPacket implements the IBCModule interface func (im IBCModule) OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, @@ -116,6 +122,7 @@ func (im IBCModule) OnRecvPacket( return ack } +// OnAcknowledgementPacket implements the IBCModule interface func (im IBCModule) OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, @@ -139,13 +146,13 @@ func (im IBCModule) OnAcknowledgementPacket( return nil } +// OnTimeoutPacket implements the IBCModule interface func (im IBCModule) OnTimeoutPacket( ctx sdk.Context, packet channeltypes.Packet, _ sdk.AccAddress, ) error { - // TODO - return nil + return im.keeper.OnTimeoutPacket(ctx, packet) } // NegotiateAppVersion implements the IBCModule interface diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index 607f9524256..b6d4f0c9284 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -164,12 +164,29 @@ func (k Keeper) OnChanOpenAck( return nil } -// Set active channel +// OnChanOpenConfirm completes the handshake process by setting the active channel in state on the host chain +// +// Host Chain func (k Keeper) OnChanOpenConfirm( ctx sdk.Context, portID, channelID string, ) error { + + k.SetActiveChannel(ctx, portID, channelID) + + return nil +} + +// OnChanCloseConfirm removes the active channel stored in state +func (k Keeper) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + + k.DeleteActiveChannel(ctx, portID) + return nil } diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index 63afb203f11..06eb217ecb5 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -428,3 +428,47 @@ func (suite *KeeperTestSuite) TestOnChanOpenConfirm() { }) } } + +func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // explicitly change fields in channel and testChannel + + err = suite.chainB.GetSimApp().ICAKeeper.OnChanCloseConfirm(suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + + activeChannel, found := suite.chainB.GetSimApp().ICAKeeper.GetActiveChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().False(found) + suite.Require().Empty(activeChannel) + } else { + suite.Require().Error(err) + } + + }) + } +} diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index 9730f5a9da7..63b3e82fcea 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -134,6 +134,12 @@ func (k Keeper) SetActiveChannel(ctx sdk.Context, portID, channelID string) { store.Set(types.KeyActiveChannel(portID), []byte(channelID)) } +// DeleteActiveChannel removes the active channel keyed by the provided portID stored in state +func (k Keeper) DeleteActiveChannel(ctx sdk.Context, portID string) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.KeyActiveChannel(portID)) +} + // IsActiveChannel returns true if there exists an active channel for the provided portID, otherwise false func (k Keeper) IsActiveChannel(ctx sdk.Context, portID string) bool { _, ok := k.GetActiveChannel(ctx, portID) diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index 35d61cb0295..0c407e88121 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -169,8 +169,7 @@ func (suite *KeeperTestSuite) SetupICAPath(path *ibctesting.Path, owner string) return err } - if err := suite.chainB.GetSimApp().ICAKeeper.OnChanOpenConfirm(suite.chainA.GetContext(), - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID); err != nil { + if err := path.EndpointB.ChanOpenConfirm(); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 18e6d552eff..afdfda2c8d0 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -233,10 +233,10 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac } } -func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.InterchainAccountPacketData) error { - if k.hook != nil { - k.hook.OnTxFailed(ctx, packet.SourcePort, packet.SourceChannel, packet.Data, data.Data) - } +// OnTimeoutPacket removes the active channel associated with the provided packet, the underlying channel end is closed +// due to the semantics of ORDERED channels +func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet) error { + k.DeleteActiveChannel(ctx, packet.SourcePort) return nil } diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index 2609f59545c..d3c7aadc2d5 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -220,3 +220,45 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { }) } } + +func (suite *KeeperTestSuite) TestOnTimeoutPacket() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := suite.SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + packet := channeltypes.NewPacket([]byte{}, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) + err = suite.chainA.GetSimApp().ICAKeeper.OnTimeoutPacket(suite.chainA.GetContext(), packet) + + channel, found := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Empty(channel) + suite.Require().False(found) + } else { + suite.Require().Error(err) + } + }) + } +} From 95959485549937a8323d08d0c4a98e8f25c313af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Fri, 8 Oct 2021 14:45:04 +0200 Subject: [PATCH 37/66] remove ica hooks (#480) --- .../27-interchain-accounts/keeper/keeper.go | 5 +---- .../apps/27-interchain-accounts/keeper/relay.go | 17 +---------------- testing/simapp/app.go | 9 +-------- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index 63b3e82fcea..f10f5b8678d 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -22,8 +22,6 @@ type Keeper struct { storeKey sdk.StoreKey cdc codec.BinaryCodec - hook types.IBCAccountHooks - channelKeeper types.ChannelKeeper portKeeper types.PortKeeper accountKeeper types.AccountKeeper @@ -37,7 +35,7 @@ type Keeper struct { func NewKeeper( cdc codec.BinaryCodec, key sdk.StoreKey, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, - accountKeeper types.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, hook types.IBCAccountHooks, + accountKeeper types.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, ) Keeper { // ensure ibc interchain accounts module account is set @@ -53,7 +51,6 @@ func NewKeeper( accountKeeper: accountKeeper, scopedKeeper: scopedKeeper, msgRouter: msgRouter, - hook: hook, } } diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index afdfda2c8d0..f01bb02aba2 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -215,22 +215,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error } func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.InterchainAccountPacketData, ack channeltypes.Acknowledgement) error { - switch ack.Response.(type) { - case *channeltypes.Acknowledgement_Error: - if k.hook != nil { - k.hook.OnTxFailed(ctx, packet.SourcePort, packet.SourceChannel, packet.Data, data.Data) - } - return nil - case *channeltypes.Acknowledgement_Result: - if k.hook != nil { - k.hook.OnTxSucceeded(ctx, packet.SourcePort, packet.SourceChannel, packet.Data, data.Data) - } - return nil - default: - // the acknowledgement succeeded on the receiving chain so nothing - // needs to be executed and no error needs to be returned - return nil - } + return nil } // OnTimeoutPacket removes the active channel associated with the provided packet, the underlying channel end is closed diff --git a/testing/simapp/app.go b/testing/simapp/app.go index c158e3fead7..00f1a631bfa 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -335,7 +335,7 @@ func NewSimApp( app.ICAKeeper = icakeeper.NewKeeper( appCodec, keys[icatypes.StoreKey], app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAKeeper, app.MsgServiceRouter(), app, + app.AccountKeeper, scopedICAKeeper, app.MsgServiceRouter(), ) icaModule := ica.NewAppModule(app.ICAKeeper) icaIBCModule := ica.NewIBCModule(app.ICAKeeper, nil) @@ -682,10 +682,3 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino return paramsKeeper } - -// Interchain Accounts code -func (*SimApp) OnTxSucceeded(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) { -} - -func (*SimApp) OnTxFailed(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) { -} From 9450085e6454fe99809de1a4bed74f3787507198 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 11 Oct 2021 11:39:29 +0200 Subject: [PATCH 38/66] chore: minor nits - renaming and error msgs (#464) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update ErrPortAlreadyBound error string - remove for address * rename RegisterInterchainAccount api portID -> counterpartyPortID * wrap claim capability errors in handshake * Update modules/apps/27-interchain-accounts/keeper/account.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * adding channel and port id in error msg * correcting error wording Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- modules/apps/27-interchain-accounts/keeper/account.go | 6 +++--- modules/apps/27-interchain-accounts/keeper/handshake.go | 4 ++-- modules/apps/27-interchain-accounts/types/errors.go | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go index f10bd73e005..0c14be4ea97 100644 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ b/modules/apps/27-interchain-accounts/keeper/account.go @@ -42,17 +42,17 @@ func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpart // RegisterInterchainAccount attempts to create a new account using the provided address and stores it in state keyed by the provided port identifier // If an account for the provided address already exists this function returns early (no-op) -func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, accAddr sdk.AccAddress, portID string) { +func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, accAddr sdk.AccAddress, controllerPortID string) { if acc := k.accountKeeper.GetAccount(ctx, accAddr); acc != nil { return } interchainAccount := types.NewInterchainAccount( authtypes.NewBaseAccountWithAddress(accAddr), - portID, + controllerPortID, ) k.accountKeeper.NewAccount(ctx, interchainAccount) k.accountKeeper.SetAccount(ctx, interchainAccount) - k.SetInterchainAccountAddress(ctx, portID, interchainAccount.Address) + k.SetInterchainAccountAddress(ctx, controllerPortID, interchainAccount.Address) } diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index b6d4f0c9284..52e179eff1d 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -64,7 +64,7 @@ func (k Keeper) OnChanOpenInit( // Claim channel capability passed back by IBC module if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, err.Error()) + return sdkerrors.Wrapf(err, "failed to claim capability for channel %s on port %s", channelID, portID) } return nil @@ -118,7 +118,7 @@ func (k Keeper) OnChanOpenTry( // On the host chain the capability may only be claimed during the OnChanOpenTry // The capability being claimed in OpenInit is for a controller chain (the port is different) if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err + return sdkerrors.Wrapf(err, "failed to claim capability for channel %s on port %s", channelID, portID) } // Check to ensure that the version string contains the expected address generated from the Counterparty portID diff --git a/modules/apps/27-interchain-accounts/types/errors.go b/modules/apps/27-interchain-accounts/types/errors.go index 6b05a626a82..77787281d1a 100644 --- a/modules/apps/27-interchain-accounts/types/errors.go +++ b/modules/apps/27-interchain-accounts/types/errors.go @@ -7,7 +7,7 @@ import ( var ( ErrUnknownPacketData = sdkerrors.Register(ModuleName, 2, "unknown packet data") ErrAccountAlreadyExist = sdkerrors.Register(ModuleName, 3, "account already exist") - ErrPortAlreadyBound = sdkerrors.Register(ModuleName, 4, "port is already bound for address") + ErrPortAlreadyBound = sdkerrors.Register(ModuleName, 4, "port is already bound") ErrUnsupportedChain = sdkerrors.Register(ModuleName, 5, "unsupported chain") ErrInvalidOutgoingData = sdkerrors.Register(ModuleName, 6, "invalid outgoing data") ErrInvalidRoute = sdkerrors.Register(ModuleName, 7, "invalid route") From 0ae4a750145ab7dd7be481bc1486b8cbf6a64fb2 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 11 Oct 2021 15:33:43 +0200 Subject: [PATCH 39/66] chore: update portkey to include port ID (#467) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update port key to use prefix, separate key prefixes to vars * updating godoc * Update modules/apps/27-interchain-accounts/keeper/keeper.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * adding todo with ica genesis issue ref * fixing failing test from browser commit * removing GetPort in favour of GetAllPorts Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- .../apps/27-interchain-accounts/genesis.go | 5 +++-- .../27-interchain-accounts/keeper/keeper.go | 19 +++++++++++++---- .../keeper/keeper_test.go | 14 ++++++++++--- .../apps/27-interchain-accounts/types/keys.go | 21 ++++++++++++++----- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/modules/apps/27-interchain-accounts/genesis.go b/modules/apps/27-interchain-accounts/genesis.go index 0fd975ace00..e052834b8a5 100644 --- a/modules/apps/27-interchain-accounts/genesis.go +++ b/modules/apps/27-interchain-accounts/genesis.go @@ -22,9 +22,10 @@ func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState // ExportGenesis exports transfer module's portID into its geneis state func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState { - portID := keeper.GetPort(ctx) + // TODO: Using a range query with KVStorePrefixIterator export all port IDs + // See https://github.com/cosmos/ibc-go/issues/448 return &types.GenesisState{ - PortId: portID, + PortId: types.PortID, } } diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index f10f5b8678d..d66026c7a6d 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -2,6 +2,7 @@ package keeper import ( "fmt" + "strings" baseapp "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" @@ -83,16 +84,26 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) } -// GetPort returns the portID for the interchain accounts module. Used in ExportGenesis -func (k Keeper) GetPort(ctx sdk.Context) string { +// GetAllPorts returns all ports to which the interchain accounts module is bound. Used in ExportGenesis +func (k Keeper) GetAllPorts(ctx sdk.Context) []string { store := ctx.KVStore(k.storeKey) - return string(store.Get([]byte(types.PortKey))) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.PortKeyPrefix)) + defer iterator.Close() + + var ports []string + for ; iterator.Valid(); iterator.Next() { + keySplit := strings.Split(string(iterator.Key()), "/") + + ports = append(ports, keySplit[1]) + } + + return ports } // BindPort stores the provided portID and binds to it, returning the associated capability func (k Keeper) BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability { store := ctx.KVStore(k.storeKey) - store.Set([]byte(types.PortKey), []byte(portID)) + store.Set(types.KeyPort(portID), []byte{0x01}) return k.portKeeper.BindPort(ctx, portID) } diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index 0c407e88121..307451fd14b 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -108,9 +108,17 @@ func (suite *KeeperTestSuite) TestIsBound() { suite.Require().True(isBound) } -func (suite *KeeperTestSuite) TestGetPort() { - port := suite.chainA.GetSimApp().ICAKeeper.GetPort(suite.chainA.GetContext()) - suite.Require().Equal(types.PortID, port) +func (suite *KeeperTestSuite) TestGetAllPorts() { + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + ports := suite.chainA.GetSimApp().ICAKeeper.GetAllPorts(suite.chainA.GetContext()) + suite.Require().Contains(ports, types.PortID) + suite.Require().Contains(ports, TestPortID) } func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { diff --git a/modules/apps/27-interchain-accounts/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go index d8e3e1c1ec4..a71f6c0c32c 100644 --- a/modules/apps/27-interchain-accounts/types/keys.go +++ b/modules/apps/27-interchain-accounts/types/keys.go @@ -38,8 +38,14 @@ const ( ) var ( - // PortKey defines the key to store the port ID in store - PortKey = []byte{0x01} + // ActiveChannelKeyPrefix defines the key prefix used to store active channels + ActiveChannelKeyPrefix = "activeChannel" + + // OwnerKeyPrefix defines the key prefix used to store interchain accounts + OwnerKeyPrefix = "owner" + + // PortKeyPrefix defines the key prefix used to store ports + PortKeyPrefix = "port" ) // NewVersion returns a complete version string in the format: VersionPrefix + Delimter + AccAddress @@ -49,12 +55,17 @@ func NewAppVersion(versionPrefix, accAddr string) string { // KeyActiveChannel creates and returns a new key used for active channels store operations func KeyActiveChannel(portID string) []byte { - return []byte(fmt.Sprintf("activeChannel/%s", portID)) + return []byte(fmt.Sprintf("%s/%s", ActiveChannelKeyPrefix, portID)) } -// KeyOwnerAccount creates and returns a new key used for owner account store operations +// KeyOwnerAccount creates and returns a new key used for interchain account store operations func KeyOwnerAccount(portID string) []byte { - return []byte(fmt.Sprintf("owner/%s", portID)) + return []byte(fmt.Sprintf("%s/%s", OwnerKeyPrefix, portID)) +} + +// KeyPort creates and returns a new key used for port store operations +func KeyPort(portID string) []byte { + return []byte(fmt.Sprintf("%s/%s", PortKeyPrefix, portID)) } // ParseControllerConnSequence attempts to parse the controller connection sequence from the provided port identifier From 3e9afcbb4814231275111a7fef87fc9fa7574170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 12 Oct 2021 14:31:37 +0200 Subject: [PATCH 40/66] ICA: Rename TxBody, Remove serialization logic from controller, introduce CosmosTx type (#474) * remove ICA TxBody type, use repeated Any in packet data * adjust SerializeCosmosTx, fix tests * apply self nits * add memo length validation --- docs/ibc/proto-docs.md | 10 +- .../27-interchain-accounts/keeper/keeper.go | 11 +- .../27-interchain-accounts/keeper/relay.go | 54 +-- .../keeper/relay_test.go | 103 ++--- .../27-interchain-accounts/types/packet.go | 41 +- .../types/packet_test.go | 66 +++ .../27-interchain-accounts/types/types.pb.go | 396 +++++++++--------- .../interchain_accounts/v1/types.proto | 11 +- 8 files changed, 390 insertions(+), 302 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/types/packet_test.go diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 986ffd334f8..fe109584bba 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -17,7 +17,7 @@ - [Query](#ibc.applications.interchain_accounts.v1.Query) - [ibc/applications/interchain_accounts/v1/types.proto](#ibc/applications/interchain_accounts/v1/types.proto) - - [IBCTxBody](#ibc.applications.interchain_accounts.v1.IBCTxBody) + - [CosmosTx](#ibc.applications.interchain_accounts.v1.CosmosTx) - [InterchainAccountPacketData](#ibc.applications.interchain_accounts.v1.InterchainAccountPacketData) - [Type](#ibc.applications.interchain_accounts.v1.Type) @@ -398,10 +398,10 @@ Query defines the gRPC querier service. - + -### IBCTxBody -Body of a tx for an ics27 IBC packet +### CosmosTx +CosmosTx contains a list of sdk.Msg's. It should be used when sending transactions to an SDK host chain. | Field | Type | Label | Description | @@ -416,7 +416,7 @@ Body of a tx for an ics27 IBC packet ### InterchainAccountPacketData -InterchainAccountPacketData is comprised of araw transaction,type of transaction and optional memo field. +InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. | Field | Type | Label | Description | diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index d66026c7a6d..2c685ade7d9 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -55,23 +55,24 @@ func NewKeeper( } } -// SerializeCosmosTx marshals data to bytes using the provided codec -func (k Keeper) SerializeCosmosTx(cdc codec.BinaryCodec, msgs []sdk.Msg) ([]byte, error) { +// SerializeCosmosTx serializes a slice of sdk.Msg's using the CosmosTx type. The sdk.Msg's are +// packed into Any's and inserted into the Messages field of a CosmosTx. The proto marshaled CosmosTx +// bytes are returned. +func (k Keeper) SerializeCosmosTx(cdc codec.BinaryCodec, msgs []sdk.Msg) (bz []byte, err error) { msgAnys := make([]*codectypes.Any, len(msgs)) for i, msg := range msgs { - var err error msgAnys[i], err = codectypes.NewAnyWithValue(msg) if err != nil { return nil, err } } - txBody := &types.IBCTxBody{ + cosmosTx := &types.CosmosTx{ Messages: msgAnys, } - bz, err := cdc.Marshal(txBody) + bz, err = cdc.Marshal(cosmosTx) if err != nil { return nil, err } diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index f01bb02aba2..446f1521837 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -12,7 +12,7 @@ import ( // TODO: implement middleware functionality, this will allow us to use capabilities to // manage helper module access to owner addresses they do not have capabilities for -func (k Keeper) TrySendTx(ctx sdk.Context, portID string, data interface{}, memo string) (uint64, error) { +func (k Keeper) TrySendTx(ctx sdk.Context, portID string, icaPacketData types.InterchainAccountPacketData) (uint64, error) { // Check for the active channel activeChannelId, found := k.GetActiveChannel(ctx, portID) if !found { @@ -27,7 +27,7 @@ func (k Keeper) TrySendTx(ctx sdk.Context, portID string, data interface{}, memo destinationPort := sourceChannelEnd.GetCounterparty().GetPortID() destinationChannel := sourceChannelEnd.GetCounterparty().GetChannelID() - return k.createOutgoingPacket(ctx, portID, activeChannelId, destinationPort, destinationChannel, data, memo) + return k.createOutgoingPacket(ctx, portID, activeChannelId, destinationPort, destinationChannel, icaPacketData) } func (k Keeper) createOutgoingPacket( @@ -36,27 +36,10 @@ func (k Keeper) createOutgoingPacket( sourceChannel, destinationPort, destinationChannel string, - data interface{}, - memo string, + icaPacketData types.InterchainAccountPacketData, ) (uint64, error) { - if data == nil { - return 0, types.ErrInvalidOutgoingData - } - - var ( - txBytes []byte - err error - ) - - switch data := data.(type) { - case []sdk.Msg: - txBytes, err = k.SerializeCosmosTx(k.cdc, data) - default: - return 0, sdkerrors.Wrapf(types.ErrInvalidOutgoingData, "message type %T is not supported", data) - } - - if err != nil { - return 0, sdkerrors.Wrap(err, "serialization of transaction data failed") + if err := icaPacketData.ValidateBasic(); err != nil { + return 0, sdkerrors.Wrap(err, "invalid interchain account packet data") } channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(sourcePort, sourceChannel)) @@ -70,18 +53,12 @@ func (k Keeper) createOutgoingPacket( return 0, channeltypes.ErrSequenceSendNotFound } - packetData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: txBytes, - Memo: memo, - } - // timeoutTimestamp is set to be a max number here so that we never recieve a timeout // ics-27-1 uses ordered channels which can close upon recieving a timeout, which is an undesired effect const timeoutTimestamp = ^uint64(0) >> 1 // Shift the unsigned bit to satisfy hermes relayer timestamp conversion packet := channeltypes.NewPacket( - packetData.GetBytes(), + icaPacketData.GetBytes(), sequence, sourcePort, sourceChannel, @@ -100,25 +77,26 @@ func (k Keeper) createOutgoingPacket( // DeserializeCosmosTx unmarshals and unpacks a slice of transaction bytes // into a slice of sdk.Msg's. -func (k Keeper) DeserializeCosmosTx(_ sdk.Context, txBytes []byte) ([]sdk.Msg, error) { - var txBody types.IBCTxBody - - if err := k.cdc.Unmarshal(txBytes, &txBody); err != nil { +func (k Keeper) DeserializeCosmosTx(_ sdk.Context, data []byte) ([]sdk.Msg, error) { + var cosmosTx types.CosmosTx + if err := k.cdc.Unmarshal(data, &cosmosTx); err != nil { return nil, err } - anys := txBody.Messages - res := make([]sdk.Msg, len(anys)) - for i, any := range anys { + msgs := make([]sdk.Msg, len(cosmosTx.Messages)) + + for i, any := range cosmosTx.Messages { var msg sdk.Msg + err := k.cdc.UnpackAny(any, &msg) if err != nil { return nil, err } - res[i] = msg + + msgs[i] = msg } - return res, nil + return msgs, nil } func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portId string) error { diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index d3c7aadc2d5..f5d02b2ec6a 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -15,9 +15,9 @@ import ( func (suite *KeeperTestSuite) TestTrySendTx() { var ( - path *ibctesting.Path - msg interface{} - portID string + path *ibctesting.Path + icaPacketData types.InterchainAccountPacketData + portID string ) testCases := []struct { @@ -27,9 +27,6 @@ func (suite *KeeperTestSuite) TestTrySendTx() { }{ { "success", func() { - amount, _ := sdk.ParseCoinsNormalized("100stake") - interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) - msg = []sdk.Msg{&banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount}} }, true, }, { @@ -38,45 +35,30 @@ func (suite *KeeperTestSuite) TestTrySendTx() { interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) msg1 := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} msg2 := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} - msg = []sdk.Msg{msg1, msg2} + data, err := suite.chainB.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg1, msg2}) + suite.Require().NoError(err) + icaPacketData.Data = data }, true, }, { - "incorrect outgoing data", func() { - msg = []byte{} - }, false, - }, - { - "incorrect outgoing data - []sdk.Msg is not used", func() { - amount, _ := sdk.ParseCoinsNormalized("100stake") - interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) - msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + "data is nil", func() { + icaPacketData.Data = nil }, false, }, { "active channel not found", func() { - amount, _ := sdk.ParseCoinsNormalized("100stake") - interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) - msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} portID = "incorrect portID" }, false, }, { "channel does not exist", func() { - amount, _ := sdk.ParseCoinsNormalized("100stake") - interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) - msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), portID, "channel-100") }, false, }, { - "data is nil", func() { - msg = nil - }, false, - }, - { - "data is not an SDK message", func() { - msg = "not an sdk message" + "SendPacket fails - channel closed", func() { + err := path.EndpointA.SetChannelClosed() + suite.Require().NoError(err) }, false, }, } @@ -88,16 +70,28 @@ func (suite *KeeperTestSuite) TestTrySendTx() { suite.SetupTest() // reset path = NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) - memo := "memo" err := suite.SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) portID = path.EndpointA.ChannelConfig.PortID + amount, _ := sdk.ParseCoinsNormalized("100stake") + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + msg := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + data, err := suite.chainB.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg}) + suite.Require().NoError(err) + + // default packet data, must be modified in malleate for test cases expected to fail + icaPacketData = types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + Memo: "memo", + } + tc.malleate() - _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), portID, msg, memo) + _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), portID, icaPacketData) if tc.expPass { suite.Require().NoError(err) @@ -112,7 +106,6 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { var ( path *ibctesting.Path msg sdk.Msg - txBytes []byte packetData []byte sourcePort string ) @@ -129,30 +122,40 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} // build packet data - txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) + data, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) suite.Require().NoError(err) - data := types.InterchainAccountPacketData{Type: types.EXECUTE_TX, - Data: txBytes} - packetData = data.GetBytes() + icaPacketData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + packetData = icaPacketData.GetBytes() }, true, }, { - "Cannot deserialize txBytes", func() { - txBytes = []byte("invalid tx bytes") - data := types.InterchainAccountPacketData{Type: types.EXECUTE_TX, - Data: txBytes} - packetData = data.GetBytes() + "Cannot deserialize packet data messages", func() { + data := []byte("invalid packet data") + + icaPacketData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + packetData = icaPacketData.GetBytes() }, false, }, { "Invalid packet type", func() { - txBytes = []byte{} + // build packet data + data, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{&banktypes.MsgSend{}}) + suite.Require().NoError(err) + // Type here is an ENUM // Valid type is types.EXECUTE_TX - data := types.InterchainAccountPacketData{Type: 100, - Data: txBytes} - packetData = data.GetBytes() + icaPacketData := types.InterchainAccountPacketData{ + Type: 100, + Data: data, + } + packetData = icaPacketData.GetBytes() }, false, }, { @@ -172,11 +175,13 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // Incorrect FromAddress msg = &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} // build packet data - txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) + data, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) suite.Require().NoError(err) - data := types.InterchainAccountPacketData{Type: types.EXECUTE_TX, - Data: txBytes} - packetData = data.GetBytes() + icaPacketData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + packetData = icaPacketData.GetBytes() }, false, }, } diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 1c64054b3ee..d69dfebd30a 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -1,9 +1,46 @@ package types import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -func (packet InterchainAccountPacketData) GetBytes() []byte { - return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&packet)) +const MaxMemoCharLength = 256 + +// ValidateBasic performs basic validation of the interchain account packet data. +// The memo may be empty. +func (iapd InterchainAccountPacketData) ValidateBasic() error { + if iapd.Data == nil { + return sdkerrors.Wrap(ErrInvalidOutgoingData, "packet data cannot be empty") + } + + if len(iapd.Memo) > MaxMemoCharLength { + return sdkerrors.Wrapf(ErrInvalidOutgoingData, "packet data memo cannot be greater than %d characters", MaxMemoCharLength) + } + // TODO: add type validation when data type enum supports unspecified type + + return nil +} + +// GetBytes returns the JSON marshalled interchain account packet data. +func (iapd InterchainAccountPacketData) GetBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&iapd)) +} + +// GetBytes returns the JSON marshalled interchain account CosmosTx. +func (ct CosmosTx) GetBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&ct)) +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (ct CosmosTx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + for _, any := range ct.Messages { + err := unpacker.UnpackAny(any, new(sdk.Msg)) + if err != nil { + return err + } + } + + return nil } diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go new file mode 100644 index 00000000000..ce2fab2f5ca --- /dev/null +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -0,0 +1,66 @@ +package types_test + +import ( + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" +) + +var largeMemo = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum" + +func (suite *TypesTestSuite) TestValidateBasic() { + testCases := []struct { + name string + packetData types.InterchainAccountPacketData + expPass bool + }{ + { + "success", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "memo", + }, + true, + }, + { + "success, empty memo", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + }, + true, + }, + { + "empty data", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: nil, + Memo: "memo", + }, + false, + }, + { + "memo too large", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: largeMemo, + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + err := tc.packetData.ValidateBasic() + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/modules/apps/27-interchain-accounts/types/types.pb.go b/modules/apps/27-interchain-accounts/types/types.pb.go index 38aa8249c28..a4fad957f7f 100644 --- a/modules/apps/27-interchain-accounts/types/types.pb.go +++ b/modules/apps/27-interchain-accounts/types/types.pb.go @@ -50,52 +50,7 @@ func (Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor_39bab93e18d89799, []int{0} } -// Body of a tx for an ics27 IBC packet -type IBCTxBody struct { - Messages []*types.Any `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` -} - -func (m *IBCTxBody) Reset() { *m = IBCTxBody{} } -func (m *IBCTxBody) String() string { return proto.CompactTextString(m) } -func (*IBCTxBody) ProtoMessage() {} -func (*IBCTxBody) Descriptor() ([]byte, []int) { - return fileDescriptor_39bab93e18d89799, []int{0} -} -func (m *IBCTxBody) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *IBCTxBody) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_IBCTxBody.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *IBCTxBody) XXX_Merge(src proto.Message) { - xxx_messageInfo_IBCTxBody.Merge(m, src) -} -func (m *IBCTxBody) XXX_Size() int { - return m.Size() -} -func (m *IBCTxBody) XXX_DiscardUnknown() { - xxx_messageInfo_IBCTxBody.DiscardUnknown(m) -} - -var xxx_messageInfo_IBCTxBody proto.InternalMessageInfo - -func (m *IBCTxBody) GetMessages() []*types.Any { - if m != nil { - return m.Messages - } - return nil -} - -// InterchainAccountPacketData is comprised of araw transaction,type of transaction and optional memo field. +// InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. type InterchainAccountPacketData struct { Type Type `protobuf:"varint,1,opt,name=type,proto3,enum=ibc.applications.interchain_accounts.v1.Type" json:"type,omitempty"` Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` @@ -106,7 +61,7 @@ func (m *InterchainAccountPacketData) Reset() { *m = InterchainAccountPa func (m *InterchainAccountPacketData) String() string { return proto.CompactTextString(m) } func (*InterchainAccountPacketData) ProtoMessage() {} func (*InterchainAccountPacketData) Descriptor() ([]byte, []int) { - return fileDescriptor_39bab93e18d89799, []int{1} + return fileDescriptor_39bab93e18d89799, []int{0} } func (m *InterchainAccountPacketData) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -156,10 +111,55 @@ func (m *InterchainAccountPacketData) GetMemo() string { return "" } +// CosmosTx contains a list of sdk.Msg's. It should be used when sending transactions to an SDK host chain. +type CosmosTx struct { + Messages []*types.Any `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` +} + +func (m *CosmosTx) Reset() { *m = CosmosTx{} } +func (m *CosmosTx) String() string { return proto.CompactTextString(m) } +func (*CosmosTx) ProtoMessage() {} +func (*CosmosTx) Descriptor() ([]byte, []int) { + return fileDescriptor_39bab93e18d89799, []int{1} +} +func (m *CosmosTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CosmosTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CosmosTx.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CosmosTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_CosmosTx.Merge(m, src) +} +func (m *CosmosTx) XXX_Size() int { + return m.Size() +} +func (m *CosmosTx) XXX_DiscardUnknown() { + xxx_messageInfo_CosmosTx.DiscardUnknown(m) +} + +var xxx_messageInfo_CosmosTx proto.InternalMessageInfo + +func (m *CosmosTx) GetMessages() []*types.Any { + if m != nil { + return m.Messages + } + return nil +} + func init() { proto.RegisterEnum("ibc.applications.interchain_accounts.v1.Type", Type_name, Type_value) - proto.RegisterType((*IBCTxBody)(nil), "ibc.applications.interchain_accounts.v1.IBCTxBody") proto.RegisterType((*InterchainAccountPacketData)(nil), "ibc.applications.interchain_accounts.v1.InterchainAccountPacketData") + proto.RegisterType((*CosmosTx)(nil), "ibc.applications.interchain_accounts.v1.CosmosTx") } func init() { @@ -167,68 +167,31 @@ func init() { } var fileDescriptor_39bab93e18d89799 = []byte{ - // 380 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0xcf, 0xaa, 0xd3, 0x40, - 0x18, 0xc5, 0x33, 0xde, 0x20, 0xde, 0x51, 0x8a, 0x84, 0x2e, 0x62, 0x0a, 0x21, 0x74, 0x63, 0x10, - 0x32, 0x63, 0xd3, 0x85, 0xab, 0x2e, 0xfa, 0x27, 0x42, 0x36, 0x52, 0x62, 0x0a, 0xd5, 0x4d, 0x98, - 0x4c, 0xc7, 0x74, 0xb0, 0xc9, 0x84, 0xce, 0xa4, 0x98, 0x37, 0x28, 0xae, 0x7c, 0x01, 0x57, 0xbe, - 0x8c, 0xcb, 0x2e, 0x5d, 0x4a, 0xfb, 0x22, 0x92, 0x04, 0x5b, 0x17, 0x2e, 0xee, 0xee, 0xf0, 0xcd, - 0xfc, 0x0e, 0xdf, 0xf9, 0x0e, 0x1c, 0xf3, 0x94, 0x62, 0x52, 0x96, 0x3b, 0x4e, 0x89, 0xe2, 0xa2, - 0x90, 0x98, 0x17, 0x8a, 0xed, 0xe9, 0x96, 0xf0, 0x22, 0x21, 0x94, 0x8a, 0xaa, 0x50, 0x12, 0x1f, - 0x46, 0x58, 0xd5, 0x25, 0x93, 0xa8, 0xdc, 0x0b, 0x25, 0x8c, 0x97, 0x3c, 0xa5, 0xe8, 0x5f, 0x08, - 0xfd, 0x07, 0x42, 0x87, 0x91, 0xf5, 0x22, 0x13, 0x22, 0xdb, 0x31, 0xdc, 0x62, 0x69, 0xf5, 0x09, - 0x93, 0xa2, 0xee, 0x3c, 0xac, 0x7e, 0x26, 0x32, 0xd1, 0x4a, 0xdc, 0xa8, 0x6e, 0x3a, 0x9c, 0xc0, - 0xfb, 0x70, 0x36, 0x8f, 0xbf, 0xcc, 0xc4, 0xa6, 0x36, 0x5e, 0xc3, 0x27, 0x39, 0x93, 0x92, 0x64, - 0x4c, 0x9a, 0xc0, 0xb9, 0x73, 0x9f, 0xfa, 0x7d, 0xd4, 0x19, 0xa2, 0xbf, 0x86, 0x68, 0x5a, 0xd4, - 0xd1, 0xf5, 0xd7, 0xf0, 0x08, 0xe0, 0x20, 0xbc, 0xae, 0x32, 0xed, 0x36, 0x59, 0x12, 0xfa, 0x99, - 0xa9, 0x05, 0x51, 0xc4, 0x98, 0x42, 0xbd, 0xc9, 0x61, 0x02, 0x07, 0xb8, 0x3d, 0xdf, 0x43, 0x0f, - 0xcc, 0x81, 0xe2, 0xba, 0x64, 0x51, 0x8b, 0x1a, 0x06, 0xd4, 0x37, 0x44, 0x11, 0xf3, 0x91, 0x03, - 0xdc, 0x67, 0x51, 0xab, 0x9b, 0x59, 0xce, 0x72, 0x61, 0xde, 0x39, 0xc0, 0xbd, 0x8f, 0x5a, 0xfd, - 0x6a, 0x02, 0xf5, 0x86, 0x32, 0x30, 0x1c, 0xc4, 0x1f, 0x96, 0x41, 0x12, 0xac, 0x83, 0xf9, 0x2a, - 0x0e, 0x92, 0x78, 0x9d, 0xac, 0xde, 0xbd, 0x5f, 0x06, 0xf3, 0xf0, 0x6d, 0x18, 0x2c, 0x9e, 0x6b, - 0x56, 0xef, 0xeb, 0x77, 0x07, 0xde, 0x5e, 0x2d, 0xfd, 0xf8, 0xc3, 0xd6, 0x66, 0xc9, 0xcf, 0xb3, - 0x0d, 0x4e, 0x67, 0x1b, 0xfc, 0x3e, 0xdb, 0xe0, 0xdb, 0xc5, 0xd6, 0x4e, 0x17, 0x5b, 0xfb, 0x75, - 0xb1, 0xb5, 0x8f, 0x41, 0xc6, 0xd5, 0xb6, 0x4a, 0x11, 0x15, 0x39, 0xa6, 0x42, 0xe6, 0x42, 0x62, - 0x9e, 0x52, 0x2f, 0x13, 0xf8, 0xe0, 0xe3, 0x5c, 0x6c, 0xaa, 0x1d, 0x93, 0x4d, 0xa3, 0x12, 0xfb, - 0x6f, 0xbc, 0x5b, 0x1e, 0xef, 0x5a, 0x66, 0xdb, 0x64, 0xfa, 0xb8, 0x3d, 0xe1, 0xf8, 0x4f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x69, 0x0c, 0xd9, 0x88, 0x01, 0x02, 0x00, 0x00, -} - -func (m *IBCTxBody) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *IBCTxBody) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *IBCTxBody) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Messages) > 0 { - for iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Messages[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil + // 376 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0x41, 0xeb, 0xd3, 0x30, + 0x18, 0xc6, 0x1b, 0xff, 0x45, 0x66, 0x94, 0x21, 0x65, 0x87, 0xda, 0x41, 0x29, 0xbb, 0x58, 0x84, + 0x26, 0xae, 0x3b, 0x78, 0xd1, 0xc3, 0xdc, 0x2a, 0xec, 0x22, 0xa3, 0x76, 0x30, 0xbd, 0x94, 0x34, + 0x8b, 0x5d, 0x70, 0x6d, 0xca, 0x92, 0x0e, 0xfb, 0x0d, 0x86, 0x27, 0xbf, 0x80, 0x27, 0xbf, 0x8c, + 0xc7, 0x1d, 0x3d, 0xca, 0xf6, 0x45, 0xa4, 0x29, 0x6e, 0x1e, 0x3c, 0x78, 0x7b, 0x78, 0x93, 0xe7, + 0xc9, 0xef, 0xcd, 0x03, 0x27, 0x3c, 0xa3, 0x98, 0x54, 0xd5, 0x8e, 0x53, 0xa2, 0xb8, 0x28, 0x25, + 0xe6, 0xa5, 0x62, 0x7b, 0xba, 0x25, 0xbc, 0x4c, 0x09, 0xa5, 0xa2, 0x2e, 0x95, 0xc4, 0x87, 0x31, + 0x56, 0x4d, 0xc5, 0x24, 0xaa, 0xf6, 0x42, 0x09, 0xeb, 0x29, 0xcf, 0x28, 0xfa, 0xdb, 0x84, 0xfe, + 0x61, 0x42, 0x87, 0xb1, 0xf3, 0x24, 0x17, 0x22, 0xdf, 0x31, 0xac, 0x6d, 0x59, 0xfd, 0x11, 0x93, + 0xb2, 0xe9, 0x32, 0x9c, 0x41, 0x2e, 0x72, 0xa1, 0x25, 0x6e, 0x55, 0x37, 0x1d, 0x1d, 0x01, 0x1c, + 0x2e, 0xae, 0x59, 0xd3, 0x2e, 0x6a, 0x49, 0xe8, 0x27, 0xa6, 0xe6, 0x44, 0x11, 0x6b, 0x0a, 0xcd, + 0x16, 0xc4, 0x06, 0x1e, 0xf0, 0xfb, 0x61, 0x80, 0xfe, 0x13, 0x04, 0x25, 0x4d, 0xc5, 0x62, 0x6d, + 0xb5, 0x2c, 0x68, 0x6e, 0x88, 0x22, 0xf6, 0x3d, 0x0f, 0xf8, 0x8f, 0x62, 0xad, 0xdb, 0x59, 0xc1, + 0x0a, 0x61, 0xdf, 0x79, 0xc0, 0x7f, 0x10, 0x6b, 0x3d, 0x7a, 0x09, 0x7b, 0x33, 0x21, 0x0b, 0x21, + 0x93, 0xcf, 0xd6, 0x73, 0xd8, 0x2b, 0x98, 0x94, 0x24, 0x67, 0xd2, 0x06, 0xde, 0x9d, 0xff, 0x30, + 0x1c, 0xa0, 0x6e, 0x35, 0xf4, 0x67, 0x35, 0x34, 0x2d, 0x9b, 0xf8, 0x7a, 0xeb, 0xd9, 0x2b, 0x68, + 0xb6, 0x6f, 0x5a, 0x18, 0x0e, 0x93, 0xf7, 0xcb, 0x28, 0x8d, 0xd6, 0xd1, 0x6c, 0x95, 0x44, 0x69, + 0xb2, 0x4e, 0x57, 0x6f, 0xdf, 0x2d, 0xa3, 0xd9, 0xe2, 0xcd, 0x22, 0x9a, 0x3f, 0x36, 0x9c, 0xfe, + 0x97, 0x6f, 0x1e, 0xbc, 0x9d, 0x3a, 0xe6, 0xf1, 0xbb, 0x6b, 0xbc, 0x4e, 0x7f, 0x9c, 0x5d, 0x70, + 0x3a, 0xbb, 0xe0, 0xd7, 0xd9, 0x05, 0x5f, 0x2f, 0xae, 0x71, 0xba, 0xb8, 0xc6, 0xcf, 0x8b, 0x6b, + 0x7c, 0x88, 0x72, 0xae, 0xb6, 0x75, 0x86, 0xa8, 0x28, 0x30, 0xd5, 0x7c, 0x98, 0x67, 0x34, 0xc8, + 0x05, 0x3e, 0x84, 0xb8, 0x10, 0x9b, 0x7a, 0xc7, 0x64, 0x5b, 0xa8, 0xc4, 0xe1, 0x8b, 0xe0, 0xf6, + 0x1b, 0xc1, 0xb5, 0x4b, 0x5d, 0x64, 0x76, 0x5f, 0x73, 0x4f, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, + 0x09, 0xbd, 0x2f, 0x2f, 0x00, 0x02, 0x00, 0x00, } func (m *InterchainAccountPacketData) Marshal() (dAtA []byte, err error) { @@ -273,6 +236,43 @@ func (m *InterchainAccountPacketData) MarshalToSizedBuffer(dAtA []byte) (int, er return len(dAtA) - i, nil } +func (m *CosmosTx) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CosmosTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CosmosTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Messages) > 0 { + for iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Messages[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { offset -= sovTypes(v) base := offset @@ -284,21 +284,6 @@ func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *IBCTxBody) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Messages) > 0 { - for _, e := range m.Messages { - l = e.Size() - n += 1 + l + sovTypes(uint64(l)) - } - } - return n -} - func (m *InterchainAccountPacketData) Size() (n int) { if m == nil { return 0 @@ -319,13 +304,28 @@ func (m *InterchainAccountPacketData) Size() (n int) { return n } +func (m *CosmosTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Messages) > 0 { + for _, e := range m.Messages { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } func sozTypes(x uint64) (n int) { return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *IBCTxBody) Unmarshal(dAtA []byte) error { +func (m *InterchainAccountPacketData) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -348,17 +348,36 @@ func (m *IBCTxBody) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: IBCTxBody: wiretype end group for non-group") + return fmt.Errorf("proto: InterchainAccountPacketData: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: IBCTxBody: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: InterchainAccountPacketData: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= Type(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Messages", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -368,26 +387,58 @@ func (m *IBCTxBody) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.Messages = append(m.Messages, &types.Any{}) - if err := m.Messages[len(m.Messages)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Memo", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Memo = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -409,7 +460,7 @@ func (m *IBCTxBody) Unmarshal(dAtA []byte) error { } return nil } -func (m *InterchainAccountPacketData) Unmarshal(dAtA []byte) error { +func (m *CosmosTx) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -432,36 +483,17 @@ func (m *InterchainAccountPacketData) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: InterchainAccountPacketData: wiretype end group for non-group") + return fmt.Errorf("proto: CosmosTx: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: InterchainAccountPacketData: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: CosmosTx: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) - } - m.Type = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Type |= Type(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Messages", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -471,57 +503,25 @@ func (m *InterchainAccountPacketData) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) - if m.Data == nil { - m.Data = []byte{} - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Memo", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF + m.Messages = append(m.Messages, &types.Any{}) + if err := m.Messages[len(m.Messages)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - m.Memo = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/proto/ibc/applications/interchain_accounts/v1/types.proto b/proto/ibc/applications/interchain_accounts/v1/types.proto index 758c2539072..b8f3683ba44 100644 --- a/proto/ibc/applications/interchain_accounts/v1/types.proto +++ b/proto/ibc/applications/interchain_accounts/v1/types.proto @@ -5,11 +5,6 @@ import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; -// Body of a tx for an ics27 IBC packet -message IBCTxBody { - repeated google.protobuf.Any messages = 1; -} - // The different types of interchain account transactions // EXECUTE_TX is used when sending a TX from the controller side to the host side. The host side will execute the tx on // behalf of the interchain account. @@ -25,3 +20,9 @@ message InterchainAccountPacketData { bytes data = 2; string memo = 3; } + +// CosmosTx contains a list of sdk.Msg's. It should be used when sending transactions to an SDK host chain. +message CosmosTx { + repeated google.protobuf.Any messages = 1; +} + From c5ac29cac6dd30a6148fa6c1a8f9e546691f1a80 Mon Sep 17 00:00:00 2001 From: Sean King Date: Wed, 13 Oct 2021 09:43:58 +0200 Subject: [PATCH 41/66] chore(spec): remove old specification --- .../27-interchain-accounts/spec/03_types.md | 30 ------- .../27-interchain-accounts/spec/04_keeper.md | 79 ------------------- .../27-interchain-accounts/spec/05_packets.md | 37 --------- .../27-interchain-accounts/spec/README.md | 21 ----- 4 files changed, 167 deletions(-) delete mode 100644 modules/apps/27-interchain-accounts/spec/03_types.md delete mode 100644 modules/apps/27-interchain-accounts/spec/04_keeper.md delete mode 100644 modules/apps/27-interchain-accounts/spec/05_packets.md delete mode 100644 modules/apps/27-interchain-accounts/spec/README.md diff --git a/modules/apps/27-interchain-accounts/spec/03_types.md b/modules/apps/27-interchain-accounts/spec/03_types.md deleted file mode 100644 index 2bb17cd4cc1..00000000000 --- a/modules/apps/27-interchain-accounts/spec/03_types.md +++ /dev/null @@ -1,30 +0,0 @@ - - -# Types - -## IBCAccount - -IBCAccount implements the standard AccountI interface similar to Cosmos SDK x/auth module's BaseAccount or Module Account - -```proto -// IBCAccount defines an account to which other chains have privileges -message IBCAccount { - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - option (cosmos_proto.implements_interface) = "IBCAccountI"; - - cosmos.auth.v1beta1.BaseAccount base_account = 1 [(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"base_account\""]; - string sourcePort = 2; - string sourceChannel = 3; - string destinationPort = 4; - string destinationChannel = 5; -} -``` - -As shown above, IBCAccount embeds the BaseAccount, and is assigned an Address and AccountNumber similar to the BaseAccount. However, because IBCAccount was designed to be used through the module, and not the user, there is no need to designate a PubKey or Sequence (which is implemented in the ModuleAccount). - -Also, IBCAccount stores the information on the IBC Port and Channel that requested the creation of the account. - -One can check if a specific address is an IBCAccount as well as the actual IBCAccount type through the IBCAccountKeeper's GetIBCAccount method. If the address queried doesn't exist or is not an IBC account, an error is returned. diff --git a/modules/apps/27-interchain-accounts/spec/04_keeper.md b/modules/apps/27-interchain-accounts/spec/04_keeper.md deleted file mode 100644 index dacc25b1124..00000000000 --- a/modules/apps/27-interchain-accounts/spec/04_keeper.md +++ /dev/null @@ -1,79 +0,0 @@ - -# Keeper - -## Structure - -```go - -type TxEncoder func(data interface{}) ([]byte, error) - -type Keeper struct { - ... - txEncoders map[string]types.TxEncoder - ... - router types.Router -} -``` - -The most important part of the IBC account keeper, as shown above, is the **map of txEncoders** and the **router**. Because ICS-027 specification defines that the chain can send arbitrary tx bytes to the counterparty chain, both chains must define the way that they process the caller's requests or make the tx bytes that the callee can process. - -The `TxEncoder` serializes the source chain's tx bytes from any data. And the map of `TxEncoder` has the key, such as `chain-id` and `keeper`, which the keeper uses to send packets. Therefore, it is necessary to know which source chain's transaction is being executed. - -`SerializeCosmosTx(cdc codec.BinaryCodec, registry codectypes.InterfaceRegistry)` provides a way to serialize the tx bytes from messages if the destination chain is based on the Cosmos-SDK. - -The router is used to delegate the process of handling the message to a module. When a packet which requests a set of transaction bytes to be run is passed, the router deserializes the tx bytes and passes the message to the handler. The keeper checks the result of each message, and if any message returns an error, the entire transaction is aborted, and state change rolled back. - -`TryRunTx(ctx sdk.Context, sourcePort, sourceChannel, typ string, data interface{}, timeoutHeight clienttypes.Height, timeoutTimestamp uint64)` method is used to request transactions to be run on the destination chain. This method uses the `typ` parameter from the `txEncoders map`'s key to find the right `txEncoder`. If the `txEncoder` exists, the transaction is serialized and a `RUNTX` packet is sent to the destination chain. The `TryRunTx` also returns the virtual txHash which is used in the 'Hook' section shown below. This virtual txHash is not related to the actual on-chain transaction, but only 'virtually' created so transactions requested by the Hook can be identified. - -### IBC Packets - -```go - -enum Type { - REGISTER = 0; - RUNTX = 1; -} - -message IBCAccountPacketData { - Type type = 1; - bytes data = 2; -} - -message IBCAccountPacketAcknowledgement { - Type type = 1; - string chainID = 2; - uint32 code = 3; - string error = 4; -} -``` - -The example above shows the IBC packets that are used in ICS-027. `Type` indicates what action the packet is performing. When a `REGISTER` packet type is delivered, the counterparty chain will create an account with the address using the hash of {destPort}/{destChannel}/{packet.data}, assuming a duplicate prior account doesn't exist. - -If the account is created successfully, it returns an acknowledgement packet to the origin chain with type `REGISTER` and code `0`. If there's an error, it returns the acknowledgement packet with type `REGISTER` and the code of the resulting error. - -When a `RUNTX` type packet is delivered, the counterparty chain will deserialize the tx bytes (packet's data field) in a predefined way. - -In this implementation of ICS27 for the Cosmos-SDK, it deserializes the tx bytes into slices of messages and gets the handler from the router and executes and checks the result like described above. - -If the all messages are successful, it returns the acknowledgment packet to the chain with type `RUNTX` and code `0`. If there's an error, it returns the acknowledgement packet with type `RUNTX` and the code and error of the first failed message. - -### Hook - -```go - -type IBCAccountHooks interface { - OnAccountCreated(ctx sdk.Context, sourcePort, sourceChannel string, address sdk.AccAddress) - OnTxSucceeded(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) - OnTxFailed(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) -} -``` - -The example above shows the hook for helping developer using the IBC account keeper. - -The hook lets the developer know whether the IBC account has been successfully created on the counterparty chain. - -After sending the packet with an `IBCAccountPacketData` with the type `REGISTER`, if the acknowledgement packet with the type `REGISTER` and code `0` is delivered, `OnAccountCreated` is executed with the counterparty chain's chain-id and address. - -After sending the packet with an `IBCAccountPacketData` with the type `RUNTX`, if the acknowledgement packet with the type `RUNTX` and code `0` is delivered, `OnTxSucceeded` is executed with the counterparty chain's chain-id, virtual tx hash and requested data that is not serialized. Virtual tx hash is used only for internal logic to distinguish the requested tx and it is computed by hashing the tx bytes and sequence of packet. Otherwise, `OnTxFailed` will be executed. diff --git a/modules/apps/27-interchain-accounts/spec/05_packets.md b/modules/apps/27-interchain-accounts/spec/05_packets.md deleted file mode 100644 index d6fdd72b006..00000000000 --- a/modules/apps/27-interchain-accounts/spec/05_packets.md +++ /dev/null @@ -1,37 +0,0 @@ - - -# Packets - -```proto -message IBCTxRaw { - bytes body_bytes = 1; -} - -message IBCTxBody { - repeated google.protobuf.Any messages = 1; -} - -enum Type { - REGISTER = 0; - RUNTX = 1; -} - -message IBCAccountPacketData { - Type type = 1; - bytes data = 2; -} - -message IBCAccountPacketAcknowledgement { - Type type = 1; - string chainID = 2; - uint32 code = 3; - bytes data = 4; - string error = 5; -} -``` - -- `IBCAccountPacketAcknowledgement` returns the result of the packet request back to the chain that sent the packet. -- `IBCAccountPacketData` is sent when the counterparty chain registers a IBCAccount or wants to execute a specific tx through the IBC Account. -- `IBCAccountPacketData` type field displays the behavior requested by the packet. If the type is `REGISTER`, this means request to register a new IBCAccount. In this case, the destination chain can set the IBCAccount's address, but typically it is recommended to refer to the data field to create the address in a deterministic way. If the IBCAccount has been successfully registered, an `IBCAccountPacketAcknowledgment` is returned to the requesting chain with the `Code` field set to `0`. If there was an error, an `IBCAccountPacketAcknowledgment` is returned to the requesting chain with the `Code` field including the error message. diff --git a/modules/apps/27-interchain-accounts/spec/README.md b/modules/apps/27-interchain-accounts/spec/README.md deleted file mode 100644 index abd08ea7d40..00000000000 --- a/modules/apps/27-interchain-accounts/spec/README.md +++ /dev/null @@ -1,21 +0,0 @@ - - -# Interchain Account - -## Abstract - -This document specifies the ICS 27 Interchain Account module for the Cosmos SDK. - -The Interchain Accounts module manages the creation of Interchain Accounts. This module is built based on the [ICS27 specification](https://github.com/cosmos/ibc/tree/master/spec/app/ics-027-interchain-accounts). Interchain Accounts allow a remote, IBC-connected **controller blockchain** to request an arbitrary transaction to be executed on the **host blockchain**(the chain which hosts the IBC account) via the interchain account. It should be noted that an interchain account has similar properties to a user account, and are bound to the same restrictions (unbonding periods, redelegation rules, etc). - -The current implementation allows the same interchain account module on the destination chain to run any of the domiciling blockchain's native transactions that a user account is able to request(i.e. same module can handle 'send', 'stake', 'vote', etc), but the controlling chain/source chain must implement its own logic for controlling the interchain account. - -## Contents -1. **[Types](03_types.md)** -2. **[Keeper](04_keeper.md)** -3. **[Packets](05_packets.md)** From cd263c795f61e9d1b23b50ad1281972b0deeaf05 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 13 Oct 2021 13:47:43 +0200 Subject: [PATCH 42/66] ica: unspecified type enum for interchain account packet data (#487) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * adding unspecified type enum, adding defensive check to ValidateBasic * Update modules/apps/27-interchain-accounts/types/packet_test.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- docs/ibc/proto-docs.md | 8 +-- .../27-interchain-accounts/types/packet.go | 4 ++ .../types/packet_test.go | 9 +++ .../27-interchain-accounts/types/types.pb.go | 70 ++++++++++--------- .../interchain_accounts/v1/types.proto | 17 ++--- 5 files changed, 63 insertions(+), 45 deletions(-) diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index fe109584bba..b5557d2d923 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -435,13 +435,13 @@ InterchainAccountPacketData is comprised of a raw transaction, type of transacti ### Type -The different types of interchain account transactions -EXECUTE_TX is used when sending a TX from the controller side to the host side. The host side will execute the tx on -behalf of the interchain account. +Type defines a classification of message issued from a controller chain to its associated interchain accounts +host | Name | Number | Description | | ---- | ------ | ----------- | -| TYPE_EXECUTE_TX_UNSPECIFIED | 0 | Execute message type | +| TYPE_UNSPECIFIED | 0 | Default zero value enumeration | +| TYPE_EXECUTE_TX | 1 | Execute a transaction on an interchain accounts host chain | diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index d69dfebd30a..8342f911bbf 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -11,6 +11,10 @@ const MaxMemoCharLength = 256 // ValidateBasic performs basic validation of the interchain account packet data. // The memo may be empty. func (iapd InterchainAccountPacketData) ValidateBasic() error { + if iapd.Type == UNSPECIFIED { + return sdkerrors.Wrap(ErrInvalidOutgoingData, "packet data type cannot be unspecified") + } + if iapd.Data == nil { return sdkerrors.Wrap(ErrInvalidOutgoingData, "packet data cannot be empty") } diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index ce2fab2f5ca..1c8d5c5fc4f 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -29,6 +29,15 @@ func (suite *TypesTestSuite) TestValidateBasic() { }, true, }, + { + "type unspecified", + types.InterchainAccountPacketData{ + Type: types.UNSPECIFIED, + Data: []byte("data"), + Memo: "memo", + }, + false, + }, { "empty data", types.InterchainAccountPacketData{ diff --git a/modules/apps/27-interchain-accounts/types/types.pb.go b/modules/apps/27-interchain-accounts/types/types.pb.go index a4fad957f7f..7ed9c1b9e7e 100644 --- a/modules/apps/27-interchain-accounts/types/types.pb.go +++ b/modules/apps/27-interchain-accounts/types/types.pb.go @@ -24,22 +24,25 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// The different types of interchain account transactions -// EXECUTE_TX is used when sending a TX from the controller side to the host side. The host side will execute the tx on -// behalf of the interchain account. +// Type defines a classification of message issued from a controller chain to its associated interchain accounts +// host type Type int32 const ( - // Execute message type - EXECUTE_TX Type = 0 + // Default zero value enumeration + UNSPECIFIED Type = 0 + // Execute a transaction on an interchain accounts host chain + EXECUTE_TX Type = 1 ) var Type_name = map[int32]string{ - 0: "TYPE_EXECUTE_TX_UNSPECIFIED", + 0: "TYPE_UNSPECIFIED", + 1: "TYPE_EXECUTE_TX", } var Type_value = map[string]int32{ - "TYPE_EXECUTE_TX_UNSPECIFIED": 0, + "TYPE_UNSPECIFIED": 0, + "TYPE_EXECUTE_TX": 1, } func (x Type) String() string { @@ -94,7 +97,7 @@ func (m *InterchainAccountPacketData) GetType() Type { if m != nil { return m.Type } - return EXECUTE_TX + return UNSPECIFIED } func (m *InterchainAccountPacketData) GetData() []byte { @@ -167,31 +170,32 @@ func init() { } var fileDescriptor_39bab93e18d89799 = []byte{ - // 376 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0x41, 0xeb, 0xd3, 0x30, - 0x18, 0xc6, 0x1b, 0xff, 0x45, 0x66, 0x94, 0x21, 0x65, 0x87, 0xda, 0x41, 0x29, 0xbb, 0x58, 0x84, - 0x26, 0xae, 0x3b, 0x78, 0xd1, 0xc3, 0xdc, 0x2a, 0xec, 0x22, 0xa3, 0x76, 0x30, 0xbd, 0x94, 0x34, - 0x8b, 0x5d, 0x70, 0x6d, 0xca, 0x92, 0x0e, 0xfb, 0x0d, 0x86, 0x27, 0xbf, 0x80, 0x27, 0xbf, 0x8c, - 0xc7, 0x1d, 0x3d, 0xca, 0xf6, 0x45, 0xa4, 0x29, 0x6e, 0x1e, 0x3c, 0x78, 0x7b, 0x78, 0x93, 0xe7, - 0xc9, 0xef, 0xcd, 0x03, 0x27, 0x3c, 0xa3, 0x98, 0x54, 0xd5, 0x8e, 0x53, 0xa2, 0xb8, 0x28, 0x25, - 0xe6, 0xa5, 0x62, 0x7b, 0xba, 0x25, 0xbc, 0x4c, 0x09, 0xa5, 0xa2, 0x2e, 0x95, 0xc4, 0x87, 0x31, - 0x56, 0x4d, 0xc5, 0x24, 0xaa, 0xf6, 0x42, 0x09, 0xeb, 0x29, 0xcf, 0x28, 0xfa, 0xdb, 0x84, 0xfe, - 0x61, 0x42, 0x87, 0xb1, 0xf3, 0x24, 0x17, 0x22, 0xdf, 0x31, 0xac, 0x6d, 0x59, 0xfd, 0x11, 0x93, - 0xb2, 0xe9, 0x32, 0x9c, 0x41, 0x2e, 0x72, 0xa1, 0x25, 0x6e, 0x55, 0x37, 0x1d, 0x1d, 0x01, 0x1c, - 0x2e, 0xae, 0x59, 0xd3, 0x2e, 0x6a, 0x49, 0xe8, 0x27, 0xa6, 0xe6, 0x44, 0x11, 0x6b, 0x0a, 0xcd, - 0x16, 0xc4, 0x06, 0x1e, 0xf0, 0xfb, 0x61, 0x80, 0xfe, 0x13, 0x04, 0x25, 0x4d, 0xc5, 0x62, 0x6d, - 0xb5, 0x2c, 0x68, 0x6e, 0x88, 0x22, 0xf6, 0x3d, 0x0f, 0xf8, 0x8f, 0x62, 0xad, 0xdb, 0x59, 0xc1, - 0x0a, 0x61, 0xdf, 0x79, 0xc0, 0x7f, 0x10, 0x6b, 0x3d, 0x7a, 0x09, 0x7b, 0x33, 0x21, 0x0b, 0x21, - 0x93, 0xcf, 0xd6, 0x73, 0xd8, 0x2b, 0x98, 0x94, 0x24, 0x67, 0xd2, 0x06, 0xde, 0x9d, 0xff, 0x30, - 0x1c, 0xa0, 0x6e, 0x35, 0xf4, 0x67, 0x35, 0x34, 0x2d, 0x9b, 0xf8, 0x7a, 0xeb, 0xd9, 0x2b, 0x68, - 0xb6, 0x6f, 0x5a, 0x18, 0x0e, 0x93, 0xf7, 0xcb, 0x28, 0x8d, 0xd6, 0xd1, 0x6c, 0x95, 0x44, 0x69, - 0xb2, 0x4e, 0x57, 0x6f, 0xdf, 0x2d, 0xa3, 0xd9, 0xe2, 0xcd, 0x22, 0x9a, 0x3f, 0x36, 0x9c, 0xfe, - 0x97, 0x6f, 0x1e, 0xbc, 0x9d, 0x3a, 0xe6, 0xf1, 0xbb, 0x6b, 0xbc, 0x4e, 0x7f, 0x9c, 0x5d, 0x70, - 0x3a, 0xbb, 0xe0, 0xd7, 0xd9, 0x05, 0x5f, 0x2f, 0xae, 0x71, 0xba, 0xb8, 0xc6, 0xcf, 0x8b, 0x6b, - 0x7c, 0x88, 0x72, 0xae, 0xb6, 0x75, 0x86, 0xa8, 0x28, 0x30, 0xd5, 0x7c, 0x98, 0x67, 0x34, 0xc8, - 0x05, 0x3e, 0x84, 0xb8, 0x10, 0x9b, 0x7a, 0xc7, 0x64, 0x5b, 0xa8, 0xc4, 0xe1, 0x8b, 0xe0, 0xf6, - 0x1b, 0xc1, 0xb5, 0x4b, 0x5d, 0x64, 0x76, 0x5f, 0x73, 0x4f, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, - 0x09, 0xbd, 0x2f, 0x2f, 0x00, 0x02, 0x00, 0x00, + // 391 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x51, 0x41, 0x8b, 0xd3, 0x40, + 0x18, 0xcd, 0xb8, 0x41, 0xd6, 0x59, 0xd9, 0x2d, 0x61, 0x0f, 0x31, 0x42, 0x08, 0x2b, 0x62, 0x10, + 0x32, 0xe3, 0x66, 0x0f, 0x5e, 0xbc, 0xd4, 0x6e, 0x84, 0x5e, 0xa4, 0xc4, 0x14, 0xaa, 0x97, 0x30, + 0x99, 0x8e, 0xe9, 0x60, 0x93, 0x09, 0x9d, 0x49, 0x31, 0xff, 0xa0, 0xf4, 0xe4, 0x1f, 0xe8, 0xc9, + 0x3f, 0xe3, 0xb1, 0x47, 0x8f, 0xd2, 0xfe, 0x11, 0xc9, 0x04, 0xdb, 0x1e, 0x3c, 0xec, 0xed, 0xf1, + 0xf8, 0xde, 0x9b, 0xf7, 0xe6, 0xc1, 0x3b, 0x9e, 0x51, 0x4c, 0xaa, 0x6a, 0xce, 0x29, 0x51, 0x5c, + 0x94, 0x12, 0xf3, 0x52, 0xb1, 0x05, 0x9d, 0x11, 0x5e, 0xa6, 0x84, 0x52, 0x51, 0x97, 0x4a, 0xe2, + 0xe5, 0x2d, 0x56, 0x4d, 0xc5, 0x24, 0xaa, 0x16, 0x42, 0x09, 0xeb, 0x15, 0xcf, 0x28, 0x3a, 0x15, + 0xa1, 0xff, 0x88, 0xd0, 0xf2, 0xd6, 0x79, 0x96, 0x0b, 0x91, 0xcf, 0x19, 0xd6, 0xb2, 0xac, 0xfe, + 0x8a, 0x49, 0xd9, 0x74, 0x1e, 0xce, 0x75, 0x2e, 0x72, 0xa1, 0x21, 0x6e, 0x51, 0xc7, 0xde, 0xac, + 0x00, 0x7c, 0x3e, 0x3c, 0x78, 0xf5, 0x3b, 0xab, 0x11, 0xa1, 0xdf, 0x98, 0xba, 0x27, 0x8a, 0x58, + 0x7d, 0x68, 0xb6, 0x41, 0x6c, 0xe0, 0x01, 0xff, 0x32, 0x0c, 0xd0, 0x03, 0x83, 0xa0, 0xa4, 0xa9, + 0x58, 0xac, 0xa5, 0x96, 0x05, 0xcd, 0x29, 0x51, 0xc4, 0x7e, 0xe4, 0x01, 0xff, 0x69, 0xac, 0x71, + 0xcb, 0x15, 0xac, 0x10, 0xf6, 0x99, 0x07, 0xfc, 0x27, 0xb1, 0xc6, 0x37, 0xef, 0xe0, 0xf9, 0x40, + 0xc8, 0x42, 0xc8, 0xe4, 0xbb, 0xf5, 0x06, 0x9e, 0x17, 0x4c, 0x4a, 0x92, 0x33, 0x69, 0x03, 0xef, + 0xcc, 0xbf, 0x08, 0xaf, 0x51, 0x57, 0x0d, 0xfd, 0xab, 0x86, 0xfa, 0x65, 0x13, 0x1f, 0xae, 0x5e, + 0x4f, 0xa0, 0xd9, 0xbe, 0x69, 0xbd, 0x84, 0xbd, 0xe4, 0xf3, 0x28, 0x4a, 0xc7, 0x1f, 0x3f, 0x8d, + 0xa2, 0xc1, 0xf0, 0xc3, 0x30, 0xba, 0xef, 0x19, 0xce, 0xd5, 0x7a, 0xe3, 0x5d, 0x9c, 0x50, 0xd6, + 0x0b, 0x78, 0xa5, 0xcf, 0xa2, 0x49, 0x34, 0x18, 0x27, 0x51, 0x9a, 0x4c, 0x7a, 0xc0, 0xb9, 0x5c, + 0x6f, 0x3c, 0x78, 0x64, 0x1c, 0x73, 0xf5, 0xd3, 0x35, 0xde, 0xa7, 0xbf, 0x76, 0x2e, 0xd8, 0xee, + 0x5c, 0xf0, 0x67, 0xe7, 0x82, 0x1f, 0x7b, 0xd7, 0xd8, 0xee, 0x5d, 0xe3, 0xf7, 0xde, 0x35, 0xbe, + 0x44, 0x39, 0x57, 0xb3, 0x3a, 0x43, 0x54, 0x14, 0x98, 0xea, 0xe8, 0x98, 0x67, 0x34, 0xc8, 0x05, + 0x5e, 0x86, 0xb8, 0x10, 0xd3, 0x7a, 0xce, 0x64, 0xbb, 0xb5, 0xc4, 0xe1, 0xdb, 0xe0, 0xf8, 0x51, + 0xc1, 0x61, 0x66, 0xbd, 0x71, 0xf6, 0x58, 0x57, 0xba, 0xfb, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xfa, + 0xbe, 0xe0, 0xb6, 0x1b, 0x02, 0x00, 0x00, } func (m *InterchainAccountPacketData) Marshal() (dAtA []byte, err error) { diff --git a/proto/ibc/applications/interchain_accounts/v1/types.proto b/proto/ibc/applications/interchain_accounts/v1/types.proto index b8f3683ba44..fe19488d986 100644 --- a/proto/ibc/applications/interchain_accounts/v1/types.proto +++ b/proto/ibc/applications/interchain_accounts/v1/types.proto @@ -5,19 +5,21 @@ import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; -// The different types of interchain account transactions -// EXECUTE_TX is used when sending a TX from the controller side to the host side. The host side will execute the tx on -// behalf of the interchain account. +// Type defines a classification of message issued from a controller chain to its associated interchain accounts +// host enum Type { option (gogoproto.goproto_enum_prefix) = false; - // Execute message type - TYPE_EXECUTE_TX_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "EXECUTE_TX"]; + + // Default zero value enumeration + TYPE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; + // Execute a transaction on an interchain accounts host chain + TYPE_EXECUTE_TX = 1 [(gogoproto.enumvalue_customname) = "EXECUTE_TX"]; } // InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. message InterchainAccountPacketData { - Type type = 1; - bytes data = 2; + Type type = 1; + bytes data = 2; string memo = 3; } @@ -25,4 +27,3 @@ message InterchainAccountPacketData { message CosmosTx { repeated google.protobuf.Any messages = 1; } - From 4db5c83acc39245d577e53cfa6cdc55cf0dc0860 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 13 Oct 2021 14:14:54 +0200 Subject: [PATCH 43/66] chore: ica audit nitpicks (#483) * updating version validation with corrections * removing unused methods from expected keeper interfaces * updating validate version error msg * update to use ErrInvalidVersion in favour of ErrInvalidAccountAddress --- .../keeper/handshake.go | 10 ++++---- .../types/expected_keepers.go | 21 +--------------- .../27-interchain-accounts/types/validate.go | 25 ++++++++----------- .../types/validate_test.go | 16 ++++++------ 4 files changed, 25 insertions(+), 47 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index 52e179eff1d..6513b65758a 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -53,8 +53,8 @@ func (k Keeper) OnChanOpenInit( return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "expected %s, got %s", types.PortID, counterparty.PortId) } - if err := types.ValidateVersion(version); err != nil { - return sdkerrors.Wrap(err, "version validation failed") + if version != types.VersionPrefix { + return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.VersionPrefix, version) } existingChannelID, found := k.GetActiveChannel(ctx, portID) @@ -111,8 +111,8 @@ func (k Keeper) OnChanOpenTry( return sdkerrors.Wrap(err, "version validation failed") } - if err := types.ValidateVersion(counterpartyVersion); err != nil { - return sdkerrors.Wrap(err, "counterparty version validation failed") + if counterpartyVersion != types.VersionPrefix { + return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.VersionPrefix, version) } // On the host chain the capability may only be claimed during the OnChanOpenTry @@ -129,7 +129,7 @@ func (k Keeper) OnChanOpenTry( } if parsedAddr != accAddr.String() { - return sdkerrors.Wrapf(types.ErrInvalidAccountAddress, "version contains invalid account address: expected %s, got %s", parsedAddr, accAddr) + return sdkerrors.Wrapf(types.ErrInvalidVersion, "version contains invalid account address: expected %s, got %s", parsedAddr, accAddr) } // Register interchain account if it does not already exist diff --git a/modules/apps/27-interchain-accounts/types/expected_keepers.go b/modules/apps/27-interchain-accounts/types/expected_keepers.go index 73a9b2ffe85..2b08a9bcfe9 100644 --- a/modules/apps/27-interchain-accounts/types/expected_keepers.go +++ b/modules/apps/27-interchain-accounts/types/expected_keepers.go @@ -5,19 +5,13 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" ) -type Router interface { - Route(ctx sdk.Context, path string) sdk.Handler -} - -// AccountKeeper defines the contract required for account APIs. +// AccountKeeper defines the expected account keeper type AccountKeeper interface { NewAccount(ctx sdk.Context, acc authtypes.AccountI) authtypes.AccountI - NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI SetAccount(ctx sdk.Context, acc authtypes.AccountI) GetModuleAccount(ctx sdk.Context, name string) authtypes.ModuleAccountI @@ -29,24 +23,11 @@ type ChannelKeeper interface { GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error - ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error - ChanOpenInit(ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, portCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string) (string, *capabilitytypes.Capability, error) CounterpartyHops(ctx sdk.Context, channel channeltypes.Channel) ([]string, bool) } -// ClientKeeper defines the expected IBC client keeper -type ClientKeeper interface { - GetClientState(ctx sdk.Context, clientID string) (ibcexported.ClientState, bool) -} - -// ConnectionKeeper defines the expected IBC connection keeper -type ConnectionKeeper interface { - GetConnection(ctx sdk.Context, connectionID string) (connection connectiontypes.ConnectionEnd, found bool) -} - // PortKeeper defines the expected IBC port keeper type PortKeeper interface { BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability IsBound(ctx sdk.Context, portID string) bool - LookupModuleByPort(ctx sdk.Context, portID string) (string, *capabilitytypes.Capability, error) } diff --git a/modules/apps/27-interchain-accounts/types/validate.go b/modules/apps/27-interchain-accounts/types/validate.go index 691eb369e41..0d36f2cd026 100644 --- a/modules/apps/27-interchain-accounts/types/validate.go +++ b/modules/apps/27-interchain-accounts/types/validate.go @@ -17,27 +17,24 @@ var IsValidAddr = regexp.MustCompile("^[a-zA-Z0-9]*$").MatchString // ValidateVersion performs basic validation of the provided ics27 version string. // An ics27 version string may include an optional account address as per [TODO: Add spec when available] // ValidateVersion first attempts to split the version string using the standard delimiter, then asserts a supported -// version prefix is included, followed by additional checks which enforce constraints on the optional account address. -// When no delimiter is present, only the version prefix is validated +// version prefix is included, followed by additional checks which enforce constraints on the account address. func ValidateVersion(version string) error { s := strings.Split(version, Delimiter) + if len(s) != 2 { + return sdkerrors.Wrapf(ErrInvalidVersion, "expected format , got %s", Delimiter, version) + } + if s[0] != VersionPrefix { return sdkerrors.Wrapf(ErrInvalidVersion, "expected %s, got %s", VersionPrefix, s[0]) } - if len(s) > 1 { - if len(s) != 2 { - return sdkerrors.Wrap(ErrInvalidAccountAddress, "unexpected address format") - } - - if !IsValidAddr(s[1]) || len(s[1]) == 0 || len(s[1]) > DefaultMaxAddrLength { - return sdkerrors.Wrapf( - ErrInvalidAccountAddress, - "address must contain strictly alphanumeric characters, not exceeding %d characters in length", - DefaultMaxAddrLength, - ) - } + if !IsValidAddr(s[1]) || len(s[1]) == 0 || len(s[1]) > DefaultMaxAddrLength { + return sdkerrors.Wrapf( + ErrInvalidAccountAddress, + "address must contain strictly alphanumeric characters, not exceeding %d characters in length", + DefaultMaxAddrLength, + ) } return nil diff --git a/modules/apps/27-interchain-accounts/types/validate_test.go b/modules/apps/27-interchain-accounts/types/validate_test.go index bca182a78b5..64e2e4fcf1b 100644 --- a/modules/apps/27-interchain-accounts/types/validate_test.go +++ b/modules/apps/27-interchain-accounts/types/validate_test.go @@ -16,9 +16,14 @@ func (suite *TypesTestSuite) TestValidateVersion() { true, }, { - "success - version prefix only", - types.VersionPrefix, - true, + "unexpected version string format", + "invalid-version-string-format", + false, + }, + { + "unexpected version string format, additional delimiter", + types.NewAppVersion(types.VersionPrefix, "cosmos17dtl0mjt3t77kpu.hg2edqzjpszulwhgzuj9ljs"), + false, }, { "invalid version", @@ -40,11 +45,6 @@ func (suite *TypesTestSuite) TestValidateVersion() { types.NewAppVersion(types.VersionPrefix, "-_-"), false, }, - { - "invalid account address - address contains additional delimiter", - types.NewAppVersion(types.VersionPrefix, "cosmos17dtl0mjt3t77kpu|hg2edqzjpszulwhgzuj9ljs"), - false, - }, } for _, tc := range testCases { From bd10403d679df1a7c23aeea1b676b6711a4112e5 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 1 Nov 2021 12:57:59 +0100 Subject: [PATCH 44/66] fixed typo (#507) --- modules/apps/27-interchain-accounts/keeper/keeper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index 2c685ade7d9..af2515316ee 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -18,7 +18,7 @@ import ( host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) -// Keeper defines the IBC transfer keeper +// Keeper defines the IBC interchain account keeper type Keeper struct { storeKey sdk.StoreKey cdc codec.BinaryCodec From 03ada27e4e6438fb748e2e3afd16c7538f8b6454 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 2 Nov 2021 11:26:31 +0100 Subject: [PATCH 45/66] ica: move Serialize/DeserializeCosmosTx to package types (#493) * moving SerializeCosmosTx and DeserializeCosmosTx to types pkg * removing dead code * adding mockSdkMsg message type for failing codec test scenarios * Update modules/apps/27-interchain-accounts/types/codec_test.go --- .../27-interchain-accounts/keeper/keeper.go | 26 ---- .../27-interchain-accounts/keeper/relay.go | 26 +--- .../keeper/relay_test.go | 10 +- .../27-interchain-accounts/types/codec.go | 50 +++++++ .../types/codec_test.go | 130 ++++++++++++++++++ .../27-interchain-accounts/types/encoder.go | 3 - .../apps/27-interchain-accounts/types/hook.go | 30 ---- 7 files changed, 186 insertions(+), 89 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/types/codec_test.go delete mode 100644 modules/apps/27-interchain-accounts/types/encoder.go delete mode 100644 modules/apps/27-interchain-accounts/types/hook.go diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index af2515316ee..d059f5a4ca8 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -6,7 +6,6 @@ import ( baseapp "github.com/cosmos/cosmos-sdk/baseapp" "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" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" @@ -55,31 +54,6 @@ func NewKeeper( } } -// SerializeCosmosTx serializes a slice of sdk.Msg's using the CosmosTx type. The sdk.Msg's are -// packed into Any's and inserted into the Messages field of a CosmosTx. The proto marshaled CosmosTx -// bytes are returned. -func (k Keeper) SerializeCosmosTx(cdc codec.BinaryCodec, msgs []sdk.Msg) (bz []byte, err error) { - msgAnys := make([]*codectypes.Any, len(msgs)) - - for i, msg := range msgs { - msgAnys[i], err = codectypes.NewAnyWithValue(msg) - if err != nil { - return nil, err - } - } - - cosmosTx := &types.CosmosTx{ - Messages: msgAnys, - } - - bz, err = cdc.Marshal(cosmosTx) - if err != nil { - return nil, err - } - - return bz, nil -} - // Logger returns the application logger, scoped to the associated module func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 446f1521837..3fbb0d7b10c 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -75,30 +75,6 @@ func (k Keeper) createOutgoingPacket( return packet.Sequence, nil } -// DeserializeCosmosTx unmarshals and unpacks a slice of transaction bytes -// into a slice of sdk.Msg's. -func (k Keeper) DeserializeCosmosTx(_ sdk.Context, data []byte) ([]sdk.Msg, error) { - var cosmosTx types.CosmosTx - if err := k.cdc.Unmarshal(data, &cosmosTx); err != nil { - return nil, err - } - - msgs := make([]sdk.Msg, len(cosmosTx.Messages)) - - for i, any := range cosmosTx.Messages { - var msg sdk.Msg - - err := k.cdc.UnpackAny(any, &msg) - if err != nil { - return nil, err - } - - msgs[i] = msg - } - - return msgs, nil -} - func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portId string) error { seen := map[string]bool{} var signers []sdk.AccAddress @@ -176,7 +152,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error switch data.Type { case types.EXECUTE_TX: - msgs, err := k.DeserializeCosmosTx(ctx, data.Data) + msgs, err := types.DeserializeCosmosTx(k.cdc, data.Data) if err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index f5d02b2ec6a..e40512dd265 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -35,7 +35,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() { interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) msg1 := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} msg2 := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} - data, err := suite.chainB.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg1, msg2}) + data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg1, msg2}) suite.Require().NoError(err) icaPacketData.Data = data }, true, @@ -79,7 +79,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() { amount, _ := sdk.ParseCoinsNormalized("100stake") interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) msg := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} - data, err := suite.chainB.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg}) + data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) // default packet data, must be modified in malleate for test cases expected to fail @@ -122,7 +122,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} // build packet data - data, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) + data, err := types.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) suite.Require().NoError(err) icaPacketData := types.InterchainAccountPacketData{ @@ -146,7 +146,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "Invalid packet type", func() { // build packet data - data, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{&banktypes.MsgSend{}}) + data, err := types.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{&banktypes.MsgSend{}}) suite.Require().NoError(err) // Type here is an ENUM @@ -175,7 +175,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // Incorrect FromAddress msg = &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} // build packet data - data, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) + data, err := types.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) suite.Require().NoError(err) icaPacketData := types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, diff --git a/modules/apps/27-interchain-accounts/types/codec.go b/modules/apps/27-interchain-accounts/types/codec.go index bfa8cde043c..d5cfa419219 100644 --- a/modules/apps/27-interchain-accounts/types/codec.go +++ b/modules/apps/27-interchain-accounts/types/codec.go @@ -3,6 +3,7 @@ package types import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -22,3 +23,52 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations((*authtypes.AccountI)(nil), &InterchainAccount{}) } + +// SerializeCosmosTx serializes a slice of sdk.Msg's using the CosmosTx type. The sdk.Msg's are +// packed into Any's and inserted into the Messages field of a CosmosTx. The proto marshaled CosmosTx +// bytes are returned. +func SerializeCosmosTx(cdc codec.BinaryCodec, msgs []sdk.Msg) (bz []byte, err error) { + msgAnys := make([]*codectypes.Any, len(msgs)) + + for i, msg := range msgs { + msgAnys[i], err = codectypes.NewAnyWithValue(msg) + if err != nil { + return nil, err + } + } + + cosmosTx := &CosmosTx{ + Messages: msgAnys, + } + + bz, err = cdc.Marshal(cosmosTx) + if err != nil { + return nil, err + } + + return bz, nil +} + +// DeserializeCosmosTx unmarshals and unpacks a slice of transaction bytes +// into a slice of sdk.Msg's. +func DeserializeCosmosTx(cdc codec.BinaryCodec, data []byte) ([]sdk.Msg, error) { + var cosmosTx CosmosTx + if err := cdc.Unmarshal(data, &cosmosTx); err != nil { + return nil, err + } + + msgs := make([]sdk.Msg, len(cosmosTx.Messages)) + + for i, any := range cosmosTx.Messages { + var msg sdk.Msg + + err := cdc.UnpackAny(any, &msg) + if err != nil { + return nil, err + } + + msgs[i] = msg + } + + return msgs, nil +} diff --git a/modules/apps/27-interchain-accounts/types/codec_test.go b/modules/apps/27-interchain-accounts/types/codec_test.go new file mode 100644 index 00000000000..49b2042c163 --- /dev/null +++ b/modules/apps/27-interchain-accounts/types/codec_test.go @@ -0,0 +1,130 @@ +package types_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v2/testing/simapp" +) + +// caseRawBytes defines a helper struct, used for testing codec operations +type caseRawBytes struct { + name string + bz []byte + expPass bool +} + +// mockSdkMsg defines a mock struct, used for testing codec error scenarios +type mockSdkMsg struct{} + +// Reset implements sdk.Msg +func (mockSdkMsg) Reset() { +} + +// String implements sdk.Msg +func (mockSdkMsg) String() string { + return "" +} + +// ProtoMessage implements sdk.Msg +func (mockSdkMsg) ProtoMessage() { +} + +// ValidateBasic implements sdk.Msg +func (mockSdkMsg) ValidateBasic() error { + return nil +} + +// GetSigners implements sdk.Msg +func (mockSdkMsg) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{} +} + +func (suite *TypesTestSuite) TestSerializeCosmosTx() { + + testCases := []struct { + name string + msgs []sdk.Msg + expPass bool + }{ + { + "single msg", + []sdk.Msg{ + &banktypes.MsgSend{ + FromAddress: TestOwnerAddress, + ToAddress: TestOwnerAddress, + Amount: sdk.NewCoins(sdk.NewCoin("bananas", sdk.NewInt(100))), + }, + }, + true, + }, + { + "multiple msgs, same types", + []sdk.Msg{ + &banktypes.MsgSend{ + FromAddress: TestOwnerAddress, + ToAddress: TestOwnerAddress, + Amount: sdk.NewCoins(sdk.NewCoin("bananas", sdk.NewInt(100))), + }, + &banktypes.MsgSend{ + FromAddress: TestOwnerAddress, + ToAddress: TestOwnerAddress, + Amount: sdk.NewCoins(sdk.NewCoin("bananas", sdk.NewInt(200))), + }, + }, + true, + }, + { + "multiple msgs, different types", + []sdk.Msg{ + &banktypes.MsgSend{ + FromAddress: TestOwnerAddress, + ToAddress: TestOwnerAddress, + Amount: sdk.NewCoins(sdk.NewCoin("bananas", sdk.NewInt(100))), + }, + &govtypes.MsgSubmitProposal{ + InitialDeposit: sdk.NewCoins(sdk.NewCoin("bananas", sdk.NewInt(100))), + Proposer: TestOwnerAddress, + }, + }, + true, + }, + { + "unregistered msg type", + []sdk.Msg{ + &mockSdkMsg{}, + }, + false, + }, + { + "multiple unregistered msg types", + []sdk.Msg{ + &mockSdkMsg{}, + &mockSdkMsg{}, + &mockSdkMsg{}, + }, + false, + }, + } + + testCasesAny := []caseRawBytes{} + + for _, tc := range testCases { + bz, err := types.SerializeCosmosTx(simapp.MakeTestEncodingConfig().Marshaler, tc.msgs) + suite.Require().NoError(err, tc.name) + + testCasesAny = append(testCasesAny, caseRawBytes{tc.name, bz, tc.expPass}) + } + + for i, tc := range testCasesAny { + msgs, err := types.DeserializeCosmosTx(simapp.MakeTestEncodingConfig().Marshaler, tc.bz) + if tc.expPass { + suite.Require().NoError(err, tc.name) + suite.Require().Equal(testCases[i].msgs, msgs, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + } +} diff --git a/modules/apps/27-interchain-accounts/types/encoder.go b/modules/apps/27-interchain-accounts/types/encoder.go deleted file mode 100644 index f3e325e1912..00000000000 --- a/modules/apps/27-interchain-accounts/types/encoder.go +++ /dev/null @@ -1,3 +0,0 @@ -package types - -type TxEncoder func(data interface{}) ([]byte, error) diff --git a/modules/apps/27-interchain-accounts/types/hook.go b/modules/apps/27-interchain-accounts/types/hook.go deleted file mode 100644 index 0218cc815cb..00000000000 --- a/modules/apps/27-interchain-accounts/types/hook.go +++ /dev/null @@ -1,30 +0,0 @@ -package types - -import sdk "github.com/cosmos/cosmos-sdk/types" - -type IBCAccountHooks interface { - OnTxSucceeded(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) - OnTxFailed(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) -} - -type MultiIBCAccountHooks []IBCAccountHooks - -var ( - _ IBCAccountHooks = MultiIBCAccountHooks{} -) - -func NewMultiIBCAccountHooks(hooks ...IBCAccountHooks) MultiIBCAccountHooks { - return hooks -} - -func (h MultiIBCAccountHooks) OnTxSucceeded(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) { - for i := range h { - h[i].OnTxSucceeded(ctx, sourcePort, sourceChannel, txHash, txBytes) - } -} - -func (h MultiIBCAccountHooks) OnTxFailed(ctx sdk.Context, sourcePort, sourceChannel string, txHash []byte, txBytes []byte) { - for i := range h { - h[i].OnTxFailed(ctx, sourcePort, sourceChannel, txHash, txBytes) - } -} From cc2c3c90a6a4ff74a88701858c064b6b82e03df8 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 3 Nov 2021 14:45:56 +0100 Subject: [PATCH 46/66] ica: TrySendTx error handling nits (#491) * updating error handling and msgs for TrySendTx flow * renaming active channel ID getter/setters, adding comment re indeterminate errs * renaming DeleteActiveChannel -> DeleteActiveChannelID --- .../keeper/account_test.go | 2 +- .../keeper/handshake.go | 10 +++++----- .../keeper/handshake_test.go | 16 ++++++++-------- .../27-interchain-accounts/keeper/keeper.go | 16 ++++++++-------- .../27-interchain-accounts/keeper/relay.go | 19 ++++++++++--------- .../keeper/relay_test.go | 7 +++---- .../27-interchain-accounts/types/errors.go | 2 +- 7 files changed, 36 insertions(+), 36 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/account_test.go b/modules/apps/27-interchain-accounts/keeper/account_test.go index 3d5a1bb31af..fceea5eb48b 100644 --- a/modules/apps/27-interchain-accounts/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/keeper/account_test.go @@ -39,7 +39,7 @@ func (suite *KeeperTestSuite) TestInitInterchainAccount() { func() { portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) suite.Require().NoError(err) - suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID) + suite.chainA.GetSimApp().ICAKeeper.SetActiveChannelID(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID) }, false, }, diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index 6513b65758a..7481898fe4b 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -57,9 +57,9 @@ func (k Keeper) OnChanOpenInit( return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.VersionPrefix, version) } - existingChannelID, found := k.GetActiveChannel(ctx, portID) + activeChannelID, found := k.GetActiveChannelID(ctx, portID) if found { - return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel %s for portID %s", existingChannelID, portID) + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel %s for portID %s", activeChannelID, portID) } // Claim channel capability passed back by IBC module @@ -152,7 +152,7 @@ func (k Keeper) OnChanOpenAck( return sdkerrors.Wrap(err, "counterparty version validation failed") } - k.SetActiveChannel(ctx, portID, channelID) + k.SetActiveChannelID(ctx, portID, channelID) accAddr, err := types.ParseAddressFromVersion(counterpartyVersion) if err != nil { @@ -173,7 +173,7 @@ func (k Keeper) OnChanOpenConfirm( channelID string, ) error { - k.SetActiveChannel(ctx, portID, channelID) + k.SetActiveChannelID(ctx, portID, channelID) return nil } @@ -185,7 +185,7 @@ func (k Keeper) OnChanCloseConfirm( channelID string, ) error { - k.DeleteActiveChannel(ctx, portID) + k.DeleteActiveChannelID(ctx, portID) return nil } diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index 06eb217ecb5..e81a5781cd5 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -99,7 +99,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { { "channel is already active", func() { - suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.chainA.GetSimApp().ICAKeeper.SetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false, }, @@ -325,7 +325,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { func (suite *KeeperTestSuite) TestOnChanOpenAck() { var ( path *ibctesting.Path - expectedChannel string + expectedChannelID string counterpartyVersion string ) @@ -339,7 +339,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { }, { "invalid counterparty version", func() { - expectedChannel = "" + expectedChannelID = "" counterpartyVersion = "version" }, false, }, @@ -359,7 +359,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { err = path.EndpointB.ChanOpenTry() suite.Require().NoError(err) - expectedChannel = path.EndpointA.ChannelID + expectedChannelID = path.EndpointA.ChannelID tc.malleate() // explicitly change fields in channel and testChannel @@ -367,9 +367,9 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyVersion, ) - activeChannel, _ := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + activeChannelID, _ := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().Equal(activeChannel, expectedChannel) + suite.Require().Equal(activeChannelID, expectedChannelID) if tc.expPass { suite.Require().NoError(err) @@ -459,12 +459,12 @@ func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { err = suite.chainB.GetSimApp().ICAKeeper.OnChanCloseConfirm(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - activeChannel, found := suite.chainB.GetSimApp().ICAKeeper.GetActiveChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + activeChannelID, found := suite.chainB.GetSimApp().ICAKeeper.GetActiveChannelID(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) if tc.expPass { suite.Require().NoError(err) suite.Require().False(found) - suite.Require().Empty(activeChannel) + suite.Require().Empty(activeChannelID) } else { suite.Require().Error(err) } diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index d059f5a4ca8..467fbc519dc 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -99,10 +99,10 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability return k.scopedKeeper.ClaimCapability(ctx, cap, name) } -// GetActiveChannel retrieves the active channelID from the store keyed by the provided portID -func (k Keeper) GetActiveChannel(ctx sdk.Context, portId string) (string, bool) { +// GetActiveChannelID retrieves the active channelID from the store keyed by the provided portID +func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool) { store := ctx.KVStore(k.storeKey) - key := types.KeyActiveChannel(portId) + key := types.KeyActiveChannel(portID) if !store.Has(key) { return "", false @@ -111,21 +111,21 @@ func (k Keeper) GetActiveChannel(ctx sdk.Context, portId string) (string, bool) return string(store.Get(key)), true } -// SetActiveChannel stores the active channelID, keyed by the provided portID -func (k Keeper) SetActiveChannel(ctx sdk.Context, portID, channelID string) { +// SetActiveChannelID stores the active channelID, keyed by the provided portID +func (k Keeper) SetActiveChannelID(ctx sdk.Context, portID, channelID string) { store := ctx.KVStore(k.storeKey) store.Set(types.KeyActiveChannel(portID), []byte(channelID)) } -// DeleteActiveChannel removes the active channel keyed by the provided portID stored in state -func (k Keeper) DeleteActiveChannel(ctx sdk.Context, portID string) { +// DeleteActiveChannelID removes the active channel keyed by the provided portID stored in state +func (k Keeper) DeleteActiveChannelID(ctx sdk.Context, portID string) { store := ctx.KVStore(k.storeKey) store.Delete(types.KeyActiveChannel(portID)) } // IsActiveChannel returns true if there exists an active channel for the provided portID, otherwise false func (k Keeper) IsActiveChannel(ctx sdk.Context, portID string) bool { - _, ok := k.GetActiveChannel(ctx, portID) + _, ok := k.GetActiveChannelID(ctx, portID) return ok } diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 3fbb0d7b10c..2e3a896858a 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -14,20 +14,20 @@ import ( // manage helper module access to owner addresses they do not have capabilities for func (k Keeper) TrySendTx(ctx sdk.Context, portID string, icaPacketData types.InterchainAccountPacketData) (uint64, error) { // Check for the active channel - activeChannelId, found := k.GetActiveChannel(ctx, portID) + activeChannelID, found := k.GetActiveChannelID(ctx, portID) if !found { - return 0, types.ErrActiveChannelNotFound + return 0, sdkerrors.Wrapf(types.ErrActiveChannelNotFound, "failed to retrieve active channel for port %s", portID) } - sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, portID, activeChannelId) + sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, portID, activeChannelID) if !found { - return 0, sdkerrors.Wrap(channeltypes.ErrChannelNotFound, activeChannelId) + return 0, sdkerrors.Wrap(channeltypes.ErrChannelNotFound, activeChannelID) } destinationPort := sourceChannelEnd.GetCounterparty().GetPortID() destinationChannel := sourceChannelEnd.GetCounterparty().GetChannelID() - return k.createOutgoingPacket(ctx, portID, activeChannelId, destinationPort, destinationChannel, icaPacketData) + return k.createOutgoingPacket(ctx, portID, activeChannelID, destinationPort, destinationChannel, icaPacketData) } func (k Keeper) createOutgoingPacket( @@ -50,7 +50,7 @@ func (k Keeper) createOutgoingPacket( // get the next sequence sequence, found := k.channelKeeper.GetNextSequenceSend(ctx, sourcePort, sourceChannel) if !found { - return 0, channeltypes.ErrSequenceSendNotFound + return 0, sdkerrors.Wrapf(channeltypes.ErrSequenceSendNotFound, "failed to retrieve next sequence send for channel %s on port %s", sourceChannel, sourcePort) } // timeoutTimestamp is set to be a max number here so that we never recieve a timeout @@ -147,7 +147,8 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error var data types.InterchainAccountPacketData if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - return sdkerrors.Wrapf(types.ErrUnknownPacketData, "cannot unmarshal ICS-27 interchain account packet data") + // UnmarshalJSON errors are indeterminate and therefore are not wrapped and included in failed acks + return sdkerrors.Wrapf(types.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain account packet data") } switch data.Type { @@ -164,7 +165,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error return nil default: - return types.ErrUnknownPacketData + return types.ErrUnknownDataType } } @@ -175,7 +176,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac // OnTimeoutPacket removes the active channel associated with the provided packet, the underlying channel end is closed // due to the semantics of ORDERED channels func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet) error { - k.DeleteActiveChannel(ctx, packet.SourcePort) + k.DeleteActiveChannelID(ctx, packet.SourcePort) return nil } diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index e40512dd265..106af7ccd96 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -9,7 +9,6 @@ import ( "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v2/testing" ) @@ -52,7 +51,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() { }, { "channel does not exist", func() { - suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), portID, "channel-100") + suite.chainA.GetSimApp().ICAKeeper.SetActiveChannelID(suite.chainA.GetContext(), portID, "channel-100") }, false, }, { @@ -255,11 +254,11 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { packet := channeltypes.NewPacket([]byte{}, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) err = suite.chainA.GetSimApp().ICAKeeper.OnTimeoutPacket(suite.chainA.GetContext(), packet) - channel, found := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + activeChannelID, found := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) if tc.expPass { suite.Require().NoError(err) - suite.Require().Empty(channel) + suite.Require().Empty(activeChannelID) suite.Require().False(found) } else { suite.Require().Error(err) diff --git a/modules/apps/27-interchain-accounts/types/errors.go b/modules/apps/27-interchain-accounts/types/errors.go index 77787281d1a..7b4bfe5d8d1 100644 --- a/modules/apps/27-interchain-accounts/types/errors.go +++ b/modules/apps/27-interchain-accounts/types/errors.go @@ -5,7 +5,7 @@ import ( ) var ( - ErrUnknownPacketData = sdkerrors.Register(ModuleName, 2, "unknown packet data") + ErrUnknownDataType = sdkerrors.Register(ModuleName, 2, "unknown data type") ErrAccountAlreadyExist = sdkerrors.Register(ModuleName, 3, "account already exist") ErrPortAlreadyBound = sdkerrors.Register(ModuleName, 4, "port is already bound") ErrUnsupportedChain = sdkerrors.Register(ModuleName, 5, "unsupported chain") From df9ec49a5b0386097de2f8a677e389b1a5fdbbeb Mon Sep 17 00:00:00 2001 From: Sean King Date: Wed, 3 Nov 2021 15:38:54 +0100 Subject: [PATCH 47/66] chore: adding damo to codeowners (#520) --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 743e1c582b5..2c6a4204e19 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -28,5 +28,5 @@ # CODEOWNERS for interchain-accounts module -/modules/apps/27-interchain-accounts/ @seantking @colin-axner @AdityaSripal -/proto/applications/interchain_accounts/ @seantking @colin-axner @AdityaSripal +/modules/apps/27-interchain-accounts/ @seantking @colin-axner @AdityaSripal @damiannolan +/proto/applications/interchain_accounts/ @seantking @colin-axner @AdityaSripal @damiannolan From f88b4d7ecaa483d49472fd1449d95babbf6337f6 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 4 Nov 2021 10:04:39 +0100 Subject: [PATCH 48/66] ica: AuthenticateTx/executeTx clean up (#490) * cleaning up AuthenticateTx and executeTx to reduce unnecessary complexity * adding error wrapping to AuthenticateTx * updating err msg to include expected signer --- .../27-interchain-accounts/keeper/relay.go | 53 +++++++------------ .../27-interchain-accounts/types/packet.go | 1 - 2 files changed, 19 insertions(+), 35 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 2e3a896858a..bbd15f32f46 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -75,26 +75,19 @@ func (k Keeper) createOutgoingPacket( return packet.Sequence, nil } -func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portId string) error { - seen := map[string]bool{} - var signers []sdk.AccAddress - for _, msg := range msgs { - for _, addr := range msg.GetSigners() { - if !seen[addr.String()] { - signers = append(signers, addr) - seen[addr.String()] = true - } - } - } - - interchainAccountAddr, found := k.GetInterchainAccountAddress(ctx, portId) +// AuthenticateTx ensures the provided msgs contain the correct interchain account signer address retrieved +// from state using the provided controller port identifier +func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portID string) error { + interchainAccountAddr, found := k.GetInterchainAccountAddress(ctx, portID) if !found { - return sdkerrors.ErrUnauthorized + return sdkerrors.Wrapf(types.ErrInterchainAccountNotFound, "failed to retrieve interchain account on port %s", portID) } - for _, signer := range signers { - if interchainAccountAddr != signer.String() { - return sdkerrors.ErrUnauthorized + for _, msg := range msgs { + for _, signer := range msg.GetSigners() { + if interchainAccountAddr != signer.String() { + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "unexpected signer address: expected %s, got %s", interchainAccountAddr, signer.String()) + } } } @@ -102,33 +95,26 @@ func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portId string) e } func (k Keeper) executeTx(ctx sdk.Context, sourcePort, destPort, destChannel string, msgs []sdk.Msg) error { - err := k.AuthenticateTx(ctx, msgs, sourcePort) - if err != nil { + if err := k.AuthenticateTx(ctx, msgs, sourcePort); err != nil { return err } for _, msg := range msgs { - err := msg.ValidateBasic() - if err != nil { + if err := msg.ValidateBasic(); err != nil { return err } } - cacheContext, writeFn := ctx.CacheContext() + // CacheContext returns a new context with the multi-store branched into a cached storage object + // writeCache is called only if all msgs succeed, performing state transitions atomically + cacheCtx, writeCache := ctx.CacheContext() for _, msg := range msgs { - _, msgErr := k.executeMsg(cacheContext, msg) - if msgErr != nil { - err = msgErr - break + if _, err := k.executeMsg(cacheCtx, msg); err != nil { + return err } } - if err != nil { - return err - } - - // Write the state transitions if all handlers succeed. - writeFn() + writeCache() return nil } @@ -158,8 +144,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error return err } - err = k.executeTx(ctx, packet.SourcePort, packet.DestinationPort, packet.DestinationChannel, msgs) - if err != nil { + if err = k.executeTx(ctx, packet.SourcePort, packet.DestinationPort, packet.DestinationChannel, msgs); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 8342f911bbf..3c5223f4390 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -22,7 +22,6 @@ func (iapd InterchainAccountPacketData) ValidateBasic() error { if len(iapd.Memo) > MaxMemoCharLength { return sdkerrors.Wrapf(ErrInvalidOutgoingData, "packet data memo cannot be greater than %d characters", MaxMemoCharLength) } - // TODO: add type validation when data type enum supports unspecified type return nil } From cd2f81d6e6c3ddb86d49442f8e28f6e438fb617d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Fri, 5 Nov 2021 12:50:21 +0100 Subject: [PATCH 49/66] ICA Controller Side Middleware (#417) * initial draft for ica middleware * add capability handling, fix build and tests * split module.go into ibc_module.go * add middleware handshake tests * fix app.go wiring and various tests * godoc self nits * remove unnecessary error * update comment * fix testing build * split channel keeper interface splits ChannelKeeper interface into ics4Wrapper and core ChannelKeeper * fix tests * remove comments * add callback for timeouts * Apply suggestions from code review Co-authored-by: Sean King Co-authored-by: Damian Nolan * fix test and update testing README apply test fix pointed out by Sean. Update testing README to reflect how to test with the mock module for middleware * add OnRecvPacket test Add test cases for OnRecvPacket, reused structure in relay_test.go * add failing test case for NegotiateAppVersion Co-authored-by: Sean King Co-authored-by: Damian Nolan --- .../apps/27-interchain-accounts/ibc_module.go | 80 +-- .../27-interchain-accounts/ibc_module_test.go | 539 ++++++++++++++++++ .../keeper/handshake.go | 5 - .../keeper/handshake_test.go | 9 - .../27-interchain-accounts/keeper/keeper.go | 4 +- .../27-interchain-accounts/keeper/relay.go | 22 +- .../keeper/relay_test.go | 16 +- modules/apps/27-interchain-accounts/module.go | 1 + .../27-interchain-accounts/module_test.go | 250 -------- .../types/expected_keepers.go | 6 +- testing/README.md | 16 +- testing/simapp/app.go | 37 +- 12 files changed, 656 insertions(+), 329 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/ibc_module_test.go delete mode 100644 modules/apps/27-interchain-accounts/module_test.go diff --git a/modules/apps/27-interchain-accounts/ibc_module.go b/modules/apps/27-interchain-accounts/ibc_module.go index abc488af67a..ce5af58f4c8 100644 --- a/modules/apps/27-interchain-accounts/ibc_module.go +++ b/modules/apps/27-interchain-accounts/ibc_module.go @@ -1,20 +1,17 @@ package interchain_accounts import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/keeper" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" ) -// IBCModule implements the ICS26 callbacks for interchain accounts given the +// IBCModule implements the ICS26 interface for interchain accounts given the // interchain account keeper and underlying application. type IBCModule struct { keeper keeper.Keeper @@ -29,7 +26,13 @@ func NewIBCModule(k keeper.Keeper, app porttypes.IBCModule) IBCModule { } } -// OnChanOpenInit implements the IBCModule interface +// OnChanOpenInit implements the IBCModule interface. Interchain Accounts is +// implemented to act as middleware for connected authentication modules on +// the controller side. The connected modules may not change the controller side portID or +// version. They will be allowed to perform custom logic without changing +// the parameters stored within a channel struct. +// +// Controller Chain func (im IBCModule) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, @@ -40,10 +43,18 @@ func (im IBCModule) OnChanOpenInit( counterparty channeltypes.Counterparty, version string, ) error { - return im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) + if err := im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version); err != nil { + return err + } + + // call underlying app's OnChanOpenInit callback with the appVersion + return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, + chanCap, counterparty, version) } // OnChanOpenTry implements the IBCModule interface +// +// Host Chain func (im IBCModule) OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, @@ -58,17 +69,30 @@ func (im IBCModule) OnChanOpenTry( return im.keeper.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version, counterpartyVersion) } -// OnChanOpenAck implements the IBCModule interface +// OnChanOpenAck implements the IBCModule interface. Interchain Accounts is +// implemented to act as middleware for connected authentication modules on +// the controller side. The connected modules may not change the portID or +// version. They will be allowed to perform custom logic without changing +// the parameters stored within a channel struct. +// +// Controller Chain func (im IBCModule) OnChanOpenAck( ctx sdk.Context, portID, channelID string, counterpartyVersion string, ) error { - return im.keeper.OnChanOpenAck(ctx, portID, channelID, counterpartyVersion) + if err := im.keeper.OnChanOpenAck(ctx, portID, channelID, counterpartyVersion); err != nil { + return err + } + + // call underlying app's OnChanOpenAck callback with the counterparty app version. + return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyVersion) } -// OnChanOpenConfirm implements the IBCModule interface +// OnChanOpenAck implements the IBCModule interface +// +// Host Chain func (im IBCModule) OnChanOpenConfirm( ctx sdk.Context, portID, @@ -97,6 +121,8 @@ func (im IBCModule) OnChanCloseConfirm( } // OnRecvPacket implements the IBCModule interface +// +// Host Chain func (im IBCModule) OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, @@ -104,11 +130,6 @@ func (im IBCModule) OnRecvPacket( ) ibcexported.Acknowledgement { ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - var data types.InterchainAccountPacketData - if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - ack = channeltypes.NewErrorAcknowledgement(fmt.Sprintf("cannot unmarshal ICS-27 interchain account packet data: %s", err.Error())) - } - // only attempt the application logic if the packet data // was successfully decoded if ack.Success() { @@ -123,36 +144,31 @@ func (im IBCModule) OnRecvPacket( } // OnAcknowledgementPacket implements the IBCModule interface +// +// Controller Chain func (im IBCModule) OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, - _ sdk.AccAddress, + relayer sdk.AccAddress, ) error { - var ack channeltypes.Acknowledgement - - if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-27 interchain account packet acknowledgment: %v", err) - } - var data types.InterchainAccountPacketData - if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-27 interchain account packet data: %s", err.Error()) - } - - if err := im.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil { - return err - } - - return nil + // call underlying app's OnAcknowledgementPacket callback. + return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) } // OnTimeoutPacket implements the IBCModule interface +// +// Controller Chain func (im IBCModule) OnTimeoutPacket( ctx sdk.Context, packet channeltypes.Packet, - _ sdk.AccAddress, + relayer sdk.AccAddress, ) error { - return im.keeper.OnTimeoutPacket(ctx, packet) + if err := im.keeper.OnTimeoutPacket(ctx, packet); err != nil { + return err + } + + return im.app.OnTimeoutPacket(ctx, packet, relayer) } // NegotiateAppVersion implements the IBCModule interface diff --git a/modules/apps/27-interchain-accounts/ibc_module_test.go b/modules/apps/27-interchain-accounts/ibc_module_test.go new file mode 100644 index 00000000000..ca010b6ede1 --- /dev/null +++ b/modules/apps/27-interchain-accounts/ibc_module_test.go @@ -0,0 +1,539 @@ +package interchain_accounts_test + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/crypto" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" + "github.com/cosmos/ibc-go/v2/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v2/testing" +) + +var ( + // TestAccAddress defines a resuable bech32 address for testing purposes + // TODO: update crypto.AddressHash() when sdk uses address.Module() + TestAccAddress = types.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))), TestPortID) + // TestOwnerAddress defines a reusable bech32 address for testing purposes + TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + // TestPortID defines a resuable port identifier for testing purposes + TestPortID, _ = types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-0") + // TestVersion defines a resuable interchainaccounts version string for testing purposes + TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) +) + +type InterchainAccountsTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + // testing chains used for convenience and readability + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain +} + +func TestICATestSuite(t *testing.T) { + suite.Run(t, new(InterchainAccountsTestSuite)) +} + +func (suite *InterchainAccountsTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) +} + +func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { + path := ibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig.PortID = types.PortID + path.EndpointB.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointA.ChannelConfig.Version = types.VersionPrefix + path.EndpointB.ChannelConfig.Version = TestVersion + + return path +} + +func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { + portID, err := types.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) + if err != nil { + return err + } + channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) + + if err := endpoint.Chain.GetSimApp().ICAKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, owner); err != nil { + return err + } + + // commit state changes for proof verification + endpoint.Chain.App.Commit() + endpoint.Chain.NextBlock() + + // update port/channel ids + endpoint.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + endpoint.ChannelConfig.PortID = portID + return nil +} + +// SetupICAPath invokes the InterchainAccounts entrypoint and subsequent channel handshake handlers +func SetupICAPath(path *ibctesting.Path, owner string) error { + if err := InitInterchainAccount(path.EndpointA, owner); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenTry(); err != nil { + return err + } + + if err := path.EndpointA.ChanOpenAck(); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenConfirm(); err != nil { + return err + } + + return nil +} + +func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { + var ( + channel *channeltypes.Channel + ) + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + { + "ICA OnChanOpenInit fails - UNORDERED channel", func() { + channel.Ordering = channeltypes.UNORDERED + }, false, + }, + { + "ICA auth module callback fails", func() { + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, + portID, channelID string, chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, version string, + ) error { + return fmt.Errorf("mock ica auth fails") + } + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + // mock init interchain account + portID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + suite.Require().NoError(err) + portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) + suite.chainA.GetSimApp().ICAKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) + + path.EndpointA.ChannelConfig.PortID = portID + path.EndpointA.ChannelID = ibctesting.FirstChannelID + + // default values + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + channel = &channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: channeltypes.ORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: types.VersionPrefix, + } + + tc.malleate() + + // ensure channel on chainA is set in state + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, *channel) + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), + ) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { + var ( + channel *channeltypes.Channel + ) + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + { + "success: ICA auth module callback returns error", func() { + // mock module callback should not be called on host side + suite.chainB.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenTry = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, + portID, channelID string, chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, version, counterpartyVersion string, + ) error { + return fmt.Errorf("mock ica auth fails") + } + + }, true, + }, + { + "ICA callback fails - invalid version", func() { + channel.Version = types.VersionPrefix + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + counterpartyVersion := types.VersionPrefix + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + path.EndpointB.ChannelID = ibctesting.FirstChannelID + + // default values + counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channel = &channeltypes.Channel{ + State: channeltypes.TRYOPEN, + Ordering: channeltypes.ORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointB.ConnectionID}, + Version: TestVersion, + } + + tc.malleate() + + // ensure channel on chainB is set in state + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, *channel) + + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + chanCap, err := suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) + suite.Require().NoError(err) + + cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.GetConnectionHops(), + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), counterpartyVersion, + ) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } + +} + +func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { + var ( + counterpartyVersion string + ) + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + { + "ICA OnChanOpenACK fails - invalid version", func() { + counterpartyVersion = "invalid|version" + }, false, + }, + { + "ICA auth module callback fails", func() { + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenAck = func( + ctx sdk.Context, portID, channelID string, counterpartyVersion string, + ) error { + return fmt.Errorf("mock ica auth fails") + } + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + counterpartyVersion = TestVersion + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + + tc.malleate() + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyVersion) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } + +} + +func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + { + "success: ICA auth module callback returns error", func() { + // mock module callback should not be called on host side + suite.chainB.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenConfirm = func( + ctx sdk.Context, portID, channelID string, + ) error { + return fmt.Errorf("mock ica auth fails") + } + + }, true, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanOpenAck() + suite.Require().NoError(err) + + tc.malleate() + + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenConfirm(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } + +} + +func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { + var ( + packetData []byte + ) + testCases := []struct { + name string + malleate func() + expAckSuccess bool + }{ + { + "success", func() {}, true, + }, + { + "success with ICA auth module callback failure", func() { + suite.chainB.GetSimApp().ICAAuthModule.IBCApp.OnRecvPacket = func( + ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, + ) exported.Acknowledgement { + return channeltypes.NewErrorAcknowledgement("failed OnRecvPacket mock callback") + } + }, true, + }, + { + "ICA OnRecvPacket fails - cannot unmarshal packet data", func() { + packetData = []byte("invalid data") + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + // send 100stake to interchain account wallet + amount, _ := sdk.ParseCoinsNormalized("100stake") + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + bankMsg := &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: interchainAccountAddr, Amount: amount} + + _, err = suite.chainB.SendMsgs(bankMsg) + suite.Require().NoError(err) + + // build packet data + msg := &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: amount, + } + data, err := types.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) + suite.Require().NoError(err) + + icaPacketData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + packetData = icaPacketData.GetBytes() + + // malleate packetData for test cases + tc.malleate() + + seq := uint64(1) + packet := channeltypes.NewPacket(packetData, seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) + + tc.malleate() + + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + ack := cbs.OnRecvPacket(suite.chainB.GetContext(), packet, nil) + suite.Require().Equal(tc.expAckSuccess, ack.Success()) + + }) + } + +} + +func (suite *InterchainAccountsTestSuite) TestNegotiateAppVersion() { + var ( + proposedVersion string + ) + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + { + "invalid proposed version", func() { + proposedVersion = "invalid version" + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + module, _, err := suite.chainA.GetSimApp().GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.GetSimApp().GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + counterpartyPortID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + suite.Require().NoError(err) + + counterparty := &channeltypes.Counterparty{ + PortId: counterpartyPortID, + ChannelId: path.EndpointB.ChannelID, + } + + proposedVersion = types.VersionPrefix + + tc.malleate() + + version, err := cbs.NegotiateAppVersion(suite.chainA.GetContext(), channeltypes.ORDERED, path.EndpointA.ConnectionID, types.PortID, *counterparty, proposedVersion) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NoError(types.ValidateVersion(version)) + suite.Require().Equal(TestVersion, version) + } else { + suite.Require().Error(err) + suite.Require().Empty(version) + } + }) + } +} diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/keeper/handshake.go index 7481898fe4b..a6c69509013 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake.go @@ -62,11 +62,6 @@ func (k Keeper) OnChanOpenInit( return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel %s for portID %s", activeChannelID, portID) } - // Claim channel capability passed back by IBC module - if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return sdkerrors.Wrapf(err, "failed to claim capability for channel %s on port %s", channelID, portID) - } - return nil } diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go index e81a5781cd5..cf27023831c 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/keeper/handshake_test.go @@ -103,15 +103,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { }, false, }, - { - "capability already claimed", - func() { - path.EndpointA.SetChannel(*channel) - err := suite.chainA.GetSimApp().ScopedICAKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().NoError(err) - }, - false, - }, } for _, tc := range testCases { diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index 467fbc519dc..c730882207d 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -22,6 +22,7 @@ type Keeper struct { storeKey sdk.StoreKey cdc codec.BinaryCodec + ics4Wrapper types.ICS4Wrapper channelKeeper types.ChannelKeeper portKeeper types.PortKeeper accountKeeper types.AccountKeeper @@ -34,7 +35,7 @@ type Keeper struct { // NewKeeper creates a new interchain account Keeper instance func NewKeeper( cdc codec.BinaryCodec, key sdk.StoreKey, - channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, + ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, accountKeeper types.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, ) Keeper { @@ -46,6 +47,7 @@ func NewKeeper( return Keeper{ storeKey: key, cdc: cdc, + ics4Wrapper: ics4Wrapper, channelKeeper: channelKeeper, portKeeper: portKeeper, accountKeeper: accountKeeper, diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index bbd15f32f46..681433e03ee 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -3,16 +3,16 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) -// TODO: implement middleware functionality, this will allow us to use capabilities to -// manage helper module access to owner addresses they do not have capabilities for -func (k Keeper) TrySendTx(ctx sdk.Context, portID string, icaPacketData types.InterchainAccountPacketData) (uint64, error) { +// TrySendTx takes in a transaction from an authentication module and attempts to send the packet +// if the base application has the capability to send on the provided portID +func (k Keeper) TrySendTx(ctx sdk.Context, chanCap *capabilitytypes.Capability, portID string, icaPacketData types.InterchainAccountPacketData) (uint64, error) { // Check for the active channel activeChannelID, found := k.GetActiveChannelID(ctx, portID) if !found { @@ -27,7 +27,7 @@ func (k Keeper) TrySendTx(ctx sdk.Context, portID string, icaPacketData types.In destinationPort := sourceChannelEnd.GetCounterparty().GetPortID() destinationChannel := sourceChannelEnd.GetCounterparty().GetChannelID() - return k.createOutgoingPacket(ctx, portID, activeChannelID, destinationPort, destinationChannel, icaPacketData) + return k.createOutgoingPacket(ctx, portID, activeChannelID, destinationPort, destinationChannel, chanCap, icaPacketData) } func (k Keeper) createOutgoingPacket( @@ -36,17 +36,13 @@ func (k Keeper) createOutgoingPacket( sourceChannel, destinationPort, destinationChannel string, + chanCap *capabilitytypes.Capability, icaPacketData types.InterchainAccountPacketData, ) (uint64, error) { if err := icaPacketData.ValidateBasic(); err != nil { return 0, sdkerrors.Wrap(err, "invalid interchain account packet data") } - channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(sourcePort, sourceChannel)) - if !ok { - return 0, sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") - } - // get the next sequence sequence, found := k.channelKeeper.GetNextSequenceSend(ctx, sourcePort, sourceChannel) if !found { @@ -68,7 +64,7 @@ func (k Keeper) createOutgoingPacket( timeoutTimestamp, ) - if err := k.channelKeeper.SendPacket(ctx, channelCap, packet); err != nil { + if err := k.ics4Wrapper.SendPacket(ctx, chanCap, packet); err != nil { return 0, err } @@ -154,10 +150,6 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error } } -func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.InterchainAccountPacketData, ack channeltypes.Acknowledgement) error { - return nil -} - // OnTimeoutPacket removes the active channel associated with the provided packet, the underlying channel end is closed // due to the semantics of ORDERED channels func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet) error { diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index 106af7ccd96..bcc1ebccf27 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -5,10 +5,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) @@ -17,6 +19,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() { path *ibctesting.Path icaPacketData types.InterchainAccountPacketData portID string + chanCap *capabilitytypes.Capability ) testCases := []struct { @@ -60,6 +63,11 @@ func (suite *KeeperTestSuite) TestTrySendTx() { suite.Require().NoError(err) }, false, }, + { + "invalid channel capability provided", func() { + chanCap = nil + }, false, + }, } for _, tc := range testCases { @@ -73,10 +81,12 @@ func (suite *KeeperTestSuite) TestTrySendTx() { err := suite.SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) + // default setup portID = path.EndpointA.ChannelConfig.PortID amount, _ := sdk.ParseCoinsNormalized("100stake") interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + msg := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) @@ -88,9 +98,13 @@ func (suite *KeeperTestSuite) TestTrySendTx() { Memo: "memo", } + var ok bool + chanCap, ok = suite.chainA.GetSimApp().ScopedICAMockKeeper.GetCapability(path.EndpointA.Chain.GetContext(), host.ChannelCapabilityPath(portID, path.EndpointA.ChannelID)) + suite.Require().True(ok) + tc.malleate() - _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), portID, icaPacketData) + _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), chanCap, portID, icaPacketData) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index ab085b886dc..8e83463aef9 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -72,6 +72,7 @@ type AppModule struct { keeper keeper.Keeper } +// NewAppModule creates an interchain accounts app module. func NewAppModule(k keeper.Keeper) AppModule { return AppModule{ keeper: k, diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go deleted file mode 100644 index a2ff103d3eb..00000000000 --- a/modules/apps/27-interchain-accounts/module_test.go +++ /dev/null @@ -1,250 +0,0 @@ -package interchain_accounts_test - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/suite" - "github.com/tendermint/tendermint/crypto" - - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v2/modules/core/24-host" - ibctesting "github.com/cosmos/ibc-go/v2/testing" -) - -var ( - // TestAccAddress defines a resuable bech32 address for testing purposes - // TODO: update crypto.AddressHash() when sdk uses address.Module() - TestAccAddress = types.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))), TestPortID) - // TestOwnerAddress defines a reusable bech32 address for testing purposes - TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" - // TestPortID defines a resuable port identifier for testing purposes - TestPortID, _ = types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-0") - // TestVersion defines a resuable interchainaccounts version string for testing purposes - TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) -) - -type InterchainAccountsTestSuite struct { - suite.Suite - - coordinator *ibctesting.Coordinator - - // testing chains used for convenience and readability - chainA *ibctesting.TestChain - chainB *ibctesting.TestChain - chainC *ibctesting.TestChain -} - -func TestICATestSuite(t *testing.T) { - suite.Run(t, new(InterchainAccountsTestSuite)) -} - -func (suite *InterchainAccountsTestSuite) SetupTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) - suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) - suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) - suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2)) -} - -func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { - path := ibctesting.NewPath(chainA, chainB) - path.EndpointA.ChannelConfig.PortID = types.PortID - path.EndpointB.ChannelConfig.PortID = types.PortID - path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointA.ChannelConfig.Version = types.VersionPrefix - path.EndpointB.ChannelConfig.Version = TestVersion - - return path -} - -func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { - portID, err := types.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) - if err != nil { - return err - } - channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - - if err := endpoint.Chain.GetSimApp().ICAKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, owner); err != nil { - return err - } - - // commit state changes for proof verification - endpoint.Chain.App.Commit() - endpoint.Chain.NextBlock() - - // update port/channel ids - endpoint.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) - endpoint.ChannelConfig.PortID = portID - return nil -} - -// SetupICAPath invokes the InterchainAccounts entrypoint and subsequent channel handshake handlers -func SetupICAPath(path *ibctesting.Path, owner string) error { - if err := InitInterchainAccount(path.EndpointA, owner); err != nil { - return err - } - - if err := path.EndpointB.ChanOpenTry(); err != nil { - return err - } - - if err := path.EndpointA.ChanOpenAck(); err != nil { - return err - } - - if err := path.EndpointB.ChanOpenConfirm(); err != nil { - return err - } - - return nil -} - -func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { - suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - // mock init interchain account - portID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - suite.Require().NoError(err) - portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) - suite.chainA.GetSimApp().ICAKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) - path.EndpointA.ChannelConfig.PortID = portID - - // default values - counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - channel := &channeltypes.Channel{ - State: channeltypes.INIT, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: types.VersionPrefix, - } - - // set channel - path.EndpointA.SetChannel(*channel) - - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) - suite.Require().NoError(err) - - chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(ibctesting.TransferPort, path.EndpointA.ChannelID)) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) - - err = cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), - ) - suite.Require().NoError(err) -} - -func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { - suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) - - // default values - counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - channel := &channeltypes.Channel{ - State: channeltypes.TRYOPEN, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointB.ConnectionID}, - Version: types.VersionPrefix, - } - - // set channel - channelSequence := path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(path.EndpointB.Chain.GetContext()) - path.EndpointB.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) - path.EndpointB.SetChannel(*channel) - - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), types.PortID) - suite.Require().NoError(err) - - chanCap, err := suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(ibctesting.TransferPort, path.EndpointB.ChannelID)) - suite.Require().NoError(err) - - cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) - - err = cbs.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.GetConnectionHops(), - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, TestVersion, types.VersionPrefix, - ) - suite.Require().NoError(err) -} - -func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { - suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) - - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) - - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) - - err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, TestVersion) - suite.Require().NoError(err) -} - -func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { - suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) - - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) - - err = path.EndpointA.ChanOpenAck() - suite.Require().NoError(err) - - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) - - err = cbs.OnChanOpenConfirm(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - suite.Require().NoError(err) -} - -func (suite *InterchainAccountsTestSuite) TestNegotiateAppVersion() { - suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - module, _, err := suite.chainA.GetSimApp().GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.GetSimApp().GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) - - counterpartyPortID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - suite.Require().NoError(err) - - counterparty := &channeltypes.Counterparty{ - PortId: counterpartyPortID, - ChannelId: path.EndpointB.ChannelID, - } - - version, err := cbs.NegotiateAppVersion(suite.chainA.GetContext(), channeltypes.ORDERED, path.EndpointA.ConnectionID, types.PortID, *counterparty, types.VersionPrefix) - suite.Require().NoError(err) - suite.Require().NoError(types.ValidateVersion(version)) - suite.Require().Equal(TestVersion, version) -} diff --git a/modules/apps/27-interchain-accounts/types/expected_keepers.go b/modules/apps/27-interchain-accounts/types/expected_keepers.go index 2b08a9bcfe9..558a38c4033 100644 --- a/modules/apps/27-interchain-accounts/types/expected_keepers.go +++ b/modules/apps/27-interchain-accounts/types/expected_keepers.go @@ -18,11 +18,15 @@ type AccountKeeper interface { GetModuleAddress(name string) sdk.AccAddress } +// ICS4Wrapper defines the expected ICS4Wrapper for middleware +type ICS4Wrapper interface { + SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error +} + // ChannelKeeper defines the expected IBC channel keeper type ChannelKeeper interface { GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) - SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error CounterpartyHops(ctx sdk.Context, channel channeltypes.Channel) ([]string, bool) } diff --git a/testing/README.md b/testing/README.md index f7a71bb1348..189f8e8c6cc 100644 --- a/testing/README.md +++ b/testing/README.md @@ -294,7 +294,7 @@ When writing IBC applications acting as middleware, it might be desirable to tes This can be done by wiring a middleware stack in the app.go file using existing applications as middleware and IBC base applications. The mock module may also be leveraged to act as a base application in the instance that such an application is not available for testing or causes dependency concerns. -The mock module contains a `MockIBCApp`. This struct contains a function field for every IBC App Module callback. +The mock IBC module contains a `MockIBCApp`. This struct contains a function field for every IBC App Module callback. Each of these functions can be individually set to mock expected behaviour of a base application. For example, if one wanted to test that the base application cannot affect the outcome of the `OnChanOpenTry` callback, the mock module base application callback could be updated as such: @@ -303,3 +303,17 @@ For example, if one wanted to test that the base application cannot affect the o return fmt.Errorf("mock base app must not be called for OnChanOpenTry") } ``` + +Using a mock module as a base application in a middleware stack may require adding the module to your `SimApp`. +This is because IBC will route to the top level IBC module of a middleware stack, so a module which never +sits at the top of middleware stack will need to be accessed via a public field in `SimApp` + +This might look like: +```go + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, + portID, channelID string, chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, version string, + ) error { + return fmt.Errorf("mock ica auth fails") + } +``` diff --git a/testing/simapp/app.go b/testing/simapp/app.go index e9f6cd33543..3050e6436d6 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -196,6 +196,11 @@ type SimApp struct { ScopedTransferKeeper capabilitykeeper.ScopedKeeper ScopedICAKeeper capabilitykeeper.ScopedKeeper ScopedIBCMockKeeper capabilitykeeper.ScopedKeeper + ScopedICAMockKeeper capabilitykeeper.ScopedKeeper + + // make IBC modules public for test purposes + // these modules are never directly routed to by the IBC Router + ICAAuthModule ibcmock.IBCModule // the module manager mm *module.Manager @@ -265,8 +270,9 @@ func NewSimApp( scopedICAKeeper := app.CapabilityKeeper.ScopeToModule(icatypes.ModuleName) // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do - // note replicate if you do not need to test core IBC or light clients. + // not replicate if you do not need to test core IBC or light clients. scopedIBCMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName) + scopedICAMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName + icatypes.ModuleName) // seal capability keeper after scoping modules app.CapabilityKeeper.Seal() @@ -333,24 +339,31 @@ func NewSimApp( transferModule := transfer.NewAppModule(app.TransferKeeper) transferIBCModule := transfer.NewIBCModule(app.TransferKeeper) + // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do + // not replicate if you do not need to test core IBC or light clients. + mockModule := ibcmock.NewAppModule(scopedIBCMockKeeper, &app.IBCKeeper.PortKeeper) + mockIBCModule := ibcmock.NewIBCModule(&ibcmock.MockIBCApp{}, scopedIBCMockKeeper) + app.ICAKeeper = icakeeper.NewKeeper( appCodec, keys[icatypes.StoreKey], + app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, scopedICAKeeper, app.MsgServiceRouter(), ) icaModule := ica.NewAppModule(app.ICAKeeper) - icaIBCModule := ica.NewIBCModule(app.ICAKeeper, nil) - // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do - // note replicate if you do not need to test core IBC or light clients. - mockModule := ibcmock.NewAppModule(scopedIBCMockKeeper, &app.IBCKeeper.PortKeeper) - mockIBCModule := ibcmock.NewIBCModule(&ibcmock.MockIBCApp{}, scopedIBCMockKeeper) + // initialize ICA module with mock module as the authentication module on the controller side + icaAuthModule := ibcmock.NewIBCModule(&ibcmock.MockIBCApp{}, scopedICAMockKeeper) + app.ICAAuthModule = icaAuthModule + + icaIBCModule := ica.NewIBCModule(app.ICAKeeper, icaAuthModule) // Create static IBC router, add transfer route, then set and seal it ibcRouter := porttypes.NewRouter() - ibcRouter.AddRoute(icatypes.ModuleName, icaIBCModule) - ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferIBCModule) - ibcRouter.AddRoute(ibcmock.ModuleName, mockIBCModule) + ibcRouter.AddRoute(icatypes.ModuleName, icaIBCModule). + AddRoute(ibcmock.ModuleName+icatypes.ModuleName, icaIBCModule). // ica with mock auth module stack route to ica (top level of middleware stack) + AddRoute(ibctransfertypes.ModuleName, transferIBCModule). + AddRoute(ibcmock.ModuleName, mockIBCModule) app.IBCKeeper.SetRouter(ibcRouter) // create evidence keeper with router @@ -486,6 +499,7 @@ func NewSimApp( // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // note replicate if you do not need to test core IBC or light clients. app.ScopedIBCMockKeeper = scopedIBCMockKeeper + app.ScopedICAMockKeeper = scopedICAMockKeeper return app } @@ -600,11 +614,6 @@ func (app *SimApp) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { return app.ScopedIBCKeeper } -// GetMockModule returns the mock module in the testing application -func (app *SimApp) GetMockModule() ibcmock.AppModule { - return app.mm.Modules[ibcmock.ModuleName].(ibcmock.AppModule) -} - // GetTxConfig implements the TestingApp interface. func (app *SimApp) GetTxConfig() client.TxConfig { return MakeTestEncodingConfig().TxConfig From 3ff5bf8749fce8232b52c1bf7bdc3ca4a561d618 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Fri, 5 Nov 2021 15:29:48 +0100 Subject: [PATCH 50/66] ica: genesis state implementation (#481) * initial genesis state draft * updating protos * including yaml tags, sorting proto file structure * updating to use range queries for active channels/interchain accounts * updating GetAllPorts test * moving test strings to expected vars --- docs/ibc/proto-docs.md | 38 +- .../apps/27-interchain-accounts/genesis.go | 31 +- .../27-interchain-accounts/genesis_test.go | 59 ++ .../27-interchain-accounts/keeper/keeper.go | 41 ++ .../keeper/keeper_test.go | 80 ++- .../27-interchain-accounts/types/genesis.go | 13 +- .../types/genesis.pb.go | 623 +++++++++++++++++- .../interchain_accounts/v1/account.proto | 5 +- .../interchain_accounts/v1/genesis.proto | 19 +- .../interchain_accounts/v1/query.proto | 5 +- .../interchain_accounts/v1/types.proto | 4 +- 11 files changed, 872 insertions(+), 46 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/genesis_test.go diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index b5557d2d923..8deda5b71e8 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -8,7 +8,9 @@ - [InterchainAccount](#ibc.applications.interchain_accounts.v1.InterchainAccount) - [ibc/applications/interchain_accounts/v1/genesis.proto](#ibc/applications/interchain_accounts/v1/genesis.proto) + - [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel) - [GenesisState](#ibc.applications.interchain_accounts.v1.GenesisState) + - [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount) - [ibc/applications/interchain_accounts/v1/query.proto](#ibc/applications/interchain_accounts/v1/query.proto) - [QueryInterchainAccountAddressRequest](#ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressRequest) @@ -311,15 +313,49 @@ An InterchainAccount is defined as a BaseAccount & the address of the account ow + + +### ActiveChannel +ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `port_id` | [string](#string) | | | +| `channel_id` | [string](#string) | | | + + + + + + ### GenesisState -GenesisState defines the interchain_account genesis state +GenesisState defines the interchain accounts genesis state + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `active_channels` | [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel) | repeated | | +| `interchain_accounts` | [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount) | repeated | | +| `ports` | [string](#string) | repeated | | + + + + + + + + +### RegisteredInterchainAccount +RegisteredInterchainAccount contains a pairing of controller port ID and associated interchain account address | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `port_id` | [string](#string) | | | +| `account_address` | [string](#string) | | | diff --git a/modules/apps/27-interchain-accounts/genesis.go b/modules/apps/27-interchain-accounts/genesis.go index e052834b8a5..dae97a236b7 100644 --- a/modules/apps/27-interchain-accounts/genesis.go +++ b/modules/apps/27-interchain-accounts/genesis.go @@ -12,20 +12,29 @@ import ( // InitGenesis initializes the interchain accounts application state from a provided genesis state func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState) { - if !keeper.IsBound(ctx, state.PortId) { - cap := keeper.BindPort(ctx, state.PortId) - if err := keeper.ClaimCapability(ctx, cap, host.PortPath(state.PortId)); err != nil { - panic(fmt.Sprintf("could not claim port capability: %v", err)) + for _, portID := range state.Ports { + if !keeper.IsBound(ctx, portID) { + cap := keeper.BindPort(ctx, portID) + if err := keeper.ClaimCapability(ctx, cap, host.PortPath(portID)); err != nil { + panic(fmt.Sprintf("could not claim port capability: %v", err)) + } } } -} -// ExportGenesis exports transfer module's portID into its geneis state -func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState { - // TODO: Using a range query with KVStorePrefixIterator export all port IDs - // See https://github.com/cosmos/ibc-go/issues/448 + for _, ch := range state.ActiveChannels { + keeper.SetActiveChannelID(ctx, ch.PortId, ch.ChannelId) + } - return &types.GenesisState{ - PortId: types.PortID, + for _, acc := range state.InterchainAccounts { + keeper.SetInterchainAccountAddress(ctx, acc.PortId, acc.AccountAddress) } } + +// ExportGenesis returns the interchain accounts exported genesis +func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState { + return types.NewGenesisState( + keeper.GetAllPorts(ctx), + keeper.GetAllActiveChannels(ctx), + keeper.GetAllInterchainAccounts(ctx), + ) +} diff --git a/modules/apps/27-interchain-accounts/genesis_test.go b/modules/apps/27-interchain-accounts/genesis_test.go new file mode 100644 index 00000000000..e403bdcadd4 --- /dev/null +++ b/modules/apps/27-interchain-accounts/genesis_test.go @@ -0,0 +1,59 @@ +package interchain_accounts_test + +import ( + ica "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" +) + +func (suite *InterchainAccountsTestSuite) TestInitGenesis() { + var ( + expectedChannelID string = "channel-0" + ) + + suite.SetupTest() + + genesisState := types.GenesisState{ + Ports: []string{types.PortID, TestPortID}, + ActiveChannels: []*types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: expectedChannelID, + }, + }, + InterchainAccounts: []*types.RegisteredInterchainAccount{ + { + PortId: TestPortID, + AccountAddress: TestAccAddress.String(), + }, + }, + } + + ica.InitGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAKeeper, genesisState) + + channelID, found := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannelID(suite.chainA.GetContext(), TestPortID) + suite.Require().True(found) + suite.Require().Equal(expectedChannelID, channelID) + + accountAdrr, found := suite.chainA.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), TestPortID) + suite.Require().True(found) + suite.Require().Equal(TestAccAddress.String(), accountAdrr) +} + +func (suite *InterchainAccountsTestSuite) TestExportGenesis() { + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + genesisState := ica.ExportGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAKeeper) + + suite.Require().Equal([]string{types.PortID, TestPortID}, genesisState.GetPorts()) + + suite.Require().Equal(path.EndpointA.ChannelID, genesisState.ActiveChannels[0].ChannelId) + suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.ActiveChannels[0].PortId) + + suite.Require().Equal(TestAccAddress.String(), genesisState.InterchainAccounts[0].AccountAddress) + suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.InterchainAccounts[0].PortId) +} diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index c730882207d..2886698b26d 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -113,6 +113,27 @@ func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool return string(store.Get(key)), true } +// GetAllActiveChannels returns a list of all active interchain accounts channels and their associated port identifiers +func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []*types.ActiveChannel { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.ActiveChannelKeyPrefix)) + defer iterator.Close() + + var activeChannels []*types.ActiveChannel + for ; iterator.Valid(); iterator.Next() { + keySplit := strings.Split(string(iterator.Key()), "/") + + ch := &types.ActiveChannel{ + PortId: keySplit[1], + ChannelId: string(iterator.Value()), + } + + activeChannels = append(activeChannels, ch) + } + + return activeChannels +} + // SetActiveChannelID stores the active channelID, keyed by the provided portID func (k Keeper) SetActiveChannelID(ctx sdk.Context, portID, channelID string) { store := ctx.KVStore(k.storeKey) @@ -143,6 +164,26 @@ func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (str return string(store.Get(key)), true } +// GetAllInterchainAccounts returns a list of all registered interchain account addresses and their associated controller port identifiers +func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []*types.RegisteredInterchainAccount { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.OwnerKeyPrefix)) + + var interchainAccounts []*types.RegisteredInterchainAccount + for ; iterator.Valid(); iterator.Next() { + keySplit := strings.Split(string(iterator.Key()), "/") + + acc := &types.RegisteredInterchainAccount{ + PortId: keySplit[1], + AccountAddress: string(iterator.Value()), + } + + interchainAccounts = append(interchainAccounts, acc) + } + + return interchainAccounts +} + // SetInterchainAccountAddress stores the InterchainAccount address, keyed by the associated portID func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portID string, address string) { store := ctx.KVStore(k.storeKey) diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index 307451fd14b..92a57e74eec 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -116,9 +116,11 @@ func (suite *KeeperTestSuite) TestGetAllPorts() { err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) + expectedPorts := []string{types.PortID, TestPortID} + ports := suite.chainA.GetSimApp().ICAKeeper.GetAllPorts(suite.chainA.GetContext()) - suite.Require().Contains(ports, types.PortID) - suite.Require().Contains(ports, TestPortID) + suite.Require().Len(ports, len(expectedPorts)) + suite.Require().Equal(expectedPorts, ports) } func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { @@ -141,6 +143,68 @@ func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { suite.Require().Empty(retrievedAddr) } +func (suite *KeeperTestSuite) TestGetAllActiveChannels() { + var ( + expectedChannelID string = "test-channel" + expectedPortID string = "test-port" + ) + + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + suite.chainA.GetSimApp().ICAKeeper.SetActiveChannelID(suite.chainA.GetContext(), expectedPortID, expectedChannelID) + + expectedChannels := []*types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: path.EndpointA.ChannelID, + }, + { + PortId: expectedPortID, + ChannelId: expectedChannelID, + }, + } + + activeChannels := suite.chainA.GetSimApp().ICAKeeper.GetAllActiveChannels(suite.chainA.GetContext()) + suite.Require().Len(activeChannels, len(expectedChannels)) + suite.Require().Equal(expectedChannels, activeChannels) +} + +func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() { + var ( + expectedAccAddr string = "test-acc-addr" + expectedPortID string = "test-port" + ) + + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr) + + expectedAccounts := []*types.RegisteredInterchainAccount{ + { + PortId: TestPortID, + AccountAddress: TestAccAddress.String(), + }, + { + PortId: expectedPortID, + AccountAddress: expectedAccAddr, + }, + } + + interchainAccounts := suite.chainA.GetSimApp().ICAKeeper.GetAllInterchainAccounts(suite.chainA.GetContext()) + suite.Require().Len(interchainAccounts, len(expectedAccounts)) + suite.Require().Equal(expectedAccounts, interchainAccounts) +} + func (suite *KeeperTestSuite) TestIsActiveChannel() { suite.SetupTest() // reset path := NewICAPath(suite.chainA, suite.chainB) @@ -156,12 +220,16 @@ func (suite *KeeperTestSuite) TestIsActiveChannel() { } func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() { - expectedAddr, portID := "address", "port" - suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), portID, expectedAddr) + var ( + expectedAccAddr string = "test-acc-addr" + expectedPortID string = "test-port" + ) + + suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr) - retrievedAddr, found := suite.chainA.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), portID) + retrievedAddr, found := suite.chainA.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID) suite.Require().True(found) - suite.Require().Equal(expectedAddr, retrievedAddr) + suite.Require().Equal(expectedAccAddr, retrievedAddr) } func (suite *KeeperTestSuite) SetupICAPath(path *ibctesting.Path, owner string) error { diff --git a/modules/apps/27-interchain-accounts/types/genesis.go b/modules/apps/27-interchain-accounts/types/genesis.go index e3a9bab7949..f98ce12caa6 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.go +++ b/modules/apps/27-interchain-accounts/types/genesis.go @@ -1,7 +1,18 @@ package types +// DefaultGenesis creates and returns the default interchain accounts GenesisState +// The default GenesisState includes the standard port identifier to which all host chains must bind func DefaultGenesis() *GenesisState { return &GenesisState{ - PortId: PortID, + Ports: []string{PortID}, + } +} + +// NewGenesisState creates a returns a new GenesisState instance +func NewGenesisState(ports []string, channels []*ActiveChannel, accounts []*RegisteredInterchainAccount) *GenesisState { + return &GenesisState{ + ActiveChannels: channels, + InterchainAccounts: accounts, + Ports: ports, } } diff --git a/modules/apps/27-interchain-accounts/types/genesis.pb.go b/modules/apps/27-interchain-accounts/types/genesis.pb.go index 44661c274c4..32d38337ac1 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.pb.go +++ b/modules/apps/27-interchain-accounts/types/genesis.pb.go @@ -23,9 +23,11 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// GenesisState defines the interchain_account genesis state +// GenesisState defines the interchain accounts genesis state type GenesisState struct { - PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + ActiveChannels []*ActiveChannel `protobuf:"bytes,1,rep,name=active_channels,json=activeChannels,proto3" json:"active_channels,omitempty" yaml:"active_channels"` + InterchainAccounts []*RegisteredInterchainAccount `protobuf:"bytes,2,rep,name=interchain_accounts,json=interchainAccounts,proto3" json:"interchain_accounts,omitempty" yaml:"interchain_accounts"` + Ports []string `protobuf:"bytes,3,rep,name=ports,proto3" json:"ports,omitempty"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -61,15 +63,137 @@ func (m *GenesisState) XXX_DiscardUnknown() { var xxx_messageInfo_GenesisState proto.InternalMessageInfo -func (m *GenesisState) GetPortId() string { +func (m *GenesisState) GetActiveChannels() []*ActiveChannel { + if m != nil { + return m.ActiveChannels + } + return nil +} + +func (m *GenesisState) GetInterchainAccounts() []*RegisteredInterchainAccount { + if m != nil { + return m.InterchainAccounts + } + return nil +} + +func (m *GenesisState) GetPorts() []string { + if m != nil { + return m.Ports + } + return nil +} + +// ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel +type ActiveChannel struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` +} + +func (m *ActiveChannel) Reset() { *m = ActiveChannel{} } +func (m *ActiveChannel) String() string { return proto.CompactTextString(m) } +func (*ActiveChannel) ProtoMessage() {} +func (*ActiveChannel) Descriptor() ([]byte, []int) { + return fileDescriptor_629b3ced0911516b, []int{1} +} +func (m *ActiveChannel) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ActiveChannel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ActiveChannel.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ActiveChannel) XXX_Merge(src proto.Message) { + xxx_messageInfo_ActiveChannel.Merge(m, src) +} +func (m *ActiveChannel) XXX_Size() int { + return m.Size() +} +func (m *ActiveChannel) XXX_DiscardUnknown() { + xxx_messageInfo_ActiveChannel.DiscardUnknown(m) +} + +var xxx_messageInfo_ActiveChannel proto.InternalMessageInfo + +func (m *ActiveChannel) GetPortId() string { if m != nil { return m.PortId } return "" } +func (m *ActiveChannel) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +// RegisteredInterchainAccount contains a pairing of controller port ID and associated interchain account address +type RegisteredInterchainAccount struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + AccountAddress string `protobuf:"bytes,2,opt,name=account_address,json=accountAddress,proto3" json:"account_address,omitempty" yaml:"account_address"` +} + +func (m *RegisteredInterchainAccount) Reset() { *m = RegisteredInterchainAccount{} } +func (m *RegisteredInterchainAccount) String() string { return proto.CompactTextString(m) } +func (*RegisteredInterchainAccount) ProtoMessage() {} +func (*RegisteredInterchainAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_629b3ced0911516b, []int{2} +} +func (m *RegisteredInterchainAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RegisteredInterchainAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RegisteredInterchainAccount.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RegisteredInterchainAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_RegisteredInterchainAccount.Merge(m, src) +} +func (m *RegisteredInterchainAccount) XXX_Size() int { + return m.Size() +} +func (m *RegisteredInterchainAccount) XXX_DiscardUnknown() { + xxx_messageInfo_RegisteredInterchainAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_RegisteredInterchainAccount proto.InternalMessageInfo + +func (m *RegisteredInterchainAccount) GetPortId() string { + if m != nil { + return m.PortId + } + return "" +} + +func (m *RegisteredInterchainAccount) GetAccountAddress() string { + if m != nil { + return m.AccountAddress + } + return "" +} + func init() { proto.RegisterType((*GenesisState)(nil), "ibc.applications.interchain_accounts.v1.GenesisState") + proto.RegisterType((*ActiveChannel)(nil), "ibc.applications.interchain_accounts.v1.ActiveChannel") + proto.RegisterType((*RegisteredInterchainAccount)(nil), "ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount") } func init() { @@ -77,23 +201,34 @@ func init() { } var fileDescriptor_629b3ced0911516b = []byte{ - // 244 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0xcd, 0x4c, 0x4a, 0xd6, - 0x4f, 0x2c, 0x28, 0xc8, 0xc9, 0x4c, 0x4e, 0x2c, 0xc9, 0xcc, 0xcf, 0x2b, 0xd6, 0xcf, 0xcc, 0x2b, - 0x49, 0x2d, 0x4a, 0xce, 0x48, 0xcc, 0xcc, 0x8b, 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0x29, - 0xd6, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, - 0xc9, 0x17, 0x52, 0xcf, 0x4c, 0x4a, 0xd6, 0x43, 0xd6, 0xa6, 0x87, 0x45, 0x9b, 0x5e, 0x99, 0xa1, - 0x94, 0x48, 0x7a, 0x7e, 0x7a, 0x3e, 0x58, 0x8f, 0x3e, 0x88, 0x05, 0xd1, 0xae, 0x64, 0xcd, 0xc5, - 0xe3, 0x0e, 0x31, 0x2f, 0xb8, 0x24, 0xb1, 0x24, 0x55, 0x48, 0x9b, 0x8b, 0xbd, 0x20, 0xbf, 0xa8, - 0x24, 0x3e, 0x33, 0x45, 0x82, 0x51, 0x81, 0x51, 0x83, 0xd3, 0x49, 0xe8, 0xd3, 0x3d, 0x79, 0xbe, - 0xca, 0xc4, 0xdc, 0x1c, 0x2b, 0x25, 0xa8, 0x84, 0x52, 0x10, 0x1b, 0x88, 0xe5, 0x99, 0xe2, 0x14, - 0x7f, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, - 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0xae, 0xe9, 0x99, 0x25, 0x19, - 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0x99, 0x49, - 0xc9, 0xba, 0xe9, 0xf9, 0xfa, 0x65, 0x46, 0xfa, 0xb9, 0xf9, 0x29, 0xa5, 0x39, 0xa9, 0xc5, 0x20, - 0xcf, 0x16, 0xeb, 0x1b, 0x99, 0xeb, 0x22, 0x1c, 0xac, 0x0b, 0xf7, 0x67, 0x49, 0x65, 0x41, 0x6a, - 0x71, 0x12, 0x1b, 0xd8, 0x91, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0xe5, 0x36, 0xd4, - 0x1c, 0x01, 0x00, 0x00, + // 426 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0x4f, 0x8b, 0x13, 0x31, + 0x18, 0xc6, 0x9b, 0x16, 0x57, 0x1a, 0x75, 0xc5, 0xb8, 0x4a, 0xa9, 0x30, 0x2d, 0xb9, 0x58, 0x90, + 0x4e, 0xd8, 0xfa, 0x0f, 0xbc, 0xb5, 0xab, 0x48, 0xaf, 0xe3, 0xcd, 0xcb, 0x90, 0xc9, 0x84, 0x69, + 0xa0, 0x33, 0x19, 0xe6, 0x4d, 0x07, 0x16, 0x3f, 0x84, 0x5e, 0xfc, 0x30, 0x7e, 0x03, 0x8f, 0x7b, + 0xf4, 0x34, 0x48, 0xfb, 0x0d, 0xe6, 0x13, 0xc8, 0x24, 0xc3, 0xee, 0x76, 0x29, 0xb2, 0x7b, 0x4b, + 0xf2, 0x3c, 0xbf, 0x37, 0x4f, 0xf2, 0xbe, 0xf8, 0xad, 0x8a, 0x04, 0xe3, 0x79, 0xbe, 0x56, 0x82, + 0x1b, 0xa5, 0x33, 0x60, 0x2a, 0x33, 0xb2, 0x10, 0x2b, 0xae, 0xb2, 0x90, 0x0b, 0xa1, 0x37, 0x99, + 0x01, 0x56, 0x9e, 0xb2, 0x44, 0x66, 0x12, 0x14, 0xf8, 0x79, 0xa1, 0x8d, 0x26, 0x2f, 0x55, 0x24, + 0xfc, 0xeb, 0x98, 0x7f, 0x00, 0xf3, 0xcb, 0xd3, 0xe1, 0x49, 0xa2, 0x13, 0x6d, 0x19, 0xd6, 0xac, + 0x1c, 0x4e, 0x7f, 0x75, 0xf1, 0xc3, 0xcf, 0xae, 0xe0, 0x17, 0xc3, 0x8d, 0x24, 0xdf, 0xf0, 0x63, + 0x2e, 0x8c, 0x2a, 0x65, 0x28, 0x56, 0x3c, 0xcb, 0xe4, 0x1a, 0x06, 0x68, 0xdc, 0x9b, 0x3c, 0x98, + 0xbd, 0xf3, 0x6f, 0x79, 0x93, 0x3f, 0xb7, 0xfc, 0x99, 0xc3, 0x17, 0xc3, 0xba, 0x1a, 0x3d, 0x3f, + 0xe7, 0xe9, 0xfa, 0x03, 0xbd, 0x51, 0x98, 0x06, 0xc7, 0xfc, 0xba, 0x15, 0xc8, 0x4f, 0x84, 0x9f, + 0x1e, 0x28, 0x3a, 0xe8, 0xda, 0x04, 0x1f, 0x6f, 0x9d, 0x20, 0x90, 0x89, 0x02, 0x23, 0x0b, 0x19, + 0x2f, 0x2f, 0x0d, 0x73, 0xa7, 0x2f, 0xbc, 0xba, 0x1a, 0x0d, 0x5d, 0x9e, 0x03, 0x34, 0x0d, 0x88, + 0xba, 0x89, 0x00, 0x39, 0xc1, 0xf7, 0x72, 0x5d, 0x18, 0x18, 0xf4, 0xc6, 0xbd, 0x49, 0x3f, 0x70, + 0x1b, 0x5a, 0xe0, 0x47, 0x7b, 0x4f, 0x25, 0xaf, 0xf0, 0xfd, 0x46, 0x09, 0x55, 0x3c, 0x40, 0x63, + 0x34, 0xe9, 0x2f, 0x48, 0x5d, 0x8d, 0x8e, 0xdd, 0x5d, 0xad, 0x40, 0x83, 0xa3, 0x66, 0xb5, 0x8c, + 0xc9, 0x1b, 0x8c, 0xdb, 0x8f, 0x68, 0xfc, 0x5d, 0xeb, 0x7f, 0x56, 0x57, 0xa3, 0x27, 0xce, 0x7f, + 0xa5, 0xd1, 0xa0, 0xdf, 0x6e, 0x96, 0x31, 0xfd, 0x8e, 0xf0, 0x8b, 0xff, 0xbc, 0xee, 0x6e, 0x11, + 0xce, 0x9a, 0x5e, 0x5b, 0x2e, 0xe4, 0x71, 0x5c, 0x48, 0x80, 0x36, 0xc7, 0x5e, 0xcf, 0xf6, 0x0c, + 0xb6, 0x67, 0xf6, 0x64, 0xee, 0x0e, 0x16, 0xe1, 0xef, 0xad, 0x87, 0x2e, 0xb6, 0x1e, 0xfa, 0xbb, + 0xf5, 0xd0, 0x8f, 0x9d, 0xd7, 0xb9, 0xd8, 0x79, 0x9d, 0x3f, 0x3b, 0xaf, 0xf3, 0xf5, 0x53, 0xa2, + 0xcc, 0x6a, 0x13, 0xf9, 0x42, 0xa7, 0x4c, 0x68, 0x48, 0x35, 0x30, 0x15, 0x89, 0x69, 0xa2, 0x59, + 0x39, 0x63, 0xa9, 0x8e, 0x37, 0x6b, 0x09, 0xcd, 0xc4, 0x03, 0x9b, 0xbd, 0x9f, 0x5e, 0xfd, 0xfa, + 0xf4, 0x72, 0xd8, 0xcd, 0x79, 0x2e, 0x21, 0x3a, 0xb2, 0x93, 0xfa, 0xfa, 0x5f, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xc5, 0x32, 0x06, 0x92, 0x21, 0x03, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -116,6 +251,110 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Ports) > 0 { + for iNdEx := len(m.Ports) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Ports[iNdEx]) + copy(dAtA[i:], m.Ports[iNdEx]) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Ports[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.InterchainAccounts) > 0 { + for iNdEx := len(m.InterchainAccounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.InterchainAccounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.ActiveChannels) > 0 { + for iNdEx := len(m.ActiveChannels) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ActiveChannels[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ActiveChannel) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ActiveChannel) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ActiveChannel) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RegisteredInterchainAccount) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RegisteredInterchainAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RegisteredInterchainAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AccountAddress) > 0 { + i -= len(m.AccountAddress) + copy(dAtA[i:], m.AccountAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.AccountAddress))) + i-- + dAtA[i] = 0x12 + } if len(m.PortId) > 0 { i -= len(m.PortId) copy(dAtA[i:], m.PortId) @@ -138,6 +377,33 @@ func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { return base } func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ActiveChannels) > 0 { + for _, e := range m.ActiveChannels { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.InterchainAccounts) > 0 { + for _, e := range m.InterchainAccounts { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.Ports) > 0 { + for _, s := range m.Ports { + l = len(s) + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *ActiveChannel) Size() (n int) { if m == nil { return 0 } @@ -147,6 +413,27 @@ func (m *GenesisState) Size() (n int) { if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *RegisteredInterchainAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.AccountAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } return n } @@ -185,6 +472,270 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ActiveChannels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ActiveChannels = append(m.ActiveChannels, &ActiveChannel{}) + if err := m.ActiveChannels[len(m.ActiveChannels)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InterchainAccounts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InterchainAccounts = append(m.InterchainAccounts, &RegisteredInterchainAccount{}) + if err := m.InterchainAccounts[len(m.InterchainAccounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ports", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Ports = append(m.Ports, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ActiveChannel) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ActiveChannel: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ActiveChannel: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RegisteredInterchainAccount) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RegisteredInterchainAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RegisteredInterchainAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) @@ -217,6 +768,38 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } m.PortId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AccountAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AccountAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/proto/ibc/applications/interchain_accounts/v1/account.proto b/proto/ibc/applications/interchain_accounts/v1/account.proto index a94519cd6ac..b7af89b502b 100644 --- a/proto/ibc/applications/interchain_accounts/v1/account.proto +++ b/proto/ibc/applications/interchain_accounts/v1/account.proto @@ -1,12 +1,13 @@ syntax = "proto3"; + package ibc.applications.interchain_accounts.v1; +option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; + import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; import "cosmos/auth/v1beta1/auth.proto"; -option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; - // An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain message InterchainAccount { option (gogoproto.goproto_getters) = false; diff --git a/proto/ibc/applications/interchain_accounts/v1/genesis.proto b/proto/ibc/applications/interchain_accounts/v1/genesis.proto index 001eeb00a6c..5645e726a3d 100644 --- a/proto/ibc/applications/interchain_accounts/v1/genesis.proto +++ b/proto/ibc/applications/interchain_accounts/v1/genesis.proto @@ -1,11 +1,26 @@ syntax = "proto3"; + package ibc.applications.interchain_accounts.v1; option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; import "gogoproto/gogo.proto"; -// GenesisState defines the interchain_account genesis state +// GenesisState defines the interchain accounts genesis state message GenesisState { - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + repeated ActiveChannel active_channels = 1 [(gogoproto.moretags) = "yaml:\"active_channels\""]; + repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.moretags) = "yaml:\"interchain_accounts\""]; + repeated string ports = 3; +} + +// ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel +message ActiveChannel { + string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; +} + +// RegisteredInterchainAccount contains a pairing of controller port ID and associated interchain account address +message RegisteredInterchainAccount { + string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string account_address = 2 [(gogoproto.moretags) = "yaml:\"account_address\""]; } diff --git a/proto/ibc/applications/interchain_accounts/v1/query.proto b/proto/ibc/applications/interchain_accounts/v1/query.proto index 160912b0610..a3b77506794 100644 --- a/proto/ibc/applications/interchain_accounts/v1/query.proto +++ b/proto/ibc/applications/interchain_accounts/v1/query.proto @@ -1,12 +1,13 @@ syntax = "proto3"; + package ibc.applications.interchain_accounts.v1; +option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; + import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; import "ibc/applications/interchain_accounts/v1/account.proto"; -option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; - // Query defines the gRPC querier service. service Query { // Query to get the address of an interchain account diff --git a/proto/ibc/applications/interchain_accounts/v1/types.proto b/proto/ibc/applications/interchain_accounts/v1/types.proto index fe19488d986..c6d9d0a3e96 100644 --- a/proto/ibc/applications/interchain_accounts/v1/types.proto +++ b/proto/ibc/applications/interchain_accounts/v1/types.proto @@ -1,9 +1,11 @@ syntax = "proto3"; + package ibc.applications.interchain_accounts.v1; +option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; + import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; -option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; // Type defines a classification of message issued from a controller chain to its associated interchain accounts // host From b8bc1a8c2a61290e679a6920eabf578d013fc296 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Fri, 12 Nov 2021 13:45:45 +0100 Subject: [PATCH 51/66] test: relay tests for TrySendTx/OnRecvPacket (#531) * adding various sdk.Msg type tests and cleaning up relay_test.go * cleaning up tests to make consistent * adding missing godoc for OnRecvPacket * adding ica test for transfertypes.MsgTranfer * updating hardcoded strings to use sdk.DefaultBondDenom * Update modules/apps/27-interchain-accounts/keeper/relay_test.go Co-authored-by: Sean King * removing staking test for insufficient funds Co-authored-by: Sean King --- .../27-interchain-accounts/keeper/relay.go | 1 + .../keeper/relay_test.go | 500 ++++++++++++++---- 2 files changed, 398 insertions(+), 103 deletions(-) diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 681433e03ee..9b5eec6e2d8 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -125,6 +125,7 @@ func (k Keeper) executeMsg(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { return handler(ctx, msg) } +// OnRecvPacket handles a given interchain accounts packet on a destination host chain func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error { var data types.InterchainAccountPacketData diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index bcc1ebccf27..e7741a8903c 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -1,13 +1,18 @@ package keeper_test import ( - "fmt" + "time" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + transfertypes "github.com/cosmos/ibc-go/v2/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" @@ -16,95 +21,127 @@ import ( func (suite *KeeperTestSuite) TestTrySendTx() { var ( - path *ibctesting.Path - icaPacketData types.InterchainAccountPacketData - portID string - chanCap *capabilitytypes.Capability + path *ibctesting.Path + packetData types.InterchainAccountPacketData + chanCap *capabilitytypes.Capability ) testCases := []struct { - name string + msg string malleate func() expPass bool }{ { - "success", func() { - }, true, + "success", + func() { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + msg := &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + } + + data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg}) + suite.Require().NoError(err) + + packetData = types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + }, + true, }, { - "success with multiple sdk.Msg", func() { - amount, _ := sdk.ParseCoinsNormalized("100stake") - interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) - msg1 := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} - msg2 := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} - data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg1, msg2}) + "success with multiple sdk.Msg", + func() { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + msgsBankSend := []sdk.Msg{ + &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + }, + &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + }, + } + + data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), msgsBankSend) suite.Require().NoError(err) - icaPacketData.Data = data - }, true, + + packetData = types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + }, + true, }, { - "data is nil", func() { - icaPacketData.Data = nil - }, false, + "data is nil", + func() { + packetData = types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: nil, + } + }, + false, }, { - "active channel not found", func() { - portID = "incorrect portID" - }, false, + "active channel not found", + func() { + path.EndpointA.ChannelConfig.PortID = "invalid-port-id" + }, + false, }, { - "channel does not exist", func() { - suite.chainA.GetSimApp().ICAKeeper.SetActiveChannelID(suite.chainA.GetContext(), portID, "channel-100") - }, false, + "channel does not exist", + func() { + suite.chainA.GetSimApp().ICAKeeper.SetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, "channel-100") + }, + false, }, { - "SendPacket fails - channel closed", func() { + "sendPacket fails - channel closed", + func() { err := path.EndpointA.SetChannelClosed() suite.Require().NoError(err) - }, false, + }, + false, }, { - "invalid channel capability provided", func() { + "invalid channel capability provided", + func() { chanCap = nil - }, false, + }, + false, }, } for _, tc := range testCases { tc := tc - suite.Run(tc.name, func() { + suite.Run(tc.msg, func() { suite.SetupTest() // reset + path = NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) err := suite.SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - // default setup - portID = path.EndpointA.ChannelConfig.PortID - - amount, _ := sdk.ParseCoinsNormalized("100stake") - interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) - - msg := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} - data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg}) - suite.Require().NoError(err) - - // default packet data, must be modified in malleate for test cases expected to fail - icaPacketData = types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: data, - Memo: "memo", - } - var ok bool - chanCap, ok = suite.chainA.GetSimApp().ScopedICAMockKeeper.GetCapability(path.EndpointA.Chain.GetContext(), host.ChannelCapabilityPath(portID, path.EndpointA.ChannelID)) + chanCap, ok = suite.chainA.GetSimApp().ScopedICAMockKeeper.GetCapability(path.EndpointA.Chain.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) suite.Require().True(ok) - tc.malleate() + tc.malleate() // malleate mutates test data - _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), chanCap, portID, icaPacketData) + _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), chanCap, path.EndpointA.ChannelConfig.PortID, packetData) if tc.expPass { suite.Require().NoError(err) @@ -118,9 +155,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() { func (suite *KeeperTestSuite) TestOnRecvPacket() { var ( path *ibctesting.Path - msg sdk.Msg packetData []byte - sourcePort string ) testCases := []struct { @@ -129,105 +164,336 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { expPass bool }{ { - "Interchain account successfully executes banktypes.MsgSend", func() { - // build MsgSend - amount, _ := sdk.ParseCoinsNormalized("100stake") - interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) - msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} - // build packet data - data, err := types.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) + "interchain account successfully executes banktypes.MsgSend", + func() { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + msg := &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + } + + data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) icaPacketData := types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: data, } + packetData = icaPacketData.GetBytes() - }, true, + }, + true, }, { - "Cannot deserialize packet data messages", func() { - data := []byte("invalid packet data") + "interchain account successfully executes stakingtypes.MsgDelegate", + func() { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) + msg := &stakingtypes.MsgDelegate{ + DelegatorAddress: interchainAccountAddr, + ValidatorAddress: validatorAddr.String(), + Amount: sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(5000)), + } + + data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + suite.Require().NoError(err) icaPacketData := types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: data, } + packetData = icaPacketData.GetBytes() - }, false, + }, + true, }, { - "Invalid packet type", func() { - // build packet data - data, err := types.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{&banktypes.MsgSend{}}) + "interchain account successfully executes stakingtypes.MsgDelegate and stakingtypes.MsgUndelegate sequentially", + func() { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) + msgDelegate := &stakingtypes.MsgDelegate{ + DelegatorAddress: interchainAccountAddr, + ValidatorAddress: validatorAddr.String(), + Amount: sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(5000)), + } + + msgUndelegate := &stakingtypes.MsgUndelegate{ + DelegatorAddress: interchainAccountAddr, + ValidatorAddress: validatorAddr.String(), + Amount: sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(5000)), + } + + data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msgDelegate, msgUndelegate}) suite.Require().NoError(err) - // Type here is an ENUM - // Valid type is types.EXECUTE_TX icaPacketData := types.InterchainAccountPacketData{ - Type: 100, + Type: types.EXECUTE_TX, Data: data, } + packetData = icaPacketData.GetBytes() - }, false, + }, + true, }, { - "Cannot unmarshal interchain account packet data into types.InterchainAccountPacketData", func() { + "interchain account successfully executes govtypes.MsgSubmitProposal", + func() { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + testProposal := &govtypes.TextProposal{ + Title: "IBC Gov Proposal", + Description: "tokens for all!", + } + + any, err := codectypes.NewAnyWithValue(testProposal) + suite.Require().NoError(err) + + msg := &govtypes.MsgSubmitProposal{ + Content: any, + InitialDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(5000))), + Proposer: interchainAccountAddr, + } + + data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + suite.Require().NoError(err) + + icaPacketData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + + packetData = icaPacketData.GetBytes() + }, + true, + }, + { + "interchain account successfully executes govtypes.MsgVote", + func() { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + // Populate the gov keeper in advance with an active proposal + testProposal := &govtypes.TextProposal{ + Title: "IBC Gov Proposal", + Description: "tokens for all!", + } + + proposal, err := govtypes.NewProposal(testProposal, govtypes.DefaultStartingProposalID, time.Now(), time.Now().Add(time.Hour)) + suite.Require().NoError(err) + + suite.chainB.GetSimApp().GovKeeper.SetProposal(suite.chainB.GetContext(), proposal) + suite.chainB.GetSimApp().GovKeeper.ActivateVotingPeriod(suite.chainB.GetContext(), proposal) + + msg := &govtypes.MsgVote{ + ProposalId: govtypes.DefaultStartingProposalID, + Voter: interchainAccountAddr, + Option: govtypes.OptionYes, + } + + data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + suite.Require().NoError(err) + + icaPacketData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + + packetData = icaPacketData.GetBytes() + }, + true, + }, + { + "interchain account successfully executes disttypes.MsgFundCommunityPool", + func() { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + msg := &disttypes.MsgFundCommunityPool{ + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(5000))), + Depositor: interchainAccountAddr, + } + + data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + suite.Require().NoError(err) + + icaPacketData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + + packetData = icaPacketData.GetBytes() + }, + true, + }, + { + "interchain account successfully executes disttypes.MsgSetWithdrawAddress", + func() { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + msg := &disttypes.MsgSetWithdrawAddress{ + DelegatorAddress: interchainAccountAddr, + WithdrawAddress: suite.chainB.SenderAccount.GetAddress().String(), + } + + data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + suite.Require().NoError(err) + + icaPacketData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + + packetData = icaPacketData.GetBytes() + }, + true, + }, + { + "interchain account successfully executes transfertypes.MsgTransfer", + func() { + transferPath := ibctesting.NewPath(suite.chainB, suite.chainC) + transferPath.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort + transferPath.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort + + suite.coordinator.Setup(transferPath) + + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + msg := &transfertypes.MsgTransfer{ + SourcePort: transferPath.EndpointA.ChannelConfig.PortID, + SourceChannel: transferPath.EndpointA.ChannelID, + Token: sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), + Sender: interchainAccountAddr, + Receiver: suite.chainA.SenderAccount.GetAddress().String(), + TimeoutHeight: clienttypes.NewHeight(0, 100), + TimeoutTimestamp: uint64(0), + } + + data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + suite.Require().NoError(err) + + icaPacketData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + + packetData = icaPacketData.GetBytes() + }, + true, + }, + { + "cannot unmarshal interchain account packet data", + func() { packetData = []byte{} - }, false, + }, + false, + }, + { + "cannot deserialize interchain account packet data messages", + func() { + data := []byte("invalid packet data") + + icaPacketData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + + packetData = icaPacketData.GetBytes() + }, + false, }, { - "Unauthorised: Interchain account not found for given source portID", func() { - sourcePort = "invalid-port-id" - }, false, + "invalid packet type - UNSPECIFIED", + func() { + data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{&banktypes.MsgSend{}}) + suite.Require().NoError(err) + + icaPacketData := types.InterchainAccountPacketData{ + Type: types.UNSPECIFIED, + Data: data, + } + + packetData = icaPacketData.GetBytes() + }, + false, + }, + { + "unauthorised: interchain account not found for controller port ID", + func() { + path.EndpointA.ChannelConfig.PortID = "invalid-port-id" + + data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{&banktypes.MsgSend{}}) + suite.Require().NoError(err) + + icaPacketData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + + packetData = icaPacketData.GetBytes() + }, + false, }, { - "Unauthorised: Signer of message is not the interchain account associated with sourcePortID", func() { - // build MsgSend - amount, _ := sdk.ParseCoinsNormalized("100stake") - // Incorrect FromAddress - msg = &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} - // build packet data - data, err := types.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) + "unauthorised: signer address is not the interchain account associated with the controller portID", + func() { + msg := &banktypes.MsgSend{ + FromAddress: suite.chainB.SenderAccount.GetAddress().String(), // unexpected signer + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + } + + data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) + icaPacketData := types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: data, } + packetData = icaPacketData.GetBytes() - }, false, + }, + false, }, } for _, tc := range testCases { tc := tc - suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.Run(tc.msg, func() { suite.SetupTest() // reset path = NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) - err := suite.SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - // send 100stake to interchain account wallet - amount, _ := sdk.ParseCoinsNormalized("100stake") - interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) - bankMsg := &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: interchainAccountAddr, Amount: amount} - - _, err = suite.chainB.SendMsgs(bankMsg) + err := suite.SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - // valid source port - sourcePort = path.EndpointA.ChannelConfig.PortID + suite.fundICAWallet(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10000)))) - // malleate packetData for test cases - tc.malleate() + tc.malleate() // malleate mutates test data - seq := uint64(1) - packet := channeltypes.NewPacket(packetData, seq, sourcePort, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) + packet := channeltypes.NewPacket( + packetData, + suite.chainA.SenderAccount.GetSequence(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) - // Pass it in here err = suite.chainB.GetSimApp().ICAKeeper.OnRecvPacket(suite.chainB.GetContext(), packet) if tc.expPass { @@ -245,18 +511,21 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { ) testCases := []struct { - name string + msg string malleate func() expPass bool }{ { - "success", func() {}, true, + "success", + func() {}, + true, }, } for _, tc := range testCases { - suite.Run(tc.name, func() { + suite.Run(tc.msg, func() { suite.SetupTest() // reset + path = NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) @@ -265,7 +534,17 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { tc.malleate() // malleate mutates test data - packet := channeltypes.NewPacket([]byte{}, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) + packet := channeltypes.NewPacket( + []byte{}, + 1, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + err = suite.chainA.GetSimApp().ICAKeeper.OnTimeoutPacket(suite.chainA.GetContext(), packet) activeChannelID, found := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) @@ -280,3 +559,18 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { }) } } + +func (suite *KeeperTestSuite) fundICAWallet(ctx sdk.Context, portID string, amount sdk.Coins) { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(ctx, portID) + suite.Require().True(found) + + msgBankSend := &banktypes.MsgSend{ + FromAddress: suite.chainB.SenderAccount.GetAddress().String(), + ToAddress: interchainAccountAddr, + Amount: amount, + } + + res, err := suite.chainB.SendMsgs(msgBankSend) + suite.Require().NotEmpty(res) + suite.Require().NoError(err) +} From 7efc38404c871a21ebb1bbe6ddb0f65e34bc32a3 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 18 Nov 2021 12:10:47 +0100 Subject: [PATCH 52/66] ICA controller/host submodules (#541) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * go mod tidy * creating new genesis types for controller and host submodules * removing dead root module code * updating genesis helpers and adding newly generated types * adding interchain-accounts controller submodule * adding interchain-accounts host submodule * updating simapp to include controller and host ica submodules * adding errors returns for disallowed handshake directions, removing embedded app from host module, updating simapp to conform * updating simapp to remove nil arg to ica host ibc module * removing ics4Wrapper arg from ica host submodule * cleaning up module.go for controller and host submodules * removing commented out tests * commit with broken tests to rebase * disabling app version negotation on controller submodule * fixing tests - now passing * various cleanup, godocs and moving code * updating error msgs to conform to pkg split * removing commented out code * adding combined ica genesis, consolidating to single ica AppModule, updating app.go * adding missing godocs * clean up, godocs, rename validate.go -> version.go, move version related funcs * updating godocs and code organization * removing controller module acc, using icatypes module name for module acc in host submodule * correcting panic error msg * Update modules/apps/27-interchain-accounts/controller/ibc_module.go * Update modules/apps/27-interchain-accounts/types/genesis.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * updating logger kvs, and simplifying OnRecvPacket * address nits on error strings and godocs Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- docs/ibc/proto-docs.md | 69 +- go.mod | 2 - .../client/cli/query.go | 52 -- .../{ => controller}/ibc_module.go | 54 +- .../controller/ibc_module_test.go | 255 ++++++++ .../{ => controller/keeper}/genesis.go | 15 +- .../{ => controller/keeper}/genesis_test.go | 34 +- .../controller/keeper/handshake.go | 133 ++++ .../controller/keeper/handshake_test.go | 258 ++++++++ .../controller/keeper/keeper.go | 215 ++++++ .../controller/keeper/keeper_test.go | 314 +++++++++ .../{ => controller}/keeper/relay.go | 80 --- .../controller/keeper/relay_test.go | 201 ++++++ .../controller/types/keys.go | 9 + .../27-interchain-accounts/host/ibc_module.go | 138 ++++ .../{ => host}/ibc_module_test.go | 165 +---- .../host/keeper/genesis.go | 37 ++ .../host/keeper/genesis_test.go | 57 ++ .../{ => host}/keeper/handshake.go | 83 --- .../host/keeper/handshake_test.go | 268 ++++++++ .../{ => host}/keeper/keeper.go | 33 +- .../{ => host}/keeper/keeper_test.go | 76 +-- .../host/keeper/relay.go | 89 +++ .../{ => host}/keeper/relay_test.go | 212 +----- .../27-interchain-accounts/host/types/keys.go | 9 + .../27-interchain-accounts/keeper/account.go | 58 -- .../keeper/account_test.go | 69 -- .../keeper/grpc_query.go | 34 - .../keeper/grpc_query_test.go | 80 --- .../keeper/handshake_test.go | 465 ------------- modules/apps/27-interchain-accounts/module.go | 91 ++- .../27-interchain-accounts/types/account.go | 79 +-- .../types/account_test.go | 74 --- .../27-interchain-accounts/types/codec.go | 5 + .../27-interchain-accounts/types/errors.go | 2 +- .../27-interchain-accounts/types/genesis.go | 39 +- .../types/genesis.pb.go | 614 +++++++++++++++++- .../apps/27-interchain-accounts/types/keys.go | 57 -- .../27-interchain-accounts/types/keys_test.go | 131 ---- .../27-interchain-accounts/types/packet.go | 1 + .../apps/27-interchain-accounts/types/port.go | 78 +++ .../27-interchain-accounts/types/port_test.go | 169 +++++ .../27-interchain-accounts/types/query.pb.go | 584 ----------------- .../types/{validate.go => version.go} | 16 + .../{validate_test.go => version_test.go} | 45 ++ .../interchain_accounts/v1/genesis.proto | 13 + .../interchain_accounts/v1/query.proto | 30 - testing/simapp/app.go | 88 ++- 48 files changed, 3205 insertions(+), 2475 deletions(-) delete mode 100644 modules/apps/27-interchain-accounts/client/cli/query.go rename modules/apps/27-interchain-accounts/{ => controller}/ibc_module.go (76%) create mode 100644 modules/apps/27-interchain-accounts/controller/ibc_module_test.go rename modules/apps/27-interchain-accounts/{ => controller/keeper}/genesis.go (63%) rename modules/apps/27-interchain-accounts/{ => controller/keeper}/genesis_test.go (51%) create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/handshake.go create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/keeper.go create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go rename modules/apps/27-interchain-accounts/{ => controller}/keeper/relay.go (54%) create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/relay_test.go create mode 100644 modules/apps/27-interchain-accounts/controller/types/keys.go create mode 100644 modules/apps/27-interchain-accounts/host/ibc_module.go rename modules/apps/27-interchain-accounts/{ => host}/ibc_module_test.go (69%) create mode 100644 modules/apps/27-interchain-accounts/host/keeper/genesis.go create mode 100644 modules/apps/27-interchain-accounts/host/keeper/genesis_test.go rename modules/apps/27-interchain-accounts/{ => host}/keeper/handshake.go (65%) create mode 100644 modules/apps/27-interchain-accounts/host/keeper/handshake_test.go rename modules/apps/27-interchain-accounts/{ => host}/keeper/keeper.go (84%) rename modules/apps/27-interchain-accounts/{ => host}/keeper/keeper_test.go (73%) create mode 100644 modules/apps/27-interchain-accounts/host/keeper/relay.go rename modules/apps/27-interchain-accounts/{ => host}/keeper/relay_test.go (65%) create mode 100644 modules/apps/27-interchain-accounts/host/types/keys.go delete mode 100644 modules/apps/27-interchain-accounts/keeper/account.go delete mode 100644 modules/apps/27-interchain-accounts/keeper/account_test.go delete mode 100644 modules/apps/27-interchain-accounts/keeper/grpc_query.go delete mode 100644 modules/apps/27-interchain-accounts/keeper/grpc_query_test.go delete mode 100644 modules/apps/27-interchain-accounts/keeper/handshake_test.go create mode 100644 modules/apps/27-interchain-accounts/types/port.go create mode 100644 modules/apps/27-interchain-accounts/types/port_test.go delete mode 100644 modules/apps/27-interchain-accounts/types/query.pb.go rename modules/apps/27-interchain-accounts/types/{validate.go => version.go} (72%) rename modules/apps/27-interchain-accounts/types/{validate_test.go => version_test.go} (60%) delete mode 100644 proto/ibc/applications/interchain_accounts/v1/query.proto diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 8deda5b71e8..da269933b46 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -9,15 +9,11 @@ - [ibc/applications/interchain_accounts/v1/genesis.proto](#ibc/applications/interchain_accounts/v1/genesis.proto) - [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel) + - [ControllerGenesisState](#ibc.applications.interchain_accounts.v1.ControllerGenesisState) - [GenesisState](#ibc.applications.interchain_accounts.v1.GenesisState) + - [HostGenesisState](#ibc.applications.interchain_accounts.v1.HostGenesisState) - [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount) -- [ibc/applications/interchain_accounts/v1/query.proto](#ibc/applications/interchain_accounts/v1/query.proto) - - [QueryInterchainAccountAddressRequest](#ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressRequest) - - [QueryInterchainAccountAddressResponse](#ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressResponse) - - - [Query](#ibc.applications.interchain_accounts.v1.Query) - - [ibc/applications/interchain_accounts/v1/types.proto](#ibc/applications/interchain_accounts/v1/types.proto) - [CosmosTx](#ibc.applications.interchain_accounts.v1.CosmosTx) - [InterchainAccountPacketData](#ibc.applications.interchain_accounts.v1.InterchainAccountPacketData) @@ -329,10 +325,10 @@ ActiveChannel contains a pairing of port ID and channel ID for an active interch - + -### GenesisState -GenesisState defines the interchain accounts genesis state +### ControllerGenesisState +ControllerGenesisState defines the interchain accounts controller genesis state | Field | Type | Label | Description | @@ -346,62 +342,49 @@ GenesisState defines the interchain accounts genesis state - + -### RegisteredInterchainAccount -RegisteredInterchainAccount contains a pairing of controller port ID and associated interchain account address +### GenesisState +GenesisState defines the interchain accounts genesis state | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `port_id` | [string](#string) | | | -| `account_address` | [string](#string) | | | - - - +| `controller_genesis_state` | [ControllerGenesisState](#ibc.applications.interchain_accounts.v1.ControllerGenesisState) | | | +| `host_genesis_state` | [HostGenesisState](#ibc.applications.interchain_accounts.v1.HostGenesisState) | | | - - - - + - - -

Top

- -## ibc/applications/interchain_accounts/v1/query.proto - - - - - -### QueryInterchainAccountAddressRequest -Query request for an interchain account address +### HostGenesisState +HostGenesisState defines the interchain accounts host genesis state | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `counterparty_port_id` | [string](#string) | | Counterparty PortID is the portID on the controller chain | +| `active_channels` | [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel) | repeated | | +| `interchain_accounts` | [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount) | repeated | | +| `port` | [string](#string) | | | - + -### QueryInterchainAccountAddressResponse -Query response for an interchain account address +### RegisteredInterchainAccount +RegisteredInterchainAccount contains a pairing of controller port ID and associated interchain account address | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `interchain_account_address` | [string](#string) | | The corresponding interchain account address on the host chain | +| `port_id` | [string](#string) | | | +| `account_address` | [string](#string) | | | @@ -413,16 +396,6 @@ Query response for an interchain account address - - - -### Query -Query defines the gRPC querier service. - -| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | -| ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `InterchainAccountAddress` | [QueryInterchainAccountAddressRequest](#ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressRequest) | [QueryInterchainAccountAddressResponse](#ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressResponse) | Query to get the address of an interchain account | | - diff --git a/go.mod b/go.mod index 748b42ede11..274ba00ded6 100644 --- a/go.mod +++ b/go.mod @@ -94,7 +94,6 @@ require ( github.com/prometheus/common v0.29.0 // indirect github.com/prometheus/procfs v0.6.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect - github.com/regen-network/cosmos-proto v0.3.1 // indirect github.com/rs/cors v1.7.0 // indirect github.com/rs/zerolog v1.23.0 // indirect github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect @@ -115,7 +114,6 @@ require ( golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect golang.org/x/text v0.3.6 // indirect gopkg.in/ini.v1 v1.63.2 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect nhooyr.io/websocket v1.8.6 // indirect ) diff --git a/modules/apps/27-interchain-accounts/client/cli/query.go b/modules/apps/27-interchain-accounts/client/cli/query.go deleted file mode 100644 index 70137749561..00000000000 --- a/modules/apps/27-interchain-accounts/client/cli/query.go +++ /dev/null @@ -1,52 +0,0 @@ -package cli - -import ( - "context" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/spf13/cobra" - - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" -) - -func GetQueryCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "interchain-accounts", - Aliases: []string{"ica"}, - Short: "Querying commands for the interchain accounts module", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand(GetInterchainAccountCmd()) - - return cmd -} - -func GetInterchainAccountCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "address [counterparty-port-id]", - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - counterpartyPortID := args[0] - - queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.InterchainAccountAddress(context.Background(), &types.QueryInterchainAccountAddressRequest{CounterpartyPortId: counterpartyPortID}) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/modules/apps/27-interchain-accounts/ibc_module.go b/modules/apps/27-interchain-accounts/controller/ibc_module.go similarity index 76% rename from modules/apps/27-interchain-accounts/ibc_module.go rename to modules/apps/27-interchain-accounts/controller/ibc_module.go index ce5af58f4c8..31e6b59a3be 100644 --- a/modules/apps/27-interchain-accounts/ibc_module.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module.go @@ -1,24 +1,24 @@ -package interchain_accounts +package controller import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" ) -// IBCModule implements the ICS26 interface for interchain accounts given the -// interchain account keeper and underlying application. +// IBCModule implements the ICS26 interface for interchain accounts controller chains type IBCModule struct { keeper keeper.Keeper app porttypes.IBCModule } -// NewIBCModule creates a new IBCModule given the keeper and underlying application +// NewIBCModule creates a new IBCModule given the associated keeper and underlying application func NewIBCModule(k keeper.Keeper, app porttypes.IBCModule) IBCModule { return IBCModule{ keeper: k, @@ -26,13 +26,12 @@ func NewIBCModule(k keeper.Keeper, app porttypes.IBCModule) IBCModule { } } -// OnChanOpenInit implements the IBCModule interface. Interchain Accounts is -// implemented to act as middleware for connected authentication modules on +// OnChanOpenInit implements the IBCModule interface +// +// Interchain Accounts is implemented to act as middleware for connected authentication modules on // the controller side. The connected modules may not change the controller side portID or // version. They will be allowed to perform custom logic without changing // the parameters stored within a channel struct. -// -// Controller Chain func (im IBCModule) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, @@ -53,8 +52,6 @@ func (im IBCModule) OnChanOpenInit( } // OnChanOpenTry implements the IBCModule interface -// -// Host Chain func (im IBCModule) OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, @@ -66,16 +63,15 @@ func (im IBCModule) OnChanOpenTry( version, counterpartyVersion string, ) error { - return im.keeper.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version, counterpartyVersion) + return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") } -// OnChanOpenAck implements the IBCModule interface. Interchain Accounts is -// implemented to act as middleware for connected authentication modules on +// OnChanOpenAck implements the IBCModule interface +// +// Interchain Accounts is implemented to act as middleware for connected authentication modules on // the controller side. The connected modules may not change the portID or // version. They will be allowed to perform custom logic without changing // the parameters stored within a channel struct. -// -// Controller Chain func (im IBCModule) OnChanOpenAck( ctx sdk.Context, portID, @@ -91,14 +87,12 @@ func (im IBCModule) OnChanOpenAck( } // OnChanOpenAck implements the IBCModule interface -// -// Host Chain func (im IBCModule) OnChanOpenConfirm( ctx sdk.Context, portID, channelID string, ) error { - return im.keeper.OnChanOpenConfirm(ctx, portID, channelID) + return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") } // OnChanCloseInit implements the IBCModule interface @@ -121,31 +115,15 @@ func (im IBCModule) OnChanCloseConfirm( } // OnRecvPacket implements the IBCModule interface -// -// Host Chain func (im IBCModule) OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, _ sdk.AccAddress, ) ibcexported.Acknowledgement { - ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - - // only attempt the application logic if the packet data - // was successfully decoded - if ack.Success() { - err := im.keeper.OnRecvPacket(ctx, packet) - if err != nil { - ack = channeltypes.NewErrorAcknowledgement(err.Error()) - } - } - - // NOTE: acknowledgement will be written synchronously during IBC handler execution. - return ack + return channeltypes.NewErrorAcknowledgement("cannot receive packet on controller chain") } // OnAcknowledgementPacket implements the IBCModule interface -// -// Controller Chain func (im IBCModule) OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, @@ -157,8 +135,6 @@ func (im IBCModule) OnAcknowledgementPacket( } // OnTimeoutPacket implements the IBCModule interface -// -// Controller Chain func (im IBCModule) OnTimeoutPacket( ctx sdk.Context, packet channeltypes.Packet, @@ -180,5 +156,5 @@ func (im IBCModule) NegotiateAppVersion( counterparty channeltypes.Counterparty, proposedVersion string, ) (string, error) { - return im.keeper.NegotiateAppVersion(ctx, order, connectionID, portID, counterparty, proposedVersion) + return "", sdkerrors.Wrap(types.ErrInvalidChannelFlow, "ICS-27 app version negotiation is unsupported on controller chains") } diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go new file mode 100644 index 00000000000..7cec17d38da --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go @@ -0,0 +1,255 @@ +package controller_test + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/crypto" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v2/testing" +) + +var ( + // TestAccAddress defines a resuable bech32 address for testing purposes + // TODO: update crypto.AddressHash() when sdk uses address.Module() + TestAccAddress = types.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))), TestPortID) + // TestOwnerAddress defines a reusable bech32 address for testing purposes + TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + // TestPortID defines a resuable port identifier for testing purposes + TestPortID, _ = types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) + // TestVersion defines a resuable interchainaccounts version string for testing purposes + TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) +) + +type InterchainAccountsTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + // testing chains used for convenience and readability + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain +} + +func TestICATestSuite(t *testing.T) { + suite.Run(t, new(InterchainAccountsTestSuite)) +} + +func (suite *InterchainAccountsTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) +} + +func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { + path := ibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig.PortID = types.PortID + path.EndpointB.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointA.ChannelConfig.Version = types.VersionPrefix + path.EndpointB.ChannelConfig.Version = TestVersion + + return path +} + +func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { + portID, err := types.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) + if err != nil { + return err + } + + channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) + + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, owner); err != nil { + return err + } + + // commit state changes for proof verification + endpoint.Chain.App.Commit() + endpoint.Chain.NextBlock() + + // update port/channel ids + endpoint.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + endpoint.ChannelConfig.PortID = portID + + return nil +} + +// SetupICAPath invokes the InterchainAccounts entrypoint and subsequent channel handshake handlers +func SetupICAPath(path *ibctesting.Path, owner string) error { + if err := InitInterchainAccount(path.EndpointA, owner); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenTry(); err != nil { + return err + } + + if err := path.EndpointA.ChanOpenAck(); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenConfirm(); err != nil { + return err + } + + return nil +} + +func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { + var ( + channel *channeltypes.Channel + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + { + "ICA OnChanOpenInit fails - UNORDERED channel", func() { + channel.Ordering = channeltypes.UNORDERED + }, false, + }, + { + "ICA auth module callback fails", func() { + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, + portID, channelID string, chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, version string, + ) error { + return fmt.Errorf("mock ica auth fails") + } + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + // mock init interchain account + portID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + suite.Require().NoError(err) + + portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) + suite.chainA.GetSimApp().ICAControllerKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) + + path.EndpointA.ChannelConfig.PortID = portID + path.EndpointA.ChannelID = ibctesting.FirstChannelID + + // default values + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + channel = &channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: channeltypes.ORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: types.VersionPrefix, + } + + tc.malleate() // malleate mutates test data + + // ensure channel on chainA is set in state + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, *channel) + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), + ) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + { + "ICA OnChanOpenACK fails - invalid version", func() { + path.EndpointB.ChannelConfig.Version = "invalid|version" + }, false, + }, + { + "ICA auth module callback fails", func() { + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenAck = func( + ctx sdk.Context, portID, channelID string, counterpartyVersion string, + ) error { + return fmt.Errorf("mock ica auth fails") + } + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.Version) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } + +} diff --git a/modules/apps/27-interchain-accounts/genesis.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go similarity index 63% rename from modules/apps/27-interchain-accounts/genesis.go rename to modules/apps/27-interchain-accounts/controller/keeper/genesis.go index dae97a236b7..8e372000e73 100644 --- a/modules/apps/27-interchain-accounts/genesis.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go @@ -1,17 +1,16 @@ -package interchain_accounts +package keeper import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/keeper" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) -// InitGenesis initializes the interchain accounts application state from a provided genesis state -func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState) { +// InitGenesis initializes the interchain accounts controller application state from a provided genesis state +func InitGenesis(ctx sdk.Context, keeper Keeper, state types.ControllerGenesisState) { for _, portID := range state.Ports { if !keeper.IsBound(ctx, portID) { cap := keeper.BindPort(ctx, portID) @@ -30,11 +29,11 @@ func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState } } -// ExportGenesis returns the interchain accounts exported genesis -func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState { - return types.NewGenesisState( - keeper.GetAllPorts(ctx), +// ExportGenesis returns the interchain accounts controller exported genesis +func ExportGenesis(ctx sdk.Context, keeper Keeper) *types.ControllerGenesisState { + return types.NewControllerGenesisState( keeper.GetAllActiveChannels(ctx), keeper.GetAllInterchainAccounts(ctx), + keeper.GetAllPorts(ctx), ) } diff --git a/modules/apps/27-interchain-accounts/genesis_test.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go similarity index 51% rename from modules/apps/27-interchain-accounts/genesis_test.go rename to modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go index e403bdcadd4..4e0f749f6d7 100644 --- a/modules/apps/27-interchain-accounts/genesis_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go @@ -1,23 +1,19 @@ -package interchain_accounts_test +package keeper_test import ( - ica "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/keeper" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v2/testing" ) -func (suite *InterchainAccountsTestSuite) TestInitGenesis() { - var ( - expectedChannelID string = "channel-0" - ) - +func (suite *KeeperTestSuite) TestInitGenesis() { suite.SetupTest() - genesisState := types.GenesisState{ - Ports: []string{types.PortID, TestPortID}, + genesisState := types.ControllerGenesisState{ ActiveChannels: []*types.ActiveChannel{ { PortId: TestPortID, - ChannelId: expectedChannelID, + ChannelId: ibctesting.FirstChannelID, }, }, InterchainAccounts: []*types.RegisteredInterchainAccount{ @@ -26,34 +22,36 @@ func (suite *InterchainAccountsTestSuite) TestInitGenesis() { AccountAddress: TestAccAddress.String(), }, }, + Ports: []string{TestPortID}, } - ica.InitGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAKeeper, genesisState) + keeper.InitGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAControllerKeeper, genesisState) - channelID, found := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannelID(suite.chainA.GetContext(), TestPortID) + channelID, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainA.GetContext(), TestPortID) suite.Require().True(found) - suite.Require().Equal(expectedChannelID, channelID) + suite.Require().Equal(ibctesting.FirstChannelID, channelID) - accountAdrr, found := suite.chainA.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), TestPortID) + accountAdrr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), TestPortID) suite.Require().True(found) suite.Require().Equal(TestAccAddress.String(), accountAdrr) } -func (suite *InterchainAccountsTestSuite) TestExportGenesis() { +func (suite *KeeperTestSuite) TestExportGenesis() { suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - genesisState := ica.ExportGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAKeeper) - - suite.Require().Equal([]string{types.PortID, TestPortID}, genesisState.GetPorts()) + genesisState := keeper.ExportGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAControllerKeeper) suite.Require().Equal(path.EndpointA.ChannelID, genesisState.ActiveChannels[0].ChannelId) suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.ActiveChannels[0].PortId) suite.Require().Equal(TestAccAddress.String(), genesisState.InterchainAccounts[0].AccountAddress) suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.InterchainAccounts[0].PortId) + + suite.Require().Equal([]string{TestPortID}, genesisState.GetPorts()) } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go new file mode 100644 index 00000000000..6145c867109 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go @@ -0,0 +1,133 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" +) + +// OnChanOpenInit performs basic validation of channel initialization. +// The channel order must be ORDERED, the counterparty port identifier +// must be the host chain representation as defined in the types package, +// the channel version must be equal to the version in the types package, +// there must not be an active channel for the specfied port identifier, +// and the interchain accounts module must be able to claim the channel +// capability. +func (k Keeper) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) error { + if order != channeltypes.ORDERED { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order) + } + + connSequence, err := types.ParseControllerConnSequence(portID) + if err != nil { + return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, portID) + } + + counterpartyConnSequence, err := types.ParseHostConnSequence(portID) + if err != nil { + return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, portID) + } + + if err := k.validateControllerPortParams(ctx, channelID, portID, connSequence, counterpartyConnSequence); err != nil { + return sdkerrors.Wrapf(err, "failed to validate controller port %s", portID) + } + + if counterparty.PortId != types.PortID { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "expected %s, got %s", types.PortID, counterparty.PortId) + } + + if version != types.VersionPrefix { + return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.VersionPrefix, version) + } + + activeChannelID, found := k.GetActiveChannelID(ctx, portID) + if found { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel %s for portID %s", activeChannelID, portID) + } + + return nil +} + +// OnChanOpenAck sets the active channel for the interchain account/owner pair +// and stores the associated interchain account address in state keyed by it's corresponding port identifier +func (k Keeper) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyVersion string, +) error { + if err := types.ValidateVersion(counterpartyVersion); err != nil { + return sdkerrors.Wrap(err, "counterparty version validation failed") + } + + k.SetActiveChannelID(ctx, portID, channelID) + + accAddr, err := types.ParseAddressFromVersion(counterpartyVersion) + if err != nil { + return sdkerrors.Wrapf(err, "expected format , got %s", types.Delimiter, counterpartyVersion) + } + + k.SetInterchainAccountAddress(ctx, portID, accAddr) + + return nil +} + +// OnChanCloseConfirm removes the active channel stored in state +func (k Keeper) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + + k.DeleteActiveChannelID(ctx, portID) + + return nil +} + +// validateControllerPortParams asserts the provided connection sequence and counterparty connection sequence +// match that of the associated connection stored in state +func (k Keeper) validateControllerPortParams(ctx sdk.Context, channelID, portID string, connectionSeq, counterpartyConnectionSeq uint64) error { + channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID) + if !found { + return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID %s channel ID %s", portID, channelID) + } + + counterpartyHops, found := k.channelKeeper.CounterpartyHops(ctx, channel) + if !found { + return sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) + } + + connSeq, err := connectiontypes.ParseConnectionSequence(channel.ConnectionHops[0]) + if err != nil { + return sdkerrors.Wrapf(err, "failed to parse connection sequence %s", channel.ConnectionHops[0]) + } + + counterpartyConnSeq, err := connectiontypes.ParseConnectionSequence(counterpartyHops[0]) + if err != nil { + return sdkerrors.Wrapf(err, "failed to parse counterparty connection sequence %s", counterpartyHops[0]) + } + + if connSeq != connectionSeq { + return sdkerrors.Wrapf(connectiontypes.ErrInvalidConnection, "sequence mismatch, expected %d, got %d", connSeq, connectionSeq) + } + + if counterpartyConnSeq != counterpartyConnectionSeq { + return sdkerrors.Wrapf(connectiontypes.ErrInvalidConnection, "counterparty sequence mismatch, expected %d, got %d", counterpartyConnSeq, counterpartyConnectionSeq) + } + + return nil +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go new file mode 100644 index 00000000000..a4bd9622eab --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go @@ -0,0 +1,258 @@ +package keeper_test + +import ( + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v2/testing" +) + +func (suite *KeeperTestSuite) TestOnChanOpenInit() { + var ( + channel *channeltypes.Channel + path *ibctesting.Path + chanCap *capabilitytypes.Capability + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", + func() { + path.EndpointA.SetChannel(*channel) + }, + true, + }, + { + "invalid order - UNORDERED", + func() { + channel.Ordering = channeltypes.UNORDERED + }, + false, + }, + { + "invalid port ID", + func() { + path.EndpointA.ChannelConfig.PortID = "invalid-port-id" + }, + false, + }, + { + "invalid counterparty port ID", + func() { + path.EndpointA.SetChannel(*channel) + channel.Counterparty.PortId = "invalid-port-id" + }, + false, + }, + { + "invalid version", + func() { + path.EndpointA.SetChannel(*channel) + channel.Version = "version" + }, + false, + }, + { + "channel not found", + func() { + path.EndpointA.ChannelID = "invalid-channel-id" + }, + false, + }, + { + "connection not found", + func() { + channel.ConnectionHops = []string{"invalid-connnection-id"} + path.EndpointA.SetChannel(*channel) + }, + false, + }, + { + "invalid connection sequence", + func() { + portID, err := types.GeneratePortID(TestOwnerAddress, "connection-1", "connection-0") + suite.Require().NoError(err) + + path.EndpointA.ChannelConfig.PortID = portID + path.EndpointA.SetChannel(*channel) + }, + false, + }, + { + "invalid counterparty connection sequence", + func() { + portID, err := types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-1") + suite.Require().NoError(err) + + path.EndpointA.ChannelConfig.PortID = portID + path.EndpointA.SetChannel(*channel) + }, + false, + }, + { + "channel is already active", + func() { + suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + // mock init interchain account + portID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + suite.Require().NoError(err) + + portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) + suite.chainA.GetSimApp().ICAControllerKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) + path.EndpointA.ChannelConfig.PortID = portID + + // default values + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + channel = &channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: channeltypes.ORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: types.VersionPrefix, + } + + chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + err = suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), + ) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } +} + +func (suite *KeeperTestSuite) TestOnChanOpenAck() { + var ( + path *ibctesting.Path + expectedChannelID string + counterpartyVersion string + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + { + "invalid counterparty version", + func() { + expectedChannelID = "" + counterpartyVersion = "version" + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + counterpartyVersion = TestVersion + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + expectedChannelID = path.EndpointA.ChannelID + + tc.malleate() // malleate mutates test data + + err = suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenAck(suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyVersion, + ) + + activeChannelID, _ := suite.chainA.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + + suite.Require().Equal(activeChannelID, expectedChannelID) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + err = suite.chainB.GetSimApp().ICAControllerKeeper.OnChanCloseConfirm(suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + + activeChannelID, found := suite.chainB.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().False(found) + suite.Require().Empty(activeChannelID) + } else { + suite.Require().Error(err) + } + + }) + } +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go new file mode 100644 index 00000000000..08de202dcc8 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -0,0 +1,215 @@ +package keeper + +import ( + "fmt" + "strings" + + baseapp "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" +) + +// Keeper defines the IBC interchain accounts controller keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc codec.BinaryCodec + + ics4Wrapper types.ICS4Wrapper + channelKeeper types.ChannelKeeper + portKeeper types.PortKeeper + accountKeeper types.AccountKeeper + + scopedKeeper capabilitykeeper.ScopedKeeper + + msgRouter *baseapp.MsgServiceRouter +} + +// NewKeeper creates a new interchain accounts controller Keeper instance +func NewKeeper( + cdc codec.BinaryCodec, key sdk.StoreKey, + ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, + accountKeeper types.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, +) Keeper { + return Keeper{ + storeKey: key, + cdc: cdc, + ics4Wrapper: ics4Wrapper, + channelKeeper: channelKeeper, + portKeeper: portKeeper, + accountKeeper: accountKeeper, + scopedKeeper: scopedKeeper, + msgRouter: msgRouter, + } +} + +// Logger returns the application logger, scoped to the associated module +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) +} + +// InitInterchainAccount is the entry point to registering an interchain account. +// It generates a new port identifier using the owner address, connection identifier, +// and counterparty connection identifier. It will bind to the port identifier and +// call 04-channel 'ChanOpenInit'. An error is returned if the port identifier is +// already in use. Gaining access to interchain accounts whose channels have closed +// cannot be done with this function. A regular MsgChanOpenInit must be used. +func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpartyConnectionID, owner string) error { + portID, err := types.GeneratePortID(owner, connectionID, counterpartyConnectionID) + if err != nil { + return err + } + + if k.portKeeper.IsBound(ctx, portID) { + return sdkerrors.Wrap(types.ErrPortAlreadyBound, portID) + } + + cap := k.BindPort(ctx, portID) + if err := k.ClaimCapability(ctx, cap, host.PortPath(portID)); err != nil { + return sdkerrors.Wrap(err, "unable to bind to newly generated portID") + } + + msg := channeltypes.NewMsgChannelOpenInit(portID, types.VersionPrefix, channeltypes.ORDERED, []string{connectionID}, types.PortID, types.ModuleName) + handler := k.msgRouter.Handler(msg) + if _, err := handler(ctx, msg); err != nil { + return err + } + + return nil +} + +// GetAllPorts returns all ports to which the interchain accounts controller module is bound. Used in ExportGenesis +func (k Keeper) GetAllPorts(ctx sdk.Context) []string { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.PortKeyPrefix)) + defer iterator.Close() + + var ports []string + for ; iterator.Valid(); iterator.Next() { + keySplit := strings.Split(string(iterator.Key()), "/") + + ports = append(ports, keySplit[1]) + } + + return ports +} + +// BindPort stores the provided portID and binds to it, returning the associated capability +func (k Keeper) BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability { + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyPort(portID), []byte{0x01}) + + return k.portKeeper.BindPort(ctx, portID) +} + +// IsBound checks if the interchain account controller module is already bound to the desired port +func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { + _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) + return ok +} + +// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function +func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { + return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) +} + +// ClaimCapability wraps the scopedKeeper's ClaimCapability function +func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { + return k.scopedKeeper.ClaimCapability(ctx, cap, name) +} + +// GetActiveChannelID retrieves the active channelID from the store keyed by the provided portID +func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool) { + store := ctx.KVStore(k.storeKey) + key := types.KeyActiveChannel(portID) + + if !store.Has(key) { + return "", false + } + + return string(store.Get(key)), true +} + +// GetAllActiveChannels returns a list of all active interchain accounts controller channels and their associated port identifiers +func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []*types.ActiveChannel { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.ActiveChannelKeyPrefix)) + defer iterator.Close() + + var activeChannels []*types.ActiveChannel + for ; iterator.Valid(); iterator.Next() { + keySplit := strings.Split(string(iterator.Key()), "/") + + ch := &types.ActiveChannel{ + PortId: keySplit[1], + ChannelId: string(iterator.Value()), + } + + activeChannels = append(activeChannels, ch) + } + + return activeChannels +} + +// SetActiveChannelID stores the active channelID, keyed by the provided portID +func (k Keeper) SetActiveChannelID(ctx sdk.Context, portID, channelID string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyActiveChannel(portID), []byte(channelID)) +} + +// DeleteActiveChannelID removes the active channel keyed by the provided portID stored in state +func (k Keeper) DeleteActiveChannelID(ctx sdk.Context, portID string) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.KeyActiveChannel(portID)) +} + +// IsActiveChannel returns true if there exists an active channel for the provided portID, otherwise false +func (k Keeper) IsActiveChannel(ctx sdk.Context, portID string) bool { + _, ok := k.GetActiveChannelID(ctx, portID) + return ok +} + +// GetInterchainAccountAddress retrieves the InterchainAccount address from the store keyed by the provided portID +func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (string, bool) { + store := ctx.KVStore(k.storeKey) + key := types.KeyOwnerAccount(portID) + + if !store.Has(key) { + return "", false + } + + return string(store.Get(key)), true +} + +// GetAllInterchainAccounts returns a list of all registered interchain account addresses and their associated controller port identifiers +func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []*types.RegisteredInterchainAccount { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.OwnerKeyPrefix)) + + var interchainAccounts []*types.RegisteredInterchainAccount + for ; iterator.Valid(); iterator.Next() { + keySplit := strings.Split(string(iterator.Key()), "/") + + acc := &types.RegisteredInterchainAccount{ + PortId: keySplit[1], + AccountAddress: string(iterator.Value()), + } + + interchainAccounts = append(interchainAccounts, acc) + } + + return interchainAccounts +} + +// SetInterchainAccountAddress stores the InterchainAccount address, keyed by the associated portID +func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portID string, address string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyOwnerAccount(portID), []byte(address)) +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go new file mode 100644 index 00000000000..3b5a21e91ec --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go @@ -0,0 +1,314 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/crypto" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v2/testing" +) + +var ( + // TestAccAddress defines a resuable bech32 address for testing purposes + // TODO: update crypto.AddressHash() when sdk uses address.Module() + TestAccAddress = types.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))), TestPortID) + // TestOwnerAddress defines a reusable bech32 address for testing purposes + TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + // TestPortID defines a resuable port identifier for testing purposes + TestPortID, _ = types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) + // TestVersion defines a resuable interchainaccounts version string for testing purposes + TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) +) + +type KeeperTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + // testing chains used for convenience and readability + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain + chainC *ibctesting.TestChain +} + +func (suite *KeeperTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2)) +} + +func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { + path := ibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig.PortID = types.PortID + path.EndpointB.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointA.ChannelConfig.Version = types.VersionPrefix + path.EndpointB.ChannelConfig.Version = TestVersion + + return path +} + +// SetupICAPath invokes the InterchainAccounts entrypoint and subsequent channel handshake handlers +func SetupICAPath(path *ibctesting.Path, owner string) error { + if err := InitInterchainAccount(path.EndpointA, owner); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenTry(); err != nil { + return err + } + + if err := path.EndpointA.ChanOpenAck(); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenConfirm(); err != nil { + return err + } + + return nil +} + +// InitInterchainAccount is a helper function for starting the channel handshake +func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { + portID, err := types.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) + if err != nil { + return err + } + + channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) + + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, owner); err != nil { + return err + } + + // commit state changes for proof verification + endpoint.Chain.App.Commit() + endpoint.Chain.NextBlock() + + // update port/channel ids + endpoint.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + endpoint.ChannelConfig.PortID = portID + + return nil +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func (suite *KeeperTestSuite) TestIsBound() { + suite.SetupTest() + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + isBound := suite.chainA.GetSimApp().ICAControllerKeeper.IsBound(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(isBound) +} + +func (suite *KeeperTestSuite) TestGetAllPorts() { + suite.SetupTest() + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + expectedPorts := []string{TestPortID} + + ports := suite.chainA.GetSimApp().ICAControllerKeeper.GetAllPorts(suite.chainA.GetContext()) + suite.Require().Len(ports, len(expectedPorts)) + suite.Require().Equal(expectedPorts, ports) +} + +func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { + suite.SetupTest() + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + counterpartyPortID := path.EndpointA.ChannelConfig.PortID + expectedAddr := authtypes.NewBaseAccountWithAddress(types.GenerateAddress(suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName), counterpartyPortID)).GetAddress() + + retrievedAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), counterpartyPortID) + suite.Require().True(found) + suite.Require().Equal(expectedAddr.String(), retrievedAddr) + + retrievedAddr, found = suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), "invalid port") + suite.Require().False(found) + suite.Require().Empty(retrievedAddr) +} + +func (suite *KeeperTestSuite) TestGetAllActiveChannels() { + var ( + expectedChannelID string = "test-channel" + expectedPortID string = "test-port" + ) + + suite.SetupTest() + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), expectedPortID, expectedChannelID) + + expectedChannels := []*types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: path.EndpointA.ChannelID, + }, + { + PortId: expectedPortID, + ChannelId: expectedChannelID, + }, + } + + activeChannels := suite.chainA.GetSimApp().ICAControllerKeeper.GetAllActiveChannels(suite.chainA.GetContext()) + suite.Require().Len(activeChannels, len(expectedChannels)) + suite.Require().Equal(expectedChannels, activeChannels) +} + +func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() { + var ( + expectedAccAddr string = "test-acc-addr" + expectedPortID string = "test-port" + ) + + suite.SetupTest() + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + suite.chainA.GetSimApp().ICAControllerKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr) + + expectedAccounts := []*types.RegisteredInterchainAccount{ + { + PortId: TestPortID, + AccountAddress: TestAccAddress.String(), + }, + { + PortId: expectedPortID, + AccountAddress: expectedAccAddr, + }, + } + + interchainAccounts := suite.chainA.GetSimApp().ICAControllerKeeper.GetAllInterchainAccounts(suite.chainA.GetContext()) + suite.Require().Len(interchainAccounts, len(expectedAccounts)) + suite.Require().Equal(expectedAccounts, interchainAccounts) +} + +func (suite *KeeperTestSuite) TestIsActiveChannel() { + suite.SetupTest() + + path := NewICAPath(suite.chainA, suite.chainB) + owner := TestOwnerAddress + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, owner) + suite.Require().NoError(err) + portID := path.EndpointA.ChannelConfig.PortID + + isActive := suite.chainA.GetSimApp().ICAControllerKeeper.IsActiveChannel(suite.chainA.GetContext(), portID) + suite.Require().Equal(isActive, true) +} + +func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() { + var ( + expectedAccAddr string = "test-acc-addr" + expectedPortID string = "test-port" + ) + + suite.chainA.GetSimApp().ICAControllerKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr) + + retrievedAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID) + suite.Require().True(found) + suite.Require().Equal(expectedAccAddr, retrievedAddr) +} + +func (suite *KeeperTestSuite) TestInitInterchainAccount() { + var ( + owner string + path *ibctesting.Path + err error + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + { + "port is already bound", + func() { + suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), TestPortID) + }, + false, + }, + { + "fails to generate port-id", + func() { + owner = "" + }, + false, + }, + { + "MsgChanOpenInit fails - channel is already active", + func() { + portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + suite.Require().NoError(err) + + suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + + // TODO: Get rid of this? + owner = TestOwnerAddress // must be explicitly changed + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + tc.malleate() // malleate mutates test data + + err = suite.chainA.GetSimApp().ICAControllerKeeper.InitInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, path.EndpointB.ConnectionID, owner) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } +} diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/controller/keeper/relay.go similarity index 54% rename from modules/apps/27-interchain-accounts/keeper/relay.go rename to modules/apps/27-interchain-accounts/controller/keeper/relay.go index 9b5eec6e2d8..02a79a00e97 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay.go @@ -71,86 +71,6 @@ func (k Keeper) createOutgoingPacket( return packet.Sequence, nil } -// AuthenticateTx ensures the provided msgs contain the correct interchain account signer address retrieved -// from state using the provided controller port identifier -func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portID string) error { - interchainAccountAddr, found := k.GetInterchainAccountAddress(ctx, portID) - if !found { - return sdkerrors.Wrapf(types.ErrInterchainAccountNotFound, "failed to retrieve interchain account on port %s", portID) - } - - for _, msg := range msgs { - for _, signer := range msg.GetSigners() { - if interchainAccountAddr != signer.String() { - return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "unexpected signer address: expected %s, got %s", interchainAccountAddr, signer.String()) - } - } - } - - return nil -} - -func (k Keeper) executeTx(ctx sdk.Context, sourcePort, destPort, destChannel string, msgs []sdk.Msg) error { - if err := k.AuthenticateTx(ctx, msgs, sourcePort); err != nil { - return err - } - - for _, msg := range msgs { - if err := msg.ValidateBasic(); err != nil { - return err - } - } - - // CacheContext returns a new context with the multi-store branched into a cached storage object - // writeCache is called only if all msgs succeed, performing state transitions atomically - cacheCtx, writeCache := ctx.CacheContext() - for _, msg := range msgs { - if _, err := k.executeMsg(cacheCtx, msg); err != nil { - return err - } - } - - writeCache() - - return nil -} - -// It tries to get the handler from router. And, if router exites, it will perform message. -func (k Keeper) executeMsg(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - handler := k.msgRouter.Handler(msg) - if handler == nil { - return nil, types.ErrInvalidRoute - } - - return handler(ctx, msg) -} - -// OnRecvPacket handles a given interchain accounts packet on a destination host chain -func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error { - var data types.InterchainAccountPacketData - - if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - // UnmarshalJSON errors are indeterminate and therefore are not wrapped and included in failed acks - return sdkerrors.Wrapf(types.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain account packet data") - } - - switch data.Type { - case types.EXECUTE_TX: - msgs, err := types.DeserializeCosmosTx(k.cdc, data.Data) - if err != nil { - return err - } - - if err = k.executeTx(ctx, packet.SourcePort, packet.DestinationPort, packet.DestinationChannel, msgs); err != nil { - return err - } - - return nil - default: - return types.ErrUnknownDataType - } -} - // OnTimeoutPacket removes the active channel associated with the provided packet, the underlying channel end is closed // due to the semantics of ORDERED channels func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet) error { diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go new file mode 100644 index 00000000000..561cc370ddf --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go @@ -0,0 +1,201 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v2/testing" +) + +func (suite *KeeperTestSuite) TestTrySendTx() { + var ( + path *ibctesting.Path + packetData types.InterchainAccountPacketData + chanCap *capabilitytypes.Capability + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "success", + func() { + interchainAccountAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + msg := &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + } + + data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg}) + suite.Require().NoError(err) + + packetData = types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + }, + true, + }, + { + "success with multiple sdk.Msg", + func() { + interchainAccountAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + msgsBankSend := []sdk.Msg{ + &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + }, + &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + }, + } + + data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), msgsBankSend) + suite.Require().NoError(err) + + packetData = types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: data, + } + }, + true, + }, + { + "data is nil", + func() { + packetData = types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: nil, + } + }, + false, + }, + { + "active channel not found", + func() { + path.EndpointA.ChannelConfig.PortID = "invalid-port-id" + }, + false, + }, + { + "channel does not exist", + func() { + suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, "channel-100") + }, + false, + }, + { + "sendPacket fails - channel closed", + func() { + err := path.EndpointA.SetChannelClosed() + suite.Require().NoError(err) + }, + false, + }, + { + "invalid channel capability provided", + func() { + chanCap = nil + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.msg, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + var ok bool + chanCap, ok = suite.chainA.GetSimApp().ScopedICAMockKeeper.GetCapability(path.EndpointA.Chain.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + suite.Require().True(ok) + + tc.malleate() // malleate mutates test data + + _, err = suite.chainA.GetSimApp().ICAControllerKeeper.TrySendTx(suite.chainA.GetContext(), chanCap, path.EndpointA.ChannelConfig.PortID, packetData) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestOnTimeoutPacket() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.msg, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + packet := channeltypes.NewPacket( + []byte{}, + 1, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + err = suite.chainA.GetSimApp().ICAControllerKeeper.OnTimeoutPacket(suite.chainA.GetContext(), packet) + + activeChannelID, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Empty(activeChannelID) + suite.Require().False(found) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/modules/apps/27-interchain-accounts/controller/types/keys.go b/modules/apps/27-interchain-accounts/controller/types/keys.go new file mode 100644 index 00000000000..1f17f79de71 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/types/keys.go @@ -0,0 +1,9 @@ +package types + +const ( + // ModuleName defines the interchain accounts controller module name + ModuleName = "icacontroller" + + // StoreKey is the store key string for the interchain accounts controller module + StoreKey = ModuleName +) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go new file mode 100644 index 00000000000..a304c121ef0 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -0,0 +1,138 @@ +package host + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" +) + +// IBCModule implements the ICS26 interface for interchain accounts host chains +type IBCModule struct { + keeper keeper.Keeper +} + +// NewIBCModule creates a new IBCModule given the associated keeper +func NewIBCModule(k keeper.Keeper) IBCModule { + return IBCModule{ + keeper: k, + } +} + +// OnChanOpenInit implements the IBCModule interface +func (im IBCModule) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) error { + return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") +} + +// OnChanOpenTry implements the IBCModule interface +func (im IBCModule) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version, + counterpartyVersion string, +) error { + return im.keeper.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version, counterpartyVersion) +} + +// OnChanOpenAck implements the IBCModule interface +func (im IBCModule) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyVersion string, +) error { + return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") +} + +// OnChanOpenAck implements the IBCModule interface +func (im IBCModule) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return im.keeper.OnChanOpenConfirm(ctx, portID, channelID) +} + +// OnChanCloseInit implements the IBCModule interface +func (im IBCModule) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + // Disallow user-initiated channel closing for interchain account channels + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") +} + +// OnChanCloseConfirm implements the IBCModule interface +func (im IBCModule) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return im.keeper.OnChanCloseConfirm(ctx, portID, channelID) +} + +// OnRecvPacket implements the IBCModule interface +func (im IBCModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + _ sdk.AccAddress, +) ibcexported.Acknowledgement { + ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + + if err := im.keeper.OnRecvPacket(ctx, packet); err != nil { + ack = channeltypes.NewErrorAcknowledgement(err.Error()) + } + + // NOTE: acknowledgement will be written synchronously during IBC handler execution. + return ack +} + +// OnAcknowledgementPacket implements the IBCModule interface +func (im IBCModule) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + relayer sdk.AccAddress, +) error { + return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "cannot receive acknowledgement on a host channel end, a host chain does not send a packet over the channel") +} + +// OnTimeoutPacket implements the IBCModule interface +func (im IBCModule) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) error { + return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "cannot cause a packet timeout on a host channel end, a host chain does not send a packet over the channel") +} + +// NegotiateAppVersion implements the IBCModule interface +func (im IBCModule) NegotiateAppVersion( + ctx sdk.Context, + order channeltypes.Order, + connectionID string, + portID string, + counterparty channeltypes.Counterparty, + proposedVersion string, +) (string, error) { + return im.keeper.NegotiateAppVersion(ctx, order, connectionID, portID, counterparty, proposedVersion) +} diff --git a/modules/apps/27-interchain-accounts/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go similarity index 69% rename from modules/apps/27-interchain-accounts/ibc_module_test.go rename to modules/apps/27-interchain-accounts/host/ibc_module_test.go index ca010b6ede1..92203c25ea8 100644 --- a/modules/apps/27-interchain-accounts/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -1,4 +1,4 @@ -package interchain_accounts_test +package host_test import ( "fmt" @@ -25,7 +25,7 @@ var ( // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes - TestPortID, _ = types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-0") + TestPortID, _ = types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) // TestVersion defines a resuable interchainaccounts version string for testing purposes TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) ) @@ -67,9 +67,10 @@ func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { if err != nil { return err } + channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, owner); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, owner); err != nil { return err } @@ -80,6 +81,7 @@ func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { // update port/channel ids endpoint.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) endpoint.ChannelConfig.PortID = portID + return nil } @@ -104,93 +106,12 @@ func SetupICAPath(path *ibctesting.Path, owner string) error { return nil } -func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { - var ( - channel *channeltypes.Channel - ) - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success", func() {}, true, - }, - { - "ICA OnChanOpenInit fails - UNORDERED channel", func() { - channel.Ordering = channeltypes.UNORDERED - }, false, - }, - { - "ICA auth module callback fails", func() { - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, version string, - ) error { - return fmt.Errorf("mock ica auth fails") - } - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - // mock init interchain account - portID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - suite.Require().NoError(err) - portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) - suite.chainA.GetSimApp().ICAKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) - - path.EndpointA.ChannelConfig.PortID = portID - path.EndpointA.ChannelID = ibctesting.FirstChannelID - - // default values - counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - channel = &channeltypes.Channel{ - State: channeltypes.INIT, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: types.VersionPrefix, - } - - tc.malleate() - - // ensure channel on chainA is set in state - suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, *channel) - - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) - - err = cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { var ( + path *ibctesting.Path channel *channeltypes.Channel ) + testCases := []struct { name string malleate func() @@ -224,8 +145,8 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { suite.Run(tc.name, func() { suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - counterpartyVersion := types.VersionPrefix + + path = NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) @@ -257,7 +178,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { suite.Require().True(ok) err = cbs.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.GetConnectionHops(), - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), counterpartyVersion, + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), path.EndpointA.ChannelConfig.Version, ) if tc.expPass { @@ -271,70 +192,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { } -func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { - var ( - counterpartyVersion string - ) - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success", func() {}, true, - }, - { - "ICA OnChanOpenACK fails - invalid version", func() { - counterpartyVersion = "invalid|version" - }, false, - }, - { - "ICA auth module callback fails", func() { - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenAck = func( - ctx sdk.Context, portID, channelID string, counterpartyVersion string, - ) error { - return fmt.Errorf("mock ica auth fails") - } - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - counterpartyVersion = TestVersion - suite.coordinator.SetupConnections(path) - - err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) - - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) - - tc.malleate() - - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) - - err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyVersion) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - - }) - } - -} - func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { testCases := []struct { name string @@ -437,7 +294,7 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { // send 100stake to interchain account wallet amount, _ := sdk.ParseCoinsNormalized("100stake") - interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) bankMsg := &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: interchainAccountAddr, Amount: amount} _, err = suite.chainB.SendMsgs(bankMsg) diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis.go b/modules/apps/27-interchain-accounts/host/keeper/genesis.go new file mode 100644 index 00000000000..7a321b88b37 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis.go @@ -0,0 +1,37 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" +) + +// InitGenesis initializes the interchain accounts host application state from a provided genesis state +func InitGenesis(ctx sdk.Context, keeper Keeper, state types.HostGenesisState) { + if !keeper.IsBound(ctx, state.Port) { + cap := keeper.BindPort(ctx, state.Port) + if err := keeper.ClaimCapability(ctx, cap, host.PortPath(state.Port)); err != nil { + panic(fmt.Sprintf("could not claim port capability: %v", err)) + } + } + + for _, ch := range state.ActiveChannels { + keeper.SetActiveChannelID(ctx, ch.PortId, ch.ChannelId) + } + + for _, acc := range state.InterchainAccounts { + keeper.SetInterchainAccountAddress(ctx, acc.PortId, acc.AccountAddress) + } +} + +// ExportGenesis returns the interchain accounts host exported genesis +func ExportGenesis(ctx sdk.Context, keeper Keeper) *types.HostGenesisState { + return types.NewHostGenesisState( + keeper.GetAllActiveChannels(ctx), + keeper.GetAllInterchainAccounts(ctx), + types.PortID, + ) +} diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go new file mode 100644 index 00000000000..9d4a0538599 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go @@ -0,0 +1,57 @@ +package keeper_test + +import ( + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v2/testing" +) + +func (suite *KeeperTestSuite) TestInitGenesis() { + suite.SetupTest() + + genesisState := types.HostGenesisState{ + ActiveChannels: []*types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: ibctesting.FirstChannelID, + }, + }, + InterchainAccounts: []*types.RegisteredInterchainAccount{ + { + PortId: TestPortID, + AccountAddress: TestAccAddress.String(), + }, + }, + Port: types.PortID, + } + + keeper.InitGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAHostKeeper, genesisState) + + channelID, found := suite.chainA.GetSimApp().ICAHostKeeper.GetActiveChannelID(suite.chainA.GetContext(), TestPortID) + suite.Require().True(found) + suite.Require().Equal(ibctesting.FirstChannelID, channelID) + + accountAdrr, found := suite.chainA.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), TestPortID) + suite.Require().True(found) + suite.Require().Equal(TestAccAddress.String(), accountAdrr) +} + +func (suite *KeeperTestSuite) TestExportGenesis() { + suite.SetupTest() + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + genesisState := keeper.ExportGenesis(suite.chainB.GetContext(), suite.chainB.GetSimApp().ICAHostKeeper) + + suite.Require().Equal(path.EndpointB.ChannelID, genesisState.ActiveChannels[0].ChannelId) + suite.Require().Equal(path.EndpointB.ChannelConfig.PortID, genesisState.ActiveChannels[0].PortId) + + suite.Require().Equal(TestAccAddress.String(), genesisState.InterchainAccounts[0].AccountAddress) + suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.InterchainAccounts[0].PortId) + + suite.Require().Equal(types.PortID, genesisState.GetPort()) +} diff --git a/modules/apps/27-interchain-accounts/keeper/handshake.go b/modules/apps/27-interchain-accounts/host/keeper/handshake.go similarity index 65% rename from modules/apps/27-interchain-accounts/keeper/handshake.go rename to modules/apps/27-interchain-accounts/host/keeper/handshake.go index a6c69509013..864498137f9 100644 --- a/modules/apps/27-interchain-accounts/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake.go @@ -12,63 +12,8 @@ import ( host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) -// OnChanOpenInit performs basic validation of channel initialization. -// The channel order must be ORDERED, the counterparty port identifier -// must be the host chain representation as defined in the types package, -// the channel version must be equal to the version in the types package, -// there must not be an active channel for the specfied port identifier, -// and the interchain accounts module must be able to claim the channel -// capability. -// -// Controller Chain -func (k Keeper) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) error { - if order != channeltypes.ORDERED { - return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order) - } - - connSequence, err := types.ParseControllerConnSequence(portID) - if err != nil { - return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, portID) - } - - counterpartyConnSequence, err := types.ParseHostConnSequence(portID) - if err != nil { - return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, portID) - } - - if err := k.validateControllerPortParams(ctx, channelID, portID, connSequence, counterpartyConnSequence); err != nil { - return sdkerrors.Wrapf(err, "failed to validate controller port %s", portID) - } - - if counterparty.PortId != types.PortID { - return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "expected %s, got %s", types.PortID, counterparty.PortId) - } - - if version != types.VersionPrefix { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.VersionPrefix, version) - } - - activeChannelID, found := k.GetActiveChannelID(ctx, portID) - if found { - return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel %s for portID %s", activeChannelID, portID) - } - - return nil -} - // OnChanOpenTry performs basic validation of the ICA channel // and registers a new interchain account (if it doesn't exist). -// -// Host Chain func (k Keeper) OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, @@ -133,35 +78,7 @@ func (k Keeper) OnChanOpenTry( return nil } -// OnChanOpenAck sets the active channel for the interchain account/owner pair -// and stores the associated interchain account address in state keyed by it's corresponding port identifier -// -// Controller Chain -func (k Keeper) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - if err := types.ValidateVersion(counterpartyVersion); err != nil { - return sdkerrors.Wrap(err, "counterparty version validation failed") - } - - k.SetActiveChannelID(ctx, portID, channelID) - - accAddr, err := types.ParseAddressFromVersion(counterpartyVersion) - if err != nil { - return sdkerrors.Wrapf(err, "expected format , got %s", types.Delimiter, counterpartyVersion) - } - - k.SetInterchainAccountAddress(ctx, portID, accAddr) - - return nil -} - // OnChanOpenConfirm completes the handshake process by setting the active channel in state on the host chain -// -// Host Chain func (k Keeper) OnChanOpenConfirm( ctx sdk.Context, portID, diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go new file mode 100644 index 00000000000..65b9a159945 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go @@ -0,0 +1,268 @@ +package keeper_test + +import ( + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v2/testing" +) + +func (suite *KeeperTestSuite) TestOnChanOpenTry() { + var ( + channel *channeltypes.Channel + path *ibctesting.Path + chanCap *capabilitytypes.Capability + counterpartyVersion string + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", + func() { + path.EndpointB.SetChannel(*channel) + }, + true, + }, + { + "invalid order - UNORDERED", + func() { + channel.Ordering = channeltypes.UNORDERED + }, + false, + }, + { + "invalid port", + func() { + path.EndpointB.ChannelConfig.PortID = "invalid-port-id" + }, + false, + }, + { + "invalid counterparty port", + func() { + channel.Counterparty.PortId = "invalid-port-id" + }, + false, + }, + { + "channel not found", + func() { + path.EndpointB.ChannelID = "invalid-channel-id" + }, + false, + }, + { + "connection not found", + func() { + channel.ConnectionHops = []string{"invalid-connnection-id"} + path.EndpointB.SetChannel(*channel) + }, + false, + }, + { + "invalid connection sequence", + func() { + portID, err := types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-1") + suite.Require().NoError(err) + + channel.Counterparty.PortId = portID + path.EndpointB.SetChannel(*channel) + }, + false, + }, + { + "invalid counterparty connection sequence", + func() { + portID, err := types.GeneratePortID(TestOwnerAddress, "connection-1", "connection-0") + suite.Require().NoError(err) + + channel.Counterparty.PortId = portID + path.EndpointB.SetChannel(*channel) + }, + false, + }, + { + "invalid version", + func() { + channel.Version = "version" + path.EndpointB.SetChannel(*channel) + }, + false, + }, + { + "invalid counterparty version", + func() { + counterpartyVersion = "version" + path.EndpointB.SetChannel(*channel) + }, + false, + }, + { + "capability already claimed", + func() { + path.EndpointB.SetChannel(*channel) + err := suite.chainB.GetSimApp().ScopedICAHostKeeper.ClaimCapability(suite.chainB.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) + suite.Require().NoError(err) + }, + false, + }, + { + "invalid account address", + func() { + portID, err := types.GeneratePortID("invalid-owner-addr", "connection-0", "connection-0") + suite.Require().NoError(err) + + channel.Counterparty.PortId = portID + path.EndpointB.SetChannel(*channel) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + counterpartyVersion = types.VersionPrefix + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + // set the channel id on host + channelSequence := path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(path.EndpointB.Chain.GetContext()) + path.EndpointB.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + + // default values + counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channel = &channeltypes.Channel{ + State: channeltypes.TRYOPEN, + Ordering: channeltypes.ORDERED, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointB.ConnectionID}, + Version: TestVersion, + } + + chanCap, err = suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + err = suite.chainB.GetSimApp().ICAHostKeeper.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.GetConnectionHops(), + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), + counterpartyVersion, + ) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } +} + +func (suite *KeeperTestSuite) TestOnChanOpenConfirm() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + + err = path.EndpointA.ChanOpenAck() + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + err = suite.chainB.GetSimApp().ICAHostKeeper.OnChanOpenConfirm(suite.chainB.GetContext(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } +} + +func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + err = suite.chainB.GetSimApp().ICAHostKeeper.OnChanCloseConfirm(suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + + activeChannelID, found := suite.chainB.GetSimApp().ICAHostKeeper.GetActiveChannelID(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().False(found) + suite.Require().Empty(activeChannelID) + } else { + suite.Require().Error(err) + } + + }) + } +} diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go similarity index 84% rename from modules/apps/27-interchain-accounts/keeper/keeper.go rename to modules/apps/27-interchain-accounts/host/keeper/keeper.go index 2886698b26d..d27962d9d63 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/tendermint/tendermint/libs/log" @@ -17,12 +18,11 @@ import ( host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) -// Keeper defines the IBC interchain account keeper +// Keeper defines the IBC interchain accounts host keeper type Keeper struct { storeKey sdk.StoreKey cdc codec.BinaryCodec - ics4Wrapper types.ICS4Wrapper channelKeeper types.ChannelKeeper portKeeper types.PortKeeper accountKeeper types.AccountKeeper @@ -32,10 +32,9 @@ type Keeper struct { msgRouter *baseapp.MsgServiceRouter } -// NewKeeper creates a new interchain account Keeper instance +// NewKeeper creates a new interchain accounts host Keeper instance func NewKeeper( - cdc codec.BinaryCodec, key sdk.StoreKey, - ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, + cdc codec.BinaryCodec, key sdk.StoreKey, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, accountKeeper types.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, ) Keeper { @@ -47,7 +46,6 @@ func NewKeeper( return Keeper{ storeKey: key, cdc: cdc, - ics4Wrapper: ics4Wrapper, channelKeeper: channelKeeper, portKeeper: portKeeper, accountKeeper: accountKeeper, @@ -61,7 +59,24 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) } -// GetAllPorts returns all ports to which the interchain accounts module is bound. Used in ExportGenesis +// RegisterInterchainAccount attempts to create a new account using the provided address and stores it in state keyed by the provided port identifier +// If an account for the provided address already exists this function returns early (no-op) +func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, accAddr sdk.AccAddress, controllerPortID string) { + if acc := k.accountKeeper.GetAccount(ctx, accAddr); acc != nil { + return + } + + interchainAccount := types.NewInterchainAccount( + authtypes.NewBaseAccountWithAddress(accAddr), + controllerPortID, + ) + + k.accountKeeper.NewAccount(ctx, interchainAccount) + k.accountKeeper.SetAccount(ctx, interchainAccount) + k.SetInterchainAccountAddress(ctx, controllerPortID, interchainAccount.Address) +} + +// GetAllPorts returns all ports to which the interchain accounts host module is bound. Used in ExportGenesis func (k Keeper) GetAllPorts(ctx sdk.Context) []string { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte(types.PortKeyPrefix)) @@ -85,7 +100,7 @@ func (k Keeper) BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capabi return k.portKeeper.BindPort(ctx, portID) } -// IsBound checks if the interchain account module is already bound to the desired port +// IsBound checks if the interchain account host module is already bound to the desired port func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) return ok @@ -113,7 +128,7 @@ func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool return string(store.Get(key)), true } -// GetAllActiveChannels returns a list of all active interchain accounts channels and their associated port identifiers +// GetAllActiveChannels returns a list of all active interchain accounts host channels and their associated port identifiers func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []*types.ActiveChannel { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte(types.ActiveChannelKeyPrefix)) diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go similarity index 73% rename from modules/apps/27-interchain-accounts/keeper/keeper_test.go rename to modules/apps/27-interchain-accounts/host/keeper/keeper_test.go index 92a57e74eec..5285dff0f98 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go @@ -20,7 +20,7 @@ var ( // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes - TestPortID, _ = types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-0") + TestPortID, _ = types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) // TestVersion defines a resuable interchainaccounts version string for testing purposes TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) ) @@ -77,15 +77,15 @@ func SetupICAPath(path *ibctesting.Path, owner string) error { } // InitInterchainAccount is a helper function for starting the channel handshake -// TODO: parse identifiers from events func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { portID, err := types.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) if err != nil { return err } + channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, owner); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, owner); err != nil { return err } @@ -96,6 +96,7 @@ func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { // update port/channel ids endpoint.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) endpoint.ChannelConfig.PortID = portID + return nil } @@ -104,27 +105,37 @@ func TestKeeperTestSuite(t *testing.T) { } func (suite *KeeperTestSuite) TestIsBound() { - isBound := suite.chainA.GetSimApp().ICAKeeper.IsBound(suite.chainA.GetContext(), types.PortID) + suite.SetupTest() + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + isBound := suite.chainB.GetSimApp().ICAHostKeeper.IsBound(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) suite.Require().True(isBound) } func (suite *KeeperTestSuite) TestGetAllPorts() { suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - expectedPorts := []string{types.PortID, TestPortID} + expectedPorts := []string{types.PortID} - ports := suite.chainA.GetSimApp().ICAKeeper.GetAllPorts(suite.chainA.GetContext()) + ports := suite.chainB.GetSimApp().ICAHostKeeper.GetAllPorts(suite.chainB.GetContext()) suite.Require().Len(ports, len(expectedPorts)) suite.Require().Equal(expectedPorts, ports) } func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) @@ -134,11 +145,11 @@ func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { counterpartyPortID := path.EndpointA.ChannelConfig.PortID expectedAddr := authtypes.NewBaseAccountWithAddress(types.GenerateAddress(suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName), counterpartyPortID)).GetAddress() - retrievedAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), counterpartyPortID) + retrievedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), counterpartyPortID) suite.Require().True(found) suite.Require().Equal(expectedAddr.String(), retrievedAddr) - retrievedAddr, found = suite.chainA.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), "invalid port") + retrievedAddr, found = suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), "invalid port") suite.Require().False(found) suite.Require().Empty(retrievedAddr) } @@ -150,18 +161,19 @@ func (suite *KeeperTestSuite) TestGetAllActiveChannels() { ) suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - suite.chainA.GetSimApp().ICAKeeper.SetActiveChannelID(suite.chainA.GetContext(), expectedPortID, expectedChannelID) + suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), expectedPortID, expectedChannelID) expectedChannels := []*types.ActiveChannel{ { - PortId: TestPortID, - ChannelId: path.EndpointA.ChannelID, + PortId: path.EndpointB.ChannelConfig.PortID, + ChannelId: path.EndpointB.ChannelID, }, { PortId: expectedPortID, @@ -169,7 +181,7 @@ func (suite *KeeperTestSuite) TestGetAllActiveChannels() { }, } - activeChannels := suite.chainA.GetSimApp().ICAKeeper.GetAllActiveChannels(suite.chainA.GetContext()) + activeChannels := suite.chainB.GetSimApp().ICAHostKeeper.GetAllActiveChannels(suite.chainB.GetContext()) suite.Require().Len(activeChannels, len(expectedChannels)) suite.Require().Equal(expectedChannels, activeChannels) } @@ -181,13 +193,14 @@ func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() { ) suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr) + suite.chainB.GetSimApp().ICAHostKeeper.SetInterchainAccountAddress(suite.chainB.GetContext(), expectedPortID, expectedAccAddr) expectedAccounts := []*types.RegisteredInterchainAccount{ { @@ -200,23 +213,22 @@ func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() { }, } - interchainAccounts := suite.chainA.GetSimApp().ICAKeeper.GetAllInterchainAccounts(suite.chainA.GetContext()) + interchainAccounts := suite.chainB.GetSimApp().ICAHostKeeper.GetAllInterchainAccounts(suite.chainB.GetContext()) suite.Require().Len(interchainAccounts, len(expectedAccounts)) suite.Require().Equal(expectedAccounts, interchainAccounts) } func (suite *KeeperTestSuite) TestIsActiveChannel() { - suite.SetupTest() // reset + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) - owner := TestOwnerAddress suite.coordinator.SetupConnections(path) - err := suite.SetupICAPath(path, owner) + err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - portID := path.EndpointA.ChannelConfig.PortID - isActive := suite.chainA.GetSimApp().ICAKeeper.IsActiveChannel(suite.chainA.GetContext(), portID) - suite.Require().Equal(isActive, true) + isActive := suite.chainB.GetSimApp().ICAHostKeeper.IsActiveChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().True(isActive) } func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() { @@ -225,29 +237,9 @@ func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() { expectedPortID string = "test-port" ) - suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr) + suite.chainB.GetSimApp().ICAHostKeeper.SetInterchainAccountAddress(suite.chainB.GetContext(), expectedPortID, expectedAccAddr) - retrievedAddr, found := suite.chainA.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID) + retrievedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), expectedPortID) suite.Require().True(found) suite.Require().Equal(expectedAccAddr, retrievedAddr) } - -func (suite *KeeperTestSuite) SetupICAPath(path *ibctesting.Path, owner string) error { - if err := InitInterchainAccount(path.EndpointA, owner); err != nil { - return err - } - - if err := path.EndpointB.ChanOpenTry(); err != nil { - return err - } - - if err := path.EndpointA.ChanOpenAck(); err != nil { - return err - } - - if err := path.EndpointB.ChanOpenConfirm(); err != nil { - return err - } - - return nil -} diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay.go b/modules/apps/27-interchain-accounts/host/keeper/relay.go new file mode 100644 index 00000000000..3c2a603de94 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/keeper/relay.go @@ -0,0 +1,89 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" +) + +// AuthenticateTx ensures the provided msgs contain the correct interchain account signer address retrieved +// from state using the provided controller port identifier +func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portID string) error { + interchainAccountAddr, found := k.GetInterchainAccountAddress(ctx, portID) + if !found { + return sdkerrors.Wrapf(types.ErrInterchainAccountNotFound, "failed to retrieve interchain account on port %s", portID) + } + + for _, msg := range msgs { + for _, signer := range msg.GetSigners() { + if interchainAccountAddr != signer.String() { + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "unexpected signer address: expected %s, got %s", interchainAccountAddr, signer.String()) + } + } + } + + return nil +} + +func (k Keeper) executeTx(ctx sdk.Context, sourcePort, destPort, destChannel string, msgs []sdk.Msg) error { + if err := k.AuthenticateTx(ctx, msgs, sourcePort); err != nil { + return err + } + + for _, msg := range msgs { + if err := msg.ValidateBasic(); err != nil { + return err + } + } + + // CacheContext returns a new context with the multi-store branched into a cached storage object + // writeCache is called only if all msgs succeed, performing state transitions atomically + cacheCtx, writeCache := ctx.CacheContext() + for _, msg := range msgs { + if _, err := k.executeMsg(cacheCtx, msg); err != nil { + return err + } + } + + writeCache() + + return nil +} + +// Attempts to get the message handler from the router and if found will then execute the message +func (k Keeper) executeMsg(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + handler := k.msgRouter.Handler(msg) + if handler == nil { + return nil, types.ErrInvalidRoute + } + + return handler(ctx, msg) +} + +// OnRecvPacket handles a given interchain accounts packet on a destination host chain +func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error { + var data types.InterchainAccountPacketData + + if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + // UnmarshalJSON errors are indeterminate and therefore are not wrapped and included in failed acks + return sdkerrors.Wrapf(types.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain account packet data") + } + + switch data.Type { + case types.EXECUTE_TX: + msgs, err := types.DeserializeCosmosTx(k.cdc, data.Data) + if err != nil { + return err + } + + if err = k.executeTx(ctx, packet.SourcePort, packet.DestinationPort, packet.DestinationChannel, msgs); err != nil { + return err + } + + return nil + default: + return types.ErrUnknownDataType + } +} diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go similarity index 65% rename from modules/apps/27-interchain-accounts/keeper/relay_test.go rename to modules/apps/27-interchain-accounts/host/keeper/relay_test.go index e7741a8903c..7bb47ed88a6 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -6,7 +6,6 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -15,143 +14,9 @@ import ( transfertypes "github.com/cosmos/ibc-go/v2/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) -func (suite *KeeperTestSuite) TestTrySendTx() { - var ( - path *ibctesting.Path - packetData types.InterchainAccountPacketData - chanCap *capabilitytypes.Capability - ) - - testCases := []struct { - msg string - malleate func() - expPass bool - }{ - { - "success", - func() { - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) - - msg := &banktypes.MsgSend{ - FromAddress: interchainAccountAddr, - ToAddress: suite.chainB.SenderAccount.GetAddress().String(), - Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), - } - - data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg}) - suite.Require().NoError(err) - - packetData = types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: data, - } - }, - true, - }, - { - "success with multiple sdk.Msg", - func() { - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) - - msgsBankSend := []sdk.Msg{ - &banktypes.MsgSend{ - FromAddress: interchainAccountAddr, - ToAddress: suite.chainB.SenderAccount.GetAddress().String(), - Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), - }, - &banktypes.MsgSend{ - FromAddress: interchainAccountAddr, - ToAddress: suite.chainB.SenderAccount.GetAddress().String(), - Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), - }, - } - - data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), msgsBankSend) - suite.Require().NoError(err) - - packetData = types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: data, - } - }, - true, - }, - { - "data is nil", - func() { - packetData = types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: nil, - } - }, - false, - }, - { - "active channel not found", - func() { - path.EndpointA.ChannelConfig.PortID = "invalid-port-id" - }, - false, - }, - { - "channel does not exist", - func() { - suite.chainA.GetSimApp().ICAKeeper.SetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, "channel-100") - }, - false, - }, - { - "sendPacket fails - channel closed", - func() { - err := path.EndpointA.SetChannelClosed() - suite.Require().NoError(err) - }, - false, - }, - { - "invalid channel capability provided", - func() { - chanCap = nil - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.msg, func() { - suite.SetupTest() // reset - - path = NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - err := suite.SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - var ok bool - chanCap, ok = suite.chainA.GetSimApp().ScopedICAMockKeeper.GetCapability(path.EndpointA.Chain.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().True(ok) - - tc.malleate() // malleate mutates test data - - _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), chanCap, path.EndpointA.ChannelConfig.PortID, packetData) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - func (suite *KeeperTestSuite) TestOnRecvPacket() { var ( path *ibctesting.Path @@ -166,7 +31,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "interchain account successfully executes banktypes.MsgSend", func() { - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) msg := &banktypes.MsgSend{ @@ -190,7 +55,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "interchain account successfully executes stakingtypes.MsgDelegate", func() { - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) @@ -215,7 +80,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "interchain account successfully executes stakingtypes.MsgDelegate and stakingtypes.MsgUndelegate sequentially", func() { - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) @@ -246,7 +111,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "interchain account successfully executes govtypes.MsgSubmitProposal", func() { - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) testProposal := &govtypes.TextProposal{ @@ -278,7 +143,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "interchain account successfully executes govtypes.MsgVote", func() { - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) // Populate the gov keeper in advance with an active proposal @@ -314,7 +179,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "interchain account successfully executes disttypes.MsgFundCommunityPool", func() { - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) msg := &disttypes.MsgFundCommunityPool{ @@ -337,7 +202,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "interchain account successfully executes disttypes.MsgSetWithdrawAddress", func() { - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) msg := &disttypes.MsgSetWithdrawAddress{ @@ -366,7 +231,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { suite.coordinator.Setup(transferPath) - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) msg := &transfertypes.MsgTransfer{ @@ -476,7 +341,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { path = NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) - err := suite.SetupICAPath(path, TestOwnerAddress) + err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) suite.fundICAWallet(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10000)))) @@ -494,65 +359,10 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { 0, ) - err = suite.chainB.GetSimApp().ICAKeeper.OnRecvPacket(suite.chainB.GetContext(), packet) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -func (suite *KeeperTestSuite) TestOnTimeoutPacket() { - var ( - path *ibctesting.Path - ) - - testCases := []struct { - msg string - malleate func() - expPass bool - }{ - { - "success", - func() {}, - true, - }, - } - - for _, tc := range testCases { - suite.Run(tc.msg, func() { - suite.SetupTest() // reset - - path = NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - err := suite.SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - tc.malleate() // malleate mutates test data - - packet := channeltypes.NewPacket( - []byte{}, - 1, - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - clienttypes.NewHeight(0, 100), - 0, - ) - - err = suite.chainA.GetSimApp().ICAKeeper.OnTimeoutPacket(suite.chainA.GetContext(), packet) - - activeChannelID, found := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + err = suite.chainB.GetSimApp().ICAHostKeeper.OnRecvPacket(suite.chainB.GetContext(), packet) if tc.expPass { suite.Require().NoError(err) - suite.Require().Empty(activeChannelID) - suite.Require().False(found) } else { suite.Require().Error(err) } @@ -561,7 +371,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { } func (suite *KeeperTestSuite) fundICAWallet(ctx sdk.Context, portID string, amount sdk.Coins) { - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(ctx, portID) + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(ctx, portID) suite.Require().True(found) msgBankSend := &banktypes.MsgSend{ diff --git a/modules/apps/27-interchain-accounts/host/types/keys.go b/modules/apps/27-interchain-accounts/host/types/keys.go new file mode 100644 index 00000000000..284284980e4 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/types/keys.go @@ -0,0 +1,9 @@ +package types + +const ( + // ModuleName defines the interchain accounts host module name + ModuleName = "icahost" + + // StoreKey is the store key string for the interchain accounts host module + StoreKey = ModuleName +) diff --git a/modules/apps/27-interchain-accounts/keeper/account.go b/modules/apps/27-interchain-accounts/keeper/account.go deleted file mode 100644 index 0c14be4ea97..00000000000 --- a/modules/apps/27-interchain-accounts/keeper/account.go +++ /dev/null @@ -1,58 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v2/modules/core/24-host" -) - -// InitInterchainAccount is the entry point to registering an interchain account. -// It generates a new port identifier using the owner address, connection identifier, -// and counterparty connection identifier. It will bind to the port identifier and -// call 04-channel 'ChanOpenInit'. An error is returned if the port identifier is -// already in use. Gaining access to interchain accounts whose channels have closed -// cannot be done with this function. A regular MsgChanOpenInit must be used. -func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpartyConnectionID, owner string) error { - portID, err := types.GeneratePortID(owner, connectionID, counterpartyConnectionID) - if err != nil { - return err - } - - if k.portKeeper.IsBound(ctx, portID) { - return sdkerrors.Wrap(types.ErrPortAlreadyBound, portID) - } - - cap := k.BindPort(ctx, portID) - if err := k.ClaimCapability(ctx, cap, host.PortPath(portID)); err != nil { - return sdkerrors.Wrap(err, "unable to bind to newly generated portID") - } - - msg := channeltypes.NewMsgChannelOpenInit(portID, types.VersionPrefix, channeltypes.ORDERED, []string{connectionID}, types.PortID, types.ModuleName) - handler := k.msgRouter.Handler(msg) - if _, err := handler(ctx, msg); err != nil { - return err - } - - return nil -} - -// RegisterInterchainAccount attempts to create a new account using the provided address and stores it in state keyed by the provided port identifier -// If an account for the provided address already exists this function returns early (no-op) -func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, accAddr sdk.AccAddress, controllerPortID string) { - if acc := k.accountKeeper.GetAccount(ctx, accAddr); acc != nil { - return - } - - interchainAccount := types.NewInterchainAccount( - authtypes.NewBaseAccountWithAddress(accAddr), - controllerPortID, - ) - - k.accountKeeper.NewAccount(ctx, interchainAccount) - k.accountKeeper.SetAccount(ctx, interchainAccount) - k.SetInterchainAccountAddress(ctx, controllerPortID, interchainAccount.Address) -} diff --git a/modules/apps/27-interchain-accounts/keeper/account_test.go b/modules/apps/27-interchain-accounts/keeper/account_test.go deleted file mode 100644 index fceea5eb48b..00000000000 --- a/modules/apps/27-interchain-accounts/keeper/account_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package keeper_test - -import ( - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" - ibctesting "github.com/cosmos/ibc-go/v2/testing" -) - -func (suite *KeeperTestSuite) TestInitInterchainAccount() { - var ( - owner string - path *ibctesting.Path - err error - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success", func() {}, true, - }, - { - "port is already bound", - func() { - suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), TestPortID) - }, - false, - }, - { - "fails to generate port-id", - func() { - owner = "" - }, - false, - }, - { - "MsgChanOpenInit fails - channel is already active", - func() { - portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - suite.Require().NoError(err) - suite.chainA.GetSimApp().ICAKeeper.SetActiveChannelID(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID) - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - owner = TestOwnerAddress // must be explicitly changed - path = NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - tc.malleate() // explicitly change fields in channel and testChannel - - err = suite.chainA.GetSimApp().ICAKeeper.InitInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, path.EndpointB.ConnectionID, owner) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - - }) - } -} diff --git a/modules/apps/27-interchain-accounts/keeper/grpc_query.go b/modules/apps/27-interchain-accounts/keeper/grpc_query.go deleted file mode 100644 index 1d110916202..00000000000 --- a/modules/apps/27-interchain-accounts/keeper/grpc_query.go +++ /dev/null @@ -1,34 +0,0 @@ -package keeper - -import ( - "context" - "strings" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" -) - -var _ types.QueryServer = Keeper{} - -// InterchainAccount implements the Query/InterchainAccount gRPC method -func (k Keeper) InterchainAccountAddress(ctx context.Context, req *types.QueryInterchainAccountAddressRequest) (*types.QueryInterchainAccountAddressResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "empty request") - } - - if strings.TrimSpace(req.CounterpartyPortId) == "" { - return nil, status.Error(codes.InvalidArgument, "counterparty portID cannot be empty") - } - - interchainAccountAddress, found := k.GetInterchainAccountAddress(sdk.UnwrapSDKContext(ctx), req.CounterpartyPortId) - if !found { - return nil, status.Error(codes.NotFound, sdkerrors.Wrap(types.ErrInterchainAccountNotFound, req.CounterpartyPortId).Error()) - } - - return &types.QueryInterchainAccountAddressResponse{InterchainAccountAddress: interchainAccountAddress}, nil -} diff --git a/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go b/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go deleted file mode 100644 index d514d6bbc34..00000000000 --- a/modules/apps/27-interchain-accounts/keeper/grpc_query_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package keeper_test - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" -) - -func (suite *KeeperTestSuite) TestQueryInterchainAccountAddress() { - var ( - req *types.QueryInterchainAccountAddressRequest - expAddr string - ) - - testCases := []struct { - msg string - malleate func() - expPass bool - }{ - { - "empty request", - func() { - req = nil - }, - false, - }, - { - "invalid counterparty portID", - func() { - req = &types.QueryInterchainAccountAddressRequest{ - CounterpartyPortId: " ", - } - }, - false, - }, - { - "interchain account address not found", - func() { - req = &types.QueryInterchainAccountAddressRequest{ - CounterpartyPortId: "ics-27", - } - }, - false, - }, - { - "success", - func() { - expAddr = authtypes.NewBaseAccountWithAddress(types.GenerateAddress(TestAccAddress, TestPortID)).GetAddress().String() - req = &types.QueryInterchainAccountAddressRequest{ - CounterpartyPortId: TestPortID, - } - - suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), TestPortID, expAddr) - }, - true, - }, - } - - for _, tc := range testCases { - suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { - suite.SetupTest() // reset - - tc.malleate() - ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) - - res, err := suite.chainA.GetSimApp().ICAKeeper.InterchainAccountAddress(ctx, req) - - if tc.expPass { - suite.Require().NoError(err) - suite.Require().NotNil(res) - suite.Require().Equal(expAddr, res.GetInterchainAccountAddress()) - } else { - suite.Require().Error(err) - } - }) - } -} diff --git a/modules/apps/27-interchain-accounts/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/keeper/handshake_test.go deleted file mode 100644 index cf27023831c..00000000000 --- a/modules/apps/27-interchain-accounts/keeper/handshake_test.go +++ /dev/null @@ -1,465 +0,0 @@ -package keeper_test - -import ( - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v2/modules/core/24-host" - ibctesting "github.com/cosmos/ibc-go/v2/testing" -) - -func (suite *KeeperTestSuite) TestOnChanOpenInit() { - var ( - channel *channeltypes.Channel - path *ibctesting.Path - chanCap *capabilitytypes.Capability - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - - { - "success", - func() { - path.EndpointA.SetChannel(*channel) - }, - true, - }, - { - "invalid order - UNORDERED", - func() { - channel.Ordering = channeltypes.UNORDERED - }, - false, - }, - { - "invalid port ID", - func() { - path.EndpointA.ChannelConfig.PortID = "invalid-port-id" - }, - false, - }, - { - "invalid counterparty port ID", - func() { - path.EndpointA.SetChannel(*channel) - channel.Counterparty.PortId = "invalid-port-id" - }, - false, - }, - { - "invalid version", - func() { - path.EndpointA.SetChannel(*channel) - channel.Version = "version" - }, - false, - }, - { - "channel not found", - func() { - path.EndpointA.ChannelID = "invalid-channel-id" - }, - false, - }, - { - "connection not found", - func() { - channel.ConnectionHops = []string{"invalid-connnection-id"} - path.EndpointA.SetChannel(*channel) - }, - false, - }, - { - "invalid connection sequence", - func() { - portID, err := types.GeneratePortID(TestOwnerAddress, "connection-1", "connection-0") - suite.Require().NoError(err) - - path.EndpointA.ChannelConfig.PortID = portID - path.EndpointA.SetChannel(*channel) - }, - false, - }, - { - "invalid counterparty connection sequence", - func() { - portID, err := types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-1") - suite.Require().NoError(err) - - path.EndpointA.ChannelConfig.PortID = portID - path.EndpointA.SetChannel(*channel) - }, - false, - }, - { - "channel is already active", - func() { - suite.chainA.GetSimApp().ICAKeeper.SetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - // mock init interchain account - portID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - suite.Require().NoError(err) - portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) - suite.chainA.GetSimApp().ICAKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) - path.EndpointA.ChannelConfig.PortID = portID - - // default values - counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - channel = &channeltypes.Channel{ - State: channeltypes.INIT, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: types.VersionPrefix, - } - - chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(portID, path.EndpointA.ChannelID)) - suite.Require().NoError(err) - - tc.malleate() // explicitly change fields in channel and testChannel - - err = suite.chainA.GetSimApp().ICAKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - - }) - } -} - -func (suite *KeeperTestSuite) TestOnChanOpenTry() { - var ( - channel *channeltypes.Channel - path *ibctesting.Path - chanCap *capabilitytypes.Capability - counterpartyVersion string - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - - { - "success", - func() { - path.EndpointB.SetChannel(*channel) - }, - true, - }, - { - "invalid order - UNORDERED", - func() { - channel.Ordering = channeltypes.UNORDERED - }, - false, - }, - { - "invalid port", - func() { - path.EndpointB.ChannelConfig.PortID = "invalid-port-id" - }, - false, - }, - { - "invalid counterparty port", - func() { - channel.Counterparty.PortId = "invalid-port-id" - }, - false, - }, - { - "channel not found", - func() { - path.EndpointB.ChannelID = "invalid-channel-id" - }, - false, - }, - { - "connection not found", - func() { - channel.ConnectionHops = []string{"invalid-connnection-id"} - path.EndpointB.SetChannel(*channel) - }, - false, - }, - { - "invalid connection sequence", - func() { - portID, err := types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-1") - suite.Require().NoError(err) - - channel.Counterparty.PortId = portID - path.EndpointB.SetChannel(*channel) - }, - false, - }, - { - "invalid counterparty connection sequence", - func() { - portID, err := types.GeneratePortID(TestOwnerAddress, "connection-1", "connection-0") - suite.Require().NoError(err) - - channel.Counterparty.PortId = portID - path.EndpointB.SetChannel(*channel) - }, - false, - }, - { - "invalid version", - func() { - channel.Version = "version" - path.EndpointB.SetChannel(*channel) - }, - false, - }, - { - "invalid counterparty version", - func() { - counterpartyVersion = "version" - path.EndpointB.SetChannel(*channel) - }, - false, - }, - { - "capability already claimed", - func() { - path.EndpointB.SetChannel(*channel) - err := suite.chainB.GetSimApp().ScopedICAKeeper.ClaimCapability(suite.chainB.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) - suite.Require().NoError(err) - }, - false, - }, - { - "invalid account address", - func() { - portID, err := types.GeneratePortID("invalid-owner-addr", "connection-0", "connection-0") - suite.Require().NoError(err) - - channel.Counterparty.PortId = portID - path.EndpointB.SetChannel(*channel) - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB) - counterpartyVersion = types.VersionPrefix - suite.coordinator.SetupConnections(path) - - err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) - - // set the channel id on host - channelSequence := path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(path.EndpointB.Chain.GetContext()) - path.EndpointB.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) - - // default values - counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - channel = &channeltypes.Channel{ - State: channeltypes.TRYOPEN, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointB.ConnectionID}, - Version: TestVersion, - } - - chanCap, err = suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) - suite.Require().NoError(err) - - tc.malleate() // explicitly change fields in channel and testChannel - - err = suite.chainB.GetSimApp().ICAKeeper.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.GetConnectionHops(), - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), - counterpartyVersion, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - - }) - } -} - -// ChainA is controller, ChainB is host chain -func (suite *KeeperTestSuite) TestOnChanOpenAck() { - var ( - path *ibctesting.Path - expectedChannelID string - counterpartyVersion string - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success", func() {}, true, - }, - { - "invalid counterparty version", func() { - expectedChannelID = "" - counterpartyVersion = "version" - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB) - counterpartyVersion = TestVersion - suite.coordinator.SetupConnections(path) - - err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) - - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) - expectedChannelID = path.EndpointA.ChannelID - - tc.malleate() // explicitly change fields in channel and testChannel - - err = suite.chainA.GetSimApp().ICAKeeper.OnChanOpenAck(suite.chainA.GetContext(), - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyVersion, - ) - - activeChannelID, _ := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - - suite.Require().Equal(activeChannelID, expectedChannelID) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// ChainA is controller, ChainB is host chain -func (suite *KeeperTestSuite) TestOnChanOpenConfirm() { - var ( - path *ibctesting.Path - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - - { - "success", func() {}, true, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) - - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) - - err = path.EndpointA.ChanOpenAck() - suite.Require().NoError(err) - - tc.malleate() // explicitly change fields in channel and testChannel - - err = suite.chainB.GetSimApp().ICAKeeper.OnChanOpenConfirm(suite.chainB.GetContext(), - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - - }) - } -} - -func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { - var ( - path *ibctesting.Path - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - - { - "success", func() {}, true, - }, - } - - for _, tc := range testCases { - suite.Run(tc.name, func() { - suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - tc.malleate() // explicitly change fields in channel and testChannel - - err = suite.chainB.GetSimApp().ICAKeeper.OnChanCloseConfirm(suite.chainB.GetContext(), - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - - activeChannelID, found := suite.chainB.GetSimApp().ICAKeeper.GetActiveChannelID(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - - if tc.expPass { - suite.Require().NoError(err) - suite.Require().False(found) - suite.Require().Empty(activeChannelID) - } else { - suite.Require().Error(err) - } - - }) - } -} diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 8e83463aef9..ed3a09c358d 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -1,4 +1,4 @@ -package interchain_accounts +package ica import ( "encoding/json" @@ -14,20 +14,26 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/runtime" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/client/cli" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller" + controllerkeeper "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host" + hostkeeper "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/keeper" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" ) var ( _ module.AppModule = AppModule{} - _ porttypes.IBCModule = IBCModule{} _ module.AppModuleBasic = AppModuleBasic{} + + _ porttypes.IBCModule = controller.IBCModule{} + _ porttypes.IBCModule = host.IBCModule{} ) +// AppModuleBasic is the IBC interchain accounts AppModuleBasic type AppModuleBasic struct{} +// Name implements AppModuleBasic interface func (AppModuleBasic) Name() string { return types.ModuleName } @@ -37,60 +43,70 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { types.RegisterLegacyAminoCodec(cdc) } +// RegisterInterfaces registers module concrete types into protobuf Any +func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { + types.RegisterInterfaces(registry) +} + +// DefaultGenesis returns default genesis state as raw bytes for the IBC +// interchain accounts module func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesis()) } +// ValidateGenesis performs genesis state validation for the IBC interchain acounts module func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { return nil } +// RegisterRESTRoutes implements AppModuleBasic interface func (AppModuleBasic) RegisterRESTRoutes(ctx client.Context, rtr *mux.Router) { - // noop } +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the interchain accounts module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { +} + +// GetTxCmd implements AppModuleBasic interface func (AppModuleBasic) GetTxCmd() *cobra.Command { - // noop return nil } +// GetQueryCmd implements AppModuleBasic interface func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return cli.GetQueryCmd() -} - -// RegisterInterfaces registers module concrete types into protobuf Any. -func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { - types.RegisterInterfaces(registry) -} - -// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the interchain accounts module. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + return nil } +// AppModule is the application module for the IBC interchain accounts module type AppModule struct { AppModuleBasic - keeper keeper.Keeper + controllerKeeper *controllerkeeper.Keeper + hostKeeper *hostkeeper.Keeper } -// NewAppModule creates an interchain accounts app module. -func NewAppModule(k keeper.Keeper) AppModule { +// NewAppModule creates a new IBC interchain accounts module +func NewAppModule(controllerKeeper *controllerkeeper.Keeper, hostKeeper *hostkeeper.Keeper) AppModule { return AppModule{ - keeper: k, + controllerKeeper: controllerKeeper, + hostKeeper: hostKeeper, } } +// RegisterInvariants implements the AppModule interface func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - // TODO } +// Route implements the AppModule interface func (AppModule) Route() sdk.Route { return sdk.NewRoute(types.RouterKey, nil) } +// NewHandler implements the AppModule interface func (AppModule) NewHandler() sdk.Handler { return nil } +// QuerierRoute implements the AppModule interface func (AppModule) QuerierRoute() string { return types.QuerierRoute } @@ -100,22 +116,44 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd return nil } -// RegisterServices registers a GRPC query service to respond to the -// module-specific GRPC queries. +// RegisterServices registers module services func (am AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterQueryServer(cfg.QueryServer(), am.keeper) } +// InitGenesis performs genesis initialization for the interchain accounts module. +// It returns no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, genesisState) + if am.controllerKeeper != nil { + controllerkeeper.InitGenesis(ctx, *am.controllerKeeper, *genesisState.ControllerGenesisState) + } + + if am.hostKeeper != nil { + hostkeeper.InitGenesis(ctx, *am.hostKeeper, *genesisState.HostGenesisState) + } + return []abci.ValidatorUpdate{} } +// ExportGenesis returns the exported genesis state as raw bytes for the interchain accounts module func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { - gs := ExportGenesis(ctx, am.keeper) + var ( + controllerGenesisState *types.ControllerGenesisState + hostGenesisState *types.HostGenesisState + ) + + if am.controllerKeeper != nil { + controllerGenesisState = controllerkeeper.ExportGenesis(ctx, *am.controllerKeeper) + } + + if am.hostKeeper != nil { + hostGenesisState = hostkeeper.ExportGenesis(ctx, *am.hostKeeper) + } + + gs := types.NewGenesisState(controllerGenesisState, hostGenesisState) + return cdc.MustMarshalJSON(gs) } @@ -124,7 +162,6 @@ func (AppModule) ConsensusVersion() uint64 { return 1 } // BeginBlock implements the AppModule interface func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { - } // EndBlock implements the AppModule interface diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index 87cd0634900..e55c57f3b35 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -2,7 +2,6 @@ package types import ( "encoding/json" - "fmt" "strings" crypto "github.com/cosmos/cosmos-sdk/crypto/types" @@ -11,54 +10,34 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" yaml "gopkg.in/yaml.v2" +) - connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" +var ( + _ authtypes.GenesisAccount = (*InterchainAccount)(nil) + _ InterchainAccountI = (*InterchainAccount)(nil) ) -// GenerateAddress returns an sdk.AccAddress derived using the provided module account address and port identifier. -// The sdk.AccAddress returned is a sub-address of the module account, using the controller chain's port identifier as the derivation key -func GenerateAddress(moduleAccAddr sdk.AccAddress, portID string) sdk.AccAddress { - return sdk.AccAddress(sdkaddress.Derive(moduleAccAddr, []byte(portID))) +// InterchainAccountI wraps the authtypes.AccountI interface +type InterchainAccountI interface { + authtypes.AccountI } -// GeneratePortID generates the portID for a specific owner -// on the controller chain in the format: -// -// 'ics-27---' -// https://github.com/seantking/ibc/tree/sean/ics-27-updates/spec/app/ics-027-interchain-accounts#registering--controlling-flows -// TODO: update link to spec -func GeneratePortID(owner, connectionID, counterpartyConnectionID string) (string, error) { - if strings.TrimSpace(owner) == "" { - return "", sdkerrors.Wrap(ErrInvalidAccountAddress, "owner address cannot be empty") - } - - connectionSeq, err := connectiontypes.ParseConnectionSequence(connectionID) - if err != nil { - return "", sdkerrors.Wrap(err, "invalid connection identifier") - } - - counterpartyConnectionSeq, err := connectiontypes.ParseConnectionSequence(counterpartyConnectionID) - if err != nil { - return "", sdkerrors.Wrap(err, "invalid counterparty connection identifier") - } - - return fmt.Sprint( - VersionPrefix, Delimiter, - connectionSeq, Delimiter, - counterpartyConnectionSeq, Delimiter, - owner, - ), nil +// interchainAccountPretty defines an unexported struct used for encoding the InterchainAccount details +type interchainAccountPretty struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + PubKey string `json:"public_key" yaml:"public_key"` + AccountNumber uint64 `json:"account_number" yaml:"account_number"` + Sequence uint64 `json:"sequence" yaml:"sequence"` + AccountOwner string `json:"account_owner" yaml:"account_owner"` } -type InterchainAccountI interface { - authtypes.AccountI +// GenerateAddress returns an sdk.AccAddress derived using the provided module account address and port identifier. +// The sdk.AccAddress returned is a sub-address of the module account, using the controller chain's port identifier as the derivation key +func GenerateAddress(moduleAccAddr sdk.AccAddress, portID string) sdk.AccAddress { + return sdk.AccAddress(sdkaddress.Derive(moduleAccAddr, []byte(portID))) } -var ( - _ authtypes.GenesisAccount = (*InterchainAccount)(nil) - _ InterchainAccountI = (*InterchainAccount)(nil) -) - +// NewInterchainAccount creates and returns a new InterchainAccount type func NewInterchainAccount(ba *authtypes.BaseAccount, accountOwner string) *InterchainAccount { return &InterchainAccount{ BaseAccount: ba, @@ -66,16 +45,17 @@ func NewInterchainAccount(ba *authtypes.BaseAccount, accountOwner string) *Inter } } -// SetPubKey - Implements AccountI +// SetPubKey implements the authtypes.AccountI interface func (ia InterchainAccount) SetPubKey(pubKey crypto.PubKey) error { return sdkerrors.Wrap(ErrUnsupported, "cannot set public key for interchain account") } -// SetSequence - Implements AccountI +// SetSequence implements the authtypes.AccountI interface func (ia InterchainAccount) SetSequence(seq uint64) error { return sdkerrors.Wrap(ErrUnsupported, "cannot set sequence number for interchain account") } +// Validate implements basic validation of the InterchainAccount func (ia InterchainAccount) Validate() error { if strings.TrimSpace(ia.AccountOwner) == "" { return sdkerrors.Wrap(ErrInvalidAccountAddress, "AccountOwner cannot be empty") @@ -84,20 +64,13 @@ func (ia InterchainAccount) Validate() error { return ia.BaseAccount.Validate() } -type interchainAccountPretty struct { - Address sdk.AccAddress `json:"address" yaml:"address"` - PubKey string `json:"public_key" yaml:"public_key"` - AccountNumber uint64 `json:"account_number" yaml:"account_number"` - Sequence uint64 `json:"sequence" yaml:"sequence"` - AccountOwner string `json:"account_owner" yaml:"account_owner"` -} - +// String returns a string representation of the InterchainAccount func (ia InterchainAccount) String() string { out, _ := ia.MarshalYAML() return string(out) } -// MarshalYAML returns the YAML representation of an InterchainAccount +// MarshalYAML returns the YAML representation of the InterchainAccount func (ia InterchainAccount) MarshalYAML() ([]byte, error) { accAddr, err := sdk.AccAddressFromBech32(ia.Address) if err != nil { @@ -119,7 +92,7 @@ func (ia InterchainAccount) MarshalYAML() ([]byte, error) { return bz, nil } -// MarshalJSON returns the JSON representation of an InterchainAccount. +// MarshalJSON returns the JSON representation of the InterchainAccount func (ia InterchainAccount) MarshalJSON() ([]byte, error) { accAddr, err := sdk.AccAddressFromBech32(ia.Address) if err != nil { @@ -141,7 +114,7 @@ func (ia InterchainAccount) MarshalJSON() ([]byte, error) { return bz, nil } -// UnmarshalJSON unmarshals raw JSON bytes into a ModuleAccount. +// UnmarshalJSON unmarshals raw JSON bytes into the InterchainAccount func (ia *InterchainAccount) UnmarshalJSON(bz []byte) error { var alias interchainAccountPretty if err := json.Unmarshal(bz, &alias); err != nil { diff --git a/modules/apps/27-interchain-accounts/types/account_test.go b/modules/apps/27-interchain-accounts/types/account_test.go index 751bc0f0fa6..b3ad5a37b1f 100644 --- a/modules/apps/27-interchain-accounts/types/account_test.go +++ b/modules/apps/27-interchain-accounts/types/account_test.go @@ -49,80 +49,6 @@ func (suite *TypesTestSuite) TestGenerateAddress() { suite.Require().NotEmpty(accAddr) } -func (suite *TypesTestSuite) TestGeneratePortID() { - var ( - path *ibctesting.Path - owner = TestOwnerAddress - ) - - testCases := []struct { - name string - malleate func() - expValue string - expPass bool - }{ - { - "success", - func() {}, - fmt.Sprint(types.VersionPrefix, types.Delimiter, "0", types.Delimiter, "0", types.Delimiter, TestOwnerAddress), - true, - }, - { - "success with non matching connection sequences", - func() { - path.EndpointA.ConnectionID = "connection-1" - }, - fmt.Sprint(types.VersionPrefix, types.Delimiter, "1", types.Delimiter, "0", types.Delimiter, TestOwnerAddress), - true, - }, - { - "invalid connectionID", - func() { - path.EndpointA.ConnectionID = "connection" - }, - "", - false, - }, - { - "invalid counterparty connectionID", - func() { - path.EndpointB.ConnectionID = "connection" - }, - "", - false, - }, - { - "invalid owner address", - func() { - owner = " " - }, - "", - false, - }, - } - - for _, tc := range testCases { - tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset - path = ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.Setup(path) - - tc.malleate() - - portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - - if tc.expPass { - suite.Require().NoError(err, tc.name) - suite.Require().Equal(tc.expValue, portID) - } else { - suite.Require().Error(err, tc.name) - suite.Require().Empty(portID) - } - }) - } -} - func (suite *TypesTestSuite) TestInterchainAccount() { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) diff --git a/modules/apps/27-interchain-accounts/types/codec.go b/modules/apps/27-interchain-accounts/types/codec.go index d5cfa419219..971554a83e4 100644 --- a/modules/apps/27-interchain-accounts/types/codec.go +++ b/modules/apps/27-interchain-accounts/types/codec.go @@ -8,6 +8,11 @@ import ( ) var ( + // ModuleCdc references the global interchain accounts module codec. Note, the codec + // should ONLY be used in certain instances of tests and for JSON encoding. + // + // The actual codec used for serialization should be provided to interchain accounts and + // defined at the application level. ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) ) diff --git a/modules/apps/27-interchain-accounts/types/errors.go b/modules/apps/27-interchain-accounts/types/errors.go index 7b4bfe5d8d1..6061c6ae243 100644 --- a/modules/apps/27-interchain-accounts/types/errors.go +++ b/modules/apps/27-interchain-accounts/types/errors.go @@ -8,7 +8,7 @@ var ( ErrUnknownDataType = sdkerrors.Register(ModuleName, 2, "unknown data type") ErrAccountAlreadyExist = sdkerrors.Register(ModuleName, 3, "account already exist") ErrPortAlreadyBound = sdkerrors.Register(ModuleName, 4, "port is already bound") - ErrUnsupportedChain = sdkerrors.Register(ModuleName, 5, "unsupported chain") + ErrInvalidChannelFlow = sdkerrors.Register(ModuleName, 5, "invalid message sent to channel end") ErrInvalidOutgoingData = sdkerrors.Register(ModuleName, 6, "invalid outgoing data") ErrInvalidRoute = sdkerrors.Register(ModuleName, 7, "invalid route") ErrInterchainAccountNotFound = sdkerrors.Register(ModuleName, 8, "interchain account not found") diff --git a/modules/apps/27-interchain-accounts/types/genesis.go b/modules/apps/27-interchain-accounts/types/genesis.go index f98ce12caa6..757f152a149 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.go +++ b/modules/apps/27-interchain-accounts/types/genesis.go @@ -1,18 +1,47 @@ package types -// DefaultGenesis creates and returns the default interchain accounts GenesisState -// The default GenesisState includes the standard port identifier to which all host chains must bind +// DefaultGenesis creates and returns the interchain accounts GenesisState func DefaultGenesis() *GenesisState { return &GenesisState{ - Ports: []string{PortID}, + ControllerGenesisState: DefaultControllerGenesis(), + HostGenesisState: DefaultHostGenesis(), } } -// NewGenesisState creates a returns a new GenesisState instance -func NewGenesisState(ports []string, channels []*ActiveChannel, accounts []*RegisteredInterchainAccount) *GenesisState { +// NewGenesisState creates and returns a new GenesisState instance from the provided controller and host genesis state types +func NewGenesisState(controllerGenesisState *ControllerGenesisState, hostGenesisState *HostGenesisState) *GenesisState { return &GenesisState{ + ControllerGenesisState: controllerGenesisState, + HostGenesisState: hostGenesisState, + } +} + +// DefaultControllerGenesis creates and returns the default interchain accounts ControllerGenesisState +func DefaultControllerGenesis() *ControllerGenesisState { + return &ControllerGenesisState{} +} + +// NewControllerGenesisState creates a returns a new ControllerGenesisState instance +func NewControllerGenesisState(channels []*ActiveChannel, accounts []*RegisteredInterchainAccount, ports []string) *ControllerGenesisState { + return &ControllerGenesisState{ ActiveChannels: channels, InterchainAccounts: accounts, Ports: ports, } } + +// DefaultHostGenesis creates and returns the default interchain accounts HostGenesisState +func DefaultHostGenesis() *HostGenesisState { + return &HostGenesisState{ + Port: PortID, + } +} + +// NewHostGenesisState creates a returns a new HostGenesisState instance +func NewHostGenesisState(channels []*ActiveChannel, accounts []*RegisteredInterchainAccount, port string) *HostGenesisState { + return &HostGenesisState{ + ActiveChannels: channels, + InterchainAccounts: accounts, + Port: port, + } +} diff --git a/modules/apps/27-interchain-accounts/types/genesis.pb.go b/modules/apps/27-interchain-accounts/types/genesis.pb.go index 32d38337ac1..3faa19c0d88 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.pb.go +++ b/modules/apps/27-interchain-accounts/types/genesis.pb.go @@ -25,9 +25,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GenesisState defines the interchain accounts genesis state type GenesisState struct { - ActiveChannels []*ActiveChannel `protobuf:"bytes,1,rep,name=active_channels,json=activeChannels,proto3" json:"active_channels,omitempty" yaml:"active_channels"` - InterchainAccounts []*RegisteredInterchainAccount `protobuf:"bytes,2,rep,name=interchain_accounts,json=interchainAccounts,proto3" json:"interchain_accounts,omitempty" yaml:"interchain_accounts"` - Ports []string `protobuf:"bytes,3,rep,name=ports,proto3" json:"ports,omitempty"` + ControllerGenesisState *ControllerGenesisState `protobuf:"bytes,1,opt,name=controller_genesis_state,json=controllerGenesisState,proto3" json:"controller_genesis_state,omitempty" yaml:"controller_genesis_state"` + HostGenesisState *HostGenesisState `protobuf:"bytes,2,opt,name=host_genesis_state,json=hostGenesisState,proto3" json:"host_genesis_state,omitempty" yaml:"host_genesis_state"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -63,27 +62,142 @@ func (m *GenesisState) XXX_DiscardUnknown() { var xxx_messageInfo_GenesisState proto.InternalMessageInfo -func (m *GenesisState) GetActiveChannels() []*ActiveChannel { +func (m *GenesisState) GetControllerGenesisState() *ControllerGenesisState { + if m != nil { + return m.ControllerGenesisState + } + return nil +} + +func (m *GenesisState) GetHostGenesisState() *HostGenesisState { + if m != nil { + return m.HostGenesisState + } + return nil +} + +// ControllerGenesisState defines the interchain accounts controller genesis state +type ControllerGenesisState struct { + ActiveChannels []*ActiveChannel `protobuf:"bytes,1,rep,name=active_channels,json=activeChannels,proto3" json:"active_channels,omitempty" yaml:"active_channels"` + InterchainAccounts []*RegisteredInterchainAccount `protobuf:"bytes,2,rep,name=interchain_accounts,json=interchainAccounts,proto3" json:"interchain_accounts,omitempty" yaml:"interchain_accounts"` + Ports []string `protobuf:"bytes,3,rep,name=ports,proto3" json:"ports,omitempty"` +} + +func (m *ControllerGenesisState) Reset() { *m = ControllerGenesisState{} } +func (m *ControllerGenesisState) String() string { return proto.CompactTextString(m) } +func (*ControllerGenesisState) ProtoMessage() {} +func (*ControllerGenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_629b3ced0911516b, []int{1} +} +func (m *ControllerGenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ControllerGenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ControllerGenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ControllerGenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_ControllerGenesisState.Merge(m, src) +} +func (m *ControllerGenesisState) XXX_Size() int { + return m.Size() +} +func (m *ControllerGenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_ControllerGenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_ControllerGenesisState proto.InternalMessageInfo + +func (m *ControllerGenesisState) GetActiveChannels() []*ActiveChannel { if m != nil { return m.ActiveChannels } return nil } -func (m *GenesisState) GetInterchainAccounts() []*RegisteredInterchainAccount { +func (m *ControllerGenesisState) GetInterchainAccounts() []*RegisteredInterchainAccount { if m != nil { return m.InterchainAccounts } return nil } -func (m *GenesisState) GetPorts() []string { +func (m *ControllerGenesisState) GetPorts() []string { if m != nil { return m.Ports } return nil } +// HostGenesisState defines the interchain accounts host genesis state +type HostGenesisState struct { + ActiveChannels []*ActiveChannel `protobuf:"bytes,1,rep,name=active_channels,json=activeChannels,proto3" json:"active_channels,omitempty" yaml:"active_channels"` + InterchainAccounts []*RegisteredInterchainAccount `protobuf:"bytes,2,rep,name=interchain_accounts,json=interchainAccounts,proto3" json:"interchain_accounts,omitempty" yaml:"interchain_accounts"` + Port string `protobuf:"bytes,3,opt,name=port,proto3" json:"port,omitempty"` +} + +func (m *HostGenesisState) Reset() { *m = HostGenesisState{} } +func (m *HostGenesisState) String() string { return proto.CompactTextString(m) } +func (*HostGenesisState) ProtoMessage() {} +func (*HostGenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_629b3ced0911516b, []int{2} +} +func (m *HostGenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HostGenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_HostGenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *HostGenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_HostGenesisState.Merge(m, src) +} +func (m *HostGenesisState) XXX_Size() int { + return m.Size() +} +func (m *HostGenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_HostGenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_HostGenesisState proto.InternalMessageInfo + +func (m *HostGenesisState) GetActiveChannels() []*ActiveChannel { + if m != nil { + return m.ActiveChannels + } + return nil +} + +func (m *HostGenesisState) GetInterchainAccounts() []*RegisteredInterchainAccount { + if m != nil { + return m.InterchainAccounts + } + return nil +} + +func (m *HostGenesisState) GetPort() string { + if m != nil { + return m.Port + } + return "" +} + // ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel type ActiveChannel struct { PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` @@ -94,7 +208,7 @@ func (m *ActiveChannel) Reset() { *m = ActiveChannel{} } func (m *ActiveChannel) String() string { return proto.CompactTextString(m) } func (*ActiveChannel) ProtoMessage() {} func (*ActiveChannel) Descriptor() ([]byte, []int) { - return fileDescriptor_629b3ced0911516b, []int{1} + return fileDescriptor_629b3ced0911516b, []int{3} } func (m *ActiveChannel) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -147,7 +261,7 @@ func (m *RegisteredInterchainAccount) Reset() { *m = RegisteredInterchai func (m *RegisteredInterchainAccount) String() string { return proto.CompactTextString(m) } func (*RegisteredInterchainAccount) ProtoMessage() {} func (*RegisteredInterchainAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_629b3ced0911516b, []int{2} + return fileDescriptor_629b3ced0911516b, []int{4} } func (m *RegisteredInterchainAccount) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -192,6 +306,8 @@ func (m *RegisteredInterchainAccount) GetAccountAddress() string { func init() { proto.RegisterType((*GenesisState)(nil), "ibc.applications.interchain_accounts.v1.GenesisState") + proto.RegisterType((*ControllerGenesisState)(nil), "ibc.applications.interchain_accounts.v1.ControllerGenesisState") + proto.RegisterType((*HostGenesisState)(nil), "ibc.applications.interchain_accounts.v1.HostGenesisState") proto.RegisterType((*ActiveChannel)(nil), "ibc.applications.interchain_accounts.v1.ActiveChannel") proto.RegisterType((*RegisteredInterchainAccount)(nil), "ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount") } @@ -201,34 +317,41 @@ func init() { } var fileDescriptor_629b3ced0911516b = []byte{ - // 426 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0x4f, 0x8b, 0x13, 0x31, - 0x18, 0xc6, 0x9b, 0x16, 0x57, 0x1a, 0x75, 0xc5, 0xb8, 0x4a, 0xa9, 0x30, 0x2d, 0xb9, 0x58, 0x90, - 0x4e, 0xd8, 0xfa, 0x0f, 0xbc, 0xb5, 0xab, 0x48, 0xaf, 0xe3, 0xcd, 0xcb, 0x90, 0xc9, 0x84, 0x69, - 0xa0, 0x33, 0x19, 0xe6, 0x4d, 0x07, 0x16, 0x3f, 0x84, 0x5e, 0xfc, 0x30, 0x7e, 0x03, 0x8f, 0x7b, - 0xf4, 0x34, 0x48, 0xfb, 0x0d, 0xe6, 0x13, 0xc8, 0x24, 0xc3, 0xee, 0x76, 0x29, 0xb2, 0x7b, 0x4b, - 0xf2, 0x3c, 0xbf, 0x37, 0x4f, 0xf2, 0xbe, 0xf8, 0xad, 0x8a, 0x04, 0xe3, 0x79, 0xbe, 0x56, 0x82, - 0x1b, 0xa5, 0x33, 0x60, 0x2a, 0x33, 0xb2, 0x10, 0x2b, 0xae, 0xb2, 0x90, 0x0b, 0xa1, 0x37, 0x99, - 0x01, 0x56, 0x9e, 0xb2, 0x44, 0x66, 0x12, 0x14, 0xf8, 0x79, 0xa1, 0x8d, 0x26, 0x2f, 0x55, 0x24, - 0xfc, 0xeb, 0x98, 0x7f, 0x00, 0xf3, 0xcb, 0xd3, 0xe1, 0x49, 0xa2, 0x13, 0x6d, 0x19, 0xd6, 0xac, - 0x1c, 0x4e, 0x7f, 0x75, 0xf1, 0xc3, 0xcf, 0xae, 0xe0, 0x17, 0xc3, 0x8d, 0x24, 0xdf, 0xf0, 0x63, - 0x2e, 0x8c, 0x2a, 0x65, 0x28, 0x56, 0x3c, 0xcb, 0xe4, 0x1a, 0x06, 0x68, 0xdc, 0x9b, 0x3c, 0x98, - 0xbd, 0xf3, 0x6f, 0x79, 0x93, 0x3f, 0xb7, 0xfc, 0x99, 0xc3, 0x17, 0xc3, 0xba, 0x1a, 0x3d, 0x3f, - 0xe7, 0xe9, 0xfa, 0x03, 0xbd, 0x51, 0x98, 0x06, 0xc7, 0xfc, 0xba, 0x15, 0xc8, 0x4f, 0x84, 0x9f, - 0x1e, 0x28, 0x3a, 0xe8, 0xda, 0x04, 0x1f, 0x6f, 0x9d, 0x20, 0x90, 0x89, 0x02, 0x23, 0x0b, 0x19, - 0x2f, 0x2f, 0x0d, 0x73, 0xa7, 0x2f, 0xbc, 0xba, 0x1a, 0x0d, 0x5d, 0x9e, 0x03, 0x34, 0x0d, 0x88, - 0xba, 0x89, 0x00, 0x39, 0xc1, 0xf7, 0x72, 0x5d, 0x18, 0x18, 0xf4, 0xc6, 0xbd, 0x49, 0x3f, 0x70, - 0x1b, 0x5a, 0xe0, 0x47, 0x7b, 0x4f, 0x25, 0xaf, 0xf0, 0xfd, 0x46, 0x09, 0x55, 0x3c, 0x40, 0x63, - 0x34, 0xe9, 0x2f, 0x48, 0x5d, 0x8d, 0x8e, 0xdd, 0x5d, 0xad, 0x40, 0x83, 0xa3, 0x66, 0xb5, 0x8c, - 0xc9, 0x1b, 0x8c, 0xdb, 0x8f, 0x68, 0xfc, 0x5d, 0xeb, 0x7f, 0x56, 0x57, 0xa3, 0x27, 0xce, 0x7f, - 0xa5, 0xd1, 0xa0, 0xdf, 0x6e, 0x96, 0x31, 0xfd, 0x8e, 0xf0, 0x8b, 0xff, 0xbc, 0xee, 0x6e, 0x11, - 0xce, 0x9a, 0x5e, 0x5b, 0x2e, 0xe4, 0x71, 0x5c, 0x48, 0x80, 0x36, 0xc7, 0x5e, 0xcf, 0xf6, 0x0c, - 0xb6, 0x67, 0xf6, 0x64, 0xee, 0x0e, 0x16, 0xe1, 0xef, 0xad, 0x87, 0x2e, 0xb6, 0x1e, 0xfa, 0xbb, - 0xf5, 0xd0, 0x8f, 0x9d, 0xd7, 0xb9, 0xd8, 0x79, 0x9d, 0x3f, 0x3b, 0xaf, 0xf3, 0xf5, 0x53, 0xa2, - 0xcc, 0x6a, 0x13, 0xf9, 0x42, 0xa7, 0x4c, 0x68, 0x48, 0x35, 0x30, 0x15, 0x89, 0x69, 0xa2, 0x59, - 0x39, 0x63, 0xa9, 0x8e, 0x37, 0x6b, 0x09, 0xcd, 0xc4, 0x03, 0x9b, 0xbd, 0x9f, 0x5e, 0xfd, 0xfa, - 0xf4, 0x72, 0xd8, 0xcd, 0x79, 0x2e, 0x21, 0x3a, 0xb2, 0x93, 0xfa, 0xfa, 0x5f, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xc5, 0x32, 0x06, 0x92, 0x21, 0x03, 0x00, 0x00, + // 540 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x94, 0xbf, 0x8f, 0xd3, 0x30, + 0x14, 0xc7, 0xeb, 0x14, 0x0e, 0xd5, 0x07, 0xc7, 0x61, 0x8e, 0x2a, 0x14, 0x91, 0x54, 0x66, 0xa0, + 0x12, 0x6a, 0xa2, 0x2b, 0xbf, 0x04, 0x0b, 0x6a, 0x0b, 0x82, 0xae, 0x61, 0x63, 0x89, 0x52, 0xc7, + 0x4a, 0x2d, 0xa5, 0x71, 0x15, 0xbb, 0x95, 0x4e, 0xec, 0xac, 0xb0, 0xb0, 0xf2, 0x77, 0x20, 0x31, + 0xb2, 0x30, 0xde, 0xc8, 0x14, 0xa1, 0xf6, 0x3f, 0xc8, 0x5f, 0x80, 0x62, 0x47, 0xa5, 0x2d, 0x01, + 0x95, 0x9d, 0xcd, 0xf6, 0x7b, 0xdf, 0xf7, 0x3e, 0xef, 0x3d, 0xf9, 0xc1, 0x87, 0x6c, 0x4c, 0xdc, + 0x60, 0x36, 0x8b, 0x19, 0x09, 0x24, 0xe3, 0x89, 0x70, 0x59, 0x22, 0x69, 0x4a, 0x26, 0x01, 0x4b, + 0xfc, 0x80, 0x10, 0x3e, 0x4f, 0xa4, 0x70, 0x17, 0xa7, 0x6e, 0x44, 0x13, 0x2a, 0x98, 0x70, 0x66, + 0x29, 0x97, 0x1c, 0xdd, 0x65, 0x63, 0xe2, 0x6c, 0xca, 0x9c, 0x0a, 0x99, 0xb3, 0x38, 0x6d, 0x9d, + 0x44, 0x3c, 0xe2, 0x4a, 0xe3, 0x16, 0x27, 0x2d, 0xc7, 0x9f, 0x0d, 0x78, 0xf9, 0xa5, 0x0e, 0xf8, + 0x5a, 0x06, 0x92, 0xa2, 0x4f, 0x00, 0x9a, 0x84, 0x27, 0x32, 0xe5, 0x71, 0x4c, 0x53, 0xbf, 0x4c, + 0xe6, 0x8b, 0xc2, 0x68, 0x82, 0x36, 0xe8, 0x1c, 0xf6, 0x9e, 0x39, 0x7b, 0xe6, 0x74, 0x86, 0xeb, + 0x40, 0x9b, 0x39, 0x06, 0x77, 0xf2, 0xcc, 0xb6, 0xcf, 0x82, 0x69, 0xfc, 0x14, 0xff, 0x29, 0x15, + 0xf6, 0x9a, 0xa4, 0x52, 0x8c, 0xde, 0x01, 0x88, 0x26, 0x5c, 0xc8, 0x1d, 0x34, 0x43, 0xa1, 0x3d, + 0xd9, 0x1b, 0xed, 0x15, 0x17, 0x72, 0x0b, 0xea, 0x76, 0x9e, 0xd9, 0x37, 0x35, 0xd4, 0xef, 0xe1, + 0xb1, 0x77, 0x3c, 0xd9, 0x11, 0xe0, 0xaf, 0x06, 0x6c, 0x56, 0x17, 0x88, 0xde, 0xc2, 0xab, 0x01, + 0x91, 0x6c, 0x41, 0x7d, 0x32, 0x09, 0x92, 0x84, 0xc6, 0xc2, 0x04, 0xed, 0x7a, 0xe7, 0xb0, 0xf7, + 0x68, 0x6f, 0xbe, 0xbe, 0xd2, 0x0f, 0xb5, 0x7c, 0xd0, 0xca, 0x33, 0xbb, 0xa9, 0xe1, 0x76, 0x02, + 0x63, 0xef, 0x28, 0xd8, 0x74, 0x15, 0xe8, 0x23, 0x80, 0xd7, 0x2b, 0x82, 0x9a, 0x86, 0x22, 0x78, + 0xbe, 0x37, 0x81, 0x47, 0x23, 0x26, 0x24, 0x4d, 0x69, 0x38, 0x5a, 0x3b, 0xf4, 0xb5, 0x7d, 0x60, + 0xe5, 0x99, 0xdd, 0xd2, 0x3c, 0x15, 0x6a, 0xec, 0x21, 0xb6, 0x2b, 0x11, 0xe8, 0x04, 0x5e, 0x9c, + 0xf1, 0x54, 0x0a, 0xb3, 0xde, 0xae, 0x77, 0x1a, 0x9e, 0xbe, 0xe0, 0x2f, 0x06, 0x3c, 0xde, 0x9d, + 0xc5, 0xff, 0xfe, 0x55, 0xf5, 0x0f, 0xc1, 0x0b, 0x45, 0xcb, 0xcc, 0x7a, 0x1b, 0x74, 0x1a, 0x9e, + 0x3a, 0xe3, 0x14, 0x5e, 0xd9, 0x2a, 0x14, 0xdd, 0x83, 0x97, 0x0a, 0x83, 0xcf, 0x42, 0xf5, 0x59, + 0x1b, 0x03, 0x94, 0x67, 0xf6, 0x91, 0xce, 0x54, 0x1a, 0xb0, 0x77, 0x50, 0x9c, 0x46, 0x21, 0x7a, + 0x00, 0x61, 0xd9, 0x86, 0xc2, 0xdf, 0x50, 0xfe, 0x37, 0xf2, 0xcc, 0xbe, 0x56, 0xfe, 0xcd, 0xb5, + 0x0d, 0x7b, 0x8d, 0xf2, 0x32, 0x0a, 0xf1, 0x7b, 0x00, 0x6f, 0xfd, 0xa5, 0xb6, 0x7f, 0x43, 0x18, + 0x16, 0x93, 0x56, 0x3a, 0x3f, 0x08, 0xc3, 0x94, 0x0a, 0x51, 0x72, 0x6c, 0x4d, 0x6c, 0xcb, 0x41, + 0x4d, 0x4c, 0xbd, 0xf4, 0xf5, 0xc3, 0xc0, 0xff, 0xb6, 0xb4, 0xc0, 0xf9, 0xd2, 0x02, 0x3f, 0x96, + 0x16, 0xf8, 0xb0, 0xb2, 0x6a, 0xe7, 0x2b, 0xab, 0xf6, 0x7d, 0x65, 0xd5, 0xde, 0xbc, 0x88, 0x98, + 0x9c, 0xcc, 0xc7, 0x0e, 0xe1, 0x53, 0x97, 0x70, 0x31, 0xe5, 0xc2, 0x65, 0x63, 0xd2, 0x8d, 0xb8, + 0xbb, 0xe8, 0xb9, 0x53, 0x1e, 0xce, 0x63, 0x2a, 0x8a, 0xa5, 0x2b, 0xdc, 0xde, 0xe3, 0xee, 0xaf, + 0x9e, 0x77, 0xd7, 0xfb, 0x56, 0x9e, 0xcd, 0xa8, 0x18, 0x1f, 0xa8, 0x65, 0x79, 0xff, 0x67, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x21, 0x52, 0x9a, 0x46, 0xa4, 0x05, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -247,6 +370,53 @@ func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { } func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.HostGenesisState != nil { + { + size, err := m.HostGenesisState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.ControllerGenesisState != nil { + { + size, err := m.ControllerGenesisState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ControllerGenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ControllerGenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ControllerGenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -291,6 +461,64 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *HostGenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HostGenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HostGenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Port) > 0 { + i -= len(m.Port) + copy(dAtA[i:], m.Port) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Port))) + i-- + dAtA[i] = 0x1a + } + if len(m.InterchainAccounts) > 0 { + for iNdEx := len(m.InterchainAccounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.InterchainAccounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.ActiveChannels) > 0 { + for iNdEx := len(m.ActiveChannels) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ActiveChannels[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *ActiveChannel) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -377,6 +605,23 @@ func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { return base } func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ControllerGenesisState != nil { + l = m.ControllerGenesisState.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + if m.HostGenesisState != nil { + l = m.HostGenesisState.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *ControllerGenesisState) Size() (n int) { if m == nil { return 0 } @@ -403,6 +648,31 @@ func (m *GenesisState) Size() (n int) { return n } +func (m *HostGenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ActiveChannels) > 0 { + for _, e := range m.ActiveChannels { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.InterchainAccounts) > 0 { + for _, e := range m.InterchainAccounts { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + l = len(m.Port) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + func (m *ActiveChannel) Size() (n int) { if m == nil { return 0 @@ -472,6 +742,128 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ControllerGenesisState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ControllerGenesisState == nil { + m.ControllerGenesisState = &ControllerGenesisState{} + } + if err := m.ControllerGenesisState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostGenesisState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.HostGenesisState == nil { + m.HostGenesisState = &HostGenesisState{} + } + if err := m.HostGenesisState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ControllerGenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ControllerGenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ControllerGenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ActiveChannels", wireType) @@ -593,6 +985,156 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } return nil } +func (m *HostGenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HostGenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HostGenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ActiveChannels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ActiveChannels = append(m.ActiveChannels, &ActiveChannel{}) + if err := m.ActiveChannels[len(m.ActiveChannels)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InterchainAccounts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InterchainAccounts = append(m.InterchainAccounts, &RegisteredInterchainAccount{}) + if err := m.InterchainAccounts[len(m.InterchainAccounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Port", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Port = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ActiveChannel) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/27-interchain-accounts/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go index a71f6c0c32c..d4df0db4c93 100644 --- a/modules/apps/27-interchain-accounts/types/keys.go +++ b/modules/apps/27-interchain-accounts/types/keys.go @@ -2,12 +2,6 @@ package types import ( "fmt" - "strconv" - "strings" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" ) const ( @@ -31,10 +25,6 @@ const ( // Delimiter is the delimiter used for the interchain accounts version string Delimiter = "." - - // ControllerPortFormat is the expected port identifier format to which controller chains must conform - // See (TODO: Link to spec when updated) - ControllerPortFormat = "..." ) var ( @@ -48,11 +38,6 @@ var ( PortKeyPrefix = "port" ) -// NewVersion returns a complete version string in the format: VersionPrefix + Delimter + AccAddress -func NewAppVersion(versionPrefix, accAddr string) string { - return fmt.Sprint(versionPrefix, Delimiter, accAddr) -} - // KeyActiveChannel creates and returns a new key used for active channels store operations func KeyActiveChannel(portID string) []byte { return []byte(fmt.Sprintf("%s/%s", ActiveChannelKeyPrefix, portID)) @@ -67,45 +52,3 @@ func KeyOwnerAccount(portID string) []byte { func KeyPort(portID string) []byte { return []byte(fmt.Sprintf("%s/%s", PortKeyPrefix, portID)) } - -// ParseControllerConnSequence attempts to parse the controller connection sequence from the provided port identifier -// The port identifier must match the controller chain format outlined in (TODO: link spec), otherwise an empty string is returned -func ParseControllerConnSequence(portID string) (uint64, error) { - s := strings.Split(portID, Delimiter) - if len(s) != 4 { - return 0, sdkerrors.Wrap(porttypes.ErrInvalidPort, "failed to parse port identifier") - } - - seq, err := strconv.ParseUint(s[1], 10, 64) - if err != nil { - return 0, sdkerrors.Wrapf(err, "failed to parse connection sequence (%s)", s[1]) - } - - return seq, nil -} - -// ParseHostConnSequence attempts to parse the host connection sequence from the provided port identifier -// The port identifier must match the controller chain format outlined in (TODO: link spec), otherwise an empty string is returned -func ParseHostConnSequence(portID string) (uint64, error) { - s := strings.Split(portID, Delimiter) - if len(s) != 4 { - return 0, sdkerrors.Wrap(porttypes.ErrInvalidPort, "failed to parse port identifier") - } - - seq, err := strconv.ParseUint(s[2], 10, 64) - if err != nil { - return 0, sdkerrors.Wrapf(err, "failed to parse connection sequence (%s)", s[2]) - } - - return seq, nil -} - -// ParseAddressFromVersion attempts to extract the associated account address from the provided version string -func ParseAddressFromVersion(version string) (string, error) { - s := strings.Split(version, Delimiter) - if len(s) != 2 { - return "", sdkerrors.Wrap(ErrInvalidVersion, "failed to parse version") - } - - return s[1], nil -} diff --git a/modules/apps/27-interchain-accounts/types/keys_test.go b/modules/apps/27-interchain-accounts/types/keys_test.go index 0bb4c7cea84..037061a3d3e 100644 --- a/modules/apps/27-interchain-accounts/types/keys_test.go +++ b/modules/apps/27-interchain-accounts/types/keys_test.go @@ -1,8 +1,6 @@ package types_test import ( - "fmt" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ) @@ -15,132 +13,3 @@ func (suite *TypesTestSuite) TestKeyOwnerAccount() { key := types.KeyOwnerAccount("port-id") suite.Require().Equal("owner/port-id", string(key)) } - -func (suite *TypesTestSuite) TestParseControllerConnSequence() { - - testCases := []struct { - name string - portID string - expValue uint64 - expPass bool - }{ - { - "success", - TestPortID, - 0, - true, - }, - { - "failed to parse port identifier", - "invalid-port-id", - 0, - false, - }, - { - "failed to parse connection sequence", - "ics27-1.x.y.cosmos1", - 0, - false, - }, - } - - for _, tc := range testCases { - suite.Run(tc.name, func() { - connSeq, err := types.ParseControllerConnSequence(tc.portID) - - if tc.expPass { - suite.Require().Equal(tc.expValue, connSeq) - suite.Require().NoError(err, tc.name) - } else { - suite.Require().Zero(connSeq) - suite.Require().Error(err, tc.name) - } - }) - } -} - -func (suite *TypesTestSuite) TestParseHostConnSequence() { - - testCases := []struct { - name string - portID string - expValue uint64 - expPass bool - }{ - { - "success", - TestPortID, - 0, - true, - }, - { - "failed to parse port identifier", - "invalid-port-id", - 0, - false, - }, - { - "failed to parse connection sequence", - "ics27-1.x.y.cosmos1", - 0, - false, - }, - } - - for _, tc := range testCases { - suite.Run(tc.name, func() { - connSeq, err := types.ParseHostConnSequence(tc.portID) - - if tc.expPass { - suite.Require().Equal(tc.expValue, connSeq) - suite.Require().NoError(err, tc.name) - } else { - suite.Require().Zero(connSeq) - suite.Require().Error(err, tc.name) - } - }) - } -} - -func (suite *TypesTestSuite) TestParseAddressFromVersion() { - - testCases := []struct { - name string - version string - expValue string - expPass bool - }{ - { - "success", - types.NewAppVersion(types.VersionPrefix, TestOwnerAddress), - TestOwnerAddress, - true, - }, - { - "failed to parse address from version", - "invalid-version-string", - "", - false, - }, - { - "failure with multiple delimiters", - fmt.Sprint(types.NewAppVersion(types.VersionPrefix, TestOwnerAddress), types.Delimiter, types.NewAppVersion(types.VersionPrefix, TestOwnerAddress)), - "", - false, - }, - } - - for _, tc := range testCases { - suite.Run(tc.name, func() { - addr, err := types.ParseAddressFromVersion(tc.version) - - if tc.expPass { - suite.Require().Equal(tc.expValue, addr) - suite.Require().NoError(err, tc.name) - } else { - suite.Require().Empty(addr) - suite.Require().Error(err, tc.name) - } - }) - } -} diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 3c5223f4390..e7669a77fc9 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -6,6 +6,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) +// MaxMemoCharLength defines the maximum length for the InterchainAccountPacketData memo field const MaxMemoCharLength = 256 // ValidateBasic performs basic validation of the interchain account packet data. diff --git a/modules/apps/27-interchain-accounts/types/port.go b/modules/apps/27-interchain-accounts/types/port.go new file mode 100644 index 00000000000..c44c5eda9ba --- /dev/null +++ b/modules/apps/27-interchain-accounts/types/port.go @@ -0,0 +1,78 @@ +package types + +import ( + "fmt" + "strconv" + "strings" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" +) + +const ( + // ControllerPortFormat is the expected port identifier format to which controller chains must conform + // See (TODO: Link to spec when updated) + ControllerPortFormat = "..." +) + +// GeneratePortID generates an interchain accounts controller port identifier for the provided owner +// in the following format: +// +// 'ics-27---' +// https://github.com/seantking/ibc/tree/sean/ics-27-updates/spec/app/ics-027-interchain-accounts#registering--controlling-flows +// TODO: update link to spec +func GeneratePortID(owner, connectionID, counterpartyConnectionID string) (string, error) { + if strings.TrimSpace(owner) == "" { + return "", sdkerrors.Wrap(ErrInvalidAccountAddress, "owner address cannot be empty") + } + + connectionSeq, err := connectiontypes.ParseConnectionSequence(connectionID) + if err != nil { + return "", sdkerrors.Wrap(err, "invalid connection identifier") + } + + counterpartyConnectionSeq, err := connectiontypes.ParseConnectionSequence(counterpartyConnectionID) + if err != nil { + return "", sdkerrors.Wrap(err, "invalid counterparty connection identifier") + } + + return fmt.Sprint( + VersionPrefix, Delimiter, + connectionSeq, Delimiter, + counterpartyConnectionSeq, Delimiter, + owner, + ), nil +} + +// ParseControllerConnSequence attempts to parse the controller connection sequence from the provided port identifier +// The port identifier must match the controller chain format outlined in (TODO: link spec), otherwise an empty string is returned +func ParseControllerConnSequence(portID string) (uint64, error) { + s := strings.Split(portID, Delimiter) + if len(s) != 4 { + return 0, sdkerrors.Wrap(porttypes.ErrInvalidPort, "failed to parse port identifier") + } + + seq, err := strconv.ParseUint(s[1], 10, 64) + if err != nil { + return 0, sdkerrors.Wrapf(err, "failed to parse connection sequence (%s)", s[1]) + } + + return seq, nil +} + +// ParseHostConnSequence attempts to parse the host connection sequence from the provided port identifier +// The port identifier must match the controller chain format outlined in (TODO: link spec), otherwise an empty string is returned +func ParseHostConnSequence(portID string) (uint64, error) { + s := strings.Split(portID, Delimiter) + if len(s) != 4 { + return 0, sdkerrors.Wrap(porttypes.ErrInvalidPort, "failed to parse port identifier") + } + + seq, err := strconv.ParseUint(s[2], 10, 64) + if err != nil { + return 0, sdkerrors.Wrapf(err, "failed to parse connection sequence (%s)", s[2]) + } + + return seq, nil +} diff --git a/modules/apps/27-interchain-accounts/types/port_test.go b/modules/apps/27-interchain-accounts/types/port_test.go new file mode 100644 index 00000000000..cd12548c8d5 --- /dev/null +++ b/modules/apps/27-interchain-accounts/types/port_test.go @@ -0,0 +1,169 @@ +package types_test + +import ( + "fmt" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v2/testing" +) + +func (suite *TypesTestSuite) TestGeneratePortID() { + var ( + path *ibctesting.Path + owner = TestOwnerAddress + ) + + testCases := []struct { + name string + malleate func() + expValue string + expPass bool + }{ + { + "success", + func() {}, + fmt.Sprint(types.VersionPrefix, types.Delimiter, "0", types.Delimiter, "0", types.Delimiter, TestOwnerAddress), + true, + }, + { + "success with non matching connection sequences", + func() { + path.EndpointA.ConnectionID = "connection-1" + }, + fmt.Sprint(types.VersionPrefix, types.Delimiter, "1", types.Delimiter, "0", types.Delimiter, TestOwnerAddress), + true, + }, + { + "invalid connectionID", + func() { + path.EndpointA.ConnectionID = "connection" + }, + "", + false, + }, + { + "invalid counterparty connectionID", + func() { + path.EndpointB.ConnectionID = "connection" + }, + "", + false, + }, + { + "invalid owner address", + func() { + owner = " " + }, + "", + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + tc.malleate() // malleate mutates test data + + portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + + if tc.expPass { + suite.Require().NoError(err, tc.name) + suite.Require().Equal(tc.expValue, portID) + } else { + suite.Require().Error(err, tc.name) + suite.Require().Empty(portID) + } + }) + } +} + +func (suite *TypesTestSuite) TestParseControllerConnSequence() { + + testCases := []struct { + name string + portID string + expValue uint64 + expPass bool + }{ + { + "success", + TestPortID, + 0, + true, + }, + { + "failed to parse port identifier", + "invalid-port-id", + 0, + false, + }, + { + "failed to parse connection sequence", + "ics27-1.x.y.cosmos1", + 0, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + connSeq, err := types.ParseControllerConnSequence(tc.portID) + + if tc.expPass { + suite.Require().Equal(tc.expValue, connSeq) + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Zero(connSeq) + suite.Require().Error(err, tc.name) + } + }) + } +} + +func (suite *TypesTestSuite) TestParseHostConnSequence() { + + testCases := []struct { + name string + portID string + expValue uint64 + expPass bool + }{ + { + "success", + TestPortID, + 0, + true, + }, + { + "failed to parse port identifier", + "invalid-port-id", + 0, + false, + }, + { + "failed to parse connection sequence", + "ics27-1.x.y.cosmos1", + 0, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + connSeq, err := types.ParseHostConnSequence(tc.portID) + + if tc.expPass { + suite.Require().Equal(tc.expValue, connSeq) + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Zero(connSeq) + suite.Require().Error(err, tc.name) + } + }) + } +} diff --git a/modules/apps/27-interchain-accounts/types/query.pb.go b/modules/apps/27-interchain-accounts/types/query.pb.go deleted file mode 100644 index 29557f53dca..00000000000 --- a/modules/apps/27-interchain-accounts/types/query.pb.go +++ /dev/null @@ -1,584 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: ibc/applications/interchain_accounts/v1/query.proto - -package types - -import ( - context "context" - fmt "fmt" - _ "github.com/gogo/protobuf/gogoproto" - grpc1 "github.com/gogo/protobuf/grpc" - proto "github.com/gogo/protobuf/proto" - _ "google.golang.org/genproto/googleapis/api/annotations" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// Query request for an interchain account address -type QueryInterchainAccountAddressRequest struct { - // Counterparty PortID is the portID on the controller chain - CounterpartyPortId string `protobuf:"bytes,1,opt,name=counterparty_port_id,json=counterpartyPortId,proto3" json:"counterparty_port_id,omitempty"` -} - -func (m *QueryInterchainAccountAddressRequest) Reset() { *m = QueryInterchainAccountAddressRequest{} } -func (m *QueryInterchainAccountAddressRequest) String() string { return proto.CompactTextString(m) } -func (*QueryInterchainAccountAddressRequest) ProtoMessage() {} -func (*QueryInterchainAccountAddressRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_72a16b57c3343764, []int{0} -} -func (m *QueryInterchainAccountAddressRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryInterchainAccountAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryInterchainAccountAddressRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryInterchainAccountAddressRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryInterchainAccountAddressRequest.Merge(m, src) -} -func (m *QueryInterchainAccountAddressRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryInterchainAccountAddressRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryInterchainAccountAddressRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryInterchainAccountAddressRequest proto.InternalMessageInfo - -// Query response for an interchain account address -type QueryInterchainAccountAddressResponse struct { - // The corresponding interchain account address on the host chain - InterchainAccountAddress string `protobuf:"bytes,1,opt,name=interchain_account_address,json=interchainAccountAddress,proto3" json:"interchain_account_address,omitempty"` -} - -func (m *QueryInterchainAccountAddressResponse) Reset() { *m = QueryInterchainAccountAddressResponse{} } -func (m *QueryInterchainAccountAddressResponse) String() string { return proto.CompactTextString(m) } -func (*QueryInterchainAccountAddressResponse) ProtoMessage() {} -func (*QueryInterchainAccountAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_72a16b57c3343764, []int{1} -} -func (m *QueryInterchainAccountAddressResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryInterchainAccountAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryInterchainAccountAddressResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryInterchainAccountAddressResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryInterchainAccountAddressResponse.Merge(m, src) -} -func (m *QueryInterchainAccountAddressResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryInterchainAccountAddressResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryInterchainAccountAddressResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryInterchainAccountAddressResponse proto.InternalMessageInfo - -func (m *QueryInterchainAccountAddressResponse) GetInterchainAccountAddress() string { - if m != nil { - return m.InterchainAccountAddress - } - return "" -} - -func init() { - proto.RegisterType((*QueryInterchainAccountAddressRequest)(nil), "ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressRequest") - proto.RegisterType((*QueryInterchainAccountAddressResponse)(nil), "ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressResponse") -} - -func init() { - proto.RegisterFile("ibc/applications/interchain_accounts/v1/query.proto", fileDescriptor_72a16b57c3343764) -} - -var fileDescriptor_72a16b57c3343764 = []byte{ - // 349 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0xbf, 0x4a, 0x03, 0x31, - 0x18, 0xbf, 0x0c, 0x8a, 0x66, 0x3c, 0x3a, 0x94, 0x43, 0xae, 0x52, 0x14, 0x5d, 0x9a, 0xd8, 0x16, - 0x11, 0xc4, 0xa5, 0x82, 0x43, 0x07, 0x45, 0x3b, 0xba, 0x1c, 0xb9, 0x5c, 0xb8, 0x06, 0xda, 0x7c, - 0x69, 0x92, 0x2b, 0xf4, 0x0d, 0x1c, 0x7d, 0x84, 0xbe, 0x87, 0xb3, 0xe0, 0xd8, 0xd1, 0x51, 0xda, - 0xc5, 0xc7, 0x90, 0xde, 0x95, 0x5a, 0xd0, 0xe2, 0x0d, 0x6e, 0x1f, 0xf9, 0x7d, 0xbf, 0x3f, 0x7c, - 0xbf, 0xe0, 0xb6, 0x8c, 0x39, 0x65, 0x5a, 0x0f, 0x24, 0x67, 0x4e, 0x82, 0xb2, 0x54, 0x2a, 0x27, - 0x0c, 0xef, 0x33, 0xa9, 0x22, 0xc6, 0x39, 0x64, 0xca, 0x59, 0x3a, 0x6e, 0xd2, 0x51, 0x26, 0xcc, - 0x84, 0x68, 0x03, 0x0e, 0xfc, 0x13, 0x19, 0x73, 0xb2, 0x49, 0x22, 0xbf, 0x90, 0xc8, 0xb8, 0x19, - 0x54, 0x52, 0x48, 0x21, 0xe7, 0xd0, 0xe5, 0x54, 0xd0, 0x83, 0x83, 0x14, 0x20, 0x1d, 0x08, 0xca, - 0xb4, 0xa4, 0x4c, 0x29, 0x70, 0x2b, 0x91, 0x02, 0x3d, 0x2f, 0x9b, 0x68, 0x35, 0x17, 0xb4, 0x7a, - 0x8c, 0x8f, 0x1e, 0x96, 0x11, 0xbb, 0xeb, 0xe5, 0x4e, 0x81, 0x77, 0x92, 0xc4, 0x08, 0x6b, 0x7b, - 0x62, 0x94, 0x09, 0xeb, 0xfc, 0x33, 0x5c, 0xc9, 0x9f, 0x85, 0xd1, 0xcc, 0xb8, 0x49, 0xa4, 0xc1, - 0xb8, 0x48, 0x26, 0x55, 0x74, 0x88, 0x4e, 0xf7, 0x7b, 0xfe, 0x26, 0x76, 0x0f, 0xc6, 0x75, 0x93, - 0xcb, 0xbd, 0xa7, 0x69, 0xcd, 0xfb, 0x9c, 0xd6, 0xbc, 0xba, 0xc0, 0xc7, 0x7f, 0x78, 0x58, 0x0d, - 0xca, 0x0a, 0xff, 0x0a, 0x07, 0x3f, 0x43, 0x47, 0xac, 0xd8, 0x5a, 0x59, 0x55, 0xe5, 0x16, 0x95, - 0xd6, 0x2b, 0xc2, 0x3b, 0xb9, 0x8f, 0xff, 0x82, 0x70, 0x75, 0x9b, 0x99, 0x7f, 0x4b, 0x4a, 0xd6, - 0x40, 0xca, 0x1c, 0x26, 0xb8, 0xfb, 0x2f, 0xb9, 0xe2, 0x06, 0x75, 0xef, 0x3a, 0x7a, 0x9b, 0x87, - 0x68, 0x36, 0x0f, 0xd1, 0xc7, 0x3c, 0x44, 0xcf, 0x8b, 0xd0, 0x9b, 0x2d, 0x42, 0xef, 0x7d, 0x11, - 0x7a, 0x8f, 0x37, 0xa9, 0x74, 0xfd, 0x2c, 0x26, 0x1c, 0x86, 0x94, 0x83, 0x1d, 0x82, 0xa5, 0x32, - 0xe6, 0x8d, 0x14, 0xe8, 0xb8, 0x45, 0x87, 0x90, 0x64, 0x03, 0x61, 0x97, 0x7f, 0xc0, 0xd2, 0xd6, - 0x45, 0xe3, 0x3b, 0x45, 0x63, 0x5d, 0xbf, 0x9b, 0x68, 0x61, 0xe3, 0xdd, 0xbc, 0xfa, 0xf6, 0x57, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x38, 0xd5, 0xa3, 0x36, 0xc5, 0x02, 0x00, 0x00, -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// QueryClient is the client API for Query service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type QueryClient interface { - // Query to get the address of an interchain account - InterchainAccountAddress(ctx context.Context, in *QueryInterchainAccountAddressRequest, opts ...grpc.CallOption) (*QueryInterchainAccountAddressResponse, error) -} - -type queryClient struct { - cc grpc1.ClientConn -} - -func NewQueryClient(cc grpc1.ClientConn) QueryClient { - return &queryClient{cc} -} - -func (c *queryClient) InterchainAccountAddress(ctx context.Context, in *QueryInterchainAccountAddressRequest, opts ...grpc.CallOption) (*QueryInterchainAccountAddressResponse, error) { - out := new(QueryInterchainAccountAddressResponse) - err := c.cc.Invoke(ctx, "/ibc.applications.interchain_accounts.v1.Query/InterchainAccountAddress", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// QueryServer is the server API for Query service. -type QueryServer interface { - // Query to get the address of an interchain account - InterchainAccountAddress(context.Context, *QueryInterchainAccountAddressRequest) (*QueryInterchainAccountAddressResponse, error) -} - -// UnimplementedQueryServer can be embedded to have forward compatible implementations. -type UnimplementedQueryServer struct { -} - -func (*UnimplementedQueryServer) InterchainAccountAddress(ctx context.Context, req *QueryInterchainAccountAddressRequest) (*QueryInterchainAccountAddressResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method InterchainAccountAddress not implemented") -} - -func RegisterQueryServer(s grpc1.Server, srv QueryServer) { - s.RegisterService(&_Query_serviceDesc, srv) -} - -func _Query_InterchainAccountAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryInterchainAccountAddressRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).InterchainAccountAddress(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/ibc.applications.interchain_accounts.v1.Query/InterchainAccountAddress", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).InterchainAccountAddress(ctx, req.(*QueryInterchainAccountAddressRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _Query_serviceDesc = grpc.ServiceDesc{ - ServiceName: "ibc.applications.interchain_accounts.v1.Query", - HandlerType: (*QueryServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "InterchainAccountAddress", - Handler: _Query_InterchainAccountAddress_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "ibc/applications/interchain_accounts/v1/query.proto", -} - -func (m *QueryInterchainAccountAddressRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryInterchainAccountAddressRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryInterchainAccountAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.CounterpartyPortId) > 0 { - i -= len(m.CounterpartyPortId) - copy(dAtA[i:], m.CounterpartyPortId) - i = encodeVarintQuery(dAtA, i, uint64(len(m.CounterpartyPortId))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryInterchainAccountAddressResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryInterchainAccountAddressResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryInterchainAccountAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.InterchainAccountAddress) > 0 { - i -= len(m.InterchainAccountAddress) - copy(dAtA[i:], m.InterchainAccountAddress) - i = encodeVarintQuery(dAtA, i, uint64(len(m.InterchainAccountAddress))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { - offset -= sovQuery(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *QueryInterchainAccountAddressRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.CounterpartyPortId) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryInterchainAccountAddressResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.InterchainAccountAddress) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func sovQuery(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozQuery(x uint64) (n int) { - return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *QueryInterchainAccountAddressRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryInterchainAccountAddressRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryInterchainAccountAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyPortId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.CounterpartyPortId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryInterchainAccountAddressResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryInterchainAccountAddressResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryInterchainAccountAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field InterchainAccountAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.InterchainAccountAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipQuery(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowQuery - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowQuery - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowQuery - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthQuery - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupQuery - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthQuery - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") -) diff --git a/modules/apps/27-interchain-accounts/types/validate.go b/modules/apps/27-interchain-accounts/types/version.go similarity index 72% rename from modules/apps/27-interchain-accounts/types/validate.go rename to modules/apps/27-interchain-accounts/types/version.go index 0d36f2cd026..0cf8e2623cd 100644 --- a/modules/apps/27-interchain-accounts/types/validate.go +++ b/modules/apps/27-interchain-accounts/types/version.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "regexp" "strings" @@ -14,6 +15,21 @@ var DefaultMaxAddrLength = 128 // strictly alphanumeric characters var IsValidAddr = regexp.MustCompile("^[a-zA-Z0-9]*$").MatchString +// NewVersion returns a complete version string in the format: VersionPrefix + Delimter + AccAddress +func NewAppVersion(versionPrefix, accAddr string) string { + return fmt.Sprint(versionPrefix, Delimiter, accAddr) +} + +// ParseAddressFromVersion attempts to extract the associated account address from the provided version string +func ParseAddressFromVersion(version string) (string, error) { + s := strings.Split(version, Delimiter) + if len(s) != 2 { + return "", sdkerrors.Wrap(ErrInvalidVersion, "failed to parse version") + } + + return s[1], nil +} + // ValidateVersion performs basic validation of the provided ics27 version string. // An ics27 version string may include an optional account address as per [TODO: Add spec when available] // ValidateVersion first attempts to split the version string using the standard delimiter, then asserts a supported diff --git a/modules/apps/27-interchain-accounts/types/validate_test.go b/modules/apps/27-interchain-accounts/types/version_test.go similarity index 60% rename from modules/apps/27-interchain-accounts/types/validate_test.go rename to modules/apps/27-interchain-accounts/types/version_test.go index 64e2e4fcf1b..0ad4a235eb7 100644 --- a/modules/apps/27-interchain-accounts/types/validate_test.go +++ b/modules/apps/27-interchain-accounts/types/version_test.go @@ -1,9 +1,54 @@ package types_test import ( + "fmt" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ) +func (suite *TypesTestSuite) TestParseAddressFromVersion() { + + testCases := []struct { + name string + version string + expValue string + expPass bool + }{ + { + "success", + types.NewAppVersion(types.VersionPrefix, TestOwnerAddress), + TestOwnerAddress, + true, + }, + { + "failed to parse address from version", + "invalid-version-string", + "", + false, + }, + { + "failure with multiple delimiters", + fmt.Sprint(types.NewAppVersion(types.VersionPrefix, TestOwnerAddress), types.Delimiter, types.NewAppVersion(types.VersionPrefix, TestOwnerAddress)), + "", + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + addr, err := types.ParseAddressFromVersion(tc.version) + + if tc.expPass { + suite.Require().Equal(tc.expValue, addr) + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Empty(addr) + suite.Require().Error(err, tc.name) + } + }) + } +} + func (suite *TypesTestSuite) TestValidateVersion() { testCases := []struct { name string diff --git a/proto/ibc/applications/interchain_accounts/v1/genesis.proto b/proto/ibc/applications/interchain_accounts/v1/genesis.proto index 5645e726a3d..bc3ee7d242f 100644 --- a/proto/ibc/applications/interchain_accounts/v1/genesis.proto +++ b/proto/ibc/applications/interchain_accounts/v1/genesis.proto @@ -8,11 +8,24 @@ import "gogoproto/gogo.proto"; // GenesisState defines the interchain accounts genesis state message GenesisState { + ControllerGenesisState controller_genesis_state = 1 [(gogoproto.moretags) = "yaml:\"controller_genesis_state\""]; + HostGenesisState host_genesis_state = 2 [(gogoproto.moretags) = "yaml:\"host_genesis_state\""]; +} + +// ControllerGenesisState defines the interchain accounts controller genesis state +message ControllerGenesisState { repeated ActiveChannel active_channels = 1 [(gogoproto.moretags) = "yaml:\"active_channels\""]; repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.moretags) = "yaml:\"interchain_accounts\""]; repeated string ports = 3; } +// HostGenesisState defines the interchain accounts host genesis state +message HostGenesisState { + repeated ActiveChannel active_channels = 1 [(gogoproto.moretags) = "yaml:\"active_channels\""]; + repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.moretags) = "yaml:\"interchain_accounts\""]; + string port = 3; +} + // ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel message ActiveChannel { string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; diff --git a/proto/ibc/applications/interchain_accounts/v1/query.proto b/proto/ibc/applications/interchain_accounts/v1/query.proto deleted file mode 100644 index a3b77506794..00000000000 --- a/proto/ibc/applications/interchain_accounts/v1/query.proto +++ /dev/null @@ -1,30 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.v1; - -option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; - -import "gogoproto/gogo.proto"; -import "google/api/annotations.proto"; -import "ibc/applications/interchain_accounts/v1/account.proto"; - -// Query defines the gRPC querier service. -service Query { - // Query to get the address of an interchain account - rpc InterchainAccountAddress(QueryInterchainAccountAddressRequest) returns (QueryInterchainAccountAddressResponse) {} -} - -// Query request for an interchain account address -message QueryInterchainAccountAddressRequest { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - - // Counterparty PortID is the portID on the controller chain - string counterparty_port_id = 1; -} - -// Query response for an interchain account address -message QueryInterchainAccountAddressResponse { - // The corresponding interchain account address on the host chain - string interchain_account_address = 1; -} diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 3050e6436d6..1955558be31 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -81,7 +81,12 @@ import ( upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ica "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts" - icakeeper "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/keeper" + icacontroller "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller" + icacontrollerkeeper "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/keeper" + icacontrollertypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" + icahost "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host" + icahostkeeper "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/keeper" + icahosttypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" transfer "github.com/cosmos/ibc-go/v2/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v2/modules/apps/transfer/keeper" @@ -173,30 +178,32 @@ type SimApp struct { memKeys map[string]*sdk.MemoryStoreKey // keepers - AccountKeeper authkeeper.AccountKeeper - BankKeeper bankkeeper.Keeper - CapabilityKeeper *capabilitykeeper.Keeper - StakingKeeper stakingkeeper.Keeper - SlashingKeeper slashingkeeper.Keeper - MintKeeper mintkeeper.Keeper - DistrKeeper distrkeeper.Keeper - GovKeeper govkeeper.Keeper - CrisisKeeper crisiskeeper.Keeper - UpgradeKeeper upgradekeeper.Keeper - ParamsKeeper paramskeeper.Keeper - AuthzKeeper authzkeeper.Keeper - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - ICAKeeper icakeeper.Keeper - EvidenceKeeper evidencekeeper.Keeper - TransferKeeper ibctransferkeeper.Keeper - FeeGrantKeeper feegrantkeeper.Keeper + AccountKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + CapabilityKeeper *capabilitykeeper.Keeper + StakingKeeper stakingkeeper.Keeper + SlashingKeeper slashingkeeper.Keeper + MintKeeper mintkeeper.Keeper + DistrKeeper distrkeeper.Keeper + GovKeeper govkeeper.Keeper + CrisisKeeper crisiskeeper.Keeper + UpgradeKeeper upgradekeeper.Keeper + ParamsKeeper paramskeeper.Keeper + AuthzKeeper authzkeeper.Keeper + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + ICAControllerKeeper icacontrollerkeeper.Keeper + ICAHostKeeper icahostkeeper.Keeper + EvidenceKeeper evidencekeeper.Keeper + TransferKeeper ibctransferkeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper // make scoped keepers public for test purposes - ScopedIBCKeeper capabilitykeeper.ScopedKeeper - ScopedTransferKeeper capabilitykeeper.ScopedKeeper - ScopedICAKeeper capabilitykeeper.ScopedKeeper - ScopedIBCMockKeeper capabilitykeeper.ScopedKeeper - ScopedICAMockKeeper capabilitykeeper.ScopedKeeper + ScopedIBCKeeper capabilitykeeper.ScopedKeeper + ScopedTransferKeeper capabilitykeeper.ScopedKeeper + ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper + ScopedICAHostKeeper capabilitykeeper.ScopedKeeper + ScopedIBCMockKeeper capabilitykeeper.ScopedKeeper + ScopedICAMockKeeper capabilitykeeper.ScopedKeeper // make IBC modules public for test purposes // these modules are never directly routed to by the IBC Router @@ -241,7 +248,7 @@ func NewSimApp( authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, - evidencetypes.StoreKey, ibctransfertypes.StoreKey, icatypes.StoreKey, capabilitytypes.StoreKey, + evidencetypes.StoreKey, ibctransfertypes.StoreKey, icacontrollertypes.StoreKey, icahosttypes.StoreKey, capabilitytypes.StoreKey, authzkeeper.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) @@ -267,12 +274,13 @@ func NewSimApp( app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) - scopedICAKeeper := app.CapabilityKeeper.ScopeToModule(icatypes.ModuleName) + scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.ModuleName) + scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.ModuleName) // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // not replicate if you do not need to test core IBC or light clients. scopedIBCMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName) - scopedICAMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName + icatypes.ModuleName) + scopedICAMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName + icacontrollertypes.ModuleName) // seal capability keeper after scoping modules app.CapabilityKeeper.Seal() @@ -344,24 +352,33 @@ func NewSimApp( mockModule := ibcmock.NewAppModule(scopedIBCMockKeeper, &app.IBCKeeper.PortKeeper) mockIBCModule := ibcmock.NewIBCModule(&ibcmock.MockIBCApp{}, scopedIBCMockKeeper) - app.ICAKeeper = icakeeper.NewKeeper( - appCodec, keys[icatypes.StoreKey], + app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( + appCodec, keys[icacontrollertypes.StoreKey], app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAKeeper, app.MsgServiceRouter(), + app.AccountKeeper, scopedICAControllerKeeper, app.MsgServiceRouter(), ) - icaModule := ica.NewAppModule(app.ICAKeeper) + + app.ICAHostKeeper = icahostkeeper.NewKeeper( + appCodec, keys[icahosttypes.StoreKey], + app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, + app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), + ) + + icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) // initialize ICA module with mock module as the authentication module on the controller side icaAuthModule := ibcmock.NewIBCModule(&ibcmock.MockIBCApp{}, scopedICAMockKeeper) app.ICAAuthModule = icaAuthModule - icaIBCModule := ica.NewIBCModule(app.ICAKeeper, icaAuthModule) + icaControllerIBCModule := icacontroller.NewIBCModule(app.ICAControllerKeeper, icaAuthModule) + icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - // Create static IBC router, add transfer route, then set and seal it + // Create static IBC router, add app routes, then set and seal it ibcRouter := porttypes.NewRouter() - ibcRouter.AddRoute(icatypes.ModuleName, icaIBCModule). - AddRoute(ibcmock.ModuleName+icatypes.ModuleName, icaIBCModule). // ica with mock auth module stack route to ica (top level of middleware stack) + ibcRouter.AddRoute(icacontrollertypes.ModuleName, icaControllerIBCModule). + AddRoute(icahosttypes.ModuleName, icaHostIBCModule). + AddRoute(ibcmock.ModuleName+icacontrollertypes.ModuleName, icaControllerIBCModule). // ica with mock auth module stack route to ica (top level of middleware stack) AddRoute(ibctransfertypes.ModuleName, transferIBCModule). AddRoute(ibcmock.ModuleName, mockIBCModule) app.IBCKeeper.SetRouter(ibcRouter) @@ -494,7 +511,8 @@ func NewSimApp( app.ScopedIBCKeeper = scopedIBCKeeper app.ScopedTransferKeeper = scopedTransferKeeper - app.ScopedICAKeeper = scopedICAKeeper + app.ScopedICAControllerKeeper = scopedICAControllerKeeper + app.ScopedICAHostKeeper = scopedICAHostKeeper // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // note replicate if you do not need to test core IBC or light clients. From b87b8060ca1ad5452569d915151aab15e39dc521 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Fri, 19 Nov 2021 12:29:14 +0100 Subject: [PATCH 53/66] chore: ica submodules minor improvements and cleanup --- .../controller/keeper/genesis.go | 2 +- .../controller/keeper/genesis_test.go | 4 +- .../controller/keeper/keeper.go | 12 +- .../controller/keeper/keeper_test.go | 4 +- .../host/keeper/genesis.go | 2 +- .../host/keeper/genesis_test.go | 4 +- .../host/keeper/keeper.go | 28 +-- .../host/keeper/keeper_test.go | 20 +-- .../host/keeper/relay.go | 8 +- modules/apps/27-interchain-accounts/module.go | 10 +- .../27-interchain-accounts/types/genesis.go | 18 +- .../types/genesis.pb.go | 164 ++++++++---------- .../interchain_accounts/v1/genesis.proto | 22 ++- 13 files changed, 128 insertions(+), 170 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/genesis.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go index 8e372000e73..101acdea21e 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/genesis.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go @@ -30,7 +30,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, state types.ControllerGenesisSt } // ExportGenesis returns the interchain accounts controller exported genesis -func ExportGenesis(ctx sdk.Context, keeper Keeper) *types.ControllerGenesisState { +func ExportGenesis(ctx sdk.Context, keeper Keeper) types.ControllerGenesisState { return types.NewControllerGenesisState( keeper.GetAllActiveChannels(ctx), keeper.GetAllInterchainAccounts(ctx), diff --git a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go index 4e0f749f6d7..5f0880eb94b 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go @@ -10,13 +10,13 @@ func (suite *KeeperTestSuite) TestInitGenesis() { suite.SetupTest() genesisState := types.ControllerGenesisState{ - ActiveChannels: []*types.ActiveChannel{ + ActiveChannels: []types.ActiveChannel{ { PortId: TestPortID, ChannelId: ibctesting.FirstChannelID, }, }, - InterchainAccounts: []*types.RegisteredInterchainAccount{ + InterchainAccounts: []types.RegisteredInterchainAccount{ { PortId: TestPortID, AccountAddress: TestAccAddress.String(), diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index 08de202dcc8..ea2d7faa832 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -138,16 +138,16 @@ func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool } // GetAllActiveChannels returns a list of all active interchain accounts controller channels and their associated port identifiers -func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []*types.ActiveChannel { +func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []types.ActiveChannel { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte(types.ActiveChannelKeyPrefix)) defer iterator.Close() - var activeChannels []*types.ActiveChannel + var activeChannels []types.ActiveChannel for ; iterator.Valid(); iterator.Next() { keySplit := strings.Split(string(iterator.Key()), "/") - ch := &types.ActiveChannel{ + ch := types.ActiveChannel{ PortId: keySplit[1], ChannelId: string(iterator.Value()), } @@ -189,15 +189,15 @@ func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (str } // GetAllInterchainAccounts returns a list of all registered interchain account addresses and their associated controller port identifiers -func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []*types.RegisteredInterchainAccount { +func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []types.RegisteredInterchainAccount { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte(types.OwnerKeyPrefix)) - var interchainAccounts []*types.RegisteredInterchainAccount + var interchainAccounts []types.RegisteredInterchainAccount for ; iterator.Valid(); iterator.Next() { keySplit := strings.Split(string(iterator.Key()), "/") - acc := &types.RegisteredInterchainAccount{ + acc := types.RegisteredInterchainAccount{ PortId: keySplit[1], AccountAddress: string(iterator.Value()), } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go index 3b5a21e91ec..9bfaef86307 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go @@ -170,7 +170,7 @@ func (suite *KeeperTestSuite) TestGetAllActiveChannels() { suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), expectedPortID, expectedChannelID) - expectedChannels := []*types.ActiveChannel{ + expectedChannels := []types.ActiveChannel{ { PortId: TestPortID, ChannelId: path.EndpointA.ChannelID, @@ -202,7 +202,7 @@ func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() { suite.chainA.GetSimApp().ICAControllerKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr) - expectedAccounts := []*types.RegisteredInterchainAccount{ + expectedAccounts := []types.RegisteredInterchainAccount{ { PortId: TestPortID, AccountAddress: TestAccAddress.String(), diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis.go b/modules/apps/27-interchain-accounts/host/keeper/genesis.go index 7a321b88b37..4a8584102f5 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/genesis.go +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis.go @@ -28,7 +28,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, state types.HostGenesisState) { } // ExportGenesis returns the interchain accounts host exported genesis -func ExportGenesis(ctx sdk.Context, keeper Keeper) *types.HostGenesisState { +func ExportGenesis(ctx sdk.Context, keeper Keeper) types.HostGenesisState { return types.NewHostGenesisState( keeper.GetAllActiveChannels(ctx), keeper.GetAllInterchainAccounts(ctx), diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go index 9d4a0538599..41cdcf5b671 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go @@ -10,13 +10,13 @@ func (suite *KeeperTestSuite) TestInitGenesis() { suite.SetupTest() genesisState := types.HostGenesisState{ - ActiveChannels: []*types.ActiveChannel{ + ActiveChannels: []types.ActiveChannel{ { PortId: TestPortID, ChannelId: ibctesting.FirstChannelID, }, }, - InterchainAccounts: []*types.RegisteredInterchainAccount{ + InterchainAccounts: []types.RegisteredInterchainAccount{ { PortId: TestPortID, AccountAddress: TestAccAddress.String(), diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go index d27962d9d63..bd21aa90397 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -76,22 +76,6 @@ func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, accAddr sdk.AccAddres k.SetInterchainAccountAddress(ctx, controllerPortID, interchainAccount.Address) } -// GetAllPorts returns all ports to which the interchain accounts host module is bound. Used in ExportGenesis -func (k Keeper) GetAllPorts(ctx sdk.Context) []string { - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, []byte(types.PortKeyPrefix)) - defer iterator.Close() - - var ports []string - for ; iterator.Valid(); iterator.Next() { - keySplit := strings.Split(string(iterator.Key()), "/") - - ports = append(ports, keySplit[1]) - } - - return ports -} - // BindPort stores the provided portID and binds to it, returning the associated capability func (k Keeper) BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability { store := ctx.KVStore(k.storeKey) @@ -129,16 +113,16 @@ func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool } // GetAllActiveChannels returns a list of all active interchain accounts host channels and their associated port identifiers -func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []*types.ActiveChannel { +func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []types.ActiveChannel { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte(types.ActiveChannelKeyPrefix)) defer iterator.Close() - var activeChannels []*types.ActiveChannel + var activeChannels []types.ActiveChannel for ; iterator.Valid(); iterator.Next() { keySplit := strings.Split(string(iterator.Key()), "/") - ch := &types.ActiveChannel{ + ch := types.ActiveChannel{ PortId: keySplit[1], ChannelId: string(iterator.Value()), } @@ -180,15 +164,15 @@ func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (str } // GetAllInterchainAccounts returns a list of all registered interchain account addresses and their associated controller port identifiers -func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []*types.RegisteredInterchainAccount { +func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []types.RegisteredInterchainAccount { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte(types.OwnerKeyPrefix)) - var interchainAccounts []*types.RegisteredInterchainAccount + var interchainAccounts []types.RegisteredInterchainAccount for ; iterator.Valid(); iterator.Next() { keySplit := strings.Split(string(iterator.Key()), "/") - acc := &types.RegisteredInterchainAccount{ + acc := types.RegisteredInterchainAccount{ PortId: keySplit[1], AccountAddress: string(iterator.Value()), } diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go index 5285dff0f98..ad79e439b34 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go @@ -117,22 +117,6 @@ func (suite *KeeperTestSuite) TestIsBound() { suite.Require().True(isBound) } -func (suite *KeeperTestSuite) TestGetAllPorts() { - suite.SetupTest() - - path := NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - expectedPorts := []string{types.PortID} - - ports := suite.chainB.GetSimApp().ICAHostKeeper.GetAllPorts(suite.chainB.GetContext()) - suite.Require().Len(ports, len(expectedPorts)) - suite.Require().Equal(expectedPorts, ports) -} - func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { suite.SetupTest() @@ -170,7 +154,7 @@ func (suite *KeeperTestSuite) TestGetAllActiveChannels() { suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), expectedPortID, expectedChannelID) - expectedChannels := []*types.ActiveChannel{ + expectedChannels := []types.ActiveChannel{ { PortId: path.EndpointB.ChannelConfig.PortID, ChannelId: path.EndpointB.ChannelID, @@ -202,7 +186,7 @@ func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() { suite.chainB.GetSimApp().ICAHostKeeper.SetInterchainAccountAddress(suite.chainB.GetContext(), expectedPortID, expectedAccAddr) - expectedAccounts := []*types.RegisteredInterchainAccount{ + expectedAccounts := []types.RegisteredInterchainAccount{ { PortId: TestPortID, AccountAddress: TestAccAddress.String(), diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay.go b/modules/apps/27-interchain-accounts/host/keeper/relay.go index 3c2a603de94..85e8e1e8dec 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay.go @@ -32,16 +32,14 @@ func (k Keeper) executeTx(ctx sdk.Context, sourcePort, destPort, destChannel str return err } + // CacheContext returns a new context with the multi-store branched into a cached storage object + // writeCache is called only if all msgs succeed, performing state transitions atomically + cacheCtx, writeCache := ctx.CacheContext() for _, msg := range msgs { if err := msg.ValidateBasic(); err != nil { return err } - } - // CacheContext returns a new context with the multi-store branched into a cached storage object - // writeCache is called only if all msgs succeed, performing state transitions atomically - cacheCtx, writeCache := ctx.CacheContext() - for _, msg := range msgs { if _, err := k.executeMsg(cacheCtx, msg); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index ed3a09c358d..88679c3a4ee 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -56,7 +56,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { // ValidateGenesis performs genesis state validation for the IBC interchain acounts module func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { - return nil + return nil // TODO: https://github.com/cosmos/ibc-go/issues/535 } // RegisterRESTRoutes implements AppModuleBasic interface @@ -127,11 +127,11 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json. cdc.MustUnmarshalJSON(data, &genesisState) if am.controllerKeeper != nil { - controllerkeeper.InitGenesis(ctx, *am.controllerKeeper, *genesisState.ControllerGenesisState) + controllerkeeper.InitGenesis(ctx, *am.controllerKeeper, genesisState.ControllerGenesisState) } if am.hostKeeper != nil { - hostkeeper.InitGenesis(ctx, *am.hostKeeper, *genesisState.HostGenesisState) + hostkeeper.InitGenesis(ctx, *am.hostKeeper, genesisState.HostGenesisState) } return []abci.ValidatorUpdate{} @@ -140,8 +140,8 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json. // ExportGenesis returns the exported genesis state as raw bytes for the interchain accounts module func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { var ( - controllerGenesisState *types.ControllerGenesisState - hostGenesisState *types.HostGenesisState + controllerGenesisState = types.DefaultControllerGenesis() + hostGenesisState = types.DefaultHostGenesis() ) if am.controllerKeeper != nil { diff --git a/modules/apps/27-interchain-accounts/types/genesis.go b/modules/apps/27-interchain-accounts/types/genesis.go index 757f152a149..9fbf9489dc1 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.go +++ b/modules/apps/27-interchain-accounts/types/genesis.go @@ -9,7 +9,7 @@ func DefaultGenesis() *GenesisState { } // NewGenesisState creates and returns a new GenesisState instance from the provided controller and host genesis state types -func NewGenesisState(controllerGenesisState *ControllerGenesisState, hostGenesisState *HostGenesisState) *GenesisState { +func NewGenesisState(controllerGenesisState ControllerGenesisState, hostGenesisState HostGenesisState) *GenesisState { return &GenesisState{ ControllerGenesisState: controllerGenesisState, HostGenesisState: hostGenesisState, @@ -17,13 +17,13 @@ func NewGenesisState(controllerGenesisState *ControllerGenesisState, hostGenesis } // DefaultControllerGenesis creates and returns the default interchain accounts ControllerGenesisState -func DefaultControllerGenesis() *ControllerGenesisState { - return &ControllerGenesisState{} +func DefaultControllerGenesis() ControllerGenesisState { + return ControllerGenesisState{} } // NewControllerGenesisState creates a returns a new ControllerGenesisState instance -func NewControllerGenesisState(channels []*ActiveChannel, accounts []*RegisteredInterchainAccount, ports []string) *ControllerGenesisState { - return &ControllerGenesisState{ +func NewControllerGenesisState(channels []ActiveChannel, accounts []RegisteredInterchainAccount, ports []string) ControllerGenesisState { + return ControllerGenesisState{ ActiveChannels: channels, InterchainAccounts: accounts, Ports: ports, @@ -31,15 +31,15 @@ func NewControllerGenesisState(channels []*ActiveChannel, accounts []*Registered } // DefaultHostGenesis creates and returns the default interchain accounts HostGenesisState -func DefaultHostGenesis() *HostGenesisState { - return &HostGenesisState{ +func DefaultHostGenesis() HostGenesisState { + return HostGenesisState{ Port: PortID, } } // NewHostGenesisState creates a returns a new HostGenesisState instance -func NewHostGenesisState(channels []*ActiveChannel, accounts []*RegisteredInterchainAccount, port string) *HostGenesisState { - return &HostGenesisState{ +func NewHostGenesisState(channels []ActiveChannel, accounts []RegisteredInterchainAccount, port string) HostGenesisState { + return HostGenesisState{ ActiveChannels: channels, InterchainAccounts: accounts, Port: port, diff --git a/modules/apps/27-interchain-accounts/types/genesis.pb.go b/modules/apps/27-interchain-accounts/types/genesis.pb.go index 3faa19c0d88..261826239bf 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.pb.go +++ b/modules/apps/27-interchain-accounts/types/genesis.pb.go @@ -25,8 +25,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GenesisState defines the interchain accounts genesis state type GenesisState struct { - ControllerGenesisState *ControllerGenesisState `protobuf:"bytes,1,opt,name=controller_genesis_state,json=controllerGenesisState,proto3" json:"controller_genesis_state,omitempty" yaml:"controller_genesis_state"` - HostGenesisState *HostGenesisState `protobuf:"bytes,2,opt,name=host_genesis_state,json=hostGenesisState,proto3" json:"host_genesis_state,omitempty" yaml:"host_genesis_state"` + ControllerGenesisState ControllerGenesisState `protobuf:"bytes,1,opt,name=controller_genesis_state,json=controllerGenesisState,proto3" json:"controller_genesis_state" yaml:"controller_genesis_state"` + HostGenesisState HostGenesisState `protobuf:"bytes,2,opt,name=host_genesis_state,json=hostGenesisState,proto3" json:"host_genesis_state" yaml:"host_genesis_state"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -62,25 +62,25 @@ func (m *GenesisState) XXX_DiscardUnknown() { var xxx_messageInfo_GenesisState proto.InternalMessageInfo -func (m *GenesisState) GetControllerGenesisState() *ControllerGenesisState { +func (m *GenesisState) GetControllerGenesisState() ControllerGenesisState { if m != nil { return m.ControllerGenesisState } - return nil + return ControllerGenesisState{} } -func (m *GenesisState) GetHostGenesisState() *HostGenesisState { +func (m *GenesisState) GetHostGenesisState() HostGenesisState { if m != nil { return m.HostGenesisState } - return nil + return HostGenesisState{} } // ControllerGenesisState defines the interchain accounts controller genesis state type ControllerGenesisState struct { - ActiveChannels []*ActiveChannel `protobuf:"bytes,1,rep,name=active_channels,json=activeChannels,proto3" json:"active_channels,omitempty" yaml:"active_channels"` - InterchainAccounts []*RegisteredInterchainAccount `protobuf:"bytes,2,rep,name=interchain_accounts,json=interchainAccounts,proto3" json:"interchain_accounts,omitempty" yaml:"interchain_accounts"` - Ports []string `protobuf:"bytes,3,rep,name=ports,proto3" json:"ports,omitempty"` + ActiveChannels []ActiveChannel `protobuf:"bytes,1,rep,name=active_channels,json=activeChannels,proto3" json:"active_channels" yaml:"active_channels"` + InterchainAccounts []RegisteredInterchainAccount `protobuf:"bytes,2,rep,name=interchain_accounts,json=interchainAccounts,proto3" json:"interchain_accounts" yaml:"interchain_accounts"` + Ports []string `protobuf:"bytes,3,rep,name=ports,proto3" json:"ports,omitempty"` } func (m *ControllerGenesisState) Reset() { *m = ControllerGenesisState{} } @@ -116,14 +116,14 @@ func (m *ControllerGenesisState) XXX_DiscardUnknown() { var xxx_messageInfo_ControllerGenesisState proto.InternalMessageInfo -func (m *ControllerGenesisState) GetActiveChannels() []*ActiveChannel { +func (m *ControllerGenesisState) GetActiveChannels() []ActiveChannel { if m != nil { return m.ActiveChannels } return nil } -func (m *ControllerGenesisState) GetInterchainAccounts() []*RegisteredInterchainAccount { +func (m *ControllerGenesisState) GetInterchainAccounts() []RegisteredInterchainAccount { if m != nil { return m.InterchainAccounts } @@ -139,9 +139,9 @@ func (m *ControllerGenesisState) GetPorts() []string { // HostGenesisState defines the interchain accounts host genesis state type HostGenesisState struct { - ActiveChannels []*ActiveChannel `protobuf:"bytes,1,rep,name=active_channels,json=activeChannels,proto3" json:"active_channels,omitempty" yaml:"active_channels"` - InterchainAccounts []*RegisteredInterchainAccount `protobuf:"bytes,2,rep,name=interchain_accounts,json=interchainAccounts,proto3" json:"interchain_accounts,omitempty" yaml:"interchain_accounts"` - Port string `protobuf:"bytes,3,opt,name=port,proto3" json:"port,omitempty"` + ActiveChannels []ActiveChannel `protobuf:"bytes,1,rep,name=active_channels,json=activeChannels,proto3" json:"active_channels" yaml:"active_channels"` + InterchainAccounts []RegisteredInterchainAccount `protobuf:"bytes,2,rep,name=interchain_accounts,json=interchainAccounts,proto3" json:"interchain_accounts" yaml:"interchain_accounts"` + Port string `protobuf:"bytes,3,opt,name=port,proto3" json:"port,omitempty"` } func (m *HostGenesisState) Reset() { *m = HostGenesisState{} } @@ -177,14 +177,14 @@ func (m *HostGenesisState) XXX_DiscardUnknown() { var xxx_messageInfo_HostGenesisState proto.InternalMessageInfo -func (m *HostGenesisState) GetActiveChannels() []*ActiveChannel { +func (m *HostGenesisState) GetActiveChannels() []ActiveChannel { if m != nil { return m.ActiveChannels } return nil } -func (m *HostGenesisState) GetInterchainAccounts() []*RegisteredInterchainAccount { +func (m *HostGenesisState) GetInterchainAccounts() []RegisteredInterchainAccount { if m != nil { return m.InterchainAccounts } @@ -317,41 +317,41 @@ func init() { } var fileDescriptor_629b3ced0911516b = []byte{ - // 540 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x94, 0xbf, 0x8f, 0xd3, 0x30, - 0x14, 0xc7, 0xeb, 0x14, 0x0e, 0xd5, 0x07, 0xc7, 0x61, 0x8e, 0x2a, 0x14, 0x91, 0x54, 0x66, 0xa0, - 0x12, 0x6a, 0xa2, 0x2b, 0xbf, 0x04, 0x0b, 0x6a, 0x0b, 0x82, 0xae, 0x61, 0x63, 0x89, 0x52, 0xc7, - 0x4a, 0x2d, 0xa5, 0x71, 0x15, 0xbb, 0x95, 0x4e, 0xec, 0xac, 0xb0, 0xb0, 0xf2, 0x77, 0x20, 0x31, - 0xb2, 0x30, 0xde, 0xc8, 0x14, 0xa1, 0xf6, 0x3f, 0xc8, 0x5f, 0x80, 0x62, 0x47, 0xa5, 0x2d, 0x01, - 0x95, 0x9d, 0xcd, 0xf6, 0x7b, 0xdf, 0xf7, 0x3e, 0xef, 0x3d, 0xf9, 0xc1, 0x87, 0x6c, 0x4c, 0xdc, - 0x60, 0x36, 0x8b, 0x19, 0x09, 0x24, 0xe3, 0x89, 0x70, 0x59, 0x22, 0x69, 0x4a, 0x26, 0x01, 0x4b, - 0xfc, 0x80, 0x10, 0x3e, 0x4f, 0xa4, 0x70, 0x17, 0xa7, 0x6e, 0x44, 0x13, 0x2a, 0x98, 0x70, 0x66, - 0x29, 0x97, 0x1c, 0xdd, 0x65, 0x63, 0xe2, 0x6c, 0xca, 0x9c, 0x0a, 0x99, 0xb3, 0x38, 0x6d, 0x9d, - 0x44, 0x3c, 0xe2, 0x4a, 0xe3, 0x16, 0x27, 0x2d, 0xc7, 0x9f, 0x0d, 0x78, 0xf9, 0xa5, 0x0e, 0xf8, - 0x5a, 0x06, 0x92, 0xa2, 0x4f, 0x00, 0x9a, 0x84, 0x27, 0x32, 0xe5, 0x71, 0x4c, 0x53, 0xbf, 0x4c, - 0xe6, 0x8b, 0xc2, 0x68, 0x82, 0x36, 0xe8, 0x1c, 0xf6, 0x9e, 0x39, 0x7b, 0xe6, 0x74, 0x86, 0xeb, - 0x40, 0x9b, 0x39, 0x06, 0x77, 0xf2, 0xcc, 0xb6, 0xcf, 0x82, 0x69, 0xfc, 0x14, 0xff, 0x29, 0x15, - 0xf6, 0x9a, 0xa4, 0x52, 0x8c, 0xde, 0x01, 0x88, 0x26, 0x5c, 0xc8, 0x1d, 0x34, 0x43, 0xa1, 0x3d, - 0xd9, 0x1b, 0xed, 0x15, 0x17, 0x72, 0x0b, 0xea, 0x76, 0x9e, 0xd9, 0x37, 0x35, 0xd4, 0xef, 0xe1, - 0xb1, 0x77, 0x3c, 0xd9, 0x11, 0xe0, 0xaf, 0x06, 0x6c, 0x56, 0x17, 0x88, 0xde, 0xc2, 0xab, 0x01, - 0x91, 0x6c, 0x41, 0x7d, 0x32, 0x09, 0x92, 0x84, 0xc6, 0xc2, 0x04, 0xed, 0x7a, 0xe7, 0xb0, 0xf7, - 0x68, 0x6f, 0xbe, 0xbe, 0xd2, 0x0f, 0xb5, 0x7c, 0xd0, 0xca, 0x33, 0xbb, 0xa9, 0xe1, 0x76, 0x02, - 0x63, 0xef, 0x28, 0xd8, 0x74, 0x15, 0xe8, 0x23, 0x80, 0xd7, 0x2b, 0x82, 0x9a, 0x86, 0x22, 0x78, - 0xbe, 0x37, 0x81, 0x47, 0x23, 0x26, 0x24, 0x4d, 0x69, 0x38, 0x5a, 0x3b, 0xf4, 0xb5, 0x7d, 0x60, - 0xe5, 0x99, 0xdd, 0xd2, 0x3c, 0x15, 0x6a, 0xec, 0x21, 0xb6, 0x2b, 0x11, 0xe8, 0x04, 0x5e, 0x9c, - 0xf1, 0x54, 0x0a, 0xb3, 0xde, 0xae, 0x77, 0x1a, 0x9e, 0xbe, 0xe0, 0x2f, 0x06, 0x3c, 0xde, 0x9d, - 0xc5, 0xff, 0xfe, 0x55, 0xf5, 0x0f, 0xc1, 0x0b, 0x45, 0xcb, 0xcc, 0x7a, 0x1b, 0x74, 0x1a, 0x9e, - 0x3a, 0xe3, 0x14, 0x5e, 0xd9, 0x2a, 0x14, 0xdd, 0x83, 0x97, 0x0a, 0x83, 0xcf, 0x42, 0xf5, 0x59, - 0x1b, 0x03, 0x94, 0x67, 0xf6, 0x91, 0xce, 0x54, 0x1a, 0xb0, 0x77, 0x50, 0x9c, 0x46, 0x21, 0x7a, - 0x00, 0x61, 0xd9, 0x86, 0xc2, 0xdf, 0x50, 0xfe, 0x37, 0xf2, 0xcc, 0xbe, 0x56, 0xfe, 0xcd, 0xb5, - 0x0d, 0x7b, 0x8d, 0xf2, 0x32, 0x0a, 0xf1, 0x7b, 0x00, 0x6f, 0xfd, 0xa5, 0xb6, 0x7f, 0x43, 0x18, - 0x16, 0x93, 0x56, 0x3a, 0x3f, 0x08, 0xc3, 0x94, 0x0a, 0x51, 0x72, 0x6c, 0x4d, 0x6c, 0xcb, 0x41, - 0x4d, 0x4c, 0xbd, 0xf4, 0xf5, 0xc3, 0xc0, 0xff, 0xb6, 0xb4, 0xc0, 0xf9, 0xd2, 0x02, 0x3f, 0x96, - 0x16, 0xf8, 0xb0, 0xb2, 0x6a, 0xe7, 0x2b, 0xab, 0xf6, 0x7d, 0x65, 0xd5, 0xde, 0xbc, 0x88, 0x98, - 0x9c, 0xcc, 0xc7, 0x0e, 0xe1, 0x53, 0x97, 0x70, 0x31, 0xe5, 0xc2, 0x65, 0x63, 0xd2, 0x8d, 0xb8, - 0xbb, 0xe8, 0xb9, 0x53, 0x1e, 0xce, 0x63, 0x2a, 0x8a, 0xa5, 0x2b, 0xdc, 0xde, 0xe3, 0xee, 0xaf, - 0x9e, 0x77, 0xd7, 0xfb, 0x56, 0x9e, 0xcd, 0xa8, 0x18, 0x1f, 0xa8, 0x65, 0x79, 0xff, 0x67, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x21, 0x52, 0x9a, 0x46, 0xa4, 0x05, 0x00, 0x00, + // 543 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x94, 0xcf, 0x8f, 0x12, 0x31, + 0x14, 0xc7, 0xe9, 0xa0, 0x6b, 0xe8, 0xea, 0xba, 0xd6, 0x75, 0x33, 0x62, 0x32, 0x60, 0x2f, 0x4b, + 0x62, 0x98, 0x66, 0xf1, 0x57, 0xf4, 0x62, 0x00, 0x8d, 0x72, 0x1d, 0x6f, 0x5e, 0x26, 0xa5, 0xd3, + 0x0c, 0x4d, 0x86, 0x29, 0x99, 0x16, 0x92, 0x3d, 0x79, 0xf7, 0xa2, 0x57, 0xaf, 0xfe, 0x25, 0x26, + 0x5e, 0x36, 0xf1, 0xb2, 0x47, 0x4f, 0xc4, 0xc0, 0x7f, 0xc0, 0x5f, 0x60, 0xa6, 0x9d, 0x20, 0x20, + 0x6e, 0xf0, 0xee, 0xad, 0xed, 0x7b, 0xdf, 0xf7, 0xfd, 0xf4, 0xbd, 0xb4, 0xf0, 0xb1, 0xe8, 0x33, + 0x42, 0x47, 0xa3, 0x44, 0x30, 0xaa, 0x85, 0x4c, 0x15, 0x11, 0xa9, 0xe6, 0x19, 0x1b, 0x50, 0x91, + 0x86, 0x94, 0x31, 0x39, 0x4e, 0xb5, 0x22, 0x93, 0x53, 0x12, 0xf3, 0x94, 0x2b, 0xa1, 0xfc, 0x51, + 0x26, 0xb5, 0x44, 0x27, 0xa2, 0xcf, 0xfc, 0x55, 0x99, 0xbf, 0x45, 0xe6, 0x4f, 0x4e, 0xab, 0x47, + 0xb1, 0x8c, 0xa5, 0xd1, 0x90, 0x7c, 0x65, 0xe5, 0xf8, 0xab, 0x03, 0xaf, 0xbf, 0xb6, 0x05, 0xdf, + 0x6a, 0xaa, 0x39, 0xfa, 0x02, 0xa0, 0xcb, 0x64, 0xaa, 0x33, 0x99, 0x24, 0x3c, 0x0b, 0x0b, 0xb3, + 0x50, 0xe5, 0x41, 0x17, 0xd4, 0x41, 0x63, 0xbf, 0xf5, 0xc2, 0xdf, 0xd1, 0xd3, 0xef, 0x2e, 0x0b, + 0xad, 0x7a, 0x74, 0x4e, 0xce, 0xa7, 0xb5, 0xd2, 0x62, 0x5a, 0xab, 0x9d, 0xd1, 0x61, 0xf2, 0x1c, + 0xff, 0xcd, 0x0e, 0x07, 0xc7, 0x6c, 0x6b, 0x01, 0xf4, 0x01, 0x40, 0x34, 0x90, 0x4a, 0x6f, 0xe0, + 0x39, 0x06, 0xef, 0xd9, 0xce, 0x78, 0x6f, 0xa4, 0xd2, 0x6b, 0x60, 0xf7, 0x0b, 0xb0, 0xbb, 0x16, + 0xec, 0x4f, 0x0b, 0x1c, 0x1c, 0x0e, 0x36, 0x44, 0xf8, 0xbb, 0x03, 0x8f, 0xb7, 0x5f, 0x14, 0xbd, + 0x87, 0x37, 0x29, 0xd3, 0x62, 0xc2, 0x43, 0x36, 0xa0, 0x69, 0xca, 0x13, 0xe5, 0x82, 0x7a, 0xb9, + 0xb1, 0xdf, 0x7a, 0xb2, 0x33, 0x63, 0xdb, 0xe8, 0xbb, 0x56, 0xde, 0xf1, 0x0a, 0xc0, 0x63, 0x0b, + 0xb8, 0x51, 0x1c, 0x07, 0x07, 0x74, 0x35, 0x5d, 0xa1, 0xcf, 0x00, 0xde, 0xde, 0x52, 0xd8, 0x75, + 0x0c, 0xc5, 0xcb, 0x9d, 0x29, 0x02, 0x1e, 0x0b, 0xa5, 0x79, 0xc6, 0xa3, 0xde, 0x32, 0xa1, 0x6d, + 0xe3, 0x1d, 0x5c, 0x30, 0x55, 0x2d, 0xd3, 0x96, 0x0a, 0x38, 0x40, 0x62, 0x53, 0xa6, 0xd0, 0x11, + 0xbc, 0x3a, 0x92, 0x99, 0x56, 0x6e, 0xb9, 0x5e, 0x6e, 0x54, 0x02, 0xbb, 0xc1, 0xdf, 0x1c, 0x78, + 0xb8, 0x39, 0x97, 0xff, 0x7d, 0xbc, 0xac, 0x8f, 0x08, 0x5e, 0xc9, 0x5b, 0xe7, 0x96, 0xeb, 0xa0, + 0x51, 0x09, 0xcc, 0x1a, 0x67, 0xf0, 0xc6, 0xda, 0x85, 0xd1, 0x03, 0x78, 0x2d, 0x0f, 0x84, 0x22, + 0x32, 0x8f, 0xb8, 0xd2, 0x41, 0x8b, 0x69, 0xed, 0xc0, 0x3a, 0x15, 0x01, 0x1c, 0xec, 0xe5, 0xab, + 0x5e, 0x84, 0x1e, 0x41, 0x58, 0xb4, 0x22, 0xcf, 0x77, 0x4c, 0xfe, 0x9d, 0xc5, 0xb4, 0x76, 0xab, + 0x78, 0xaf, 0xcb, 0x18, 0x0e, 0x2a, 0xc5, 0xa6, 0x17, 0xe1, 0x8f, 0x00, 0xde, 0xbb, 0xe4, 0x7e, + 0xff, 0x86, 0xd0, 0xcd, 0x27, 0x6e, 0x74, 0x21, 0x8d, 0xa2, 0x8c, 0x2b, 0x55, 0x70, 0x54, 0x57, + 0xa7, 0xb6, 0x96, 0x60, 0xa6, 0x66, 0x4e, 0xda, 0xf6, 0xa0, 0x13, 0x9e, 0xcf, 0x3c, 0x70, 0x31, + 0xf3, 0xc0, 0xcf, 0x99, 0x07, 0x3e, 0xcd, 0xbd, 0xd2, 0xc5, 0xdc, 0x2b, 0xfd, 0x98, 0x7b, 0xa5, + 0x77, 0xaf, 0x62, 0xa1, 0x07, 0xe3, 0xbe, 0xcf, 0xe4, 0x90, 0x30, 0xa9, 0x86, 0x52, 0x11, 0xd1, + 0x67, 0xcd, 0x58, 0x92, 0x49, 0x8b, 0x0c, 0x65, 0x34, 0x4e, 0xb8, 0xca, 0x3f, 0x63, 0x45, 0x5a, + 0x4f, 0x9b, 0xbf, 0x7b, 0xde, 0x5c, 0xfe, 0xc3, 0xfa, 0x6c, 0xc4, 0x55, 0x7f, 0xcf, 0x7c, 0xa2, + 0x0f, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x47, 0x25, 0xf6, 0xbc, 0x05, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -374,30 +374,26 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.HostGenesisState != nil { - { - size, err := m.HostGenesisState.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) + { + size, err := m.HostGenesisState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x12 + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) } - if m.ControllerGenesisState != nil { - { - size, err := m.ControllerGenesisState.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + { + size, err := m.ControllerGenesisState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0xa + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -610,14 +606,10 @@ func (m *GenesisState) Size() (n int) { } var l int _ = l - if m.ControllerGenesisState != nil { - l = m.ControllerGenesisState.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - if m.HostGenesisState != nil { - l = m.HostGenesisState.Size() - n += 1 + l + sovGenesis(uint64(l)) - } + l = m.ControllerGenesisState.Size() + n += 1 + l + sovGenesis(uint64(l)) + l = m.HostGenesisState.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -771,9 +763,6 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.ControllerGenesisState == nil { - m.ControllerGenesisState = &ControllerGenesisState{} - } if err := m.ControllerGenesisState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -807,9 +796,6 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.HostGenesisState == nil { - m.HostGenesisState = &HostGenesisState{} - } if err := m.HostGenesisState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -893,7 +879,7 @@ func (m *ControllerGenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ActiveChannels = append(m.ActiveChannels, &ActiveChannel{}) + m.ActiveChannels = append(m.ActiveChannels, ActiveChannel{}) if err := m.ActiveChannels[len(m.ActiveChannels)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -927,7 +913,7 @@ func (m *ControllerGenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.InterchainAccounts = append(m.InterchainAccounts, &RegisteredInterchainAccount{}) + m.InterchainAccounts = append(m.InterchainAccounts, RegisteredInterchainAccount{}) if err := m.InterchainAccounts[len(m.InterchainAccounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -1043,7 +1029,7 @@ func (m *HostGenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ActiveChannels = append(m.ActiveChannels, &ActiveChannel{}) + m.ActiveChannels = append(m.ActiveChannels, ActiveChannel{}) if err := m.ActiveChannels[len(m.ActiveChannels)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -1077,7 +1063,7 @@ func (m *HostGenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.InterchainAccounts = append(m.InterchainAccounts, &RegisteredInterchainAccount{}) + m.InterchainAccounts = append(m.InterchainAccounts, RegisteredInterchainAccount{}) if err := m.InterchainAccounts[len(m.InterchainAccounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/proto/ibc/applications/interchain_accounts/v1/genesis.proto b/proto/ibc/applications/interchain_accounts/v1/genesis.proto index bc3ee7d242f..69527bd867a 100644 --- a/proto/ibc/applications/interchain_accounts/v1/genesis.proto +++ b/proto/ibc/applications/interchain_accounts/v1/genesis.proto @@ -8,22 +8,28 @@ import "gogoproto/gogo.proto"; // GenesisState defines the interchain accounts genesis state message GenesisState { - ControllerGenesisState controller_genesis_state = 1 [(gogoproto.moretags) = "yaml:\"controller_genesis_state\""]; - HostGenesisState host_genesis_state = 2 [(gogoproto.moretags) = "yaml:\"host_genesis_state\""]; + ControllerGenesisState controller_genesis_state = 1 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"controller_genesis_state\""]; + HostGenesisState host_genesis_state = 2 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"host_genesis_state\""]; } // ControllerGenesisState defines the interchain accounts controller genesis state message ControllerGenesisState { - repeated ActiveChannel active_channels = 1 [(gogoproto.moretags) = "yaml:\"active_channels\""]; - repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.moretags) = "yaml:\"interchain_accounts\""]; - repeated string ports = 3; + repeated ActiveChannel active_channels = 1 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"active_channels\""]; + repeated RegisteredInterchainAccount interchain_accounts = 2 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"interchain_accounts\""]; + repeated string ports = 3; } // HostGenesisState defines the interchain accounts host genesis state message HostGenesisState { - repeated ActiveChannel active_channels = 1 [(gogoproto.moretags) = "yaml:\"active_channels\""]; - repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.moretags) = "yaml:\"interchain_accounts\""]; - string port = 3; + repeated ActiveChannel active_channels = 1 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"active_channels\""]; + repeated RegisteredInterchainAccount interchain_accounts = 2 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"interchain_accounts\""]; + string port = 3; } // ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel From 3a06187a36a1d4ee855505f1403717dd956b5a54 Mon Sep 17 00:00:00 2001 From: Sean King Date: Fri, 19 Nov 2021 16:40:55 +0100 Subject: [PATCH 54/66] =?UTF-8?q?test:=20adding=20test=20for=20RegisterInt?= =?UTF-8?q?erchainAccount=20&=20adding=20check=20to=20rel=E2=80=A6=20(#552?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: adding test for RegisterInterchainAccount & adding check to relay_test * Update modules/apps/27-interchain-accounts/host/keeper/relay_test.go Co-authored-by: Damian Nolan * Update modules/apps/27-interchain-accounts/host/keeper/relay_test.go Co-authored-by: Damian Nolan * Update modules/apps/27-interchain-accounts/host/keeper/account_test.go * Update modules/apps/27-interchain-accounts/host/keeper/account_test.go Co-authored-by: Damian Nolan --- .../host/keeper/account.go | 26 +++++++++++++++ .../host/keeper/account_test.go | 33 +++++++++++++++++++ .../host/keeper/handshake_test.go | 1 - .../host/keeper/keeper.go | 18 ---------- .../host/keeper/relay_test.go | 14 ++++++++ 5 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/host/keeper/account.go create mode 100644 modules/apps/27-interchain-accounts/host/keeper/account_test.go diff --git a/modules/apps/27-interchain-accounts/host/keeper/account.go b/modules/apps/27-interchain-accounts/host/keeper/account.go new file mode 100644 index 00000000000..d9e213f4ace --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/keeper/account.go @@ -0,0 +1,26 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" +) + +// RegisterInterchainAccount attempts to create a new account using the provided address and stores it in state keyed by the provided port identifier +// If an account for the provided address already exists this function returns early (no-op) +func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, accAddr sdk.AccAddress, controllerPortID string) { + if acc := k.accountKeeper.GetAccount(ctx, accAddr); acc != nil { + return + } + + interchainAccount := types.NewInterchainAccount( + authtypes.NewBaseAccountWithAddress(accAddr), + controllerPortID, + ) + + k.accountKeeper.NewAccount(ctx, interchainAccount) + k.accountKeeper.SetAccount(ctx, interchainAccount) + + k.SetInterchainAccountAddress(ctx, controllerPortID, interchainAccount.Address) +} diff --git a/modules/apps/27-interchain-accounts/host/keeper/account_test.go b/modules/apps/27-interchain-accounts/host/keeper/account_test.go new file mode 100644 index 00000000000..65ce1646905 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/keeper/account_test.go @@ -0,0 +1,33 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v2/testing" +) + +func (suite *KeeperTestSuite) TestRegisterInterchainAccount() { + suite.SetupTest() + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + // InitInterchainAccount + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + portID, err := types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) + suite.Require().NoError(err) + + // Get the address of the interchain account stored in state during handshake step + storedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), portID) + suite.Require().True(found) + + icaAddr, err := sdk.AccAddressFromBech32(storedAddr) + suite.Require().NoError(err) + + // Check if account is created + interchainAccount := suite.chainB.GetSimApp().AccountKeeper.GetAccount(suite.chainB.GetContext(), icaAddr) + suite.Require().Equal(interchainAccount.GetAddress().String(), storedAddr) +} diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go index 65b9a159945..fde51a961ff 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go @@ -168,7 +168,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { } else { suite.Require().Error(err) } - }) } } diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go index bd21aa90397..44735ae81ea 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -8,7 +8,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/tendermint/tendermint/libs/log" @@ -59,23 +58,6 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) } -// RegisterInterchainAccount attempts to create a new account using the provided address and stores it in state keyed by the provided port identifier -// If an account for the provided address already exists this function returns early (no-op) -func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, accAddr sdk.AccAddress, controllerPortID string) { - if acc := k.accountKeeper.GetAccount(ctx, accAddr); acc != nil { - return - } - - interchainAccount := types.NewInterchainAccount( - authtypes.NewBaseAccountWithAddress(accAddr), - controllerPortID, - ) - - k.accountKeeper.NewAccount(ctx, interchainAccount) - k.accountKeeper.SetAccount(ctx, interchainAccount) - k.SetInterchainAccountAddress(ctx, controllerPortID, interchainAccount.Address) -} - // BindPort stores the provided portID and binds to it, returning the associated capability func (k Keeper) BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability { store := ctx.KVStore(k.storeKey) diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index 7bb47ed88a6..9109f7559e5 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -344,6 +344,20 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) + portID, err := types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) + suite.Require().NoError(err) + + // Get the address of the interchain account stored in state during handshake step + storedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), portID) + suite.Require().True(found) + + icaAddr, err := sdk.AccAddressFromBech32(storedAddr) + suite.Require().NoError(err) + + // Check if account is created + interchainAccount := suite.chainB.GetSimApp().AccountKeeper.GetAccount(suite.chainB.GetContext(), icaAddr) + suite.Require().Equal(interchainAccount.GetAddress().String(), storedAddr) + suite.fundICAWallet(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10000)))) tc.malleate() // malleate mutates test data From 37f5c9f48d366a976cb5c43646311a04a5f09e56 Mon Sep 17 00:00:00 2001 From: Sean King Date: Fri, 19 Nov 2021 17:56:30 +0100 Subject: [PATCH 55/66] ICA Code Hygiene (#553) * chore: re-creating account.go for controller side for consitency * chore: remove comment * Update modules/apps/27-interchain-accounts/controller/keeper/account.go --- .../controller/keeper/account.go | 40 +++++++++++ .../controller/keeper/account_test.go | 72 +++++++++++++++++++ .../controller/keeper/keeper.go | 32 --------- .../controller/keeper/keeper_test.go | 67 ----------------- 4 files changed, 112 insertions(+), 99 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/account.go create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/account_test.go diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account.go b/modules/apps/27-interchain-accounts/controller/keeper/account.go new file mode 100644 index 00000000000..ccbe1f38a61 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/account.go @@ -0,0 +1,40 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" +) + +// InitInterchainAccount is the entry point to registering an interchain account. +// It generates a new port identifier using the owner address, connection identifier, +// and counterparty connection identifier. It will bind to the port identifier and +// call 04-channel 'ChanOpenInit'. An error is returned if the port identifier is +// already in use. Gaining access to interchain accounts whose channels have closed +// cannot be done with this function. A regular MsgChanOpenInit must be used. +func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpartyConnectionID, owner string) error { + portID, err := types.GeneratePortID(owner, connectionID, counterpartyConnectionID) + if err != nil { + return err + } + + if k.portKeeper.IsBound(ctx, portID) { + return sdkerrors.Wrap(types.ErrPortAlreadyBound, portID) + } + + cap := k.BindPort(ctx, portID) + if err := k.ClaimCapability(ctx, cap, host.PortPath(portID)); err != nil { + return sdkerrors.Wrap(err, "unable to bind to newly generated portID") + } + + msg := channeltypes.NewMsgChannelOpenInit(portID, types.VersionPrefix, channeltypes.ORDERED, []string{connectionID}, types.PortID, types.ModuleName) + handler := k.msgRouter.Handler(msg) + if _, err := handler(ctx, msg); err != nil { + return err + } + + return nil +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account_test.go b/modules/apps/27-interchain-accounts/controller/keeper/account_test.go new file mode 100644 index 00000000000..8627d6f1ce0 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/account_test.go @@ -0,0 +1,72 @@ +package keeper_test + +import ( + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v2/testing" +) + +func (suite *KeeperTestSuite) TestInitInterchainAccount() { + var ( + owner string + path *ibctesting.Path + err error + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + { + "port is already bound", + func() { + suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), TestPortID) + }, + false, + }, + { + "fails to generate port-id", + func() { + owner = "" + }, + false, + }, + { + "MsgChanOpenInit fails - channel is already active", + func() { + portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + suite.Require().NoError(err) + + suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + + owner = TestOwnerAddress // must be explicitly changed + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + tc.malleate() // malleate mutates test data + + err = suite.chainA.GetSimApp().ICAControllerKeeper.InitInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, path.EndpointB.ConnectionID, owner) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index ea2d7faa832..1fed7445a7a 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -7,13 +7,11 @@ import ( baseapp "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) @@ -55,36 +53,6 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) } -// InitInterchainAccount is the entry point to registering an interchain account. -// It generates a new port identifier using the owner address, connection identifier, -// and counterparty connection identifier. It will bind to the port identifier and -// call 04-channel 'ChanOpenInit'. An error is returned if the port identifier is -// already in use. Gaining access to interchain accounts whose channels have closed -// cannot be done with this function. A regular MsgChanOpenInit must be used. -func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpartyConnectionID, owner string) error { - portID, err := types.GeneratePortID(owner, connectionID, counterpartyConnectionID) - if err != nil { - return err - } - - if k.portKeeper.IsBound(ctx, portID) { - return sdkerrors.Wrap(types.ErrPortAlreadyBound, portID) - } - - cap := k.BindPort(ctx, portID) - if err := k.ClaimCapability(ctx, cap, host.PortPath(portID)); err != nil { - return sdkerrors.Wrap(err, "unable to bind to newly generated portID") - } - - msg := channeltypes.NewMsgChannelOpenInit(portID, types.VersionPrefix, channeltypes.ORDERED, []string{connectionID}, types.PortID, types.ModuleName) - handler := k.msgRouter.Handler(msg) - if _, err := handler(ctx, msg); err != nil { - return err - } - - return nil -} - // GetAllPorts returns all ports to which the interchain accounts controller module is bound. Used in ExportGenesis func (k Keeper) GetAllPorts(ctx sdk.Context) []string { store := ctx.KVStore(k.storeKey) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go index 9bfaef86307..0e61d738826 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go @@ -245,70 +245,3 @@ func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() { suite.Require().True(found) suite.Require().Equal(expectedAccAddr, retrievedAddr) } - -func (suite *KeeperTestSuite) TestInitInterchainAccount() { - var ( - owner string - path *ibctesting.Path - err error - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success", func() {}, true, - }, - { - "port is already bound", - func() { - suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), TestPortID) - }, - false, - }, - { - "fails to generate port-id", - func() { - owner = "" - }, - false, - }, - { - "MsgChanOpenInit fails - channel is already active", - func() { - portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - suite.Require().NoError(err) - - suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID) - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() - - // TODO: Get rid of this? - owner = TestOwnerAddress // must be explicitly changed - - path = NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) - - tc.malleate() // malleate mutates test data - - err = suite.chainA.GetSimApp().ICAControllerKeeper.InitInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, path.EndpointB.ConnectionID, owner) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - - }) - } -} From 009cbecea4bf5c6c056bdc59ecfeea9fec8a7b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Fri, 26 Nov 2021 11:01:19 +0100 Subject: [PATCH 56/66] ica: wrong handshake flow tests (#538) * add tests for testing wrong handshake flow Adds tests for each handshake test attempting to initialize the handshake using the wrong flow. Adds an additional portID check to OnChanOpenAck. * remove unnecessary comment * readjust tests based on new layout * Add tests provided by Damian * add tests for OnChanCloseInit and OnChanCloseConfirm on host side * add OnChanCloseInit/Confirm and NegotiateAppVersion tests to controller side * fix failing test --- .../controller/ibc_module_test.go | 276 ++++++++++++++++++ .../controller/keeper/handshake.go | 4 + .../controller/keeper/handshake_test.go | 6 + .../host/ibc_module_test.go | 231 ++++++++++++++- 4 files changed, 516 insertions(+), 1 deletion(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go index 7cec17d38da..54f07bee76c 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go @@ -10,6 +10,7 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v2/testing" @@ -189,6 +190,54 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { } } +// Test initiating a ChanOpenTry using the controller chain instead of the host chain +// ChainA is the controller chain. ChainB creates a controller port as well, +// attempting to trick chainA. +// Sending a MsgChanOpenTry will never reach the application callback due to +// core IBC checks not passing, so a call to the application callback is also +// done directly. +func (suite *InterchainAccountsTestSuite) TestChanOpenTry() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + // chainB also creates a controller port + err = InitInterchainAccount(path.EndpointB, TestOwnerAddress) + suite.Require().NoError(err) + + path.EndpointA.UpdateClient() + channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + proofInit, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) + + // use chainA (controller) for ChanOpenTry + msg := channeltypes.NewMsgChannelOpenTry(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, TestVersion, channeltypes.ORDERED, []string{path.EndpointA.ConnectionID}, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, types.VersionPrefix, proofInit, proofHeight, types.ModuleName) + handler := suite.chainA.GetSimApp().MsgServiceRouter().Handler(msg) + _, err = handler(suite.chainA.GetContext(), msg) + + suite.Require().Error(err) + + // call application callback directly + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + chanCap, found := suite.chainA.App.GetScopedIBCKeeper().GetCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + suite.Require().True(found) + + err = cbs.OnChanOpenTry( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.Order, []string{path.EndpointA.ConnectionID}, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, + counterparty, path.EndpointA.ChannelConfig.Version, path.EndpointB.ChannelConfig.Version, + ) + suite.Require().Error(err) +} + func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { var ( path *ibctesting.Path @@ -253,3 +302,230 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { } } + +// Test initiating a ChanOpenConfirm using the controller chain instead of the host chain +// ChainA is the controller chain. ChainB is the host chain +// Sending a MsgChanOpenConfirm will never reach the application callback due to +// core IBC checks not passing, so a call to the application callback is also +// done directly. +func (suite *InterchainAccountsTestSuite) TestChanOpenConfirm() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + + // chainB maliciously sets channel to OPEN + channel := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID), []string{path.EndpointB.ConnectionID}, TestVersion) + suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel) + + // commit state changes so proof can be created + suite.chainB.App.Commit() + suite.chainB.NextBlock() + + path.EndpointA.UpdateClient() + + // query proof from ChainB + channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + proofAck, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) + + // use chainA (controller) for ChanOpenConfirm + msg := channeltypes.NewMsgChannelOpenConfirm(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, proofAck, proofHeight, types.ModuleName) + handler := suite.chainA.GetSimApp().MsgServiceRouter().Handler(msg) + _, err = handler(suite.chainA.GetContext(), msg) + + suite.Require().Error(err) + + // call application callback directly + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenConfirm( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + ) + suite.Require().Error(err) + +} + +// OnChanCloseInit on controller (chainA) +func (suite *InterchainAccountsTestSuite) TestOnChanCloseInit() { + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanCloseInit( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + ) + + suite.Require().Error(err) +} + +func (suite *InterchainAccountsTestSuite) TestOnChanCloseConfirm() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanCloseConfirm( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + activeChannelID, found := suite.chainA.GetSimApp().ICAHostKeeper.GetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().False(found) + suite.Require().Empty(activeChannelID) + } else { + suite.Require().Error(err) + } + + }) + } +} + +func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "ICA OnRecvPacket fails with ErrInvalidChannelFlow", func() {}, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + packet := channeltypes.NewPacket( + []byte("empty packet data"), + suite.chainA.SenderAccount.GetSequence(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + ack := cbs.OnRecvPacket(suite.chainA.GetContext(), packet, TestAccAddress) + suite.Require().Equal(tc.expPass, ack.Success()) + }) + } +} + +func (suite *InterchainAccountsTestSuite) TestNegotiateAppVersion() { + var ( + proposedVersion string + ) + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "ICA OnRecvPacket fails with ErrInvalidChannelFlow", func() {}, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + module, _, err := suite.chainA.GetSimApp().GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.GetSimApp().GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + counterpartyPortID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + suite.Require().NoError(err) + + counterparty := channeltypes.Counterparty{ + PortId: counterpartyPortID, + ChannelId: path.EndpointB.ChannelID, + } + + proposedVersion = types.VersionPrefix + + tc.malleate() + + version, err := cbs.NegotiateAppVersion(suite.chainA.GetContext(), channeltypes.ORDERED, path.EndpointA.ConnectionID, path.EndpointA.ChannelConfig.PortID, counterparty, proposedVersion) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NoError(types.ValidateVersion(version)) + suite.Require().Equal(TestVersion, version) + } else { + suite.Require().Error(err) + suite.Require().Empty(version) + } + }) + } +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go index 6145c867109..f88f8f1fadc 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go @@ -70,6 +70,10 @@ func (k Keeper) OnChanOpenAck( channelID string, counterpartyVersion string, ) error { + if portID == types.PortID { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "portID cannot be host chain port ID: %s", types.PortID) + } + if err := types.ValidateVersion(counterpartyVersion); err != nil { return sdkerrors.Wrap(err, "counterparty version validation failed") } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go index a4bd9622eab..f0e634fd362 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go @@ -174,6 +174,12 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { }, false, }, + { + "invalid portID", func() { + path.EndpointA.ChannelConfig.PortID = types.PortID + expectedChannelID = "" + }, false, + }, } for _, tc := range testCases { diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 92203c25ea8..b3362d9faaa 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -45,7 +45,7 @@ func TestICATestSuite(t *testing.T) { } func (suite *InterchainAccountsTestSuite) SetupTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) } @@ -106,6 +106,21 @@ func SetupICAPath(path *ibctesting.Path, owner string) error { return nil } +// Test initiating a ChanOpenInit using the host chain instead of the controller chain +// ChainA is the controller chain. ChainB is the host chain +func (suite *InterchainAccountsTestSuite) TestChanOpenInit() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + // use chainB (host) for ChanOpenInit + msg := channeltypes.NewMsgChannelOpenInit(path.EndpointB.ChannelConfig.PortID, types.VersionPrefix, channeltypes.ORDERED, []string{path.EndpointB.ConnectionID}, path.EndpointA.ChannelConfig.PortID, types.ModuleName) + handler := suite.chainB.GetSimApp().MsgServiceRouter().Handler(msg) + _, err := handler(suite.chainB.GetContext(), msg) + + suite.Require().Error(err) +} + func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { var ( path *ibctesting.Path @@ -192,6 +207,41 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { } +// Test initiating a ChanOpenAck using the host chain instead of the controller chain +// ChainA is the controller chain. ChainB is the host chain +func (suite *InterchainAccountsTestSuite) TestChanOpenAck() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + + // chainA maliciously sets channel to TRYOPEN + channel := channeltypes.NewChannel(channeltypes.TRYOPEN, channeltypes.ORDERED, channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID), []string{path.EndpointA.ConnectionID}, TestVersion) + suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel) + + // commit state changes so proof can be created + suite.chainA.App.Commit() + suite.chainA.NextBlock() + + path.EndpointB.UpdateClient() + + // query proof from ChainA + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + proofTry, proofHeight := path.EndpointA.Chain.QueryProof(channelKey) + + // use chainB (host) for ChanOpenAck + msg := channeltypes.NewMsgChannelOpenAck(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelID, TestVersion, proofTry, proofHeight, types.ModuleName) + handler := suite.chainB.GetSimApp().MsgServiceRouter().Handler(msg) + _, err = handler(suite.chainB.GetContext(), msg) + + suite.Require().Error(err) +} + func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { testCases := []struct { name string @@ -253,6 +303,77 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { } +// OnChanCloseInit on host (chainB) +func (suite *InterchainAccountsTestSuite) TestOnChanCloseInit() { + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanCloseInit( + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, + ) + + suite.Require().Error(err) +} + +func (suite *InterchainAccountsTestSuite) TestOnChanCloseConfirm() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + + { + "success", func() {}, true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanCloseConfirm( + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + + activeChannelID, found := suite.chainB.GetSimApp().ICAHostKeeper.GetActiveChannelID(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().False(found) + suite.Require().Empty(activeChannelID) + } else { + suite.Require().Error(err) + } + + }) + } +} + func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { var ( packetData []byte @@ -337,6 +458,114 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { } +func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "ICA OnAcknowledgementPacket fails with ErrInvalidChannelFlow", func() {}, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + packet := channeltypes.NewPacket( + []byte("empty packet data"), + suite.chainA.SenderAccount.GetSequence(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + err = cbs.OnAcknowledgementPacket(suite.chainB.GetContext(), packet, []byte("ackBytes"), TestAccAddress) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "ICA OnTimeoutPacket fails with ErrInvalidChannelFlow", func() {}, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + packet := channeltypes.NewPacket( + []byte("empty packet data"), + suite.chainA.SenderAccount.GetSequence(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, TestAccAddress) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + func (suite *InterchainAccountsTestSuite) TestNegotiateAppVersion() { var ( proposedVersion string From 5bed1d7cab55fc8d86f8e10f3aa4e86a6109c6c1 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 29 Nov 2021 12:14:51 +0100 Subject: [PATCH 57/66] ica: genesis state validation (#554) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * adding genesis state validation * adding genesis state validation tests * Update modules/apps/27-interchain-accounts/types/genesis_test.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/27-interchain-accounts/types/genesis_test.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * adding ValidateAccountAddress helper to reduce code duplication Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- modules/apps/27-interchain-accounts/module.go | 8 +- .../27-interchain-accounts/types/genesis.go | 77 +++++ .../types/genesis_test.go | 311 ++++++++++++++++++ .../27-interchain-accounts/types/version.go | 12 +- 4 files changed, 406 insertions(+), 2 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/types/genesis_test.go diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 88679c3a4ee..954bd5ec497 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -2,6 +2,7 @@ package ica import ( "encoding/json" + "fmt" "github.com/gorilla/mux" "github.com/spf13/cobra" @@ -56,7 +57,12 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { // ValidateGenesis performs genesis state validation for the IBC interchain acounts module func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { - return nil // TODO: https://github.com/cosmos/ibc-go/issues/535 + var gs types.GenesisState + if err := cdc.UnmarshalJSON(bz, &gs); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + + return gs.Validate() } // RegisterRESTRoutes implements AppModuleBasic interface diff --git a/modules/apps/27-interchain-accounts/types/genesis.go b/modules/apps/27-interchain-accounts/types/genesis.go index 9fbf9489dc1..84e489a4df6 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.go +++ b/modules/apps/27-interchain-accounts/types/genesis.go @@ -1,5 +1,9 @@ package types +import ( + host "github.com/cosmos/ibc-go/v2/modules/core/24-host" +) + // DefaultGenesis creates and returns the interchain accounts GenesisState func DefaultGenesis() *GenesisState { return &GenesisState{ @@ -16,6 +20,19 @@ func NewGenesisState(controllerGenesisState ControllerGenesisState, hostGenesisS } } +// Validate performs basic validation of the interchain accounts GenesisState +func (gs GenesisState) Validate() error { + if err := gs.ControllerGenesisState.Validate(); err != nil { + return err + } + + if err := gs.HostGenesisState.Validate(); err != nil { + return err + } + + return nil +} + // DefaultControllerGenesis creates and returns the default interchain accounts ControllerGenesisState func DefaultControllerGenesis() ControllerGenesisState { return ControllerGenesisState{} @@ -30,6 +47,37 @@ func NewControllerGenesisState(channels []ActiveChannel, accounts []RegisteredIn } } +// Validate performs basic validation of the ControllerGenesisState +func (gs ControllerGenesisState) Validate() error { + for _, ch := range gs.ActiveChannels { + if err := host.ChannelIdentifierValidator(ch.ChannelId); err != nil { + return err + } + + if err := host.PortIdentifierValidator(ch.PortId); err != nil { + return err + } + } + + for _, acc := range gs.InterchainAccounts { + if err := host.PortIdentifierValidator(acc.PortId); err != nil { + return err + } + + if err := ValidateAccountAddress(acc.AccountAddress); err != nil { + return err + } + } + + for _, port := range gs.Ports { + if err := host.PortIdentifierValidator(port); err != nil { + return err + } + } + + return nil +} + // DefaultHostGenesis creates and returns the default interchain accounts HostGenesisState func DefaultHostGenesis() HostGenesisState { return HostGenesisState{ @@ -45,3 +93,32 @@ func NewHostGenesisState(channels []ActiveChannel, accounts []RegisteredIntercha Port: port, } } + +// Validate performs basic validation of the HostGenesisState +func (gs HostGenesisState) Validate() error { + for _, ch := range gs.ActiveChannels { + if err := host.ChannelIdentifierValidator(ch.ChannelId); err != nil { + return err + } + + if err := host.PortIdentifierValidator(ch.PortId); err != nil { + return err + } + } + + for _, acc := range gs.InterchainAccounts { + if err := host.PortIdentifierValidator(acc.PortId); err != nil { + return err + } + + if err := ValidateAccountAddress(acc.AccountAddress); err != nil { + return err + } + } + + if err := host.PortIdentifierValidator(gs.Port); err != nil { + return err + } + + return nil +} diff --git a/modules/apps/27-interchain-accounts/types/genesis_test.go b/modules/apps/27-interchain-accounts/types/genesis_test.go new file mode 100644 index 00000000000..939339f5fb3 --- /dev/null +++ b/modules/apps/27-interchain-accounts/types/genesis_test.go @@ -0,0 +1,311 @@ +package types_test + +import ( + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v2/testing" +) + +func (suite *TypesTestSuite) TestValidateGenesisState() { + var ( + genesisState types.GenesisState + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "failed to validate - empty value", + func() { + genesisState = types.GenesisState{} + }, + false, + }, + { + "failed to validate - invalid controller genesis", + func() { + genesisState = *types.NewGenesisState(types.ControllerGenesisState{Ports: []string{"invalid|port"}}, types.DefaultHostGenesis()) + }, + false, + }, + { + "failed to validate - invalid host genesis", + func() { + genesisState = *types.NewGenesisState(types.DefaultControllerGenesis(), types.HostGenesisState{}) + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + genesisState = *types.DefaultGenesis() + + tc.malleate() // malleate mutates test data + + err := genesisState.Validate() + + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + }) + } +} + +func (suite *TypesTestSuite) TestValidateControllerGenesisState() { + var ( + genesisState types.ControllerGenesisState + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "failed to validate active channel - invalid port identifier", + func() { + activeChannels := []types.ActiveChannel{ + { + PortId: "invalid|port", + ChannelId: ibctesting.FirstChannelID, + }, + } + + genesisState = types.NewControllerGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, []string{}) + }, + false, + }, + { + "failed to validate active channel - invalid channel identifier", + func() { + activeChannels := []types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: "invalid|channel", + }, + } + + genesisState = types.NewControllerGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, []string{}) + }, + false, + }, + { + "failed to validate registered account - invalid port identifier", + func() { + activeChannels := []types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: ibctesting.FirstChannelID, + }, + } + + registeredAccounts := []types.RegisteredInterchainAccount{ + { + PortId: "invalid|port", + AccountAddress: TestOwnerAddress, + }, + } + + genesisState = types.NewControllerGenesisState(activeChannels, registeredAccounts, []string{}) + }, + false, + }, + { + "failed to validate registered account - invalid owner address", + func() { + activeChannels := []types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: ibctesting.FirstChannelID, + }, + } + + registeredAccounts := []types.RegisteredInterchainAccount{ + { + PortId: TestPortID, + AccountAddress: "", + }, + } + + genesisState = types.NewControllerGenesisState(activeChannels, registeredAccounts, []string{}) + }, + false, + }, + { + "failed to validate controller ports - invalid port identifier", + func() { + activeChannels := []types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: ibctesting.FirstChannelID, + }, + } + + registeredAccounts := []types.RegisteredInterchainAccount{ + { + PortId: TestPortID, + AccountAddress: TestOwnerAddress, + }, + } + + genesisState = types.NewControllerGenesisState(activeChannels, registeredAccounts, []string{"invalid|port"}) + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + genesisState = types.DefaultControllerGenesis() + + tc.malleate() // malleate mutates test data + + err := genesisState.Validate() + + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + }) + } +} + +func (suite *TypesTestSuite) TestValidateHostGenesisState() { + var ( + genesisState types.HostGenesisState + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "failed to validate active channel - invalid port identifier", + func() { + activeChannels := []types.ActiveChannel{ + { + PortId: "invalid|port", + ChannelId: ibctesting.FirstChannelID, + }, + } + + genesisState = types.NewHostGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, types.PortID) + }, + false, + }, + { + "failed to validate active channel - invalid channel identifier", + func() { + activeChannels := []types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: "invalid|channel", + }, + } + + genesisState = types.NewHostGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, types.PortID) + }, + false, + }, + { + "failed to validate registered account - invalid port identifier", + func() { + activeChannels := []types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: ibctesting.FirstChannelID, + }, + } + + registeredAccounts := []types.RegisteredInterchainAccount{ + { + PortId: "invalid|port", + AccountAddress: TestOwnerAddress, + }, + } + + genesisState = types.NewHostGenesisState(activeChannels, registeredAccounts, types.PortID) + }, + false, + }, + { + "failed to validate registered account - invalid owner address", + func() { + activeChannels := []types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: ibctesting.FirstChannelID, + }, + } + + registeredAccounts := []types.RegisteredInterchainAccount{ + { + PortId: TestPortID, + AccountAddress: "", + }, + } + + genesisState = types.NewHostGenesisState(activeChannels, registeredAccounts, types.PortID) + }, + false, + }, + { + "failed to validate controller ports - invalid port identifier", + func() { + activeChannels := []types.ActiveChannel{ + { + PortId: TestPortID, + ChannelId: ibctesting.FirstChannelID, + }, + } + + registeredAccounts := []types.RegisteredInterchainAccount{ + { + PortId: TestPortID, + AccountAddress: TestOwnerAddress, + }, + } + + genesisState = types.NewHostGenesisState(activeChannels, registeredAccounts, "invalid|port") + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + genesisState = types.DefaultHostGenesis() + + tc.malleate() // malleate mutates test data + + err := genesisState.Validate() + + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + }) + } +} diff --git a/modules/apps/27-interchain-accounts/types/version.go b/modules/apps/27-interchain-accounts/types/version.go index 0cf8e2623cd..ffa33aa0017 100644 --- a/modules/apps/27-interchain-accounts/types/version.go +++ b/modules/apps/27-interchain-accounts/types/version.go @@ -45,7 +45,17 @@ func ValidateVersion(version string) error { return sdkerrors.Wrapf(ErrInvalidVersion, "expected %s, got %s", VersionPrefix, s[0]) } - if !IsValidAddr(s[1]) || len(s[1]) == 0 || len(s[1]) > DefaultMaxAddrLength { + if err := ValidateAccountAddress(s[1]); err != nil { + return err + } + + return nil +} + +// ValidateAccountAddress performs basic validation of interchain account addresses, enforcing constraints +// on address length and character set +func ValidateAccountAddress(addr string) error { + if !IsValidAddr(addr) || len(addr) == 0 || len(addr) > DefaultMaxAddrLength { return sdkerrors.Wrapf( ErrInvalidAccountAddress, "address must contain strictly alphanumeric characters, not exceeding %d characters in length", From e6a5583091230c10efc9b087e6e33802a7b79322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 30 Nov 2021 17:17:42 +0100 Subject: [PATCH 58/66] Rename imports within host/controller (#571) * alias ica types import to for host submodule * alias ica types import to for controller submodule --- .../controller/ibc_module.go | 8 +- .../controller/ibc_module_test.go | 30 ++++---- .../controller/keeper/account.go | 8 +- .../controller/keeper/account_test.go | 4 +- .../controller/keeper/genesis.go | 8 +- .../controller/keeper/genesis_test.go | 8 +- .../controller/keeper/handshake.go | 28 +++---- .../controller/keeper/handshake_test.go | 12 +-- .../controller/keeper/keeper.go | 46 ++++++------ .../controller/keeper/keeper_test.go | 22 +++--- .../controller/keeper/relay.go | 8 +- .../controller/keeper/relay_test.go | 20 ++--- .../27-interchain-accounts/host/ibc_module.go | 10 +-- .../host/ibc_module_test.go | 38 +++++----- .../host/keeper/account.go | 4 +- .../host/keeper/account_test.go | 4 +- .../host/keeper/genesis.go | 10 +-- .../host/keeper/genesis_test.go | 12 +-- .../host/keeper/handshake.go | 28 +++---- .../host/keeper/handshake_test.go | 10 +-- .../host/keeper/keeper.go | 54 +++++++------- .../host/keeper/keeper_test.go | 22 +++--- .../host/keeper/relay.go | 18 ++--- .../host/keeper/relay_test.go | 74 +++++++++---------- 24 files changed, 243 insertions(+), 243 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module.go b/modules/apps/27-interchain-accounts/controller/ibc_module.go index 31e6b59a3be..74d9d0800c1 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module.go @@ -6,7 +6,7 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/keeper" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" @@ -63,7 +63,7 @@ func (im IBCModule) OnChanOpenTry( version, counterpartyVersion string, ) error { - return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") + return sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") } // OnChanOpenAck implements the IBCModule interface @@ -92,7 +92,7 @@ func (im IBCModule) OnChanOpenConfirm( portID, channelID string, ) error { - return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") + return sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") } // OnChanCloseInit implements the IBCModule interface @@ -156,5 +156,5 @@ func (im IBCModule) NegotiateAppVersion( counterparty channeltypes.Counterparty, proposedVersion string, ) (string, error) { - return "", sdkerrors.Wrap(types.ErrInvalidChannelFlow, "ICS-27 app version negotiation is unsupported on controller chains") + return "", sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "ICS-27 app version negotiation is unsupported on controller chains") } diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go index 54f07bee76c..cf01f0c5f29 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" @@ -19,13 +19,13 @@ import ( var ( // TestAccAddress defines a resuable bech32 address for testing purposes // TODO: update crypto.AddressHash() when sdk uses address.Module() - TestAccAddress = types.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))), TestPortID) + TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), TestPortID) // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes - TestPortID, _ = types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) + TestPortID, _ = icatypes.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) // TestVersion defines a resuable interchainaccounts version string for testing purposes - TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) + TestVersion = icatypes.NewAppVersion(icatypes.VersionPrefix, TestAccAddress.String()) ) type InterchainAccountsTestSuite struct { @@ -50,18 +50,18 @@ func (suite *InterchainAccountsTestSuite) SetupTest() { func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { path := ibctesting.NewPath(chainA, chainB) - path.EndpointA.ChannelConfig.PortID = types.PortID - path.EndpointB.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.PortID = icatypes.PortID + path.EndpointB.ChannelConfig.PortID = icatypes.PortID path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointA.ChannelConfig.Version = types.VersionPrefix + path.EndpointA.ChannelConfig.Version = icatypes.VersionPrefix path.EndpointB.ChannelConfig.Version = TestVersion return path } func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { - portID, err := types.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) + portID, err := icatypes.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) if err != nil { return err } @@ -144,7 +144,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { suite.coordinator.SetupConnections(path) // mock init interchain account - portID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + portID, err := icatypes.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) suite.Require().NoError(err) portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) @@ -160,7 +160,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { Ordering: channeltypes.ORDERED, Counterparty: counterparty, ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: types.VersionPrefix, + Version: icatypes.VersionPrefix, } tc.malleate() // malleate mutates test data @@ -213,7 +213,7 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenTry() { proofInit, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) // use chainA (controller) for ChanOpenTry - msg := channeltypes.NewMsgChannelOpenTry(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, TestVersion, channeltypes.ORDERED, []string{path.EndpointA.ConnectionID}, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, types.VersionPrefix, proofInit, proofHeight, types.ModuleName) + msg := channeltypes.NewMsgChannelOpenTry(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, TestVersion, channeltypes.ORDERED, []string{path.EndpointA.ConnectionID}, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, icatypes.VersionPrefix, proofInit, proofHeight, icatypes.ModuleName) handler := suite.chainA.GetSimApp().MsgServiceRouter().Handler(msg) _, err = handler(suite.chainA.GetContext(), msg) @@ -334,7 +334,7 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenConfirm() { proofAck, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) // use chainA (controller) for ChanOpenConfirm - msg := channeltypes.NewMsgChannelOpenConfirm(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, proofAck, proofHeight, types.ModuleName) + msg := channeltypes.NewMsgChannelOpenConfirm(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, proofAck, proofHeight, icatypes.ModuleName) handler := suite.chainA.GetSimApp().MsgServiceRouter().Handler(msg) _, err = handler(suite.chainA.GetContext(), msg) @@ -505,7 +505,7 @@ func (suite *InterchainAccountsTestSuite) TestNegotiateAppVersion() { cbs, ok := suite.chainA.GetSimApp().GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - counterpartyPortID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + counterpartyPortID, err := icatypes.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) suite.Require().NoError(err) counterparty := channeltypes.Counterparty{ @@ -513,14 +513,14 @@ func (suite *InterchainAccountsTestSuite) TestNegotiateAppVersion() { ChannelId: path.EndpointB.ChannelID, } - proposedVersion = types.VersionPrefix + proposedVersion = icatypes.VersionPrefix tc.malleate() version, err := cbs.NegotiateAppVersion(suite.chainA.GetContext(), channeltypes.ORDERED, path.EndpointA.ConnectionID, path.EndpointA.ChannelConfig.PortID, counterparty, proposedVersion) if tc.expPass { suite.Require().NoError(err) - suite.Require().NoError(types.ValidateVersion(version)) + suite.Require().NoError(icatypes.ValidateVersion(version)) suite.Require().Equal(TestVersion, version) } else { suite.Require().Error(err) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account.go b/modules/apps/27-interchain-accounts/controller/keeper/account.go index ccbe1f38a61..8876b3467b6 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/account.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/account.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) @@ -16,13 +16,13 @@ import ( // already in use. Gaining access to interchain accounts whose channels have closed // cannot be done with this function. A regular MsgChanOpenInit must be used. func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpartyConnectionID, owner string) error { - portID, err := types.GeneratePortID(owner, connectionID, counterpartyConnectionID) + portID, err := icatypes.GeneratePortID(owner, connectionID, counterpartyConnectionID) if err != nil { return err } if k.portKeeper.IsBound(ctx, portID) { - return sdkerrors.Wrap(types.ErrPortAlreadyBound, portID) + return sdkerrors.Wrap(icatypes.ErrPortAlreadyBound, portID) } cap := k.BindPort(ctx, portID) @@ -30,7 +30,7 @@ func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, counterpart return sdkerrors.Wrap(err, "unable to bind to newly generated portID") } - msg := channeltypes.NewMsgChannelOpenInit(portID, types.VersionPrefix, channeltypes.ORDERED, []string{connectionID}, types.PortID, types.ModuleName) + msg := channeltypes.NewMsgChannelOpenInit(portID, icatypes.VersionPrefix, channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName) handler := k.msgRouter.Handler(msg) if _, err := handler(ctx, msg); err != nil { return err diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account_test.go b/modules/apps/27-interchain-accounts/controller/keeper/account_test.go index 8627d6f1ce0..3a019deac95 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/account_test.go @@ -1,7 +1,7 @@ package keeper_test import ( - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) @@ -37,7 +37,7 @@ func (suite *KeeperTestSuite) TestInitInterchainAccount() { { "MsgChanOpenInit fails - channel is already active", func() { - portID, err := types.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + portID, err := icatypes.GeneratePortID(owner, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) suite.Require().NoError(err) suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/genesis.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go index 101acdea21e..d38a4ed6e77 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/genesis.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go @@ -5,12 +5,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) // InitGenesis initializes the interchain accounts controller application state from a provided genesis state -func InitGenesis(ctx sdk.Context, keeper Keeper, state types.ControllerGenesisState) { +func InitGenesis(ctx sdk.Context, keeper Keeper, state icatypes.ControllerGenesisState) { for _, portID := range state.Ports { if !keeper.IsBound(ctx, portID) { cap := keeper.BindPort(ctx, portID) @@ -30,8 +30,8 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, state types.ControllerGenesisSt } // ExportGenesis returns the interchain accounts controller exported genesis -func ExportGenesis(ctx sdk.Context, keeper Keeper) types.ControllerGenesisState { - return types.NewControllerGenesisState( +func ExportGenesis(ctx sdk.Context, keeper Keeper) icatypes.ControllerGenesisState { + return icatypes.NewControllerGenesisState( keeper.GetAllActiveChannels(ctx), keeper.GetAllInterchainAccounts(ctx), keeper.GetAllPorts(ctx), diff --git a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go index 5f0880eb94b..398100458ac 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go @@ -2,21 +2,21 @@ package keeper_test import ( "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/keeper" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) func (suite *KeeperTestSuite) TestInitGenesis() { suite.SetupTest() - genesisState := types.ControllerGenesisState{ - ActiveChannels: []types.ActiveChannel{ + genesisState := icatypes.ControllerGenesisState{ + ActiveChannels: []icatypes.ActiveChannel{ { PortId: TestPortID, ChannelId: ibctesting.FirstChannelID, }, }, - InterchainAccounts: []types.RegisteredInterchainAccount{ + InterchainAccounts: []icatypes.RegisteredInterchainAccount{ { PortId: TestPortID, AccountAddress: TestAccAddress.String(), diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go index f88f8f1fadc..e48dee00f08 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go @@ -5,7 +5,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" @@ -32,26 +32,26 @@ func (k Keeper) OnChanOpenInit( return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order) } - connSequence, err := types.ParseControllerConnSequence(portID) + connSequence, err := icatypes.ParseControllerConnSequence(portID) if err != nil { - return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, portID) + return sdkerrors.Wrapf(err, "expected format %s, got %s", icatypes.ControllerPortFormat, portID) } - counterpartyConnSequence, err := types.ParseHostConnSequence(portID) + counterpartyConnSequence, err := icatypes.ParseHostConnSequence(portID) if err != nil { - return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, portID) + return sdkerrors.Wrapf(err, "expected format %s, got %s", icatypes.ControllerPortFormat, portID) } if err := k.validateControllerPortParams(ctx, channelID, portID, connSequence, counterpartyConnSequence); err != nil { return sdkerrors.Wrapf(err, "failed to validate controller port %s", portID) } - if counterparty.PortId != types.PortID { - return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "expected %s, got %s", types.PortID, counterparty.PortId) + if counterparty.PortId != icatypes.PortID { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "expected %s, got %s", icatypes.PortID, counterparty.PortId) } - if version != types.VersionPrefix { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.VersionPrefix, version) + if version != icatypes.VersionPrefix { + return sdkerrors.Wrapf(icatypes.ErrInvalidVersion, "expected %s, got %s", icatypes.VersionPrefix, version) } activeChannelID, found := k.GetActiveChannelID(ctx, portID) @@ -70,19 +70,19 @@ func (k Keeper) OnChanOpenAck( channelID string, counterpartyVersion string, ) error { - if portID == types.PortID { - return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "portID cannot be host chain port ID: %s", types.PortID) + if portID == icatypes.PortID { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "portID cannot be host chain port ID: %s", icatypes.PortID) } - if err := types.ValidateVersion(counterpartyVersion); err != nil { + if err := icatypes.ValidateVersion(counterpartyVersion); err != nil { return sdkerrors.Wrap(err, "counterparty version validation failed") } k.SetActiveChannelID(ctx, portID, channelID) - accAddr, err := types.ParseAddressFromVersion(counterpartyVersion) + accAddr, err := icatypes.ParseAddressFromVersion(counterpartyVersion) if err != nil { - return sdkerrors.Wrapf(err, "expected format , got %s", types.Delimiter, counterpartyVersion) + return sdkerrors.Wrapf(err, "expected format , got %s", icatypes.Delimiter, counterpartyVersion) } k.SetInterchainAccountAddress(ctx, portID, accAddr) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go index f0e634fd362..31aaf9d028e 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go @@ -3,7 +3,7 @@ package keeper_test import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v2/testing" @@ -77,7 +77,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { { "invalid connection sequence", func() { - portID, err := types.GeneratePortID(TestOwnerAddress, "connection-1", "connection-0") + portID, err := icatypes.GeneratePortID(TestOwnerAddress, "connection-1", "connection-0") suite.Require().NoError(err) path.EndpointA.ChannelConfig.PortID = portID @@ -88,7 +88,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { { "invalid counterparty connection sequence", func() { - portID, err := types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-1") + portID, err := icatypes.GeneratePortID(TestOwnerAddress, "connection-0", "connection-1") suite.Require().NoError(err) path.EndpointA.ChannelConfig.PortID = portID @@ -115,7 +115,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { suite.coordinator.SetupConnections(path) // mock init interchain account - portID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + portID, err := icatypes.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) suite.Require().NoError(err) portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) @@ -129,7 +129,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { Ordering: channeltypes.ORDERED, Counterparty: counterparty, ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: types.VersionPrefix, + Version: icatypes.VersionPrefix, } chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) @@ -176,7 +176,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { }, { "invalid portID", func() { - path.EndpointA.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.PortID = icatypes.PortID expectedChannelID = "" }, false, }, diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index 1fed7445a7a..4f021c1eb16 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -11,7 +11,7 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) @@ -20,10 +20,10 @@ type Keeper struct { storeKey sdk.StoreKey cdc codec.BinaryCodec - ics4Wrapper types.ICS4Wrapper - channelKeeper types.ChannelKeeper - portKeeper types.PortKeeper - accountKeeper types.AccountKeeper + ics4Wrapper icatypes.ICS4Wrapper + channelKeeper icatypes.ChannelKeeper + portKeeper icatypes.PortKeeper + accountKeeper icatypes.AccountKeeper scopedKeeper capabilitykeeper.ScopedKeeper @@ -33,8 +33,8 @@ type Keeper struct { // NewKeeper creates a new interchain accounts controller Keeper instance func NewKeeper( cdc codec.BinaryCodec, key sdk.StoreKey, - ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, - accountKeeper types.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, + ics4Wrapper icatypes.ICS4Wrapper, channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, + accountKeeper icatypes.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, ) Keeper { return Keeper{ storeKey: key, @@ -50,13 +50,13 @@ func NewKeeper( // Logger returns the application logger, scoped to the associated module func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) + return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, icatypes.ModuleName)) } // GetAllPorts returns all ports to which the interchain accounts controller module is bound. Used in ExportGenesis func (k Keeper) GetAllPorts(ctx sdk.Context) []string { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, []byte(types.PortKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte(icatypes.PortKeyPrefix)) defer iterator.Close() var ports []string @@ -72,7 +72,7 @@ func (k Keeper) GetAllPorts(ctx sdk.Context) []string { // BindPort stores the provided portID and binds to it, returning the associated capability func (k Keeper) BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability { store := ctx.KVStore(k.storeKey) - store.Set(types.KeyPort(portID), []byte{0x01}) + store.Set(icatypes.KeyPort(portID), []byte{0x01}) return k.portKeeper.BindPort(ctx, portID) } @@ -96,7 +96,7 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability // GetActiveChannelID retrieves the active channelID from the store keyed by the provided portID func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool) { store := ctx.KVStore(k.storeKey) - key := types.KeyActiveChannel(portID) + key := icatypes.KeyActiveChannel(portID) if !store.Has(key) { return "", false @@ -106,16 +106,16 @@ func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool } // GetAllActiveChannels returns a list of all active interchain accounts controller channels and their associated port identifiers -func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []types.ActiveChannel { +func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []icatypes.ActiveChannel { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, []byte(types.ActiveChannelKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte(icatypes.ActiveChannelKeyPrefix)) defer iterator.Close() - var activeChannels []types.ActiveChannel + var activeChannels []icatypes.ActiveChannel for ; iterator.Valid(); iterator.Next() { keySplit := strings.Split(string(iterator.Key()), "/") - ch := types.ActiveChannel{ + ch := icatypes.ActiveChannel{ PortId: keySplit[1], ChannelId: string(iterator.Value()), } @@ -129,13 +129,13 @@ func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []types.ActiveChannel { // SetActiveChannelID stores the active channelID, keyed by the provided portID func (k Keeper) SetActiveChannelID(ctx sdk.Context, portID, channelID string) { store := ctx.KVStore(k.storeKey) - store.Set(types.KeyActiveChannel(portID), []byte(channelID)) + store.Set(icatypes.KeyActiveChannel(portID), []byte(channelID)) } // DeleteActiveChannelID removes the active channel keyed by the provided portID stored in state func (k Keeper) DeleteActiveChannelID(ctx sdk.Context, portID string) { store := ctx.KVStore(k.storeKey) - store.Delete(types.KeyActiveChannel(portID)) + store.Delete(icatypes.KeyActiveChannel(portID)) } // IsActiveChannel returns true if there exists an active channel for the provided portID, otherwise false @@ -147,7 +147,7 @@ func (k Keeper) IsActiveChannel(ctx sdk.Context, portID string) bool { // GetInterchainAccountAddress retrieves the InterchainAccount address from the store keyed by the provided portID func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (string, bool) { store := ctx.KVStore(k.storeKey) - key := types.KeyOwnerAccount(portID) + key := icatypes.KeyOwnerAccount(portID) if !store.Has(key) { return "", false @@ -157,15 +157,15 @@ func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (str } // GetAllInterchainAccounts returns a list of all registered interchain account addresses and their associated controller port identifiers -func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []types.RegisteredInterchainAccount { +func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []icatypes.RegisteredInterchainAccount { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, []byte(types.OwnerKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte(icatypes.OwnerKeyPrefix)) - var interchainAccounts []types.RegisteredInterchainAccount + var interchainAccounts []icatypes.RegisteredInterchainAccount for ; iterator.Valid(); iterator.Next() { keySplit := strings.Split(string(iterator.Key()), "/") - acc := types.RegisteredInterchainAccount{ + acc := icatypes.RegisteredInterchainAccount{ PortId: keySplit[1], AccountAddress: string(iterator.Value()), } @@ -179,5 +179,5 @@ func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []types.RegisteredInte // SetInterchainAccountAddress stores the InterchainAccount address, keyed by the associated portID func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portID string, address string) { store := ctx.KVStore(k.storeKey) - store.Set(types.KeyOwnerAccount(portID), []byte(address)) + store.Set(icatypes.KeyOwnerAccount(portID), []byte(address)) } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go index 0e61d738826..f522a954fa1 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) @@ -16,13 +16,13 @@ import ( var ( // TestAccAddress defines a resuable bech32 address for testing purposes // TODO: update crypto.AddressHash() when sdk uses address.Module() - TestAccAddress = types.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))), TestPortID) + TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), TestPortID) // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes - TestPortID, _ = types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) + TestPortID, _ = icatypes.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) // TestVersion defines a resuable interchainaccounts version string for testing purposes - TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) + TestVersion = icatypes.NewAppVersion(icatypes.VersionPrefix, TestAccAddress.String()) ) type KeeperTestSuite struct { @@ -45,11 +45,11 @@ func (suite *KeeperTestSuite) SetupTest() { func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { path := ibctesting.NewPath(chainA, chainB) - path.EndpointA.ChannelConfig.PortID = types.PortID - path.EndpointB.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.PortID = icatypes.PortID + path.EndpointB.ChannelConfig.PortID = icatypes.PortID path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointA.ChannelConfig.Version = types.VersionPrefix + path.EndpointA.ChannelConfig.Version = icatypes.VersionPrefix path.EndpointB.ChannelConfig.Version = TestVersion return path @@ -78,7 +78,7 @@ func SetupICAPath(path *ibctesting.Path, owner string) error { // InitInterchainAccount is a helper function for starting the channel handshake func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { - portID, err := types.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) + portID, err := icatypes.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) if err != nil { return err } @@ -143,7 +143,7 @@ func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { suite.Require().NoError(err) counterpartyPortID := path.EndpointA.ChannelConfig.PortID - expectedAddr := authtypes.NewBaseAccountWithAddress(types.GenerateAddress(suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName), counterpartyPortID)).GetAddress() + expectedAddr := authtypes.NewBaseAccountWithAddress(icatypes.GenerateAddress(suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(icatypes.ModuleName), counterpartyPortID)).GetAddress() retrievedAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), counterpartyPortID) suite.Require().True(found) @@ -170,7 +170,7 @@ func (suite *KeeperTestSuite) TestGetAllActiveChannels() { suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), expectedPortID, expectedChannelID) - expectedChannels := []types.ActiveChannel{ + expectedChannels := []icatypes.ActiveChannel{ { PortId: TestPortID, ChannelId: path.EndpointA.ChannelID, @@ -202,7 +202,7 @@ func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() { suite.chainA.GetSimApp().ICAControllerKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr) - expectedAccounts := []types.RegisteredInterchainAccount{ + expectedAccounts := []icatypes.RegisteredInterchainAccount{ { PortId: TestPortID, AccountAddress: TestAccAddress.String(), diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay.go b/modules/apps/27-interchain-accounts/controller/keeper/relay.go index 02a79a00e97..a7bbda175af 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay.go @@ -5,18 +5,18 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" ) // TrySendTx takes in a transaction from an authentication module and attempts to send the packet // if the base application has the capability to send on the provided portID -func (k Keeper) TrySendTx(ctx sdk.Context, chanCap *capabilitytypes.Capability, portID string, icaPacketData types.InterchainAccountPacketData) (uint64, error) { +func (k Keeper) TrySendTx(ctx sdk.Context, chanCap *capabilitytypes.Capability, portID string, icaPacketData icatypes.InterchainAccountPacketData) (uint64, error) { // Check for the active channel activeChannelID, found := k.GetActiveChannelID(ctx, portID) if !found { - return 0, sdkerrors.Wrapf(types.ErrActiveChannelNotFound, "failed to retrieve active channel for port %s", portID) + return 0, sdkerrors.Wrapf(icatypes.ErrActiveChannelNotFound, "failed to retrieve active channel for port %s", portID) } sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, portID, activeChannelID) @@ -37,7 +37,7 @@ func (k Keeper) createOutgoingPacket( destinationPort, destinationChannel string, chanCap *capabilitytypes.Capability, - icaPacketData types.InterchainAccountPacketData, + icaPacketData icatypes.InterchainAccountPacketData, ) (uint64, error) { if err := icaPacketData.ValidateBasic(); err != nil { return 0, sdkerrors.Wrap(err, "invalid interchain account packet data") diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go index 561cc370ddf..d00ed6a936a 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go @@ -5,7 +5,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" @@ -15,7 +15,7 @@ import ( func (suite *KeeperTestSuite) TestTrySendTx() { var ( path *ibctesting.Path - packetData types.InterchainAccountPacketData + packetData icatypes.InterchainAccountPacketData chanCap *capabilitytypes.Capability ) @@ -36,11 +36,11 @@ func (suite *KeeperTestSuite) TestTrySendTx() { Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), } - data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg}) + data, err := icatypes.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) - packetData = types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + packetData = icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } }, @@ -65,11 +65,11 @@ func (suite *KeeperTestSuite) TestTrySendTx() { }, } - data, err := types.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), msgsBankSend) + data, err := icatypes.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), msgsBankSend) suite.Require().NoError(err) - packetData = types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + packetData = icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } }, @@ -78,8 +78,8 @@ func (suite *KeeperTestSuite) TestTrySendTx() { { "data is nil", func() { - packetData = types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + packetData = icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: nil, } }, diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index a304c121ef0..3e28117ba22 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -6,7 +6,7 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/keeper" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" ) @@ -34,7 +34,7 @@ func (im IBCModule) OnChanOpenInit( counterparty channeltypes.Counterparty, version string, ) error { - return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") + return sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") } // OnChanOpenTry implements the IBCModule interface @@ -59,7 +59,7 @@ func (im IBCModule) OnChanOpenAck( channelID string, counterpartyVersion string, ) error { - return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") + return sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") } // OnChanOpenAck implements the IBCModule interface @@ -113,7 +113,7 @@ func (im IBCModule) OnAcknowledgementPacket( acknowledgement []byte, relayer sdk.AccAddress, ) error { - return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "cannot receive acknowledgement on a host channel end, a host chain does not send a packet over the channel") + return sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "cannot receive acknowledgement on a host channel end, a host chain does not send a packet over the channel") } // OnTimeoutPacket implements the IBCModule interface @@ -122,7 +122,7 @@ func (im IBCModule) OnTimeoutPacket( packet channeltypes.Packet, relayer sdk.AccAddress, ) error { - return sdkerrors.Wrap(types.ErrInvalidChannelFlow, "cannot cause a packet timeout on a host channel end, a host chain does not send a packet over the channel") + return sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "cannot cause a packet timeout on a host channel end, a host chain does not send a packet over the channel") } // NegotiateAppVersion implements the IBCModule interface diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index b3362d9faaa..aa99ac811f5 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" @@ -21,13 +21,13 @@ import ( var ( // TestAccAddress defines a resuable bech32 address for testing purposes // TODO: update crypto.AddressHash() when sdk uses address.Module() - TestAccAddress = types.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))), TestPortID) + TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), TestPortID) // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes - TestPortID, _ = types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) + TestPortID, _ = icatypes.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) // TestVersion defines a resuable interchainaccounts version string for testing purposes - TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) + TestVersion = icatypes.NewAppVersion(icatypes.VersionPrefix, TestAccAddress.String()) ) type InterchainAccountsTestSuite struct { @@ -52,18 +52,18 @@ func (suite *InterchainAccountsTestSuite) SetupTest() { func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { path := ibctesting.NewPath(chainA, chainB) - path.EndpointA.ChannelConfig.PortID = types.PortID - path.EndpointB.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.PortID = icatypes.PortID + path.EndpointB.ChannelConfig.PortID = icatypes.PortID path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointA.ChannelConfig.Version = types.VersionPrefix + path.EndpointA.ChannelConfig.Version = icatypes.VersionPrefix path.EndpointB.ChannelConfig.Version = TestVersion return path } func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { - portID, err := types.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) + portID, err := icatypes.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) if err != nil { return err } @@ -114,7 +114,7 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenInit() { suite.coordinator.SetupConnections(path) // use chainB (host) for ChanOpenInit - msg := channeltypes.NewMsgChannelOpenInit(path.EndpointB.ChannelConfig.PortID, types.VersionPrefix, channeltypes.ORDERED, []string{path.EndpointB.ConnectionID}, path.EndpointA.ChannelConfig.PortID, types.ModuleName) + msg := channeltypes.NewMsgChannelOpenInit(path.EndpointB.ChannelConfig.PortID, icatypes.VersionPrefix, channeltypes.ORDERED, []string{path.EndpointB.ConnectionID}, path.EndpointA.ChannelConfig.PortID, icatypes.ModuleName) handler := suite.chainB.GetSimApp().MsgServiceRouter().Handler(msg) _, err := handler(suite.chainB.GetContext(), msg) @@ -150,7 +150,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { }, { "ICA callback fails - invalid version", func() { - channel.Version = types.VersionPrefix + channel.Version = icatypes.VersionPrefix }, false, }, } @@ -235,7 +235,7 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenAck() { proofTry, proofHeight := path.EndpointA.Chain.QueryProof(channelKey) // use chainB (host) for ChanOpenAck - msg := channeltypes.NewMsgChannelOpenAck(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelID, TestVersion, proofTry, proofHeight, types.ModuleName) + msg := channeltypes.NewMsgChannelOpenAck(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelID, TestVersion, proofTry, proofHeight, icatypes.ModuleName) handler := suite.chainB.GetSimApp().MsgServiceRouter().Handler(msg) _, err = handler(suite.chainB.GetContext(), msg) @@ -427,11 +427,11 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount, } - data, err := types.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } packetData = icaPacketData.GetBytes() @@ -593,13 +593,13 @@ func (suite *InterchainAccountsTestSuite) TestNegotiateAppVersion() { path := NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) - module, _, err := suite.chainA.GetSimApp().GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) + module, _, err := suite.chainA.GetSimApp().GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), icatypes.PortID) suite.Require().NoError(err) cbs, ok := suite.chainA.GetSimApp().GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - counterpartyPortID, err := types.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + counterpartyPortID, err := icatypes.GeneratePortID(TestOwnerAddress, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) suite.Require().NoError(err) counterparty := &channeltypes.Counterparty{ @@ -607,14 +607,14 @@ func (suite *InterchainAccountsTestSuite) TestNegotiateAppVersion() { ChannelId: path.EndpointB.ChannelID, } - proposedVersion = types.VersionPrefix + proposedVersion = icatypes.VersionPrefix tc.malleate() - version, err := cbs.NegotiateAppVersion(suite.chainA.GetContext(), channeltypes.ORDERED, path.EndpointA.ConnectionID, types.PortID, *counterparty, proposedVersion) + version, err := cbs.NegotiateAppVersion(suite.chainA.GetContext(), channeltypes.ORDERED, path.EndpointA.ConnectionID, icatypes.PortID, *counterparty, proposedVersion) if tc.expPass { suite.Require().NoError(err) - suite.Require().NoError(types.ValidateVersion(version)) + suite.Require().NoError(icatypes.ValidateVersion(version)) suite.Require().Equal(TestVersion, version) } else { suite.Require().Error(err) diff --git a/modules/apps/27-interchain-accounts/host/keeper/account.go b/modules/apps/27-interchain-accounts/host/keeper/account.go index d9e213f4ace..4ed947eb285 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/account.go +++ b/modules/apps/27-interchain-accounts/host/keeper/account.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ) // RegisterInterchainAccount attempts to create a new account using the provided address and stores it in state keyed by the provided port identifier @@ -14,7 +14,7 @@ func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, accAddr sdk.AccAddres return } - interchainAccount := types.NewInterchainAccount( + interchainAccount := icatypes.NewInterchainAccount( authtypes.NewBaseAccountWithAddress(accAddr), controllerPortID, ) diff --git a/modules/apps/27-interchain-accounts/host/keeper/account_test.go b/modules/apps/27-interchain-accounts/host/keeper/account_test.go index 65ce1646905..90be30ff2c8 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/account_test.go @@ -3,7 +3,7 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) @@ -17,7 +17,7 @@ func (suite *KeeperTestSuite) TestRegisterInterchainAccount() { err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - portID, err := types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) + portID, err := icatypes.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) suite.Require().NoError(err) // Get the address of the interchain account stored in state during handshake step diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis.go b/modules/apps/27-interchain-accounts/host/keeper/genesis.go index 4a8584102f5..3fd5c02f8da 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/genesis.go +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis.go @@ -5,12 +5,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) // InitGenesis initializes the interchain accounts host application state from a provided genesis state -func InitGenesis(ctx sdk.Context, keeper Keeper, state types.HostGenesisState) { +func InitGenesis(ctx sdk.Context, keeper Keeper, state icatypes.HostGenesisState) { if !keeper.IsBound(ctx, state.Port) { cap := keeper.BindPort(ctx, state.Port) if err := keeper.ClaimCapability(ctx, cap, host.PortPath(state.Port)); err != nil { @@ -28,10 +28,10 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, state types.HostGenesisState) { } // ExportGenesis returns the interchain accounts host exported genesis -func ExportGenesis(ctx sdk.Context, keeper Keeper) types.HostGenesisState { - return types.NewHostGenesisState( +func ExportGenesis(ctx sdk.Context, keeper Keeper) icatypes.HostGenesisState { + return icatypes.NewHostGenesisState( keeper.GetAllActiveChannels(ctx), keeper.GetAllInterchainAccounts(ctx), - types.PortID, + icatypes.PortID, ) } diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go index 41cdcf5b671..272109b5412 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go @@ -2,27 +2,27 @@ package keeper_test import ( "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/keeper" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) func (suite *KeeperTestSuite) TestInitGenesis() { suite.SetupTest() - genesisState := types.HostGenesisState{ - ActiveChannels: []types.ActiveChannel{ + genesisState := icatypes.HostGenesisState{ + ActiveChannels: []icatypes.ActiveChannel{ { PortId: TestPortID, ChannelId: ibctesting.FirstChannelID, }, }, - InterchainAccounts: []types.RegisteredInterchainAccount{ + InterchainAccounts: []icatypes.RegisteredInterchainAccount{ { PortId: TestPortID, AccountAddress: TestAccAddress.String(), }, }, - Port: types.PortID, + Port: icatypes.PortID, } keeper.InitGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAHostKeeper, genesisState) @@ -53,5 +53,5 @@ func (suite *KeeperTestSuite) TestExportGenesis() { suite.Require().Equal(TestAccAddress.String(), genesisState.InterchainAccounts[0].AccountAddress) suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.InterchainAccounts[0].PortId) - suite.Require().Equal(types.PortID, genesisState.GetPort()) + suite.Require().Equal(icatypes.PortID, genesisState.GetPort()) } diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake.go b/modules/apps/27-interchain-accounts/host/keeper/handshake.go index 864498137f9..c4c40e68d8e 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake.go @@ -5,7 +5,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" connectiontypes "github.com/cosmos/ibc-go/v2/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" @@ -29,30 +29,30 @@ func (k Keeper) OnChanOpenTry( return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order) } - if portID != types.PortID { - return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "expected %s, got %s", types.PortID, portID) + if portID != icatypes.PortID { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "expected %s, got %s", icatypes.PortID, portID) } - connSequence, err := types.ParseHostConnSequence(counterparty.PortId) + connSequence, err := icatypes.ParseHostConnSequence(counterparty.PortId) if err != nil { - return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, counterparty.PortId) + return sdkerrors.Wrapf(err, "expected format %s, got %s", icatypes.ControllerPortFormat, counterparty.PortId) } - counterpartyConnSequence, err := types.ParseControllerConnSequence(counterparty.PortId) + counterpartyConnSequence, err := icatypes.ParseControllerConnSequence(counterparty.PortId) if err != nil { - return sdkerrors.Wrapf(err, "expected format %s, got %s", types.ControllerPortFormat, counterparty.PortId) + return sdkerrors.Wrapf(err, "expected format %s, got %s", icatypes.ControllerPortFormat, counterparty.PortId) } if err := k.validateControllerPortParams(ctx, channelID, portID, connSequence, counterpartyConnSequence); err != nil { return sdkerrors.Wrapf(err, "failed to validate controller port %s", counterparty.PortId) } - if err := types.ValidateVersion(version); err != nil { + if err := icatypes.ValidateVersion(version); err != nil { return sdkerrors.Wrap(err, "version validation failed") } - if counterpartyVersion != types.VersionPrefix { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.VersionPrefix, version) + if counterpartyVersion != icatypes.VersionPrefix { + return sdkerrors.Wrapf(icatypes.ErrInvalidVersion, "expected %s, got %s", icatypes.VersionPrefix, version) } // On the host chain the capability may only be claimed during the OnChanOpenTry @@ -62,14 +62,14 @@ func (k Keeper) OnChanOpenTry( } // Check to ensure that the version string contains the expected address generated from the Counterparty portID - accAddr := types.GenerateAddress(k.accountKeeper.GetModuleAddress(types.ModuleName), counterparty.PortId) - parsedAddr, err := types.ParseAddressFromVersion(version) + accAddr := icatypes.GenerateAddress(k.accountKeeper.GetModuleAddress(icatypes.ModuleName), counterparty.PortId) + parsedAddr, err := icatypes.ParseAddressFromVersion(version) if err != nil { - return sdkerrors.Wrapf(err, "expected format , got %s", types.Delimiter, version) + return sdkerrors.Wrapf(err, "expected format , got %s", icatypes.Delimiter, version) } if parsedAddr != accAddr.String() { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "version contains invalid account address: expected %s, got %s", parsedAddr, accAddr) + return sdkerrors.Wrapf(icatypes.ErrInvalidVersion, "version contains invalid account address: expected %s, got %s", parsedAddr, accAddr) } // Register interchain account if it does not already exist diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go index fde51a961ff..c07b46834e6 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go @@ -3,7 +3,7 @@ package keeper_test import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v2/testing" @@ -69,7 +69,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { { "invalid connection sequence", func() { - portID, err := types.GeneratePortID(TestOwnerAddress, "connection-0", "connection-1") + portID, err := icatypes.GeneratePortID(TestOwnerAddress, "connection-0", "connection-1") suite.Require().NoError(err) channel.Counterparty.PortId = portID @@ -80,7 +80,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { { "invalid counterparty connection sequence", func() { - portID, err := types.GeneratePortID(TestOwnerAddress, "connection-1", "connection-0") + portID, err := icatypes.GeneratePortID(TestOwnerAddress, "connection-1", "connection-0") suite.Require().NoError(err) channel.Counterparty.PortId = portID @@ -116,7 +116,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { { "invalid account address", func() { - portID, err := types.GeneratePortID("invalid-owner-addr", "connection-0", "connection-0") + portID, err := icatypes.GeneratePortID("invalid-owner-addr", "connection-0", "connection-0") suite.Require().NoError(err) channel.Counterparty.PortId = portID @@ -133,7 +133,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { suite.SetupTest() // reset path = NewICAPath(suite.chainA, suite.chainB) - counterpartyVersion = types.VersionPrefix + counterpartyVersion = icatypes.VersionPrefix suite.coordinator.SetupConnections(path) err := InitInterchainAccount(path.EndpointA, TestOwnerAddress) diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go index 44735ae81ea..23fcd168c5a 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -12,7 +12,7 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) @@ -22,9 +22,9 @@ type Keeper struct { storeKey sdk.StoreKey cdc codec.BinaryCodec - channelKeeper types.ChannelKeeper - portKeeper types.PortKeeper - accountKeeper types.AccountKeeper + channelKeeper icatypes.ChannelKeeper + portKeeper icatypes.PortKeeper + accountKeeper icatypes.AccountKeeper scopedKeeper capabilitykeeper.ScopedKeeper @@ -33,12 +33,12 @@ type Keeper struct { // NewKeeper creates a new interchain accounts host Keeper instance func NewKeeper( - cdc codec.BinaryCodec, key sdk.StoreKey, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, - accountKeeper types.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, + cdc codec.BinaryCodec, key sdk.StoreKey, channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, + accountKeeper icatypes.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, ) Keeper { // ensure ibc interchain accounts module account is set - if addr := accountKeeper.GetModuleAddress(types.ModuleName); addr == nil { + if addr := accountKeeper.GetModuleAddress(icatypes.ModuleName); addr == nil { panic("the Interchain Accounts module account has not been set") } @@ -55,13 +55,13 @@ func NewKeeper( // Logger returns the application logger, scoped to the associated module func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) + return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, icatypes.ModuleName)) } // BindPort stores the provided portID and binds to it, returning the associated capability func (k Keeper) BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability { store := ctx.KVStore(k.storeKey) - store.Set(types.KeyPort(portID), []byte{0x01}) + store.Set(icatypes.KeyPort(portID), []byte{0x01}) return k.portKeeper.BindPort(ctx, portID) } @@ -85,7 +85,7 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability // GetActiveChannelID retrieves the active channelID from the store keyed by the provided portID func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool) { store := ctx.KVStore(k.storeKey) - key := types.KeyActiveChannel(portID) + key := icatypes.KeyActiveChannel(portID) if !store.Has(key) { return "", false @@ -95,16 +95,16 @@ func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool } // GetAllActiveChannels returns a list of all active interchain accounts host channels and their associated port identifiers -func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []types.ActiveChannel { +func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []icatypes.ActiveChannel { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, []byte(types.ActiveChannelKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte(icatypes.ActiveChannelKeyPrefix)) defer iterator.Close() - var activeChannels []types.ActiveChannel + var activeChannels []icatypes.ActiveChannel for ; iterator.Valid(); iterator.Next() { keySplit := strings.Split(string(iterator.Key()), "/") - ch := types.ActiveChannel{ + ch := icatypes.ActiveChannel{ PortId: keySplit[1], ChannelId: string(iterator.Value()), } @@ -118,13 +118,13 @@ func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []types.ActiveChannel { // SetActiveChannelID stores the active channelID, keyed by the provided portID func (k Keeper) SetActiveChannelID(ctx sdk.Context, portID, channelID string) { store := ctx.KVStore(k.storeKey) - store.Set(types.KeyActiveChannel(portID), []byte(channelID)) + store.Set(icatypes.KeyActiveChannel(portID), []byte(channelID)) } // DeleteActiveChannelID removes the active channel keyed by the provided portID stored in state func (k Keeper) DeleteActiveChannelID(ctx sdk.Context, portID string) { store := ctx.KVStore(k.storeKey) - store.Delete(types.KeyActiveChannel(portID)) + store.Delete(icatypes.KeyActiveChannel(portID)) } // IsActiveChannel returns true if there exists an active channel for the provided portID, otherwise false @@ -136,7 +136,7 @@ func (k Keeper) IsActiveChannel(ctx sdk.Context, portID string) bool { // GetInterchainAccountAddress retrieves the InterchainAccount address from the store keyed by the provided portID func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (string, bool) { store := ctx.KVStore(k.storeKey) - key := types.KeyOwnerAccount(portID) + key := icatypes.KeyOwnerAccount(portID) if !store.Has(key) { return "", false @@ -146,15 +146,15 @@ func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (str } // GetAllInterchainAccounts returns a list of all registered interchain account addresses and their associated controller port identifiers -func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []types.RegisteredInterchainAccount { +func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []icatypes.RegisteredInterchainAccount { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, []byte(types.OwnerKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte(icatypes.OwnerKeyPrefix)) - var interchainAccounts []types.RegisteredInterchainAccount + var interchainAccounts []icatypes.RegisteredInterchainAccount for ; iterator.Valid(); iterator.Next() { keySplit := strings.Split(string(iterator.Key()), "/") - acc := types.RegisteredInterchainAccount{ + acc := icatypes.RegisteredInterchainAccount{ PortId: keySplit[1], AccountAddress: string(iterator.Value()), } @@ -168,7 +168,7 @@ func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []types.RegisteredInte // SetInterchainAccountAddress stores the InterchainAccount address, keyed by the associated portID func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portID string, address string) { store := ctx.KVStore(k.storeKey) - store.Set(types.KeyOwnerAccount(portID), []byte(address)) + store.Set(icatypes.KeyOwnerAccount(portID), []byte(address)) } // NegotiateAppVersion handles application version negotation for the IBC interchain accounts module @@ -180,12 +180,12 @@ func (k Keeper) NegotiateAppVersion( counterparty channeltypes.Counterparty, proposedVersion string, ) (string, error) { - if proposedVersion != types.VersionPrefix { - return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "failed to negotiate app version: expected %s, got %s", types.VersionPrefix, proposedVersion) + if proposedVersion != icatypes.VersionPrefix { + return "", sdkerrors.Wrapf(icatypes.ErrInvalidVersion, "failed to negotiate app version: expected %s, got %s", icatypes.VersionPrefix, proposedVersion) } - moduleAccAddr := k.accountKeeper.GetModuleAddress(types.ModuleName) - accAddr := types.GenerateAddress(moduleAccAddr, counterparty.PortId) + moduleAccAddr := k.accountKeeper.GetModuleAddress(icatypes.ModuleName) + accAddr := icatypes.GenerateAddress(moduleAccAddr, counterparty.PortId) - return types.NewAppVersion(types.VersionPrefix, accAddr.String()), nil + return icatypes.NewAppVersion(icatypes.VersionPrefix, accAddr.String()), nil } diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go index ad79e439b34..5f12ab2dfd1 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) @@ -16,13 +16,13 @@ import ( var ( // TestAccAddress defines a resuable bech32 address for testing purposes // TODO: update crypto.AddressHash() when sdk uses address.Module() - TestAccAddress = types.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))), TestPortID) + TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), TestPortID) // TestOwnerAddress defines a reusable bech32 address for testing purposes TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" // TestPortID defines a resuable port identifier for testing purposes - TestPortID, _ = types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) + TestPortID, _ = icatypes.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) // TestVersion defines a resuable interchainaccounts version string for testing purposes - TestVersion = types.NewAppVersion(types.VersionPrefix, TestAccAddress.String()) + TestVersion = icatypes.NewAppVersion(icatypes.VersionPrefix, TestAccAddress.String()) ) type KeeperTestSuite struct { @@ -45,11 +45,11 @@ func (suite *KeeperTestSuite) SetupTest() { func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { path := ibctesting.NewPath(chainA, chainB) - path.EndpointA.ChannelConfig.PortID = types.PortID - path.EndpointB.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.PortID = icatypes.PortID + path.EndpointB.ChannelConfig.PortID = icatypes.PortID path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointA.ChannelConfig.Version = types.VersionPrefix + path.EndpointA.ChannelConfig.Version = icatypes.VersionPrefix path.EndpointB.ChannelConfig.Version = TestVersion return path @@ -78,7 +78,7 @@ func SetupICAPath(path *ibctesting.Path, owner string) error { // InitInterchainAccount is a helper function for starting the channel handshake func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { - portID, err := types.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) + portID, err := icatypes.GeneratePortID(owner, endpoint.ConnectionID, endpoint.Counterparty.ConnectionID) if err != nil { return err } @@ -127,7 +127,7 @@ func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { suite.Require().NoError(err) counterpartyPortID := path.EndpointA.ChannelConfig.PortID - expectedAddr := authtypes.NewBaseAccountWithAddress(types.GenerateAddress(suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName), counterpartyPortID)).GetAddress() + expectedAddr := authtypes.NewBaseAccountWithAddress(icatypes.GenerateAddress(suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(icatypes.ModuleName), counterpartyPortID)).GetAddress() retrievedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), counterpartyPortID) suite.Require().True(found) @@ -154,7 +154,7 @@ func (suite *KeeperTestSuite) TestGetAllActiveChannels() { suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), expectedPortID, expectedChannelID) - expectedChannels := []types.ActiveChannel{ + expectedChannels := []icatypes.ActiveChannel{ { PortId: path.EndpointB.ChannelConfig.PortID, ChannelId: path.EndpointB.ChannelID, @@ -186,7 +186,7 @@ func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() { suite.chainB.GetSimApp().ICAHostKeeper.SetInterchainAccountAddress(suite.chainB.GetContext(), expectedPortID, expectedAccAddr) - expectedAccounts := []types.RegisteredInterchainAccount{ + expectedAccounts := []icatypes.RegisteredInterchainAccount{ { PortId: TestPortID, AccountAddress: TestAccAddress.String(), diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay.go b/modules/apps/27-interchain-accounts/host/keeper/relay.go index 85e8e1e8dec..dc53cdc54f0 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" ) @@ -13,7 +13,7 @@ import ( func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portID string) error { interchainAccountAddr, found := k.GetInterchainAccountAddress(ctx, portID) if !found { - return sdkerrors.Wrapf(types.ErrInterchainAccountNotFound, "failed to retrieve interchain account on port %s", portID) + return sdkerrors.Wrapf(icatypes.ErrInterchainAccountNotFound, "failed to retrieve interchain account on port %s", portID) } for _, msg := range msgs { @@ -54,7 +54,7 @@ func (k Keeper) executeTx(ctx sdk.Context, sourcePort, destPort, destChannel str func (k Keeper) executeMsg(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { handler := k.msgRouter.Handler(msg) if handler == nil { - return nil, types.ErrInvalidRoute + return nil, icatypes.ErrInvalidRoute } return handler(ctx, msg) @@ -62,16 +62,16 @@ func (k Keeper) executeMsg(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { // OnRecvPacket handles a given interchain accounts packet on a destination host chain func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error { - var data types.InterchainAccountPacketData + var data icatypes.InterchainAccountPacketData - if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + if err := icatypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { // UnmarshalJSON errors are indeterminate and therefore are not wrapped and included in failed acks - return sdkerrors.Wrapf(types.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain account packet data") + return sdkerrors.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain account packet data") } switch data.Type { - case types.EXECUTE_TX: - msgs, err := types.DeserializeCosmosTx(k.cdc, data.Data) + case icatypes.EXECUTE_TX: + msgs, err := icatypes.DeserializeCosmosTx(k.cdc, data.Data) if err != nil { return err } @@ -82,6 +82,6 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error return nil default: - return types.ErrUnknownDataType + return icatypes.ErrUnknownDataType } } diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index 9109f7559e5..cdfba6956b1 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -10,7 +10,7 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" transfertypes "github.com/cosmos/ibc-go/v2/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" @@ -40,11 +40,11 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), } - data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } @@ -65,11 +65,11 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { Amount: sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(5000)), } - data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } @@ -96,11 +96,11 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { Amount: sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(5000)), } - data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msgDelegate, msgUndelegate}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msgDelegate, msgUndelegate}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } @@ -128,11 +128,11 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { Proposer: interchainAccountAddr, } - data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } @@ -164,11 +164,11 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { Option: govtypes.OptionYes, } - data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } @@ -187,11 +187,11 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { Depositor: interchainAccountAddr, } - data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } @@ -210,11 +210,11 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { WithdrawAddress: suite.chainB.SenderAccount.GetAddress().String(), } - data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } @@ -244,11 +244,11 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { TimeoutTimestamp: uint64(0), } - data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } @@ -268,8 +268,8 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { func() { data := []byte("invalid packet data") - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } @@ -280,11 +280,11 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "invalid packet type - UNSPECIFIED", func() { - data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{&banktypes.MsgSend{}}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{&banktypes.MsgSend{}}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.UNSPECIFIED, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.UNSPECIFIED, Data: data, } @@ -297,11 +297,11 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { func() { path.EndpointA.ChannelConfig.PortID = "invalid-port-id" - data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{&banktypes.MsgSend{}}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{&banktypes.MsgSend{}}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } @@ -318,11 +318,11 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), } - data, err := types.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) suite.Require().NoError(err) - icaPacketData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, Data: data, } @@ -344,7 +344,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - portID, err := types.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) + portID, err := icatypes.GeneratePortID(TestOwnerAddress, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) suite.Require().NoError(err) // Get the address of the interchain account stored in state during handshake step From d681c0d20023ba4a12a1e27a7d3e0d59e3344f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 1 Dec 2021 11:03:40 +0100 Subject: [PATCH 59/66] Add Enable/Disable controller/host on-chain params (#566) * add ica params Add new Params type to ICA. A single test is added to check defaults and validation. Usage within the ICA keepers is still needed * regenerate params proto into host and controller submodules * split params implementation into host/controller * add keeper params logic * Apply suggestions from code review Co-authored-by: Damian Nolan * add host genesis init/export params test case * add genesis validation for controller and host params Co-authored-by: Damian Nolan --- docs/ibc/proto-docs.md | 2 + .../controller/keeper/genesis.go | 3 + .../controller/keeper/genesis_test.go | 9 + .../controller/keeper/keeper.go | 16 +- .../controller/keeper/params.go | 24 ++ .../controller/keeper/params_test.go | 15 + .../controller/types/controller.pb.go | 318 ++++++++++++++++++ .../controller/types/params.go | 59 ++++ .../controller/types/params_test.go | 14 + .../host/keeper/genesis.go | 3 + .../host/keeper/genesis_test.go | 8 + .../host/keeper/keeper.go | 16 +- .../host/keeper/params.go | 24 ++ .../host/keeper/params_test.go | 15 + .../host/types/host.pb.go | 318 ++++++++++++++++++ .../host/types/params.go | 59 ++++ .../host/types/params_test.go | 14 + .../27-interchain-accounts/types/genesis.go | 23 +- .../types/genesis.pb.go | 183 ++++++++-- .../types/genesis_test.go | 22 +- .../controller/v1/controller.proto | 15 + .../interchain_accounts/host/v1/host.proto | 15 + .../interchain_accounts/v1/genesis.proto | 4 + .../interchain_accounts/v1/types.proto | 1 + testing/simapp/app.go | 6 +- 25 files changed, 1129 insertions(+), 57 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/params.go create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/params_test.go create mode 100644 modules/apps/27-interchain-accounts/controller/types/controller.pb.go create mode 100644 modules/apps/27-interchain-accounts/controller/types/params.go create mode 100644 modules/apps/27-interchain-accounts/controller/types/params_test.go create mode 100644 modules/apps/27-interchain-accounts/host/keeper/params.go create mode 100644 modules/apps/27-interchain-accounts/host/keeper/params_test.go create mode 100644 modules/apps/27-interchain-accounts/host/types/host.pb.go create mode 100644 modules/apps/27-interchain-accounts/host/types/params.go create mode 100644 modules/apps/27-interchain-accounts/host/types/params_test.go create mode 100644 proto/ibc/applications/interchain_accounts/controller/v1/controller.proto create mode 100644 proto/ibc/applications/interchain_accounts/host/v1/host.proto diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index da269933b46..c1eaa081667 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -336,6 +336,7 @@ ControllerGenesisState defines the interchain accounts controller genesis state | `active_channels` | [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel) | repeated | | | `interchain_accounts` | [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount) | repeated | | | `ports` | [string](#string) | repeated | | +| `params` | [ibc.applications.interchain_accounts.controller.v1.Params](#ibc.applications.interchain_accounts.controller.v1.Params) | | | @@ -369,6 +370,7 @@ HostGenesisState defines the interchain accounts host genesis state | `active_channels` | [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel) | repeated | | | `interchain_accounts` | [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount) | repeated | | | `port` | [string](#string) | | | +| `params` | [ibc.applications.interchain_accounts.host.v1.Params](#ibc.applications.interchain_accounts.host.v1.Params) | | | diff --git a/modules/apps/27-interchain-accounts/controller/keeper/genesis.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go index d38a4ed6e77..19bcb1de6cc 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/genesis.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go @@ -27,6 +27,8 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, state icatypes.ControllerGenesi for _, acc := range state.InterchainAccounts { keeper.SetInterchainAccountAddress(ctx, acc.PortId, acc.AccountAddress) } + + keeper.SetParams(ctx, state.Params) } // ExportGenesis returns the interchain accounts controller exported genesis @@ -35,5 +37,6 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) icatypes.ControllerGenesisSta keeper.GetAllActiveChannels(ctx), keeper.GetAllInterchainAccounts(ctx), keeper.GetAllPorts(ctx), + keeper.GetParams(ctx), ) } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go index 398100458ac..488d39d982b 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) @@ -34,6 +35,11 @@ func (suite *KeeperTestSuite) TestInitGenesis() { accountAdrr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), TestPortID) suite.Require().True(found) suite.Require().Equal(TestAccAddress.String(), accountAdrr) + + expParams := types.NewParams(false) + params := suite.chainA.GetSimApp().ICAControllerKeeper.GetParams(suite.chainA.GetContext()) + suite.Require().Equal(expParams, params) + } func (suite *KeeperTestSuite) TestExportGenesis() { @@ -54,4 +60,7 @@ func (suite *KeeperTestSuite) TestExportGenesis() { suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.InterchainAccounts[0].PortId) suite.Require().Equal([]string{TestPortID}, genesisState.GetPorts()) + + expParams := types.DefaultParams() + suite.Require().Equal(expParams, genesisState.GetParams()) } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index 4f021c1eb16..91705ae89e1 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -9,16 +9,19 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/tendermint/tendermint/libs/log" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) // Keeper defines the IBC interchain accounts controller keeper type Keeper struct { - storeKey sdk.StoreKey - cdc codec.BinaryCodec + storeKey sdk.StoreKey + cdc codec.BinaryCodec + paramSpace paramtypes.Subspace ics4Wrapper icatypes.ICS4Wrapper channelKeeper icatypes.ChannelKeeper @@ -32,13 +35,20 @@ type Keeper struct { // NewKeeper creates a new interchain accounts controller Keeper instance func NewKeeper( - cdc codec.BinaryCodec, key sdk.StoreKey, + cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace, ics4Wrapper icatypes.ICS4Wrapper, channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, accountKeeper icatypes.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, ) Keeper { + + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + return Keeper{ storeKey: key, cdc: cdc, + paramSpace: paramSpace, ics4Wrapper: ics4Wrapper, channelKeeper: channelKeeper, portKeeper: portKeeper, diff --git a/modules/apps/27-interchain-accounts/controller/keeper/params.go b/modules/apps/27-interchain-accounts/controller/keeper/params.go new file mode 100644 index 00000000000..5169d51e6a9 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/params.go @@ -0,0 +1,24 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" +) + +// GetControllerEnabled retrieves the host enabled boolean from the paramstore +func (k Keeper) GetControllerEnabled(ctx sdk.Context) bool { + var res bool + k.paramSpace.Get(ctx, types.KeyControllerEnabled, &res) + return res +} + +// GetParams returns the total set of the host submodule parameters. +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + return types.NewParams(k.GetControllerEnabled(ctx)) +} + +// SetParams sets the total set of the host submodule parameters. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/params_test.go b/modules/apps/27-interchain-accounts/controller/keeper/params_test.go new file mode 100644 index 00000000000..27138d42de5 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/params_test.go @@ -0,0 +1,15 @@ +package keeper_test + +import "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" + +func (suite *KeeperTestSuite) TestParams() { + expParams := types.DefaultParams() + + params := suite.chainA.GetSimApp().ICAControllerKeeper.GetParams(suite.chainA.GetContext()) + suite.Require().Equal(expParams, params) + + expParams.ControllerEnabled = false + suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), expParams) + params = suite.chainA.GetSimApp().ICAControllerKeeper.GetParams(suite.chainA.GetContext()) + suite.Require().Equal(expParams, params) +} diff --git a/modules/apps/27-interchain-accounts/controller/types/controller.pb.go b/modules/apps/27-interchain-accounts/controller/types/controller.pb.go new file mode 100644 index 00000000000..3a292e9a77b --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/types/controller.pb.go @@ -0,0 +1,318 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/interchain_accounts/controller/v1/controller.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the set of on-chain interchain accounts parameters. +// The following parameters may be used to disable the controller submodule. +type Params struct { + // controller_enabled enables or disables the controller submodule. + ControllerEnabled bool `protobuf:"varint,1,opt,name=controller_enabled,json=controllerEnabled,proto3" json:"controller_enabled,omitempty" yaml:"controller_enabled"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_177fd0fec5eb3400, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetControllerEnabled() bool { + if m != nil { + return m.ControllerEnabled + } + return false +} + +func init() { + proto.RegisterType((*Params)(nil), "ibc.applications.interchain_accounts.controller.v1.Params") +} + +func init() { + proto.RegisterFile("ibc/applications/interchain_accounts/controller/v1/controller.proto", fileDescriptor_177fd0fec5eb3400) +} + +var fileDescriptor_177fd0fec5eb3400 = []byte{ + // 268 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xb1, 0x4e, 0xc3, 0x30, + 0x14, 0x45, 0x93, 0xa5, 0x42, 0xd9, 0x88, 0x18, 0x68, 0x25, 0x0c, 0xca, 0xc4, 0x92, 0x3c, 0x35, + 0x0c, 0x48, 0x8c, 0x45, 0x6c, 0x0c, 0x15, 0x03, 0x03, 0x4b, 0x65, 0xbb, 0xc6, 0x35, 0x72, 0xfc, + 0x22, 0xdb, 0x89, 0x94, 0xbf, 0xe0, 0xb3, 0x18, 0x3b, 0x32, 0x21, 0x94, 0xfc, 0x01, 0x5f, 0x80, + 0x9a, 0x0c, 0x89, 0xd4, 0x6e, 0xd7, 0x47, 0x7e, 0x47, 0xba, 0x37, 0x7a, 0x54, 0x8c, 0x03, 0x2d, + 0x4b, 0xad, 0x38, 0xf5, 0x0a, 0x8d, 0x03, 0x65, 0xbc, 0xb0, 0x7c, 0x47, 0x95, 0xd9, 0x50, 0xce, + 0xb1, 0x32, 0xde, 0x01, 0x47, 0xe3, 0x2d, 0x6a, 0x2d, 0x2c, 0xd4, 0xcb, 0xc9, 0x2b, 0x2b, 0x2d, + 0x7a, 0x8c, 0x73, 0xc5, 0x78, 0x36, 0x95, 0x64, 0x27, 0x24, 0xd9, 0xe4, 0xac, 0x5e, 0x2e, 0xe6, + 0x12, 0x51, 0x6a, 0x01, 0xbd, 0x81, 0x55, 0xef, 0x40, 0x4d, 0x33, 0xe8, 0x16, 0x17, 0x12, 0x25, + 0xf6, 0x11, 0x0e, 0x69, 0xa0, 0xc9, 0x6b, 0x34, 0x5b, 0x53, 0x4b, 0x0b, 0x17, 0x3f, 0x47, 0xf1, + 0xe8, 0xda, 0x08, 0x43, 0x99, 0x16, 0xdb, 0xcb, 0xf0, 0x26, 0xbc, 0x3d, 0x5b, 0x5d, 0xfd, 0xfd, + 0x5c, 0xcf, 0x1b, 0x5a, 0xe8, 0x87, 0xe4, 0xf8, 0x4f, 0xf2, 0x72, 0x3e, 0xc2, 0xa7, 0x81, 0xad, + 0x3e, 0xbe, 0x5a, 0x12, 0xee, 0x5b, 0x12, 0xfe, 0xb6, 0x24, 0xfc, 0xec, 0x48, 0xb0, 0xef, 0x48, + 0xf0, 0xdd, 0x91, 0xe0, 0x6d, 0x2d, 0x95, 0xdf, 0x55, 0x2c, 0xe3, 0x58, 0x00, 0x47, 0x57, 0xa0, + 0x03, 0xc5, 0x78, 0x2a, 0x11, 0xea, 0x1c, 0x0a, 0xdc, 0x56, 0x5a, 0xb8, 0xc3, 0x76, 0x0e, 0xf2, + 0xfb, 0x74, 0x6c, 0x9c, 0x9e, 0x9a, 0xcd, 0x37, 0xa5, 0x70, 0x6c, 0xd6, 0x57, 0xb9, 0xfb, 0x0f, + 0x00, 0x00, 0xff, 0xff, 0x0f, 0xf9, 0x46, 0xeb, 0x76, 0x01, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ControllerEnabled { + i-- + if m.ControllerEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintController(dAtA []byte, offset int, v uint64) int { + offset -= sovController(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ControllerEnabled { + n += 2 + } + return n +} + +func sovController(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozController(x uint64) (n int) { + return sovController(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowController + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ControllerEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowController + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ControllerEnabled = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipController(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthController + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipController(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowController + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowController + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowController + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthController + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupController + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthController + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthController = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowController = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupController = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/27-interchain-accounts/controller/types/params.go b/modules/apps/27-interchain-accounts/controller/types/params.go new file mode 100644 index 00000000000..eb9c413bec0 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/types/params.go @@ -0,0 +1,59 @@ +package types + +import ( + "fmt" + + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +const ( + // DefaultControllerEnabled is the default value for the controller param (set to true) + DefaultControllerEnabled = true +) + +var ( + // KeyControllerEnabled is the store key for ControllerEnabled Params + KeyControllerEnabled = []byte("ControllerEnabled") +) + +// ParamKeyTable type declaration for parameters +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new parameter configuration for the controller submodule +func NewParams(enableController bool) Params { + return Params{ + ControllerEnabled: enableController, + } +} + +// DefaultParams is the default parameter configuration for the controller submodule +func DefaultParams() Params { + return NewParams(DefaultControllerEnabled) +} + +// Validate validates all controller submodule parameters +func (p Params) Validate() error { + if err := validateEnabled(p.ControllerEnabled); err != nil { + return err + } + + return nil +} + +// ParamSetPairs implements params.ParamSet +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyControllerEnabled, p.ControllerEnabled, validateEnabled), + } +} + +func validateEnabled(i interface{}) error { + _, ok := i.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} diff --git a/modules/apps/27-interchain-accounts/controller/types/params_test.go b/modules/apps/27-interchain-accounts/controller/types/params_test.go new file mode 100644 index 00000000000..0a25fd213a0 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/types/params_test.go @@ -0,0 +1,14 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" +) + +func TestValidateParams(t *testing.T) { + require.NoError(t, types.DefaultParams().Validate()) + require.NoError(t, types.NewParams(false).Validate()) +} diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis.go b/modules/apps/27-interchain-accounts/host/keeper/genesis.go index 3fd5c02f8da..12174ca3f26 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/genesis.go +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis.go @@ -25,6 +25,8 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, state icatypes.HostGenesisState for _, acc := range state.InterchainAccounts { keeper.SetInterchainAccountAddress(ctx, acc.PortId, acc.AccountAddress) } + + keeper.SetParams(ctx, state.Params) } // ExportGenesis returns the interchain accounts host exported genesis @@ -33,5 +35,6 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) icatypes.HostGenesisState { keeper.GetAllActiveChannels(ctx), keeper.GetAllInterchainAccounts(ctx), icatypes.PortID, + keeper.GetParams(ctx), ) } diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go index 272109b5412..7dba9ea121a 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) @@ -34,6 +35,10 @@ func (suite *KeeperTestSuite) TestInitGenesis() { accountAdrr, found := suite.chainA.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), TestPortID) suite.Require().True(found) suite.Require().Equal(TestAccAddress.String(), accountAdrr) + + expParams := types.NewParams(false) + params := suite.chainA.GetSimApp().ICAHostKeeper.GetParams(suite.chainA.GetContext()) + suite.Require().Equal(expParams, params) } func (suite *KeeperTestSuite) TestExportGenesis() { @@ -54,4 +59,7 @@ func (suite *KeeperTestSuite) TestExportGenesis() { suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.InterchainAccounts[0].PortId) suite.Require().Equal(icatypes.PortID, genesisState.GetPort()) + + expParams := types.DefaultParams() + suite.Require().Equal(expParams, genesisState.GetParams()) } diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go index 23fcd168c5a..c4d9261651b 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -10,8 +10,10 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/tendermint/tendermint/libs/log" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" @@ -19,8 +21,9 @@ import ( // Keeper defines the IBC interchain accounts host keeper type Keeper struct { - storeKey sdk.StoreKey - cdc codec.BinaryCodec + storeKey sdk.StoreKey + cdc codec.BinaryCodec + paramSpace paramtypes.Subspace channelKeeper icatypes.ChannelKeeper portKeeper icatypes.PortKeeper @@ -33,7 +36,8 @@ type Keeper struct { // NewKeeper creates a new interchain accounts host Keeper instance func NewKeeper( - cdc codec.BinaryCodec, key sdk.StoreKey, channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, + cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace, + channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, accountKeeper icatypes.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, ) Keeper { @@ -42,9 +46,15 @@ func NewKeeper( panic("the Interchain Accounts module account has not been set") } + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + return Keeper{ storeKey: key, cdc: cdc, + paramSpace: paramSpace, channelKeeper: channelKeeper, portKeeper: portKeeper, accountKeeper: accountKeeper, diff --git a/modules/apps/27-interchain-accounts/host/keeper/params.go b/modules/apps/27-interchain-accounts/host/keeper/params.go new file mode 100644 index 00000000000..c5198283b53 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/keeper/params.go @@ -0,0 +1,24 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" +) + +// GetHostEnabled retrieves the host enabled boolean from the paramstore +func (k Keeper) GetHostEnabled(ctx sdk.Context) bool { + var res bool + k.paramSpace.Get(ctx, types.KeyHostEnabled, &res) + return res +} + +// GetParams returns the total set of the host submodule parameters. +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + return types.NewParams(k.GetHostEnabled(ctx)) +} + +// SetParams sets the total set of the host submodule parameters. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) +} diff --git a/modules/apps/27-interchain-accounts/host/keeper/params_test.go b/modules/apps/27-interchain-accounts/host/keeper/params_test.go new file mode 100644 index 00000000000..9f8e53068ae --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/keeper/params_test.go @@ -0,0 +1,15 @@ +package keeper_test + +import "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" + +func (suite *KeeperTestSuite) TestParams() { + expParams := types.DefaultParams() + + params := suite.chainA.GetSimApp().ICAHostKeeper.GetParams(suite.chainA.GetContext()) + suite.Require().Equal(expParams, params) + + expParams.HostEnabled = false + suite.chainA.GetSimApp().ICAHostKeeper.SetParams(suite.chainA.GetContext(), expParams) + params = suite.chainA.GetSimApp().ICAHostKeeper.GetParams(suite.chainA.GetContext()) + suite.Require().Equal(expParams, params) +} diff --git a/modules/apps/27-interchain-accounts/host/types/host.pb.go b/modules/apps/27-interchain-accounts/host/types/host.pb.go new file mode 100644 index 00000000000..f926909215b --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/types/host.pb.go @@ -0,0 +1,318 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/interchain_accounts/host/v1/host.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the set of on-chain interchain accounts parameters. +// The following parameters may be used to disable the host submodule. +type Params struct { + // host_enabled enables or disables the host submodule. + HostEnabled bool `protobuf:"varint,1,opt,name=host_enabled,json=hostEnabled,proto3" json:"host_enabled,omitempty" yaml:"host_enabled"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_48e202774f13d08e, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetHostEnabled() bool { + if m != nil { + return m.HostEnabled + } + return false +} + +func init() { + proto.RegisterType((*Params)(nil), "ibc.applications.interchain_accounts.host.v1.Params") +} + +func init() { + proto.RegisterFile("ibc/applications/interchain_accounts/host/v1/host.proto", fileDescriptor_48e202774f13d08e) +} + +var fileDescriptor_48e202774f13d08e = []byte{ + // 264 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xb1, 0x4e, 0xc3, 0x30, + 0x10, 0x86, 0x93, 0xa5, 0x42, 0x81, 0xa9, 0x20, 0x01, 0x1d, 0x0c, 0xca, 0xc4, 0x40, 0x72, 0x6a, + 0x19, 0x2a, 0x75, 0xac, 0x60, 0x61, 0x42, 0x8c, 0x2c, 0x95, 0xed, 0x18, 0xc7, 0x92, 0xed, 0x8b, + 0x62, 0x27, 0x52, 0xde, 0x82, 0xc7, 0x62, 0xec, 0xc8, 0x84, 0x50, 0xf2, 0x06, 0x3c, 0x01, 0x8a, + 0x33, 0x50, 0x24, 0x26, 0xff, 0xbf, 0x4f, 0xdf, 0xaf, 0xbb, 0x3f, 0x59, 0x2b, 0xc6, 0x81, 0x56, + 0x95, 0x56, 0x9c, 0x7a, 0x85, 0xd6, 0x81, 0xb2, 0x5e, 0xd4, 0xbc, 0xa4, 0xca, 0xee, 0x28, 0xe7, + 0xd8, 0x58, 0xef, 0xa0, 0x44, 0xe7, 0xa1, 0x5d, 0x86, 0x37, 0xaf, 0x6a, 0xf4, 0x38, 0xbf, 0x55, + 0x8c, 0xe7, 0x87, 0x60, 0xfe, 0x0f, 0x98, 0x07, 0xa0, 0x5d, 0x2e, 0x2e, 0x25, 0xa2, 0xd4, 0x02, + 0x02, 0xcb, 0x9a, 0x57, 0xa0, 0xb6, 0x9b, 0x82, 0x16, 0x67, 0x12, 0x25, 0x06, 0x09, 0xa3, 0x9a, + 0x7e, 0xd3, 0xfb, 0x64, 0xf6, 0x44, 0x6b, 0x6a, 0xdc, 0x7c, 0x93, 0x9c, 0x8c, 0x29, 0x3b, 0x61, + 0x29, 0xd3, 0xa2, 0xb8, 0x88, 0xaf, 0xe3, 0x9b, 0xa3, 0xed, 0xf9, 0xf7, 0xe7, 0xd5, 0x69, 0x47, + 0x8d, 0xde, 0xa4, 0x87, 0xd3, 0xf4, 0xf9, 0x78, 0xb4, 0x0f, 0x93, 0xdb, 0x16, 0xef, 0x3d, 0x89, + 0xf7, 0x3d, 0x89, 0xbf, 0x7a, 0x12, 0xbf, 0x0d, 0x24, 0xda, 0x0f, 0x24, 0xfa, 0x18, 0x48, 0xf4, + 0xf2, 0x28, 0x95, 0x2f, 0x1b, 0x96, 0x73, 0x34, 0xc0, 0xd1, 0x19, 0x74, 0xa0, 0x18, 0xcf, 0x24, + 0x42, 0xbb, 0x02, 0x83, 0x45, 0xa3, 0x85, 0x1b, 0x7b, 0x71, 0xb0, 0x5a, 0x67, 0xbf, 0x97, 0x65, + 0x7f, 0x2b, 0xf1, 0x5d, 0x25, 0x1c, 0x9b, 0x85, 0x95, 0xef, 0x7e, 0x02, 0x00, 0x00, 0xff, 0xff, + 0x78, 0x3c, 0xa0, 0x19, 0x4c, 0x01, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.HostEnabled { + i-- + if m.HostEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintHost(dAtA []byte, offset int, v uint64) int { + offset -= sovHost(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.HostEnabled { + n += 2 + } + return n +} + +func sovHost(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozHost(x uint64) (n int) { + return sovHost(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHost + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HostEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHost + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.HostEnabled = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipHost(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthHost + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipHost(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowHost + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowHost + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowHost + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthHost + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupHost + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthHost + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthHost = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowHost = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupHost = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/27-interchain-accounts/host/types/params.go b/modules/apps/27-interchain-accounts/host/types/params.go new file mode 100644 index 00000000000..589de75fc23 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/types/params.go @@ -0,0 +1,59 @@ +package types + +import ( + "fmt" + + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +const ( + // DefaultHostEnabled is the default value for the host param (set to true) + DefaultHostEnabled = true +) + +var ( + // KeyHostEnabled is the store key for HostEnabled Params + KeyHostEnabled = []byte("HostEnabled") +) + +// ParamKeyTable type declaration for parameters +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new parameter configuration for the host submodule +func NewParams(enableHost bool) Params { + return Params{ + HostEnabled: enableHost, + } +} + +// DefaultParams is the default parameter configuration for the host submodule +func DefaultParams() Params { + return NewParams(DefaultHostEnabled) +} + +// Validate validates all host submodule parameters +func (p Params) Validate() error { + if err := validateEnabled(p.HostEnabled); err != nil { + return err + } + + return nil +} + +// ParamSetPairs implements params.ParamSet +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyHostEnabled, p.HostEnabled, validateEnabled), + } +} + +func validateEnabled(i interface{}) error { + _, ok := i.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} diff --git a/modules/apps/27-interchain-accounts/host/types/params_test.go b/modules/apps/27-interchain-accounts/host/types/params_test.go new file mode 100644 index 00000000000..b8a0d418bc2 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/types/params_test.go @@ -0,0 +1,14 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" +) + +func TestValidateParams(t *testing.T) { + require.NoError(t, types.DefaultParams().Validate()) + require.NoError(t, types.NewParams(false).Validate()) +} diff --git a/modules/apps/27-interchain-accounts/types/genesis.go b/modules/apps/27-interchain-accounts/types/genesis.go index 84e489a4df6..97a906cf5f5 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.go +++ b/modules/apps/27-interchain-accounts/types/genesis.go @@ -1,6 +1,8 @@ package types import ( + controllertypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" + hosttypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" host "github.com/cosmos/ibc-go/v2/modules/core/24-host" ) @@ -35,15 +37,18 @@ func (gs GenesisState) Validate() error { // DefaultControllerGenesis creates and returns the default interchain accounts ControllerGenesisState func DefaultControllerGenesis() ControllerGenesisState { - return ControllerGenesisState{} + return ControllerGenesisState{ + Params: controllertypes.DefaultParams(), + } } // NewControllerGenesisState creates a returns a new ControllerGenesisState instance -func NewControllerGenesisState(channels []ActiveChannel, accounts []RegisteredInterchainAccount, ports []string) ControllerGenesisState { +func NewControllerGenesisState(channels []ActiveChannel, accounts []RegisteredInterchainAccount, ports []string, controllerParams controllertypes.Params) ControllerGenesisState { return ControllerGenesisState{ ActiveChannels: channels, InterchainAccounts: accounts, Ports: ports, + Params: controllerParams, } } @@ -75,22 +80,28 @@ func (gs ControllerGenesisState) Validate() error { } } + if err := gs.Params.Validate(); err != nil { + return err + } + return nil } // DefaultHostGenesis creates and returns the default interchain accounts HostGenesisState func DefaultHostGenesis() HostGenesisState { return HostGenesisState{ - Port: PortID, + Port: PortID, + Params: hosttypes.DefaultParams(), } } // NewHostGenesisState creates a returns a new HostGenesisState instance -func NewHostGenesisState(channels []ActiveChannel, accounts []RegisteredInterchainAccount, port string) HostGenesisState { +func NewHostGenesisState(channels []ActiveChannel, accounts []RegisteredInterchainAccount, port string, hostParams hosttypes.Params) HostGenesisState { return HostGenesisState{ ActiveChannels: channels, InterchainAccounts: accounts, Port: port, + Params: hostParams, } } @@ -120,5 +131,9 @@ func (gs HostGenesisState) Validate() error { return err } + if err := gs.Params.Validate(); err != nil { + return err + } + return nil } diff --git a/modules/apps/27-interchain-accounts/types/genesis.pb.go b/modules/apps/27-interchain-accounts/types/genesis.pb.go index 261826239bf..5a226263fb8 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.pb.go +++ b/modules/apps/27-interchain-accounts/types/genesis.pb.go @@ -5,6 +5,8 @@ package types import ( fmt "fmt" + types "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" + types1 "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -81,6 +83,7 @@ type ControllerGenesisState struct { ActiveChannels []ActiveChannel `protobuf:"bytes,1,rep,name=active_channels,json=activeChannels,proto3" json:"active_channels" yaml:"active_channels"` InterchainAccounts []RegisteredInterchainAccount `protobuf:"bytes,2,rep,name=interchain_accounts,json=interchainAccounts,proto3" json:"interchain_accounts" yaml:"interchain_accounts"` Ports []string `protobuf:"bytes,3,rep,name=ports,proto3" json:"ports,omitempty"` + Params types.Params `protobuf:"bytes,4,opt,name=params,proto3" json:"params"` } func (m *ControllerGenesisState) Reset() { *m = ControllerGenesisState{} } @@ -137,11 +140,19 @@ func (m *ControllerGenesisState) GetPorts() []string { return nil } +func (m *ControllerGenesisState) GetParams() types.Params { + if m != nil { + return m.Params + } + return types.Params{} +} + // HostGenesisState defines the interchain accounts host genesis state type HostGenesisState struct { ActiveChannels []ActiveChannel `protobuf:"bytes,1,rep,name=active_channels,json=activeChannels,proto3" json:"active_channels" yaml:"active_channels"` InterchainAccounts []RegisteredInterchainAccount `protobuf:"bytes,2,rep,name=interchain_accounts,json=interchainAccounts,proto3" json:"interchain_accounts" yaml:"interchain_accounts"` Port string `protobuf:"bytes,3,opt,name=port,proto3" json:"port,omitempty"` + Params types1.Params `protobuf:"bytes,4,opt,name=params,proto3" json:"params"` } func (m *HostGenesisState) Reset() { *m = HostGenesisState{} } @@ -198,6 +209,13 @@ func (m *HostGenesisState) GetPort() string { return "" } +func (m *HostGenesisState) GetParams() types1.Params { + if m != nil { + return m.Params + } + return types1.Params{} +} + // ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel type ActiveChannel struct { PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` @@ -317,41 +335,46 @@ func init() { } var fileDescriptor_629b3ced0911516b = []byte{ - // 543 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x94, 0xcf, 0x8f, 0x12, 0x31, - 0x14, 0xc7, 0xe9, 0xa0, 0x6b, 0xe8, 0xea, 0xba, 0xd6, 0x75, 0x33, 0x62, 0x32, 0x60, 0x2f, 0x4b, - 0x62, 0x98, 0x66, 0xf1, 0x57, 0xf4, 0x62, 0x00, 0x8d, 0x72, 0x1d, 0x6f, 0x5e, 0x26, 0xa5, 0xd3, - 0x0c, 0x4d, 0x86, 0x29, 0x99, 0x16, 0x92, 0x3d, 0x79, 0xf7, 0xa2, 0x57, 0xaf, 0xfe, 0x25, 0x26, - 0x5e, 0x36, 0xf1, 0xb2, 0x47, 0x4f, 0xc4, 0xc0, 0x7f, 0xc0, 0x5f, 0x60, 0xa6, 0x9d, 0x20, 0x20, - 0x6e, 0xf0, 0xee, 0xad, 0xed, 0x7b, 0xdf, 0xf7, 0xfd, 0xf4, 0xbd, 0xb4, 0xf0, 0xb1, 0xe8, 0x33, - 0x42, 0x47, 0xa3, 0x44, 0x30, 0xaa, 0x85, 0x4c, 0x15, 0x11, 0xa9, 0xe6, 0x19, 0x1b, 0x50, 0x91, - 0x86, 0x94, 0x31, 0x39, 0x4e, 0xb5, 0x22, 0x93, 0x53, 0x12, 0xf3, 0x94, 0x2b, 0xa1, 0xfc, 0x51, - 0x26, 0xb5, 0x44, 0x27, 0xa2, 0xcf, 0xfc, 0x55, 0x99, 0xbf, 0x45, 0xe6, 0x4f, 0x4e, 0xab, 0x47, - 0xb1, 0x8c, 0xa5, 0xd1, 0x90, 0x7c, 0x65, 0xe5, 0xf8, 0xab, 0x03, 0xaf, 0xbf, 0xb6, 0x05, 0xdf, - 0x6a, 0xaa, 0x39, 0xfa, 0x02, 0xa0, 0xcb, 0x64, 0xaa, 0x33, 0x99, 0x24, 0x3c, 0x0b, 0x0b, 0xb3, - 0x50, 0xe5, 0x41, 0x17, 0xd4, 0x41, 0x63, 0xbf, 0xf5, 0xc2, 0xdf, 0xd1, 0xd3, 0xef, 0x2e, 0x0b, - 0xad, 0x7a, 0x74, 0x4e, 0xce, 0xa7, 0xb5, 0xd2, 0x62, 0x5a, 0xab, 0x9d, 0xd1, 0x61, 0xf2, 0x1c, - 0xff, 0xcd, 0x0e, 0x07, 0xc7, 0x6c, 0x6b, 0x01, 0xf4, 0x01, 0x40, 0x34, 0x90, 0x4a, 0x6f, 0xe0, - 0x39, 0x06, 0xef, 0xd9, 0xce, 0x78, 0x6f, 0xa4, 0xd2, 0x6b, 0x60, 0xf7, 0x0b, 0xb0, 0xbb, 0x16, - 0xec, 0x4f, 0x0b, 0x1c, 0x1c, 0x0e, 0x36, 0x44, 0xf8, 0xbb, 0x03, 0x8f, 0xb7, 0x5f, 0x14, 0xbd, - 0x87, 0x37, 0x29, 0xd3, 0x62, 0xc2, 0x43, 0x36, 0xa0, 0x69, 0xca, 0x13, 0xe5, 0x82, 0x7a, 0xb9, - 0xb1, 0xdf, 0x7a, 0xb2, 0x33, 0x63, 0xdb, 0xe8, 0xbb, 0x56, 0xde, 0xf1, 0x0a, 0xc0, 0x63, 0x0b, - 0xb8, 0x51, 0x1c, 0x07, 0x07, 0x74, 0x35, 0x5d, 0xa1, 0xcf, 0x00, 0xde, 0xde, 0x52, 0xd8, 0x75, - 0x0c, 0xc5, 0xcb, 0x9d, 0x29, 0x02, 0x1e, 0x0b, 0xa5, 0x79, 0xc6, 0xa3, 0xde, 0x32, 0xa1, 0x6d, - 0xe3, 0x1d, 0x5c, 0x30, 0x55, 0x2d, 0xd3, 0x96, 0x0a, 0x38, 0x40, 0x62, 0x53, 0xa6, 0xd0, 0x11, - 0xbc, 0x3a, 0x92, 0x99, 0x56, 0x6e, 0xb9, 0x5e, 0x6e, 0x54, 0x02, 0xbb, 0xc1, 0xdf, 0x1c, 0x78, - 0xb8, 0x39, 0x97, 0xff, 0x7d, 0xbc, 0xac, 0x8f, 0x08, 0x5e, 0xc9, 0x5b, 0xe7, 0x96, 0xeb, 0xa0, - 0x51, 0x09, 0xcc, 0x1a, 0x67, 0xf0, 0xc6, 0xda, 0x85, 0xd1, 0x03, 0x78, 0x2d, 0x0f, 0x84, 0x22, - 0x32, 0x8f, 0xb8, 0xd2, 0x41, 0x8b, 0x69, 0xed, 0xc0, 0x3a, 0x15, 0x01, 0x1c, 0xec, 0xe5, 0xab, - 0x5e, 0x84, 0x1e, 0x41, 0x58, 0xb4, 0x22, 0xcf, 0x77, 0x4c, 0xfe, 0x9d, 0xc5, 0xb4, 0x76, 0xab, - 0x78, 0xaf, 0xcb, 0x18, 0x0e, 0x2a, 0xc5, 0xa6, 0x17, 0xe1, 0x8f, 0x00, 0xde, 0xbb, 0xe4, 0x7e, - 0xff, 0x86, 0xd0, 0xcd, 0x27, 0x6e, 0x74, 0x21, 0x8d, 0xa2, 0x8c, 0x2b, 0x55, 0x70, 0x54, 0x57, - 0xa7, 0xb6, 0x96, 0x60, 0xa6, 0x66, 0x4e, 0xda, 0xf6, 0xa0, 0x13, 0x9e, 0xcf, 0x3c, 0x70, 0x31, - 0xf3, 0xc0, 0xcf, 0x99, 0x07, 0x3e, 0xcd, 0xbd, 0xd2, 0xc5, 0xdc, 0x2b, 0xfd, 0x98, 0x7b, 0xa5, - 0x77, 0xaf, 0x62, 0xa1, 0x07, 0xe3, 0xbe, 0xcf, 0xe4, 0x90, 0x30, 0xa9, 0x86, 0x52, 0x11, 0xd1, - 0x67, 0xcd, 0x58, 0x92, 0x49, 0x8b, 0x0c, 0x65, 0x34, 0x4e, 0xb8, 0xca, 0x3f, 0x63, 0x45, 0x5a, - 0x4f, 0x9b, 0xbf, 0x7b, 0xde, 0x5c, 0xfe, 0xc3, 0xfa, 0x6c, 0xc4, 0x55, 0x7f, 0xcf, 0x7c, 0xa2, - 0x0f, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x47, 0x25, 0xf6, 0xbc, 0x05, 0x00, 0x00, + // 609 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x94, 0xcf, 0x6f, 0xd3, 0x30, + 0x14, 0xc7, 0x9b, 0x66, 0x0c, 0xd5, 0x83, 0x31, 0xcc, 0x98, 0x42, 0x91, 0xd2, 0xe2, 0xcb, 0x2a, + 0xa1, 0x25, 0x5a, 0x19, 0x4c, 0xec, 0x82, 0x96, 0x82, 0x60, 0x37, 0x14, 0x2e, 0x88, 0x4b, 0xe4, + 0x3a, 0x56, 0x6a, 0x29, 0x8d, 0xa3, 0xd8, 0xab, 0xb4, 0x13, 0x77, 0x2e, 0x70, 0x43, 0x5c, 0x91, + 0xf8, 0x3f, 0x38, 0xee, 0xb8, 0x23, 0xa7, 0x0a, 0xad, 0xff, 0x41, 0xff, 0x02, 0x64, 0x27, 0xea, + 0x8f, 0xd0, 0x4d, 0xe1, 0xce, 0xa9, 0x76, 0xfc, 0xbe, 0xdf, 0xf7, 0x79, 0x7e, 0xee, 0x03, 0x4f, + 0x59, 0x9f, 0xb8, 0x38, 0x4d, 0x63, 0x46, 0xb0, 0x64, 0x3c, 0x11, 0x2e, 0x4b, 0x24, 0xcd, 0xc8, + 0x00, 0xb3, 0x24, 0xc0, 0x84, 0xf0, 0xd3, 0x44, 0x0a, 0x77, 0xb4, 0xef, 0x46, 0x34, 0xa1, 0x82, + 0x09, 0x27, 0xcd, 0xb8, 0xe4, 0x70, 0x97, 0xf5, 0x89, 0xb3, 0x28, 0x73, 0x56, 0xc8, 0x9c, 0xd1, + 0x7e, 0x73, 0x3b, 0xe2, 0x11, 0xd7, 0x1a, 0x57, 0xad, 0x72, 0x79, 0xb3, 0x57, 0x29, 0x2b, 0xe1, + 0x89, 0xcc, 0x78, 0x1c, 0xd3, 0x4c, 0x01, 0xcc, 0x77, 0x85, 0xc9, 0x61, 0x25, 0x93, 0x01, 0x17, + 0x52, 0xc9, 0xd5, 0x6f, 0x2e, 0x44, 0x3f, 0xeb, 0xe0, 0xd6, 0xeb, 0xbc, 0x9c, 0x77, 0x12, 0x4b, + 0x0a, 0xbf, 0x1b, 0xc0, 0x9a, 0xdb, 0x07, 0x45, 0xa9, 0x81, 0x50, 0x87, 0x96, 0xd1, 0x36, 0x3a, + 0x1b, 0xdd, 0x17, 0x4e, 0xc5, 0x8a, 0x9d, 0xde, 0xcc, 0x68, 0x31, 0x87, 0xb7, 0x7b, 0x3e, 0x6e, + 0xd5, 0xa6, 0xe3, 0x56, 0xeb, 0x0c, 0x0f, 0xe3, 0x23, 0x74, 0x55, 0x3a, 0xe4, 0xef, 0x90, 0x95, + 0x06, 0xf0, 0x93, 0x01, 0xa0, 0x2a, 0xa2, 0x84, 0x57, 0xd7, 0x78, 0xcf, 0x2b, 0xe3, 0xbd, 0xe1, + 0x42, 0x2e, 0x81, 0x3d, 0x2a, 0xc0, 0x1e, 0xe4, 0x60, 0x7f, 0xa7, 0x40, 0xfe, 0xd6, 0xa0, 0x24, + 0x42, 0x3f, 0x4c, 0xb0, 0xb3, 0xba, 0x50, 0xf8, 0x11, 0xdc, 0xc1, 0x44, 0xb2, 0x11, 0x0d, 0xc8, + 0x00, 0x27, 0x09, 0x8d, 0x85, 0x65, 0xb4, 0xcd, 0xce, 0x46, 0xf7, 0x59, 0x65, 0xc6, 0x63, 0xad, + 0xef, 0xe5, 0x72, 0xcf, 0x2e, 0x00, 0x77, 0x72, 0xc0, 0x92, 0x39, 0xf2, 0x37, 0xf1, 0x62, 0xb8, + 0x80, 0xdf, 0x0c, 0x70, 0x6f, 0x85, 0xb1, 0x55, 0xd7, 0x14, 0x2f, 0x2b, 0x53, 0xf8, 0x34, 0x62, + 0x42, 0xd2, 0x8c, 0x86, 0x27, 0xb3, 0x80, 0xe3, 0xfc, 0xdc, 0x43, 0x05, 0x53, 0x33, 0x67, 0x5a, + 0xe1, 0x80, 0x7c, 0xc8, 0xca, 0x32, 0x01, 0xb7, 0xc1, 0x8d, 0x94, 0x67, 0x52, 0x58, 0x66, 0xdb, + 0xec, 0x34, 0xfc, 0x7c, 0x03, 0xdf, 0x83, 0xf5, 0x14, 0x67, 0x78, 0x28, 0xac, 0x35, 0xdd, 0xcd, + 0xa3, 0x6a, 0x8c, 0x0b, 0xff, 0x88, 0xd1, 0xbe, 0xf3, 0x56, 0x3b, 0x78, 0x6b, 0x8a, 0xcc, 0x2f, + 0xfc, 0xd0, 0x57, 0x13, 0x6c, 0x95, 0x3b, 0xfe, 0xbf, 0x43, 0xd7, 0x75, 0x08, 0x82, 0x35, 0xd5, + 0x14, 0xcb, 0x6c, 0x1b, 0x9d, 0x86, 0xaf, 0xd7, 0xd0, 0x2f, 0xf5, 0xe7, 0xa0, 0x1a, 0xa1, 0x1e, + 0x39, 0x57, 0x75, 0x26, 0x03, 0xb7, 0x97, 0x2e, 0x11, 0x3e, 0x06, 0x37, 0x55, 0xb2, 0x80, 0x85, + 0x7a, 0xe4, 0x34, 0x3c, 0x38, 0x1d, 0xb7, 0x36, 0x73, 0xfa, 0xe2, 0x00, 0xf9, 0xeb, 0x6a, 0x75, + 0x12, 0xc2, 0x03, 0x00, 0x8a, 0xeb, 0x55, 0xf1, 0x75, 0x1d, 0x7f, 0x7f, 0x3a, 0x6e, 0xdd, 0x2d, + 0xa6, 0xcb, 0xec, 0x0c, 0xf9, 0x8d, 0x62, 0x73, 0x12, 0xa2, 0xcf, 0x06, 0x78, 0x78, 0xcd, 0x9d, + 0xfd, 0x1b, 0x42, 0x4f, 0xbd, 0x22, 0xad, 0x0b, 0x70, 0x18, 0x66, 0x54, 0x88, 0x82, 0xa3, 0xb9, + 0xf8, 0x12, 0x96, 0x02, 0xf4, 0x4b, 0xd0, 0x5f, 0x8e, 0xf3, 0x0f, 0x5e, 0x70, 0x7e, 0x69, 0x1b, + 0x17, 0x97, 0xb6, 0xf1, 0xfb, 0xd2, 0x36, 0xbe, 0x4c, 0xec, 0xda, 0xc5, 0xc4, 0xae, 0xfd, 0x9a, + 0xd8, 0xb5, 0x0f, 0xaf, 0x22, 0x26, 0x07, 0xa7, 0x7d, 0x87, 0xf0, 0xa1, 0x4b, 0xb8, 0x18, 0x72, + 0xe1, 0xb2, 0x3e, 0xd9, 0x8b, 0xb8, 0x3b, 0xea, 0xba, 0x43, 0x1e, 0x9e, 0xc6, 0x54, 0xa8, 0xe9, + 0x2f, 0xdc, 0xee, 0xe1, 0xde, 0xfc, 0xf6, 0xf7, 0x66, 0x83, 0x5f, 0x9e, 0xa5, 0x54, 0xf4, 0xd7, + 0xf5, 0xc8, 0x7f, 0xf2, 0x27, 0x00, 0x00, 0xff, 0xff, 0x61, 0x4a, 0xb3, 0xe7, 0xe8, 0x06, 0x00, + 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -417,6 +440,16 @@ func (m *ControllerGenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 if len(m.Ports) > 0 { for iNdEx := len(m.Ports) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.Ports[iNdEx]) @@ -477,6 +510,16 @@ func (m *HostGenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 if len(m.Port) > 0 { i -= len(m.Port) copy(dAtA[i:], m.Port) @@ -637,6 +680,8 @@ func (m *ControllerGenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -662,6 +707,8 @@ func (m *HostGenesisState) Size() (n int) { if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -950,6 +997,39 @@ func (m *ControllerGenesisState) Unmarshal(dAtA []byte) error { } m.Ports = append(m.Ports, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) @@ -1100,6 +1180,39 @@ func (m *HostGenesisState) Unmarshal(dAtA []byte) error { } m.Port = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/modules/apps/27-interchain-accounts/types/genesis_test.go b/modules/apps/27-interchain-accounts/types/genesis_test.go index 939339f5fb3..2ac017c63ad 100644 --- a/modules/apps/27-interchain-accounts/types/genesis_test.go +++ b/modules/apps/27-interchain-accounts/types/genesis_test.go @@ -1,6 +1,8 @@ package types_test import ( + controllertypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" + hosttypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/v2/testing" ) @@ -85,7 +87,7 @@ func (suite *TypesTestSuite) TestValidateControllerGenesisState() { }, } - genesisState = types.NewControllerGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, []string{}) + genesisState = types.NewControllerGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, []string{}, controllertypes.DefaultParams()) }, false, }, @@ -99,7 +101,7 @@ func (suite *TypesTestSuite) TestValidateControllerGenesisState() { }, } - genesisState = types.NewControllerGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, []string{}) + genesisState = types.NewControllerGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, []string{}, controllertypes.DefaultParams()) }, false, }, @@ -120,7 +122,7 @@ func (suite *TypesTestSuite) TestValidateControllerGenesisState() { }, } - genesisState = types.NewControllerGenesisState(activeChannels, registeredAccounts, []string{}) + genesisState = types.NewControllerGenesisState(activeChannels, registeredAccounts, []string{}, controllertypes.DefaultParams()) }, false, }, @@ -141,7 +143,7 @@ func (suite *TypesTestSuite) TestValidateControllerGenesisState() { }, } - genesisState = types.NewControllerGenesisState(activeChannels, registeredAccounts, []string{}) + genesisState = types.NewControllerGenesisState(activeChannels, registeredAccounts, []string{}, controllertypes.DefaultParams()) }, false, }, @@ -162,7 +164,7 @@ func (suite *TypesTestSuite) TestValidateControllerGenesisState() { }, } - genesisState = types.NewControllerGenesisState(activeChannels, registeredAccounts, []string{"invalid|port"}) + genesisState = types.NewControllerGenesisState(activeChannels, registeredAccounts, []string{"invalid|port"}, controllertypes.DefaultParams()) }, false, }, @@ -210,7 +212,7 @@ func (suite *TypesTestSuite) TestValidateHostGenesisState() { }, } - genesisState = types.NewHostGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, types.PortID) + genesisState = types.NewHostGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, types.PortID, hosttypes.DefaultParams()) }, false, }, @@ -224,7 +226,7 @@ func (suite *TypesTestSuite) TestValidateHostGenesisState() { }, } - genesisState = types.NewHostGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, types.PortID) + genesisState = types.NewHostGenesisState(activeChannels, []types.RegisteredInterchainAccount{}, types.PortID, hosttypes.DefaultParams()) }, false, }, @@ -245,7 +247,7 @@ func (suite *TypesTestSuite) TestValidateHostGenesisState() { }, } - genesisState = types.NewHostGenesisState(activeChannels, registeredAccounts, types.PortID) + genesisState = types.NewHostGenesisState(activeChannels, registeredAccounts, types.PortID, hosttypes.DefaultParams()) }, false, }, @@ -266,7 +268,7 @@ func (suite *TypesTestSuite) TestValidateHostGenesisState() { }, } - genesisState = types.NewHostGenesisState(activeChannels, registeredAccounts, types.PortID) + genesisState = types.NewHostGenesisState(activeChannels, registeredAccounts, types.PortID, hosttypes.DefaultParams()) }, false, }, @@ -287,7 +289,7 @@ func (suite *TypesTestSuite) TestValidateHostGenesisState() { }, } - genesisState = types.NewHostGenesisState(activeChannels, registeredAccounts, "invalid|port") + genesisState = types.NewHostGenesisState(activeChannels, registeredAccounts, "invalid|port", hosttypes.DefaultParams()) }, false, }, diff --git a/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto b/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto new file mode 100644 index 00000000000..79430e89e7e --- /dev/null +++ b/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.controller.v1; + +option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types"; + +import "google/protobuf/any.proto"; +import "gogoproto/gogo.proto"; + +// Params defines the set of on-chain interchain accounts parameters. +// The following parameters may be used to disable the controller submodule. +message Params { + // controller_enabled enables or disables the controller submodule. + bool controller_enabled = 1 [(gogoproto.moretags) = "yaml:\"controller_enabled\""]; +} diff --git a/proto/ibc/applications/interchain_accounts/host/v1/host.proto b/proto/ibc/applications/interchain_accounts/host/v1/host.proto new file mode 100644 index 00000000000..a5301199286 --- /dev/null +++ b/proto/ibc/applications/interchain_accounts/host/v1/host.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.host.v1; + +option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types"; + +import "google/protobuf/any.proto"; +import "gogoproto/gogo.proto"; + +// Params defines the set of on-chain interchain accounts parameters. +// The following parameters may be used to disable the host submodule. +message Params { + // host_enabled enables or disables the host submodule. + bool host_enabled = 1 [(gogoproto.moretags) = "yaml:\"host_enabled\""]; +} diff --git a/proto/ibc/applications/interchain_accounts/v1/genesis.proto b/proto/ibc/applications/interchain_accounts/v1/genesis.proto index 69527bd867a..7fc5cd846bd 100644 --- a/proto/ibc/applications/interchain_accounts/v1/genesis.proto +++ b/proto/ibc/applications/interchain_accounts/v1/genesis.proto @@ -5,6 +5,8 @@ package ibc.applications.interchain_accounts.v1; option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"; import "gogoproto/gogo.proto"; +import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; +import "ibc/applications/interchain_accounts/host/v1/host.proto"; // GenesisState defines the interchain accounts genesis state message GenesisState { @@ -21,6 +23,7 @@ message ControllerGenesisState { repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"interchain_accounts\""]; repeated string ports = 3; + ibc.applications.interchain_accounts.controller.v1.Params params = 4 [(gogoproto.nullable) = false]; } // HostGenesisState defines the interchain accounts host genesis state @@ -30,6 +33,7 @@ message HostGenesisState { repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"interchain_accounts\""]; string port = 3; + ibc.applications.interchain_accounts.host.v1.Params params = 4 [(gogoproto.nullable) = false]; } // ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel diff --git a/proto/ibc/applications/interchain_accounts/v1/types.proto b/proto/ibc/applications/interchain_accounts/v1/types.proto index c6d9d0a3e96..43350212934 100644 --- a/proto/ibc/applications/interchain_accounts/v1/types.proto +++ b/proto/ibc/applications/interchain_accounts/v1/types.proto @@ -29,3 +29,4 @@ message InterchainAccountPacketData { message CosmosTx { repeated google.protobuf.Any messages = 1; } + diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 1955558be31..18aba3e1ec6 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -353,14 +353,14 @@ func NewSimApp( mockIBCModule := ibcmock.NewIBCModule(&ibcmock.MockIBCApp{}, scopedIBCMockKeeper) app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], + appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.ModuleName), app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, scopedICAControllerKeeper, app.MsgServiceRouter(), ) app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], + appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.ModuleName), app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), ) @@ -708,6 +708,8 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(crisistypes.ModuleName) paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) + paramsKeeper.Subspace(icacontrollertypes.ModuleName) + paramsKeeper.Subspace(icahosttypes.ModuleName) return paramsKeeper } From eedb0cbe120d9da2e0d3b5d5b5be9d5a3a2f95be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 1 Dec 2021 11:34:58 +0100 Subject: [PATCH 60/66] Disable usage of controller and host submodules based on on-chain params (#575) * add usage of enabling/disabling controller and host submodules Adds if statement checks in controller/host ibc_module.go. Adds tests for each added if statements. Tests not added for controller ack/timeout since tests do not exist for those functions yet. * Update modules/apps/27-interchain-accounts/controller/ibc_module_test.go --- .../controller/ibc_module.go | 17 +++++++++++++++++ .../controller/ibc_module_test.go | 17 ++++++++++++++--- .../controller/keeper/params.go | 7 ++++--- .../controller/types/errors.go | 10 ++++++++++ .../27-interchain-accounts/host/ibc_module.go | 13 +++++++++++++ .../host/ibc_module_test.go | 16 ++++++++++++++++ .../host/keeper/params.go | 7 ++++--- .../27-interchain-accounts/host/types/errors.go | 10 ++++++++++ 8 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/controller/types/errors.go create mode 100644 modules/apps/27-interchain-accounts/host/types/errors.go diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module.go b/modules/apps/27-interchain-accounts/controller/ibc_module.go index 74d9d0800c1..897191eca08 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module.go @@ -6,6 +6,7 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" @@ -42,6 +43,10 @@ func (im IBCModule) OnChanOpenInit( counterparty channeltypes.Counterparty, version string, ) error { + if !im.keeper.IsControllerEnabled(ctx) { + return types.ErrControllerSubModuleDisabled + } + if err := im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version); err != nil { return err } @@ -78,6 +83,10 @@ func (im IBCModule) OnChanOpenAck( channelID string, counterpartyVersion string, ) error { + if !im.keeper.IsControllerEnabled(ctx) { + return types.ErrControllerSubModuleDisabled + } + if err := im.keeper.OnChanOpenAck(ctx, portID, channelID, counterpartyVersion); err != nil { return err } @@ -130,6 +139,10 @@ func (im IBCModule) OnAcknowledgementPacket( acknowledgement []byte, relayer sdk.AccAddress, ) error { + if !im.keeper.IsControllerEnabled(ctx) { + return types.ErrControllerSubModuleDisabled + } + // call underlying app's OnAcknowledgementPacket callback. return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) } @@ -140,6 +153,10 @@ func (im IBCModule) OnTimeoutPacket( packet channeltypes.Packet, relayer sdk.AccAddress, ) error { + if !im.keeper.IsControllerEnabled(ctx) { + return types.ErrControllerSubModuleDisabled + } + if err := im.keeper.OnTimeoutPacket(ctx, packet); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go index cf01f0c5f29..f1aa84be591 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" @@ -117,6 +118,11 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { { "success", func() {}, true, }, + { + "controller submodule disabled", func() { + suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) + }, false, + }, { "ICA OnChanOpenInit fails - UNORDERED channel", func() { channel.Ordering = channeltypes.UNORDERED @@ -251,6 +257,11 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { { "success", func() {}, true, }, + { + "controller submodule disabled", func() { + suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) + }, false, + }, { "ICA OnChanOpenACK fails - invalid version", func() { path.EndpointB.ChannelConfig.Version = "invalid|version" @@ -460,15 +471,15 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { packet := channeltypes.NewPacket( []byte("empty packet data"), suite.chainA.SenderAccount.GetSequence(), - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0, ) - ack := cbs.OnRecvPacket(suite.chainA.GetContext(), packet, TestAccAddress) + ack := cbs.OnRecvPacket(suite.chainB.GetContext(), packet, TestAccAddress) suite.Require().Equal(tc.expPass, ack.Success()) }) } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/params.go b/modules/apps/27-interchain-accounts/controller/keeper/params.go index 5169d51e6a9..55e15e26d97 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/params.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/params.go @@ -6,8 +6,9 @@ import ( "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" ) -// GetControllerEnabled retrieves the host enabled boolean from the paramstore -func (k Keeper) GetControllerEnabled(ctx sdk.Context) bool { +// IsControllerEnabled retrieves the host enabled boolean from the paramstore. +// True is returned if the controller submodule is enabled. +func (k Keeper) IsControllerEnabled(ctx sdk.Context) bool { var res bool k.paramSpace.Get(ctx, types.KeyControllerEnabled, &res) return res @@ -15,7 +16,7 @@ func (k Keeper) GetControllerEnabled(ctx sdk.Context) bool { // GetParams returns the total set of the host submodule parameters. func (k Keeper) GetParams(ctx sdk.Context) types.Params { - return types.NewParams(k.GetControllerEnabled(ctx)) + return types.NewParams(k.IsControllerEnabled(ctx)) } // SetParams sets the total set of the host submodule parameters. diff --git a/modules/apps/27-interchain-accounts/controller/types/errors.go b/modules/apps/27-interchain-accounts/controller/types/errors.go new file mode 100644 index 00000000000..efb316097e4 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/types/errors.go @@ -0,0 +1,10 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// ICA Controller sentinel errors +var ( + ErrControllerSubModuleDisabled = sdkerrors.Register(ModuleName, 2, "controller submodule is disabled") +) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 3e28117ba22..b8dbc15d42e 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -6,6 +6,7 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/keeper" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" @@ -49,6 +50,10 @@ func (im IBCModule) OnChanOpenTry( version, counterpartyVersion string, ) error { + if !im.keeper.IsHostEnabled(ctx) { + return types.ErrHostSubModuleDisabled + } + return im.keeper.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version, counterpartyVersion) } @@ -68,6 +73,10 @@ func (im IBCModule) OnChanOpenConfirm( portID, channelID string, ) error { + if !im.keeper.IsHostEnabled(ctx) { + return types.ErrHostSubModuleDisabled + } + return im.keeper.OnChanOpenConfirm(ctx, portID, channelID) } @@ -96,6 +105,10 @@ func (im IBCModule) OnRecvPacket( packet channeltypes.Packet, _ sdk.AccAddress, ) ibcexported.Acknowledgement { + if !im.keeper.IsHostEnabled(ctx) { + return channeltypes.NewErrorAcknowledgement(types.ErrHostSubModuleDisabled.Error()) + } + ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) if err := im.keeper.OnRecvPacket(ctx, packet); err != nil { diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index aa99ac811f5..2a75c71ce0e 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" @@ -136,6 +137,11 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { { "success", func() {}, true, }, + { + "host submodule disabled", func() { + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(false)) + }, false, + }, { "success: ICA auth module callback returns error", func() { // mock module callback should not be called on host side @@ -252,6 +258,11 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { { "success", func() {}, true, }, + { + "host submodule disabled", func() { + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(false)) + }, false, + }, { "success: ICA auth module callback returns error", func() { // mock module callback should not be called on host side @@ -386,6 +397,11 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { { "success", func() {}, true, }, + { + "host submodule disabled", func() { + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(false)) + }, false, + }, { "success with ICA auth module callback failure", func() { suite.chainB.GetSimApp().ICAAuthModule.IBCApp.OnRecvPacket = func( diff --git a/modules/apps/27-interchain-accounts/host/keeper/params.go b/modules/apps/27-interchain-accounts/host/keeper/params.go index c5198283b53..7b91c1bf110 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/params.go +++ b/modules/apps/27-interchain-accounts/host/keeper/params.go @@ -6,8 +6,9 @@ import ( "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" ) -// GetHostEnabled retrieves the host enabled boolean from the paramstore -func (k Keeper) GetHostEnabled(ctx sdk.Context) bool { +// IsHostEnabled retrieves the host enabled boolean from the paramstore. +// True is returned if the host submodule is enabled. +func (k Keeper) IsHostEnabled(ctx sdk.Context) bool { var res bool k.paramSpace.Get(ctx, types.KeyHostEnabled, &res) return res @@ -15,7 +16,7 @@ func (k Keeper) GetHostEnabled(ctx sdk.Context) bool { // GetParams returns the total set of the host submodule parameters. func (k Keeper) GetParams(ctx sdk.Context) types.Params { - return types.NewParams(k.GetHostEnabled(ctx)) + return types.NewParams(k.IsHostEnabled(ctx)) } // SetParams sets the total set of the host submodule parameters. diff --git a/modules/apps/27-interchain-accounts/host/types/errors.go b/modules/apps/27-interchain-accounts/host/types/errors.go new file mode 100644 index 00000000000..b188ac027c7 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/types/errors.go @@ -0,0 +1,10 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// ICA Host sentinel errors +var ( + ErrHostSubModuleDisabled = sdkerrors.Register(ModuleName, 2, "host submodule is disabled") +) From e6e4caa62b503cb8d747e6f2ca4ea71bd8cf6910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 1 Dec 2021 11:52:39 +0100 Subject: [PATCH 61/66] add grpc query for controller and host params (#574) Adds gRPC routes for controller params and host params. Add tests and registers the gRPC gateways on the ica module --- .../controller/keeper/grpc_query.go | 19 + .../controller/keeper/grpc_query_test.go | 14 + .../controller/types/query.pb.go | 547 ++++++++++++++++++ .../controller/types/query.pb.gw.go | 148 +++++ .../host/keeper/grpc_query.go | 19 + .../host/keeper/grpc_query_test.go | 14 + .../host/types/query.pb.go | 547 ++++++++++++++++++ .../host/types/query.pb.gw.go | 148 +++++ modules/apps/27-interchain-accounts/module.go | 5 + .../controller/v1/query.proto | 27 + .../interchain_accounts/host/v1/query.proto | 27 + 11 files changed, 1515 insertions(+) create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/grpc_query.go create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go create mode 100644 modules/apps/27-interchain-accounts/controller/types/query.pb.go create mode 100644 modules/apps/27-interchain-accounts/controller/types/query.pb.gw.go create mode 100644 modules/apps/27-interchain-accounts/host/keeper/grpc_query.go create mode 100644 modules/apps/27-interchain-accounts/host/keeper/grpc_query_test.go create mode 100644 modules/apps/27-interchain-accounts/host/types/query.pb.go create mode 100644 modules/apps/27-interchain-accounts/host/types/query.pb.gw.go create mode 100644 proto/ibc/applications/interchain_accounts/controller/v1/query.proto create mode 100644 proto/ibc/applications/interchain_accounts/host/v1/query.proto diff --git a/modules/apps/27-interchain-accounts/controller/keeper/grpc_query.go b/modules/apps/27-interchain-accounts/controller/keeper/grpc_query.go new file mode 100644 index 00000000000..1e74921269d --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/grpc_query.go @@ -0,0 +1,19 @@ +package keeper + +import ( + "context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" +) + +var _ types.QueryServer = Keeper{} + +// Params implements the Query/Params gRPC method +func (q Keeper) Params(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + params := q.GetParams(ctx) + + return &types.QueryParamsResponse{ + Params: ¶ms, + }, nil +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go b/modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go new file mode 100644 index 00000000000..03aa63474a2 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go @@ -0,0 +1,14 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" +) + +func (suite *KeeperTestSuite) TestQueryParams() { + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + expParams := types.DefaultParams() + res, _ := suite.chainA.GetSimApp().ICAControllerKeeper.Params(ctx, &types.QueryParamsRequest{}) + suite.Require().Equal(&expParams, res.Params) +} diff --git a/modules/apps/27-interchain-accounts/controller/types/query.pb.go b/modules/apps/27-interchain-accounts/controller/types/query.pb.go new file mode 100644 index 00000000000..659605862e9 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/types/query.pb.go @@ -0,0 +1,547 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/interchain_accounts/controller/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryParamsRequest is the request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_df0d8b259d72854e, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is the response type for the Query/Params RPC method. +type QueryParamsResponse struct { + // params defines the parameters of the module. + Params *Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_df0d8b259d72854e, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() *Params { + if m != nil { + return m.Params + } + return nil +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "ibc.applications.interchain_accounts.controller.v1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "ibc.applications.interchain_accounts.controller.v1.QueryParamsResponse") +} + +func init() { + proto.RegisterFile("ibc/applications/interchain_accounts/controller/v1/query.proto", fileDescriptor_df0d8b259d72854e) +} + +var fileDescriptor_df0d8b259d72854e = []byte{ + // 326 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x91, 0x31, 0x4b, 0x3b, 0x31, + 0x18, 0xc6, 0x9b, 0x3f, 0xfc, 0x3b, 0x9c, 0xdb, 0xd9, 0x41, 0x8a, 0x1c, 0xd2, 0xc9, 0xa5, 0x79, + 0xe9, 0x29, 0x08, 0x1d, 0x1c, 0x14, 0x74, 0xad, 0x1d, 0x5d, 0x24, 0x17, 0x43, 0x1a, 0xb9, 0xcb, + 0x9b, 0x26, 0xb9, 0x42, 0x57, 0x3f, 0x81, 0xe0, 0x97, 0x72, 0x2c, 0x88, 0xe0, 0xa6, 0xb4, 0x7e, + 0x10, 0xe9, 0xe5, 0xa0, 0x15, 0x3b, 0x68, 0xdd, 0x42, 0x5e, 0x9e, 0xdf, 0xf3, 0x3c, 0x3c, 0xd1, + 0xa9, 0xca, 0x38, 0x30, 0x63, 0x72, 0xc5, 0x99, 0x57, 0xa8, 0x1d, 0x28, 0xed, 0x85, 0xe5, 0x23, + 0xa6, 0xf4, 0x0d, 0xe3, 0x1c, 0x4b, 0xed, 0x1d, 0x70, 0xd4, 0xde, 0x62, 0x9e, 0x0b, 0x0b, 0x93, + 0x1e, 0x8c, 0x4b, 0x61, 0xa7, 0xd4, 0x58, 0xf4, 0x18, 0xa7, 0x2a, 0xe3, 0x74, 0x5d, 0x4f, 0x37, + 0xe8, 0xe9, 0x4a, 0x4f, 0x27, 0xbd, 0x76, 0x4b, 0xa2, 0xc4, 0x4a, 0x0e, 0xcb, 0x57, 0x20, 0xb5, + 0xcf, 0xb7, 0x48, 0xb2, 0xc6, 0x0d, 0x90, 0x7d, 0x89, 0x28, 0x73, 0x01, 0xcc, 0x28, 0x60, 0x5a, + 0xa3, 0xaf, 0x43, 0x55, 0xd7, 0x4e, 0x2b, 0x8a, 0xaf, 0x96, 0xd9, 0x07, 0xcc, 0xb2, 0xc2, 0x0d, + 0xc5, 0xb8, 0x14, 0xce, 0x77, 0x54, 0xb4, 0xfb, 0xe5, 0xd7, 0x19, 0xd4, 0x4e, 0xc4, 0xc3, 0xa8, + 0x69, 0xaa, 0x9f, 0x3d, 0x72, 0x40, 0x0e, 0x77, 0xd2, 0x3e, 0xfd, 0x7d, 0x55, 0x5a, 0x33, 0x6b, + 0x52, 0xfa, 0x46, 0xa2, 0xff, 0x95, 0x57, 0xfc, 0x42, 0xa2, 0x66, 0x38, 0xc6, 0x17, 0xdb, 0x80, + 0xbf, 0xf7, 0x68, 0x5f, 0xfe, 0x99, 0x13, 0x9a, 0x77, 0xfa, 0xf7, 0xcf, 0x1f, 0x8f, 0xff, 0x8e, + 0xe3, 0x14, 0xea, 0x49, 0x7e, 0x32, 0x45, 0x68, 0x78, 0x76, 0xf7, 0x34, 0x4f, 0xc8, 0x6c, 0x9e, + 0x90, 0xf7, 0x79, 0x42, 0x1e, 0x16, 0x49, 0x63, 0xb6, 0x48, 0x1a, 0xaf, 0x8b, 0xa4, 0x71, 0x3d, + 0x90, 0xca, 0x8f, 0xca, 0x8c, 0x72, 0x2c, 0x80, 0xa3, 0x2b, 0xd0, 0x2d, 0xf1, 0x5d, 0x89, 0x30, + 0x49, 0xa1, 0xc0, 0xdb, 0x32, 0x17, 0x2e, 0x98, 0xa5, 0x27, 0xdd, 0x95, 0x5f, 0x77, 0x93, 0x9f, + 0x9f, 0x1a, 0xe1, 0xb2, 0x66, 0xb5, 0xea, 0xd1, 0x67, 0x00, 0x00, 0x00, 0xff, 0xff, 0xef, 0xec, + 0xb6, 0x2f, 0xc4, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Params queries all parameters of the ICA controller submodule. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.interchain_accounts.controller.v1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Params queries all parameters of the ICA controller submodule. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.interchain_accounts.controller.v1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ibc.applications.interchain_accounts.controller.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ibc/applications/interchain_accounts/controller/v1/query.proto", +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Params != nil { + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Params != nil { + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Params == nil { + m.Params = &Params{} + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/27-interchain-accounts/controller/types/query.pb.gw.go b/modules/apps/27-interchain-accounts/controller/types/query.pb.gw.go new file mode 100644 index 00000000000..a9ac1bc03bb --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/types/query.pb.gw.go @@ -0,0 +1,148 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: ibc/applications/interchain_accounts/controller/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"ibc", "apps", "interchain_accounts", "controller", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage +) diff --git a/modules/apps/27-interchain-accounts/host/keeper/grpc_query.go b/modules/apps/27-interchain-accounts/host/keeper/grpc_query.go new file mode 100644 index 00000000000..5cb4b569b00 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/keeper/grpc_query.go @@ -0,0 +1,19 @@ +package keeper + +import ( + "context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" +) + +var _ types.QueryServer = Keeper{} + +// Params implements the Query/Params gRPC method +func (q Keeper) Params(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + params := q.GetParams(ctx) + + return &types.QueryParamsResponse{ + Params: ¶ms, + }, nil +} diff --git a/modules/apps/27-interchain-accounts/host/keeper/grpc_query_test.go b/modules/apps/27-interchain-accounts/host/keeper/grpc_query_test.go new file mode 100644 index 00000000000..123679f7b86 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/keeper/grpc_query_test.go @@ -0,0 +1,14 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" +) + +func (suite *KeeperTestSuite) TestQueryParams() { + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + expParams := types.DefaultParams() + res, _ := suite.chainA.GetSimApp().ICAHostKeeper.Params(ctx, &types.QueryParamsRequest{}) + suite.Require().Equal(&expParams, res.Params) +} diff --git a/modules/apps/27-interchain-accounts/host/types/query.pb.go b/modules/apps/27-interchain-accounts/host/types/query.pb.go new file mode 100644 index 00000000000..5f8f55bf816 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/types/query.pb.go @@ -0,0 +1,547 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/interchain_accounts/host/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryParamsRequest is the request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_e6b7e23fc90c353a, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is the response type for the Query/Params RPC method. +type QueryParamsResponse struct { + // params defines the parameters of the module. + Params *Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_e6b7e23fc90c353a, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() *Params { + if m != nil { + return m.Params + } + return nil +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "ibc.applications.interchain_accounts.host.v1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "ibc.applications.interchain_accounts.host.v1.QueryParamsResponse") +} + +func init() { + proto.RegisterFile("ibc/applications/interchain_accounts/host/v1/query.proto", fileDescriptor_e6b7e23fc90c353a) +} + +var fileDescriptor_e6b7e23fc90c353a = []byte{ + // 322 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x91, 0x31, 0x4b, 0x3b, 0x31, + 0x18, 0xc6, 0x9b, 0x3f, 0xfc, 0x3b, 0x9c, 0xdb, 0xd9, 0x41, 0x8a, 0x04, 0xe9, 0xe4, 0xd0, 0xe6, + 0xa5, 0x67, 0xa1, 0x8e, 0xea, 0x28, 0x0e, 0xea, 0xe8, 0x22, 0xb9, 0x34, 0xa4, 0x81, 0x5e, 0xde, + 0xf4, 0x92, 0x2b, 0x74, 0xf5, 0x13, 0x08, 0x7e, 0x24, 0x17, 0x17, 0xa1, 0xe0, 0xe2, 0x28, 0xad, + 0x1f, 0x44, 0x2e, 0x77, 0xa0, 0x45, 0x11, 0x0e, 0xb7, 0x97, 0x37, 0x3c, 0xbf, 0xe7, 0x79, 0xde, + 0x44, 0xc7, 0x3a, 0x15, 0xc0, 0xad, 0x9d, 0x69, 0xc1, 0xbd, 0x46, 0xe3, 0x40, 0x1b, 0x2f, 0x73, + 0x31, 0xe5, 0xda, 0xdc, 0x72, 0x21, 0xb0, 0x30, 0xde, 0xc1, 0x14, 0x9d, 0x87, 0xc5, 0x10, 0xe6, + 0x85, 0xcc, 0x97, 0xcc, 0xe6, 0xe8, 0x31, 0xee, 0xeb, 0x54, 0xb0, 0xaf, 0x4a, 0xf6, 0x83, 0x92, + 0x95, 0x4a, 0xb6, 0x18, 0x76, 0xf7, 0x15, 0xa2, 0x9a, 0x49, 0xe0, 0x56, 0x03, 0x37, 0x06, 0x7d, + 0xad, 0x09, 0xac, 0x6e, 0x47, 0xa1, 0xc2, 0x30, 0x42, 0x39, 0xd5, 0xdb, 0x71, 0xa3, 0x6c, 0xc1, + 0x29, 0x08, 0x7b, 0x9d, 0x28, 0xbe, 0x2a, 0x93, 0x5e, 0xf2, 0x9c, 0x67, 0xee, 0x5a, 0xce, 0x0b, + 0xe9, 0x7c, 0x4f, 0x44, 0xbb, 0x5b, 0x5b, 0x67, 0xd1, 0x38, 0x19, 0x5f, 0x44, 0x6d, 0x1b, 0x36, + 0x7b, 0xe4, 0x80, 0x1c, 0xee, 0x24, 0x23, 0xd6, 0xa4, 0x18, 0xab, 0x69, 0x35, 0x23, 0x79, 0x26, + 0xd1, 0xff, 0xe0, 0x12, 0x3f, 0x92, 0xa8, 0x5d, 0x3d, 0xc6, 0x27, 0xcd, 0x90, 0xdf, 0xb3, 0x77, + 0x4f, 0xff, 0x40, 0xa8, 0x7a, 0xf6, 0x46, 0x77, 0x2f, 0xef, 0x0f, 0xff, 0x58, 0xdc, 0x87, 0xfa, + 0xac, 0xbf, 0x9f, 0xb3, 0xea, 0x73, 0x36, 0x79, 0x5a, 0x53, 0xb2, 0x5a, 0x53, 0xf2, 0xb6, 0xa6, + 0xe4, 0x7e, 0x43, 0x5b, 0xab, 0x0d, 0x6d, 0xbd, 0x6e, 0x68, 0xeb, 0xe6, 0x5c, 0x69, 0x3f, 0x2d, + 0x52, 0x26, 0x30, 0x03, 0x81, 0x2e, 0x43, 0x57, 0x82, 0x07, 0x0a, 0x61, 0x91, 0x40, 0x86, 0x93, + 0x62, 0x26, 0x5d, 0x65, 0x93, 0x8c, 0x07, 0x9f, 0x4e, 0x83, 0x6d, 0x27, 0xbf, 0xb4, 0xd2, 0xa5, + 0xed, 0xf0, 0x6f, 0x47, 0x1f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x60, 0xf9, 0x1a, 0x0c, 0x8e, 0x02, + 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Params queries all parameters of the ICA host submodule. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.interchain_accounts.host.v1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Params queries all parameters of the ICA host submodule. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.interchain_accounts.host.v1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ibc.applications.interchain_accounts.host.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ibc/applications/interchain_accounts/host/v1/query.proto", +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Params != nil { + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Params != nil { + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Params == nil { + m.Params = &Params{} + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/27-interchain-accounts/host/types/query.pb.gw.go b/modules/apps/27-interchain-accounts/host/types/query.pb.gw.go new file mode 100644 index 00000000000..fbf8503339f --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/types/query.pb.gw.go @@ -0,0 +1,148 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: ibc/applications/interchain_accounts/host/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"ibc", "apps", "interchain_accounts", "host", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage +) diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 954bd5ec497..15984690ef1 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -1,6 +1,7 @@ package ica import ( + "context" "encoding/json" "fmt" @@ -17,8 +18,10 @@ import ( "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller" controllerkeeper "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/keeper" + controllertypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host" hostkeeper "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/keeper" + hosttypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" ) @@ -71,6 +74,8 @@ func (AppModuleBasic) RegisterRESTRoutes(ctx client.Context, rtr *mux.Router) { // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the interchain accounts module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + controllertypes.RegisterQueryHandlerClient(context.Background(), mux, controllertypes.NewQueryClient(clientCtx)) + hosttypes.RegisterQueryHandlerClient(context.Background(), mux, hosttypes.NewQueryClient(clientCtx)) } // GetTxCmd implements AppModuleBasic interface diff --git a/proto/ibc/applications/interchain_accounts/controller/v1/query.proto b/proto/ibc/applications/interchain_accounts/controller/v1/query.proto new file mode 100644 index 00000000000..d6e25f8a252 --- /dev/null +++ b/proto/ibc/applications/interchain_accounts/controller/v1/query.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.controller.v1; + +option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types"; + +import "gogoproto/gogo.proto"; +import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; +import "google/api/annotations.proto"; + +// Query provides defines the gRPC querier service. +service Query { + // Params queries all parameters of the ICA controller submodule. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/ibc/apps/interchain_accounts/controller/v1/params"; + } +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params defines the parameters of the module. + Params params = 1; +} + diff --git a/proto/ibc/applications/interchain_accounts/host/v1/query.proto b/proto/ibc/applications/interchain_accounts/host/v1/query.proto new file mode 100644 index 00000000000..4802b724af9 --- /dev/null +++ b/proto/ibc/applications/interchain_accounts/host/v1/query.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.host.v1; + +option go_package = "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types"; + +import "google/api/annotations.proto"; +import "gogoproto/gogo.proto"; +import "ibc/applications/interchain_accounts/host/v1/host.proto"; + +// Query provides defines the gRPC querier service. +service Query { + // Params queries all parameters of the ICA host submodule. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/ibc/apps/interchain_accounts/host/v1/params"; + } +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params defines the parameters of the module. + Params params = 1; +} + From eac5aded907b8ef964f86c9aa2ae53736e502b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 1 Dec 2021 12:18:16 +0100 Subject: [PATCH 62/66] modify ica portid to be interchain-account instead of ibcaccount (#577) --- modules/apps/27-interchain-accounts/types/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/27-interchain-accounts/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go index d4df0db4c93..3f535a01489 100644 --- a/modules/apps/27-interchain-accounts/types/keys.go +++ b/modules/apps/27-interchain-accounts/types/keys.go @@ -12,7 +12,7 @@ const ( VersionPrefix = "ics27-1" // PortID is the default port id that the interchain accounts module binds to - PortID = "ibcaccount" + PortID = "interchain-account" // StoreKey is the store key string for interchain accounts StoreKey = ModuleName From 4fed4a76e6955ecaa3360457b42f739d38986888 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 1 Dec 2021 13:01:42 +0100 Subject: [PATCH 63/66] feat: allowlist host param using msg typeURLs (#576) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add ica params Add new Params type to ICA. A single test is added to check defaults and validation. Usage within the ICA keepers is still needed * regenerate params proto into host and controller submodules * split params implementation into host/controller * add keeper params logic * Apply suggestions from code review Co-authored-by: Damian Nolan * add host genesis init/export params test case * updating host proto params to include msg allowlist * adding surrounds for new allowlist host param * enforcing msg is present in allowlist in AuthenticateTx, updating tests * regenerating protos post merge conflict * applying suggestinons from review * adding strings.Trimspace as suggested Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> --- .../host/ibc_module_test.go | 9 +- .../host/keeper/genesis_test.go | 2 +- .../host/keeper/params.go | 9 +- .../host/keeper/params_test.go | 1 + .../host/keeper/relay.go | 6 ++ .../host/keeper/relay_test.go | 49 ++++++++++ .../host/types/host.pb.go | 95 +++++++++++++++---- .../27-interchain-accounts/host/types/keys.go | 15 +++ .../host/types/params.go | 30 +++++- .../host/types/params_test.go | 2 +- .../controller/v1/controller.proto | 2 +- .../interchain_accounts/host/v1/host.proto | 4 +- .../interchain_accounts/v1/genesis.proto | 6 +- .../interchain_accounts/v1/types.proto | 1 - 14 files changed, 198 insertions(+), 33 deletions(-) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 2a75c71ce0e..823ae74b8ad 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -139,7 +139,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { }, { "host submodule disabled", func() { - suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(false)) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(false, []string{})) }, false, }, { @@ -260,7 +260,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { }, { "host submodule disabled", func() { - suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(false)) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(false, []string{})) }, false, }, { @@ -399,7 +399,7 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { }, { "host submodule disabled", func() { - suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(false)) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(false, []string{})) }, false, }, { @@ -452,6 +452,9 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { } packetData = icaPacketData.GetBytes() + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) + // malleate packetData for test cases tc.malleate() diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go index 7dba9ea121a..ba1e7e252c4 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go @@ -36,7 +36,7 @@ func (suite *KeeperTestSuite) TestInitGenesis() { suite.Require().True(found) suite.Require().Equal(TestAccAddress.String(), accountAdrr) - expParams := types.NewParams(false) + expParams := types.NewParams(false, nil) params := suite.chainA.GetSimApp().ICAHostKeeper.GetParams(suite.chainA.GetContext()) suite.Require().Equal(expParams, params) } diff --git a/modules/apps/27-interchain-accounts/host/keeper/params.go b/modules/apps/27-interchain-accounts/host/keeper/params.go index 7b91c1bf110..b126dd6bd8a 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/params.go +++ b/modules/apps/27-interchain-accounts/host/keeper/params.go @@ -14,9 +14,16 @@ func (k Keeper) IsHostEnabled(ctx sdk.Context) bool { return res } +// GetAllowMessages retrieves the host enabled msg types from the paramstore +func (k Keeper) GetAllowMessages(ctx sdk.Context) []string { + var res []string + k.paramSpace.Get(ctx, types.KeyAllowMessages, &res) + return res +} + // GetParams returns the total set of the host submodule parameters. func (k Keeper) GetParams(ctx sdk.Context) types.Params { - return types.NewParams(k.IsHostEnabled(ctx)) + return types.NewParams(k.IsHostEnabled(ctx), k.GetAllowMessages(ctx)) } // SetParams sets the total set of the host submodule parameters. diff --git a/modules/apps/27-interchain-accounts/host/keeper/params_test.go b/modules/apps/27-interchain-accounts/host/keeper/params_test.go index 9f8e53068ae..ff4d6d55868 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/params_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/params_test.go @@ -9,6 +9,7 @@ func (suite *KeeperTestSuite) TestParams() { suite.Require().Equal(expParams, params) expParams.HostEnabled = false + expParams.AllowMessages = []string{"/cosmos.staking.v1beta1.MsgDelegate"} suite.chainA.GetSimApp().ICAHostKeeper.SetParams(suite.chainA.GetContext(), expParams) params = suite.chainA.GetSimApp().ICAHostKeeper.GetParams(suite.chainA.GetContext()) suite.Require().Equal(expParams, params) diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay.go b/modules/apps/27-interchain-accounts/host/keeper/relay.go index dc53cdc54f0..244e0d06e0c 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" ) @@ -16,7 +17,12 @@ func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portID string) e return sdkerrors.Wrapf(icatypes.ErrInterchainAccountNotFound, "failed to retrieve interchain account on port %s", portID) } + allowMsgs := k.GetAllowMessages(ctx) for _, msg := range msgs { + if !types.ContainsMsgType(allowMsgs, msg) { + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "message type not allowed: %s", sdk.MsgTypeURL(msg)) + } + for _, signer := range msg.GetSigners() { if interchainAccountAddr != signer.String() { return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "unexpected signer address: expected %s, got %s", interchainAccountAddr, signer.String()) diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index cdfba6956b1..d77e0735bbd 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -10,6 +10,7 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types" transfertypes "github.com/cosmos/ibc-go/v2/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" @@ -49,6 +50,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { } packetData = icaPacketData.GetBytes() + + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) }, true, }, @@ -74,6 +78,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { } packetData = icaPacketData.GetBytes() + + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) }, true, }, @@ -105,6 +112,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { } packetData = icaPacketData.GetBytes() + + params := types.NewParams(true, []string{sdk.MsgTypeURL(msgDelegate), sdk.MsgTypeURL(msgUndelegate)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) }, true, }, @@ -137,6 +147,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { } packetData = icaPacketData.GetBytes() + + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) }, true, }, @@ -173,6 +186,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { } packetData = icaPacketData.GetBytes() + + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) }, true, }, @@ -196,6 +212,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { } packetData = icaPacketData.GetBytes() + + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) }, true, }, @@ -219,6 +238,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { } packetData = icaPacketData.GetBytes() + + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) }, true, }, @@ -253,6 +275,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { } packetData = icaPacketData.GetBytes() + + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) }, true, }, @@ -309,6 +334,27 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { }, false, }, + { + "unauthorised: message type not allowed", // NOTE: do not update params to explicitly force the error + func() { + msg := &banktypes.MsgSend{ + FromAddress: suite.chainB.SenderAccount.GetAddress().String(), + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + } + + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + suite.Require().NoError(err) + + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + + packetData = icaPacketData.GetBytes() + }, + false, + }, { "unauthorised: signer address is not the interchain account associated with the controller portID", func() { @@ -327,6 +373,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { } packetData = icaPacketData.GetBytes() + + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) }, false, }, diff --git a/modules/apps/27-interchain-accounts/host/types/host.pb.go b/modules/apps/27-interchain-accounts/host/types/host.pb.go index f926909215b..8ad1c15c24b 100644 --- a/modules/apps/27-interchain-accounts/host/types/host.pb.go +++ b/modules/apps/27-interchain-accounts/host/types/host.pb.go @@ -29,6 +29,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Params struct { // host_enabled enables or disables the host submodule. HostEnabled bool `protobuf:"varint,1,opt,name=host_enabled,json=hostEnabled,proto3" json:"host_enabled,omitempty" yaml:"host_enabled"` + // allow_messages defines a list of sdk message typeURLs allowed to be executed on a host chain. + AllowMessages []string `protobuf:"bytes,2,rep,name=allow_messages,json=allowMessages,proto3" json:"allow_messages,omitempty" yaml:"allow_messages"` } func (m *Params) Reset() { *m = Params{} } @@ -71,6 +73,13 @@ func (m *Params) GetHostEnabled() bool { return false } +func (m *Params) GetAllowMessages() []string { + if m != nil { + return m.AllowMessages + } + return nil +} + func init() { proto.RegisterType((*Params)(nil), "ibc.applications.interchain_accounts.host.v1.Params") } @@ -80,24 +89,27 @@ func init() { } var fileDescriptor_48e202774f13d08e = []byte{ - // 264 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xb1, 0x4e, 0xc3, 0x30, - 0x10, 0x86, 0x93, 0xa5, 0x42, 0x81, 0xa9, 0x20, 0x01, 0x1d, 0x0c, 0xca, 0xc4, 0x40, 0x72, 0x6a, - 0x19, 0x2a, 0x75, 0xac, 0x60, 0x61, 0x42, 0x8c, 0x2c, 0x95, 0xed, 0x18, 0xc7, 0x92, 0xed, 0x8b, - 0x62, 0x27, 0x52, 0xde, 0x82, 0xc7, 0x62, 0xec, 0xc8, 0x84, 0x50, 0xf2, 0x06, 0x3c, 0x01, 0x8a, - 0x33, 0x50, 0x24, 0x26, 0xff, 0xbf, 0x4f, 0xdf, 0xaf, 0xbb, 0x3f, 0x59, 0x2b, 0xc6, 0x81, 0x56, - 0x95, 0x56, 0x9c, 0x7a, 0x85, 0xd6, 0x81, 0xb2, 0x5e, 0xd4, 0xbc, 0xa4, 0xca, 0xee, 0x28, 0xe7, - 0xd8, 0x58, 0xef, 0xa0, 0x44, 0xe7, 0xa1, 0x5d, 0x86, 0x37, 0xaf, 0x6a, 0xf4, 0x38, 0xbf, 0x55, - 0x8c, 0xe7, 0x87, 0x60, 0xfe, 0x0f, 0x98, 0x07, 0xa0, 0x5d, 0x2e, 0x2e, 0x25, 0xa2, 0xd4, 0x02, - 0x02, 0xcb, 0x9a, 0x57, 0xa0, 0xb6, 0x9b, 0x82, 0x16, 0x67, 0x12, 0x25, 0x06, 0x09, 0xa3, 0x9a, - 0x7e, 0xd3, 0xfb, 0x64, 0xf6, 0x44, 0x6b, 0x6a, 0xdc, 0x7c, 0x93, 0x9c, 0x8c, 0x29, 0x3b, 0x61, - 0x29, 0xd3, 0xa2, 0xb8, 0x88, 0xaf, 0xe3, 0x9b, 0xa3, 0xed, 0xf9, 0xf7, 0xe7, 0xd5, 0x69, 0x47, - 0x8d, 0xde, 0xa4, 0x87, 0xd3, 0xf4, 0xf9, 0x78, 0xb4, 0x0f, 0x93, 0xdb, 0x16, 0xef, 0x3d, 0x89, - 0xf7, 0x3d, 0x89, 0xbf, 0x7a, 0x12, 0xbf, 0x0d, 0x24, 0xda, 0x0f, 0x24, 0xfa, 0x18, 0x48, 0xf4, - 0xf2, 0x28, 0x95, 0x2f, 0x1b, 0x96, 0x73, 0x34, 0xc0, 0xd1, 0x19, 0x74, 0xa0, 0x18, 0xcf, 0x24, - 0x42, 0xbb, 0x02, 0x83, 0x45, 0xa3, 0x85, 0x1b, 0x7b, 0x71, 0xb0, 0x5a, 0x67, 0xbf, 0x97, 0x65, - 0x7f, 0x2b, 0xf1, 0x5d, 0x25, 0x1c, 0x9b, 0x85, 0x95, 0xef, 0x7e, 0x02, 0x00, 0x00, 0xff, 0xff, - 0x78, 0x3c, 0xa0, 0x19, 0x4c, 0x01, 0x00, 0x00, + // 306 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xbf, 0x6a, 0x32, 0x41, + 0x14, 0xc5, 0xdd, 0xef, 0x03, 0x49, 0x36, 0x7f, 0x0a, 0x93, 0x10, 0xb5, 0x58, 0x65, 0x2b, 0x8b, + 0xb8, 0x17, 0x4d, 0x21, 0x58, 0x05, 0x21, 0x4d, 0x20, 0x10, 0x2c, 0xd3, 0xc8, 0xcc, 0x38, 0x19, + 0x07, 0x66, 0xe7, 0x2e, 0xde, 0x59, 0x83, 0x2f, 0x90, 0x3a, 0x8f, 0x95, 0xd2, 0x32, 0x95, 0x04, + 0x7d, 0x03, 0x9f, 0x20, 0xec, 0x6c, 0x20, 0x0a, 0xa9, 0xe6, 0x9e, 0x73, 0xf8, 0x1d, 0x98, 0x13, + 0x0e, 0x34, 0x17, 0xc0, 0xb2, 0xcc, 0x68, 0xc1, 0x9c, 0x46, 0x4b, 0xa0, 0xad, 0x93, 0x73, 0x31, + 0x63, 0xda, 0x4e, 0x98, 0x10, 0x98, 0x5b, 0x47, 0x30, 0x43, 0x72, 0xb0, 0xe8, 0xf9, 0x37, 0xc9, + 0xe6, 0xe8, 0xb0, 0x76, 0xa3, 0xb9, 0x48, 0xf6, 0xc1, 0xe4, 0x0f, 0x30, 0xf1, 0xc0, 0xa2, 0xd7, + 0x6c, 0x28, 0x44, 0x65, 0x24, 0x78, 0x96, 0xe7, 0x2f, 0xc0, 0xec, 0xb2, 0x2c, 0x6a, 0x5e, 0x2a, + 0x54, 0xe8, 0x4f, 0x28, 0xae, 0xd2, 0x8d, 0xdf, 0x82, 0xb0, 0xfa, 0xc4, 0xe6, 0x2c, 0xa5, 0xda, + 0x30, 0x3c, 0x2d, 0x6a, 0x26, 0xd2, 0x32, 0x6e, 0xe4, 0xb4, 0x1e, 0xb4, 0x83, 0xce, 0xd1, 0xe8, + 0x7a, 0xb7, 0x6e, 0x5d, 0x2c, 0x59, 0x6a, 0x86, 0xf1, 0x7e, 0x1a, 0x8f, 0x4f, 0x0a, 0x79, 0x5f, + 0xaa, 0xda, 0x5d, 0x78, 0xce, 0x8c, 0xc1, 0xd7, 0x49, 0x2a, 0x89, 0x98, 0x92, 0x54, 0xff, 0xd7, + 0xfe, 0xdf, 0x39, 0x1e, 0x35, 0x76, 0xeb, 0xd6, 0x55, 0x49, 0x1f, 0xe6, 0xf1, 0xf8, 0xcc, 0x1b, + 0x8f, 0x3f, 0x7a, 0x34, 0xfd, 0xd8, 0x44, 0xc1, 0x6a, 0x13, 0x05, 0x5f, 0x9b, 0x28, 0x78, 0xdf, + 0x46, 0x95, 0xd5, 0x36, 0xaa, 0x7c, 0x6e, 0xa3, 0xca, 0xf3, 0x83, 0xd2, 0x6e, 0x96, 0xf3, 0x44, + 0x60, 0x0a, 0x02, 0x29, 0x45, 0x02, 0xcd, 0x45, 0x57, 0x21, 0x2c, 0xfa, 0x90, 0xe2, 0x34, 0x37, + 0x92, 0x8a, 0x69, 0x09, 0xfa, 0x83, 0xee, 0xef, 0x38, 0xdd, 0xc3, 0x55, 0xdd, 0x32, 0x93, 0xc4, + 0xab, 0xfe, 0xd7, 0xb7, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x6b, 0x0d, 0x8d, 0xb8, 0x8f, 0x01, + 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -120,6 +132,15 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.AllowMessages) > 0 { + for iNdEx := len(m.AllowMessages) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.AllowMessages[iNdEx]) + copy(dAtA[i:], m.AllowMessages[iNdEx]) + i = encodeVarintHost(dAtA, i, uint64(len(m.AllowMessages[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } if m.HostEnabled { i-- if m.HostEnabled { @@ -153,6 +174,12 @@ func (m *Params) Size() (n int) { if m.HostEnabled { n += 2 } + if len(m.AllowMessages) > 0 { + for _, s := range m.AllowMessages { + l = len(s) + n += 1 + l + sovHost(uint64(l)) + } + } return n } @@ -211,6 +238,38 @@ func (m *Params) Unmarshal(dAtA []byte) error { } } m.HostEnabled = bool(v != 0) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowMessages", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHost + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthHost + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHost + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AllowMessages = append(m.AllowMessages, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipHost(dAtA[iNdEx:]) diff --git a/modules/apps/27-interchain-accounts/host/types/keys.go b/modules/apps/27-interchain-accounts/host/types/keys.go index 284284980e4..2e0a1081c10 100644 --- a/modules/apps/27-interchain-accounts/host/types/keys.go +++ b/modules/apps/27-interchain-accounts/host/types/keys.go @@ -1,5 +1,9 @@ package types +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + const ( // ModuleName defines the interchain accounts host module name ModuleName = "icahost" @@ -7,3 +11,14 @@ const ( // StoreKey is the store key string for the interchain accounts host module StoreKey = ModuleName ) + +// ContainsMsgType returns true if the sdk.Msg TypeURL is present in allowMsgs, otherwise false +func ContainsMsgType(allowMsgs []string, msg sdk.Msg) bool { + for _, v := range allowMsgs { + if v == sdk.MsgTypeURL(msg) { + return true + } + } + + return false +} diff --git a/modules/apps/27-interchain-accounts/host/types/params.go b/modules/apps/27-interchain-accounts/host/types/params.go index 589de75fc23..480de05c286 100644 --- a/modules/apps/27-interchain-accounts/host/types/params.go +++ b/modules/apps/27-interchain-accounts/host/types/params.go @@ -2,6 +2,7 @@ package types import ( "fmt" + "strings" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) @@ -14,6 +15,8 @@ const ( var ( // KeyHostEnabled is the store key for HostEnabled Params KeyHostEnabled = []byte("HostEnabled") + // KeyAllowMessages is the store key for the AllowMessages Params + KeyAllowMessages = []byte("AllowMessages") ) // ParamKeyTable type declaration for parameters @@ -22,15 +25,16 @@ func ParamKeyTable() paramtypes.KeyTable { } // NewParams creates a new parameter configuration for the host submodule -func NewParams(enableHost bool) Params { +func NewParams(enableHost bool, allowMsgs []string) Params { return Params{ - HostEnabled: enableHost, + HostEnabled: enableHost, + AllowMessages: allowMsgs, } } // DefaultParams is the default parameter configuration for the host submodule func DefaultParams() Params { - return NewParams(DefaultHostEnabled) + return NewParams(DefaultHostEnabled, nil) } // Validate validates all host submodule parameters @@ -39,6 +43,10 @@ func (p Params) Validate() error { return err } + if err := validateAllowlist(p.AllowMessages); err != nil { + return err + } + return nil } @@ -46,6 +54,7 @@ func (p Params) Validate() error { func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { return paramtypes.ParamSetPairs{ paramtypes.NewParamSetPair(KeyHostEnabled, p.HostEnabled, validateEnabled), + paramtypes.NewParamSetPair(KeyAllowMessages, p.AllowMessages, validateAllowlist), } } @@ -57,3 +66,18 @@ func validateEnabled(i interface{}) error { return nil } + +func validateAllowlist(i interface{}) error { + allowMsgs, ok := i.([]string) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + for _, typeURL := range allowMsgs { + if strings.TrimSpace(typeURL) == "" { + return fmt.Errorf("parameter must not contain empty strings: %s", allowMsgs) + } + } + + return nil +} diff --git a/modules/apps/27-interchain-accounts/host/types/params_test.go b/modules/apps/27-interchain-accounts/host/types/params_test.go index b8a0d418bc2..75dc5ff342e 100644 --- a/modules/apps/27-interchain-accounts/host/types/params_test.go +++ b/modules/apps/27-interchain-accounts/host/types/params_test.go @@ -10,5 +10,5 @@ import ( func TestValidateParams(t *testing.T) { require.NoError(t, types.DefaultParams().Validate()) - require.NoError(t, types.NewParams(false).Validate()) + require.NoError(t, types.NewParams(false, []string{}).Validate()) } diff --git a/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto b/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto index 79430e89e7e..4689b72124e 100644 --- a/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto +++ b/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto @@ -10,6 +10,6 @@ import "gogoproto/gogo.proto"; // Params defines the set of on-chain interchain accounts parameters. // The following parameters may be used to disable the controller submodule. message Params { - // controller_enabled enables or disables the controller submodule. + // controller_enabled enables or disables the controller submodule. bool controller_enabled = 1 [(gogoproto.moretags) = "yaml:\"controller_enabled\""]; } diff --git a/proto/ibc/applications/interchain_accounts/host/v1/host.proto b/proto/ibc/applications/interchain_accounts/host/v1/host.proto index a5301199286..5798c2f95c9 100644 --- a/proto/ibc/applications/interchain_accounts/host/v1/host.proto +++ b/proto/ibc/applications/interchain_accounts/host/v1/host.proto @@ -10,6 +10,8 @@ import "gogoproto/gogo.proto"; // Params defines the set of on-chain interchain accounts parameters. // The following parameters may be used to disable the host submodule. message Params { - // host_enabled enables or disables the host submodule. + // host_enabled enables or disables the host submodule. bool host_enabled = 1 [(gogoproto.moretags) = "yaml:\"host_enabled\""]; + // allow_messages defines a list of sdk message typeURLs allowed to be executed on a host chain. + repeated string allow_messages = 2 [(gogoproto.moretags) = "yaml:\"allow_messages\""]; } diff --git a/proto/ibc/applications/interchain_accounts/v1/genesis.proto b/proto/ibc/applications/interchain_accounts/v1/genesis.proto index 7fc5cd846bd..670d05de534 100644 --- a/proto/ibc/applications/interchain_accounts/v1/genesis.proto +++ b/proto/ibc/applications/interchain_accounts/v1/genesis.proto @@ -22,7 +22,7 @@ message ControllerGenesisState { [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"active_channels\""]; repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"interchain_accounts\""]; - repeated string ports = 3; + repeated string ports = 3; ibc.applications.interchain_accounts.controller.v1.Params params = 4 [(gogoproto.nullable) = false]; } @@ -32,8 +32,8 @@ message HostGenesisState { [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"active_channels\""]; repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"interchain_accounts\""]; - string port = 3; - ibc.applications.interchain_accounts.host.v1.Params params = 4 [(gogoproto.nullable) = false]; + string port = 3; + ibc.applications.interchain_accounts.host.v1.Params params = 4 [(gogoproto.nullable) = false]; } // ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel diff --git a/proto/ibc/applications/interchain_accounts/v1/types.proto b/proto/ibc/applications/interchain_accounts/v1/types.proto index 43350212934..c6d9d0a3e96 100644 --- a/proto/ibc/applications/interchain_accounts/v1/types.proto +++ b/proto/ibc/applications/interchain_accounts/v1/types.proto @@ -29,4 +29,3 @@ message InterchainAccountPacketData { message CosmosTx { repeated google.protobuf.Any messages = 1; } - From f77f4be7b3d2b5bc951bb0dee3762eafba7958d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 1 Dec 2021 13:17:27 +0100 Subject: [PATCH 64/66] Add cli query for host and controller params (#578) * add cli query commands for host/controller params * Update modules/apps/27-interchain-accounts/client/cli/cli.go * Update modules/apps/27-interchain-accounts/controller/client/cli/query.go Co-authored-by: Damian Nolan * Update modules/apps/27-interchain-accounts/host/client/cli/query.go Co-authored-by: Damian Nolan Co-authored-by: Damian Nolan --- .../27-interchain-accounts/client/cli/cli.go | 26 +++++++++++++ .../controller/client/cli/cli.go | 21 +++++++++++ .../controller/client/cli/query.go | 37 +++++++++++++++++++ .../host/client/cli/cli.go | 21 +++++++++++ .../host/client/cli/query.go | 37 +++++++++++++++++++ modules/apps/27-interchain-accounts/module.go | 3 +- 6 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 modules/apps/27-interchain-accounts/client/cli/cli.go create mode 100644 modules/apps/27-interchain-accounts/controller/client/cli/cli.go create mode 100644 modules/apps/27-interchain-accounts/controller/client/cli/query.go create mode 100644 modules/apps/27-interchain-accounts/host/client/cli/cli.go create mode 100644 modules/apps/27-interchain-accounts/host/client/cli/query.go diff --git a/modules/apps/27-interchain-accounts/client/cli/cli.go b/modules/apps/27-interchain-accounts/client/cli/cli.go new file mode 100644 index 00000000000..25a89600be7 --- /dev/null +++ b/modules/apps/27-interchain-accounts/client/cli/cli.go @@ -0,0 +1,26 @@ +package cli + +import ( + "github.com/spf13/cobra" + + controllercli "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/client/cli" + hostcli "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/client/cli" +) + +// GetQueryCmd returns the query commands for the interchain-accounts submodule +func GetQueryCmd() *cobra.Command { + icaQueryCmd := &cobra.Command{ + Use: "interchain-accounts", + Aliases: []string{"ica"}, + Short: "interchain-accounts subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + icaQueryCmd.AddCommand( + controllercli.GetQueryCmd(), + hostcli.GetQueryCmd(), + ) + + return icaQueryCmd +} diff --git a/modules/apps/27-interchain-accounts/controller/client/cli/cli.go b/modules/apps/27-interchain-accounts/controller/client/cli/cli.go new file mode 100644 index 00000000000..0d2f54bd59b --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/client/cli/cli.go @@ -0,0 +1,21 @@ +package cli + +import ( + "github.com/spf13/cobra" +) + +// GetQueryCmd returns the query commands for the ICA controller submodule +func GetQueryCmd() *cobra.Command { + queryCmd := &cobra.Command{ + Use: "controller", + Short: "interchain-accounts controller subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + queryCmd.AddCommand( + GetCmdParams(), + ) + + return queryCmd +} diff --git a/modules/apps/27-interchain-accounts/controller/client/cli/query.go b/modules/apps/27-interchain-accounts/controller/client/cli/query.go new file mode 100644 index 00000000000..18c007ea2e9 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/client/cli/query.go @@ -0,0 +1,37 @@ +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/version" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" +) + +// GetCmdParams returns the command handler for the controller submodule parameter querying. +func GetCmdParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "Query the current interchain-accounts controller submodule parameters", + Long: "Query the current interchain-accounts controller submodule parameters", + Args: cobra.NoArgs, + Example: fmt.Sprintf("%s query interchain-accounts controller params", version.AppName), + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, _ := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) + return clientCtx.PrintProto(res.Params) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/modules/apps/27-interchain-accounts/host/client/cli/cli.go b/modules/apps/27-interchain-accounts/host/client/cli/cli.go new file mode 100644 index 00000000000..9d88f4cba21 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/client/cli/cli.go @@ -0,0 +1,21 @@ +package cli + +import ( + "github.com/spf13/cobra" +) + +// GetQueryCmd returns the query commands for the ICA host submodule +func GetQueryCmd() *cobra.Command { + queryCmd := &cobra.Command{ + Use: "host", + Short: "interchain-accounts host subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + queryCmd.AddCommand( + GetCmdParams(), + ) + + return queryCmd +} diff --git a/modules/apps/27-interchain-accounts/host/client/cli/query.go b/modules/apps/27-interchain-accounts/host/client/cli/query.go new file mode 100644 index 00000000000..822e4ec2577 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/client/cli/query.go @@ -0,0 +1,37 @@ +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/version" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/host/types" +) + +// GetCmdParams returns the command handler for the host submodule parameter querying. +func GetCmdParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "Query the current interchain-accounts host submodule parameters", + Long: "Query the current interchain-accounts host submodule parameters", + Args: cobra.NoArgs, + Example: fmt.Sprintf("%s query interchain-accounts host params", version.AppName), + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, _ := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) + return clientCtx.PrintProto(res.Params) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 15984690ef1..8691111bbb1 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -16,6 +16,7 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/runtime" abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/client/cli" "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller" controllerkeeper "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/keeper" controllertypes "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/controller/types" @@ -85,7 +86,7 @@ func (AppModuleBasic) GetTxCmd() *cobra.Command { // GetQueryCmd implements AppModuleBasic interface func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return nil + return cli.GetQueryCmd() } // AppModule is the application module for the IBC interchain accounts module From 7fc714fab5b3e9d155c7eb31a5e620018087d5c4 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 1 Dec 2021 16:46:00 +0100 Subject: [PATCH 65/66] renmaing ModuleName to SubModuleName for ica controller/host (#579) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- .../controller/types/errors.go | 2 +- .../controller/types/keys.go | 6 +++--- .../host/types/errors.go | 2 +- .../27-interchain-accounts/host/types/keys.go | 6 +++--- testing/simapp/app.go | 20 +++++++++---------- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/types/errors.go b/modules/apps/27-interchain-accounts/controller/types/errors.go index efb316097e4..3a0ade00fe1 100644 --- a/modules/apps/27-interchain-accounts/controller/types/errors.go +++ b/modules/apps/27-interchain-accounts/controller/types/errors.go @@ -6,5 +6,5 @@ import ( // ICA Controller sentinel errors var ( - ErrControllerSubModuleDisabled = sdkerrors.Register(ModuleName, 2, "controller submodule is disabled") + ErrControllerSubModuleDisabled = sdkerrors.Register(SubModuleName, 2, "controller submodule is disabled") ) diff --git a/modules/apps/27-interchain-accounts/controller/types/keys.go b/modules/apps/27-interchain-accounts/controller/types/keys.go index 1f17f79de71..238c8f603f9 100644 --- a/modules/apps/27-interchain-accounts/controller/types/keys.go +++ b/modules/apps/27-interchain-accounts/controller/types/keys.go @@ -1,9 +1,9 @@ package types const ( - // ModuleName defines the interchain accounts controller module name - ModuleName = "icacontroller" + // SubModuleName defines the interchain accounts controller module name + SubModuleName = "icacontroller" // StoreKey is the store key string for the interchain accounts controller module - StoreKey = ModuleName + StoreKey = SubModuleName ) diff --git a/modules/apps/27-interchain-accounts/host/types/errors.go b/modules/apps/27-interchain-accounts/host/types/errors.go index b188ac027c7..b16b4093e5e 100644 --- a/modules/apps/27-interchain-accounts/host/types/errors.go +++ b/modules/apps/27-interchain-accounts/host/types/errors.go @@ -6,5 +6,5 @@ import ( // ICA Host sentinel errors var ( - ErrHostSubModuleDisabled = sdkerrors.Register(ModuleName, 2, "host submodule is disabled") + ErrHostSubModuleDisabled = sdkerrors.Register(SubModuleName, 2, "host submodule is disabled") ) diff --git a/modules/apps/27-interchain-accounts/host/types/keys.go b/modules/apps/27-interchain-accounts/host/types/keys.go index 2e0a1081c10..74c93cdb605 100644 --- a/modules/apps/27-interchain-accounts/host/types/keys.go +++ b/modules/apps/27-interchain-accounts/host/types/keys.go @@ -5,11 +5,11 @@ import ( ) const ( - // ModuleName defines the interchain accounts host module name - ModuleName = "icahost" + // SubModuleName defines the interchain accounts host module name + SubModuleName = "icahost" // StoreKey is the store key string for the interchain accounts host module - StoreKey = ModuleName + StoreKey = SubModuleName ) // ContainsMsgType returns true if the sdk.Msg TypeURL is present in allowMsgs, otherwise false diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 18aba3e1ec6..d1463889779 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -274,13 +274,13 @@ func NewSimApp( app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) - scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.ModuleName) - scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.ModuleName) + scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) + scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // not replicate if you do not need to test core IBC or light clients. scopedIBCMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName) - scopedICAMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName + icacontrollertypes.ModuleName) + scopedICAMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName + icacontrollertypes.SubModuleName) // seal capability keeper after scoping modules app.CapabilityKeeper.Seal() @@ -353,14 +353,14 @@ func NewSimApp( mockIBCModule := ibcmock.NewIBCModule(&ibcmock.MockIBCApp{}, scopedIBCMockKeeper) app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.ModuleName), + appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, scopedICAControllerKeeper, app.MsgServiceRouter(), ) app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.ModuleName), + appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), ) @@ -376,9 +376,9 @@ func NewSimApp( // Create static IBC router, add app routes, then set and seal it ibcRouter := porttypes.NewRouter() - ibcRouter.AddRoute(icacontrollertypes.ModuleName, icaControllerIBCModule). - AddRoute(icahosttypes.ModuleName, icaHostIBCModule). - AddRoute(ibcmock.ModuleName+icacontrollertypes.ModuleName, icaControllerIBCModule). // ica with mock auth module stack route to ica (top level of middleware stack) + ibcRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerIBCModule). + AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). + AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerIBCModule). // ica with mock auth module stack route to ica (top level of middleware stack) AddRoute(ibctransfertypes.ModuleName, transferIBCModule). AddRoute(ibcmock.ModuleName, mockIBCModule) app.IBCKeeper.SetRouter(ibcRouter) @@ -708,8 +708,8 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(crisistypes.ModuleName) paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) - paramsKeeper.Subspace(icacontrollertypes.ModuleName) - paramsKeeper.Subspace(icahosttypes.ModuleName) + paramsKeeper.Subspace(icacontrollertypes.SubModuleName) + paramsKeeper.Subspace(icahosttypes.SubModuleName) return paramsKeeper } From 22e87deacd35f287586d1e2d529e869ce1cfa208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Fri, 3 Dec 2021 11:34:52 +0100 Subject: [PATCH 66/66] add tests/code coverage for OnRecv, OnTimeout and OnAck for controller submodule (#585) --- .../controller/ibc_module_test.go | 154 +++++++++++++++++- 1 file changed, 150 insertions(+), 4 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go index f1aa84be591..0cba3a54eae 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go @@ -462,12 +462,70 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { tc.malleate() // malleate mutates test data - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) suite.Require().NoError(err) - cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) + packet := channeltypes.NewPacket( + []byte("empty packet data"), + suite.chainB.SenderAccount.GetSequence(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + ack := cbs.OnRecvPacket(suite.chainA.GetContext(), packet, TestAccAddress) + suite.Require().Equal(tc.expPass, ack.Success()) + }) + } +} + +func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "controller submodule disabled", func() { + suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) + }, false, + }, + { + "ICA auth module callback fails", func() { + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnAcknowledgementPacket = func( + ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, + ) error { + return fmt.Errorf("mock ica auth fails") + } + }, false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.msg, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + packet := channeltypes.NewPacket( []byte("empty packet data"), suite.chainA.SenderAccount.GetSequence(), @@ -479,8 +537,96 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { 0, ) - ack := cbs.OnRecvPacket(suite.chainB.GetContext(), packet, TestAccAddress) - suite.Require().Equal(tc.expPass, ack.Success()) + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, []byte("ack"), nil) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { + var ( + path *ibctesting.Path + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "controller submodule disabled", func() { + suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) + }, false, + }, + { + "ICA auth module callback fails", func() { + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnTimeoutPacket = func( + ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, + ) error { + return fmt.Errorf("mock ica auth fails") + } + }, false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.msg, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + packet := channeltypes.NewPacket( + []byte("empty packet data"), + suite.chainA.SenderAccount.GetSequence(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, nil) + + activeChannelID, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Empty(activeChannelID) + suite.Require().False(found) + } else { + suite.Require().Error(err) + } }) } }