diff --git a/docs/docs/02-apps/02-interchain-accounts/04-integration.md b/docs/docs/02-apps/02-interchain-accounts/04-integration.md index 974e7f978df..8547c2198ef 100644 --- a/docs/docs/02-apps/02-interchain-accounts/04-integration.md +++ b/docs/docs/02-apps/02-interchain-accounts/04-integration.md @@ -82,14 +82,16 @@ scopedICAAuthKeeper := app.CapabilityKeeper.ScopeToModule(icaauthtypes.ModuleNam app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( 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.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, scopedICAControllerKeeper, app.MsgServiceRouter(), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.ICAHostKeeper = icahostkeeper.NewKeeper( appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), + app.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, app.AccountKeeper, + scopedICAHostKeeper, app.MsgServiceRouter(), app.GRPCQueryRouter(), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) // Create Interchain Accounts AppModule diff --git a/docs/docs/02-apps/02-interchain-accounts/05-messages.md b/docs/docs/02-apps/02-interchain-accounts/05-messages.md index 4e108fa1243..0fabc21e094 100644 --- a/docs/docs/02-apps/02-interchain-accounts/05-messages.md +++ b/docs/docs/02-apps/02-interchain-accounts/05-messages.md @@ -72,6 +72,31 @@ type MsgSendTxResponse struct { The packet `Sequence` is returned in the message response. +### Queries + +It is possible to use [`MsgModuleQuerySafe`](https://github.com/cosmos/ibc-go/blob/eecfa5c09a4c38a5c9f2cc2a322d2286f45911da/proto/ibc/applications/interchain_accounts/host/v1/tx.proto#L41-L51) to execute a list of queries on the host chain. This message can be included in the list of encoded `sdk.Msg`s of `InterchainPacketData`. The host chain will return on the acknowledgment the responses for all the queries. Please note that only module safe queries can be executed. The following code block shows an example of how this message can be used to query the account balance of an account on the host chain. The resulting packet data variable is used to set the `PacketData` of `MsgSendTx`. + +```go +balanceQuery := banktypes.NewQueryBalanceRequest("cosmos1...", "uatom") +queryBz, err := balanceQuery.Marshal() + +// signer of message must be the interchain account on the host +queryMsg := icahosttypes.NewMsgModuleQuerySafe("cosmos2...", []*icahosttypes.QueryRequest{ + { + Path: "/cosmos.bank.v1beta1.Query/Balance", + Data: queryBz, + }, +}) + +bz, err := icatypes.SerializeCosmosTx(cdc, []proto.Message{queryMsg}, icatypes.EncodingProtobuf) + +packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: bz, + Memo: "", +} +``` + ## Atomicity As the Interchain Accounts module supports the execution of multiple transactions using the Cosmos SDK `Msg` interface, it provides the same atomicity guarantees as Cosmos SDK-based applications, leveraging the [`CacheMultiStore`](https://docs.cosmos.network/main/learn/advanced/store#cachemultistore) architecture provided by the [`Context`](https://docs.cosmos.network/main/learn/advanced/context.html) type. diff --git a/docs/docs/05-migrations/13-v8-to-v9.md b/docs/docs/05-migrations/13-v8-to-v9.md index 1fafc4c8265..fc97b0a26c4 100644 --- a/docs/docs/05-migrations/13-v8-to-v9.md +++ b/docs/docs/05-migrations/13-v8-to-v9.md @@ -47,6 +47,21 @@ Please use the new functions `path.Setup`, `path.SetupClients`, `path.SetupConne - Functions `ConstructUpdateTMClientHeader` and `ConstructUpdateTMClientHeaderWithTrustedHeight` of `TestChain` type have been replaced with `IBCClientHeader`. This function will construct a `07-tendermint` header to update the light client on the counterparty chain. The trusted height must be passed in as a non-zero height. - `GetValsAtHeight` has been renamed to `GetTrustedValidators` +### ICS27 - Interchain Accounts + +In [#5785](https://github.com/cosmos/ibc-go/pull/5785) the list of arguments of the `NewKeeper` constructor function of the host submodule was extended with an extra argument for the gRPC query router that the submodule uses when executing a [`MsgModuleQuerySafe`](https://github.com/cosmos/ibc-go/blob/eecfa5c09a4c38a5c9f2cc2a322d2286f45911da/proto/ibc/applications/interchain_accounts/host/v1/tx.proto#L41-L51) to perform queries that are module safe: + +```diff +func NewKeeper( + cdc codec.Codec, key storetypes.StoreKey, legacySubspace icatypes.ParamSubspace, + ics4Wrapper porttypes.ICS4Wrapper, channelKeeper icatypes.ChannelKeeper, + portKeeper icatypes.PortKeeper, accountKeeper icatypes.AccountKeeper, + scopedKeeper exported.ScopedKeeper, msgRouter icatypes.MessageRouter, ++ queryRouter icatypes.QueryRouter, + authority string, +) Keeper +``` + ## Relayers - Renaming of event attribute keys in [#5603](https://github.com/cosmos/ibc-go/pull/5603). diff --git a/modules/apps/27-interchain-accounts/host/types/msgs_test.go b/modules/apps/27-interchain-accounts/host/types/msgs_test.go index b9d1d96e2bc..eb088d7c597 100644 --- a/modules/apps/27-interchain-accounts/host/types/msgs_test.go +++ b/modules/apps/27-interchain-accounts/host/types/msgs_test.go @@ -10,6 +10,7 @@ import ( ica "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -74,3 +75,75 @@ func TestMsgUpdateParamsGetSigners(t *testing.T) { } } } + +func TestMsgModuleQuerySafeValidateBasic(t *testing.T) { + queryRequest := &types.QueryRequest{ + Path: "/cosmos.bank.v1beta1.Query/Balance", + Data: []byte{}, + } + + testCases := []struct { + name string + msg *types.MsgModuleQuerySafe + expErr error + }{ + { + "success: valid signer address", + types.NewMsgModuleQuerySafe(sdk.AccAddress(ibctesting.TestAccAddress).String(), []*types.QueryRequest{queryRequest}), + nil, + }, + { + "failure: invalid signer address", + types.NewMsgModuleQuerySafe("signer", []*types.QueryRequest{queryRequest}), + ibcerrors.ErrInvalidAddress, + }, + { + "failure: empty query requests", + types.NewMsgModuleQuerySafe(sdk.AccAddress(ibctesting.TestAccAddress).String(), []*types.QueryRequest{}), + ibcerrors.ErrInvalidRequest, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + require.NoError(t, err) + } else { + require.Error(t, err) + require.ErrorIs(t, err, tc.expErr) + } + }) + } +} + +func TestMsgModuleQuerySafeGetSigners(t *testing.T) { + testCases := []struct { + name string + address sdk.AccAddress + expPass bool + }{ + {"success: valid address", sdk.AccAddress(ibctesting.TestAccAddress), true}, + {"failure: nil address", nil, false}, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + msg := types.NewMsgModuleQuerySafe(tc.address.String(), []*types.QueryRequest{}) + encodingCfg := moduletestutil.MakeTestEncodingConfig(ica.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) + if tc.expPass { + require.NoError(t, err) + require.Equal(t, tc.address.Bytes(), signers[0]) + } else { + require.Error(t, err) + } + }) + } +}