-
Notifications
You must be signed in to change notification settings - Fork 645
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: allow module safe queries in ICA (#5785)
* imp: initial modification of tx.proto * imp: ran 'make proto-all' * fix: compiler errors * imp: added query router interface * imp: added queryRouter to icahost keeper * imp: improved proto definitions * imp: ran 'make proto-all' * imp: added sdk.Msg helpers * feat: basic implementation * style: improved field names * imp: ran 'make proto-all' * fix: compiler errors * imp: ran gofumpt * feat: tests passing * feat: tests improved * test: removed unneeded code * imp: improved 'IsModuleSafe' function * imp: added IsModuleQuerySafe to msg_server * imp: added more test cases * fix: callbacks compiler * fix: non determinancy issues * fix: added query msg to codec * imp: whitelist logic added * e2e: new test added * fix: new test * fix: test * fix: e2e * fix: e2e * imp(e2e): added the QueryTxsByEvents function * fix: e2e * e2e: lint fix * fix: e2e * e2e: debug * fix: e2e * test: debug helpers * debug * test: added codec_test case * imp: additional test case * imp: added important unit test * r4r * e2e: debug * imp: added logs * fix: e2e * fix: e2e * fix: e2e * imp: added height to proto response * imp: ran 'make proto-all' * imp: added height * e2e: updated e2e to test height * imp: review suggestions * e2e: remove unneeded log * refactor: refactored 'ExtractValueFromEvents' * e2e: review item * imp: review item * nit: review item * docs: added godocs * test: unit test for mqsWhitelist added * imp: added logging * style: rename to allow list * add changelog --------- Co-authored-by: Carlos Rodriguez <[email protected]> (cherry picked from commit eecfa5c) # Conflicts: # CHANGELOG.md # e2e/testsuite/codec.go # e2e/testsuite/tx.go # modules/apps/27-interchain-accounts/host/types/msgs.go # modules/light-clients/08-wasm/testing/simapp/app.go
- Loading branch information
1 parent
92a91f2
commit 75a0dbd
Showing
21 changed files
with
2,928 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
//go:build !test_e2e | ||
|
||
package interchainaccounts | ||
|
||
import ( | ||
"context" | ||
"encoding/hex" | ||
"encoding/json" | ||
"testing" | ||
"time" | ||
|
||
"github.com/cosmos/gogoproto/proto" | ||
"github.com/strangelove-ventures/interchaintest/v8/testutil" | ||
testifysuite "github.com/stretchr/testify/suite" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" | ||
|
||
"github.com/cosmos/ibc-go/e2e/testsuite" | ||
"github.com/cosmos/ibc-go/e2e/testvalues" | ||
controllertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" | ||
icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" | ||
icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" | ||
channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" | ||
ibctesting "github.com/cosmos/ibc-go/v8/testing" | ||
) | ||
|
||
func TestInterchainAccountsQueryTestSuite(t *testing.T) { | ||
testifysuite.Run(t, new(InterchainAccountsQueryTestSuite)) | ||
} | ||
|
||
type InterchainAccountsQueryTestSuite struct { | ||
testsuite.E2ETestSuite | ||
} | ||
|
||
func (s *InterchainAccountsQueryTestSuite) TestInterchainAccountsQuery() { | ||
t := s.T() | ||
ctx := context.TODO() | ||
|
||
// setup relayers and connection-0 between two chains | ||
// channel-0 is a transfer channel but it will not be used in this test case | ||
relayer, _ := s.SetupChainsRelayerAndChannel(ctx, nil) | ||
chainA, chainB := s.GetChains() | ||
|
||
// setup 2 accounts: controller account on chain A, a second chain B account. | ||
// host account will be created when the ICA is registered | ||
controllerAccount := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) | ||
controllerAddress := controllerAccount.FormattedAddress() | ||
chainBAccount := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) | ||
var hostAccount string | ||
|
||
t.Run("broadcast MsgRegisterInterchainAccount", func(t *testing.T) { | ||
// explicitly set the version string because we don't want to use incentivized channels. | ||
version := icatypes.NewDefaultMetadataString(ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) | ||
msgRegisterAccount := controllertypes.NewMsgRegisterInterchainAccount(ibctesting.FirstConnectionID, controllerAddress, version, channeltypes.UNORDERED) | ||
|
||
txResp := s.BroadcastMessages(ctx, chainA, controllerAccount, msgRegisterAccount) | ||
s.AssertTxSuccess(txResp) | ||
}) | ||
|
||
t.Run("start relayer", func(t *testing.T) { | ||
s.StartRelayer(relayer) | ||
}) | ||
|
||
t.Run("verify interchain account", func(t *testing.T) { | ||
var err error | ||
hostAccount, err = s.QueryInterchainAccount(ctx, chainA, controllerAddress, ibctesting.FirstConnectionID) | ||
s.Require().NoError(err) | ||
s.Require().NotZero(len(hostAccount)) | ||
|
||
channels, err := relayer.GetChannels(ctx, s.GetRelayerExecReporter(), chainA.Config().ChainID) | ||
s.Require().NoError(err) | ||
s.Require().Len(channels, 2) | ||
}) | ||
|
||
t.Run("query via interchain account", func(t *testing.T) { | ||
// the host account need not be funded | ||
t.Run("broadcast query packet", func(t *testing.T) { | ||
balanceQuery := banktypes.NewQueryBalanceRequest(chainBAccount.Address(), chainB.Config().Denom) | ||
queryBz, err := balanceQuery.Marshal() | ||
s.Require().NoError(err) | ||
|
||
queryMsg := icahosttypes.NewMsgModuleQuerySafe(hostAccount, []*icahosttypes.QueryRequest{ | ||
{ | ||
Path: "/cosmos.bank.v1beta1.Query/Balance", | ||
Data: queryBz, | ||
}, | ||
}) | ||
|
||
cdc := testsuite.Codec() | ||
bz, err := icatypes.SerializeCosmosTx(cdc, []proto.Message{queryMsg}, icatypes.EncodingProtobuf) | ||
s.Require().NoError(err) | ||
|
||
packetData := icatypes.InterchainAccountPacketData{ | ||
Type: icatypes.EXECUTE_TX, | ||
Data: bz, | ||
Memo: "e2e", | ||
} | ||
|
||
icaQueryMsg := controllertypes.NewMsgSendTx(controllerAddress, ibctesting.FirstConnectionID, uint64(time.Hour.Nanoseconds()), packetData) | ||
|
||
txResp := s.BroadcastMessages(ctx, chainA, controllerAccount, icaQueryMsg) | ||
s.AssertTxSuccess(txResp) | ||
|
||
s.Require().NoError(testutil.WaitForBlocks(ctx, 10, chainA, chainB)) | ||
}) | ||
|
||
t.Run("verify query response", func(t *testing.T) { | ||
var expQueryHeight uint64 | ||
|
||
ack := &channeltypes.Acknowledgement_Result{} | ||
t.Run("retrieve acknowledgement", func(t *testing.T) { | ||
txSearchRes, err := s.QueryTxsByEvents( | ||
ctx, chainB, 1, 1, | ||
"message.action='/ibc.core.channel.v1.MsgRecvPacket'", "", | ||
) | ||
s.Require().NoError(err) | ||
s.Require().Len(txSearchRes.Txs, 1) | ||
|
||
expQueryHeight = uint64(txSearchRes.Txs[0].Height) | ||
|
||
ackHexValue, isFound := s.ExtractValueFromEvents( | ||
txSearchRes.Txs[0].Events, | ||
channeltypes.EventTypeWriteAck, | ||
channeltypes.AttributeKeyAckHex, | ||
) | ||
s.Require().True(isFound) | ||
s.Require().NotEmpty(ackHexValue) | ||
|
||
ackBz, err := hex.DecodeString(ackHexValue) | ||
s.Require().NoError(err) | ||
|
||
err = json.Unmarshal(ackBz, ack) | ||
s.Require().NoError(err) | ||
}) | ||
|
||
icaAck := &sdk.TxMsgData{} | ||
t.Run("unmarshal ica response", func(t *testing.T) { | ||
err := proto.Unmarshal(ack.Result, icaAck) | ||
s.Require().NoError(err) | ||
s.Require().Len(icaAck.GetMsgResponses(), 1) | ||
}) | ||
|
||
queryTxResp := &icahosttypes.MsgModuleQuerySafeResponse{} | ||
t.Run("unmarshal MsgModuleQuerySafeResponse", func(t *testing.T) { | ||
err := proto.Unmarshal(icaAck.MsgResponses[0].Value, queryTxResp) | ||
s.Require().NoError(err) | ||
s.Require().Len(queryTxResp.Responses, 1) | ||
s.Require().Equal(expQueryHeight, queryTxResp.Height) | ||
}) | ||
|
||
balanceResp := &banktypes.QueryBalanceResponse{} | ||
t.Run("unmarshal and verify bank query response", func(t *testing.T) { | ||
err := proto.Unmarshal(queryTxResp.Responses[0], balanceResp) | ||
s.Require().NoError(err) | ||
s.Require().Equal(chainB.Config().Denom, balanceResp.Balance.Denom) | ||
s.Require().Equal(testvalues.StartingTokenAmount, balanceResp.Balance.Amount.Int64()) | ||
}) | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package testsuite | ||
|
||
import ( | ||
"bytes" | ||
"encoding/hex" | ||
|
||
"github.com/cosmos/gogoproto/jsonpb" | ||
"github.com/cosmos/gogoproto/proto" | ||
|
||
upgradetypes "cosmossdk.io/x/upgrade/types" | ||
|
||
"github.com/cosmos/cosmos-sdk/codec" | ||
codectypes "github.com/cosmos/cosmos-sdk/codec/types" | ||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/types/module/testutil" | ||
txtypes "github.com/cosmos/cosmos-sdk/types/tx" | ||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
"github.com/cosmos/cosmos-sdk/x/authz" | ||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" | ||
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" | ||
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" | ||
grouptypes "github.com/cosmos/cosmos-sdk/x/group" | ||
proposaltypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" | ||
|
||
wasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" | ||
Check failure on line 26 in e2e/testsuite/codec.go GitHub Actions / build (arm)
Check failure on line 26 in e2e/testsuite/codec.go GitHub Actions / build (arm64)
|
||
icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" | ||
icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" | ||
feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" | ||
transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" | ||
v7migrations "github.com/cosmos/ibc-go/v8/modules/core/02-client/migrations/v7" | ||
clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" | ||
connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" | ||
channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" | ||
solomachine "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine" | ||
ibctmtypes "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" | ||
localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost" | ||
ibctesting "github.com/cosmos/ibc-go/v8/testing" | ||
simappparams "github.com/cosmos/ibc-go/v8/testing/simapp/params" | ||
) | ||
|
||
// Codec returns the global E2E protobuf codec. | ||
func Codec() *codec.ProtoCodec { | ||
cdc, _ := codecAndEncodingConfig() | ||
return cdc | ||
} | ||
|
||
// EncodingConfig returns the global E2E encoding config. | ||
func EncodingConfig() simappparams.EncodingConfig { | ||
_, cfg := codecAndEncodingConfig() | ||
return cfg | ||
} | ||
|
||
// SDKEncodingConfig returns the global E2E encoding config. | ||
func SDKEncodingConfig() *testutil.TestEncodingConfig { | ||
_, cfg := codecAndEncodingConfig() | ||
return &testutil.TestEncodingConfig{ | ||
InterfaceRegistry: cfg.InterfaceRegistry, | ||
Codec: cfg.Codec, | ||
TxConfig: cfg.TxConfig, | ||
Amino: cfg.Amino, | ||
} | ||
} | ||
|
||
func codecAndEncodingConfig() (*codec.ProtoCodec, simappparams.EncodingConfig) { | ||
cfg := simappparams.MakeTestEncodingConfig() | ||
|
||
// ibc types | ||
icacontrollertypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
icahosttypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
feetypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
solomachine.RegisterInterfaces(cfg.InterfaceRegistry) | ||
v7migrations.RegisterInterfaces(cfg.InterfaceRegistry) | ||
transfertypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
clienttypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
channeltypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
connectiontypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
ibctmtypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
localhost.RegisterInterfaces(cfg.InterfaceRegistry) | ||
wasmtypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
|
||
// all other types | ||
upgradetypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
banktypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
govv1beta1.RegisterInterfaces(cfg.InterfaceRegistry) | ||
govv1.RegisterInterfaces(cfg.InterfaceRegistry) | ||
authtypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
cryptocodec.RegisterInterfaces(cfg.InterfaceRegistry) | ||
grouptypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
proposaltypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
authz.RegisterInterfaces(cfg.InterfaceRegistry) | ||
txtypes.RegisterInterfaces(cfg.InterfaceRegistry) | ||
|
||
cdc := codec.NewProtoCodec(cfg.InterfaceRegistry) | ||
return cdc, cfg | ||
} | ||
|
||
// UnmarshalMsgResponses attempts to unmarshal the tx msg responses into the provided message types. | ||
func UnmarshalMsgResponses(txResp sdk.TxResponse, msgs ...codec.ProtoMarshaler) error { | ||
cdc := Codec() | ||
bz, err := hex.DecodeString(txResp.Data) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return ibctesting.UnmarshalMsgResponses(cdc, bz, msgs...) | ||
} | ||
|
||
// MustProtoMarshalJSON provides an auxiliary function to return Proto3 JSON encoded | ||
// bytes of a message. This function should be used when marshalling a proto.Message | ||
// from the e2e tests. This function strips out unknown fields. This is useful for | ||
// backwards compatibility tests where the the types imported by the e2e package have | ||
// new fields that older versions do not recognize. | ||
func MustProtoMarshalJSON(msg proto.Message) []byte { | ||
anyResolver := codectypes.NewInterfaceRegistry() | ||
|
||
// EmitDefaults is set to false to prevent marshalling of unpopulated fields (memo) | ||
// OrigName and the anyResovler match the fields the original SDK function would expect | ||
// in order to minimize changes. | ||
|
||
// OrigName is true since there is no particular reason to use camel case | ||
// The any resolver is empty, but provided anyways. | ||
jm := &jsonpb.Marshaler{OrigName: true, EmitDefaults: false, AnyResolver: anyResolver} | ||
|
||
err := codectypes.UnpackInterfaces(msg, codectypes.ProtoJSONPacker{JSONPBMarshaler: jm}) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
buf := new(bytes.Buffer) | ||
if err := jm.Marshal(buf, msg); err != nil { | ||
panic(err) | ||
} | ||
|
||
return buf.Bytes() | ||
} |
Oops, something went wrong.