Skip to content

Commit

Permalink
imp(e2e): add contract query clients (#103)
Browse files Browse the repository at this point in the history
* e2e: generated query clients

* e2e: using query client now

* fix: e2e

* imp: regenerated query client
  • Loading branch information
srdtrk committed May 10, 2024
1 parent a9f503b commit f1ee2dc
Show file tree
Hide file tree
Showing 8 changed files with 557 additions and 179 deletions.
162 changes: 66 additions & 96 deletions e2e/interchaintest/contract_test.go

Large diffs are not rendered by default.

44 changes: 23 additions & 21 deletions e2e/interchaintest/owner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type OwnerTestSuite struct {

IcaContractCodeId int64
OwnerContract *types.Contract[
owner.InstantiateMsg, owner.ExecuteMsg, owner.QueryMsg,
owner.InstantiateMsg, owner.ExecuteMsg, owner.QueryMsg, owner.QueryClient,
]
NumOfIcaContracts uint32
}
Expand All @@ -47,9 +47,14 @@ func (s *OwnerTestSuite) SetupOwnerTestSuite(ctx context.Context) {
s.Require().NoError(err)

instantiateMsg := owner.InstantiateMsg{IcaControllerCodeId: int(s.IcaContractCodeId)}
s.OwnerContract, err = types.Instantiate[owner.InstantiateMsg, owner.ExecuteMsg, owner.QueryMsg](ctx, s.UserA.KeyName(), codeId, s.ChainA, instantiateMsg)
s.OwnerContract, err = types.Instantiate[owner.InstantiateMsg, owner.ExecuteMsg, owner.QueryMsg, owner.QueryClient](ctx, s.UserA.KeyName(), codeId, s.ChainA, instantiateMsg)
s.Require().NoError(err)

ownerQueryClient, err := owner.NewQueryClient(s.OwnerContract.Chain.GetHostGRPCAddress(), s.OwnerContract.Address)
s.Require().NoError(err)

s.OwnerContract.SetQueryClient(ownerQueryClient)

s.NumOfIcaContracts = 0

// Create the ICA Contract
Expand Down Expand Up @@ -85,18 +90,20 @@ func (s *OwnerTestSuite) TestOwnerCreateIcaContract() {
s.SetupOwnerTestSuite(ctx)
wasmd, simd := s.ChainA, s.ChainB

icaStateRequest := owner.QueryMsg{GetIcaContractState: &owner.QueryMsg_GetIcaContractState{IcaId: 0}}
icaState := &owner.IcaContractState{}
err := s.OwnerContract.Query(ctx, icaStateRequest, &icaState)
icaState, err := s.OwnerContract.QueryClient().GetIcaContractState(ctx, &owner.QueryMsg_GetIcaContractState{IcaId: 0})
s.Require().NoError(err)
s.Require().NotNil(icaState.IcaState)

icaContract := types.Contract[icacontroller.InstantiateMsg, icacontroller.ExecuteMsg, icacontroller.QueryMsg]{
icaContract := types.Contract[icacontroller.InstantiateMsg, icacontroller.ExecuteMsg, icacontroller.QueryMsg, icacontroller.QueryClient]{
Address: string(icaState.ContractAddr),
CodeID: strconv.FormatInt(s.IcaContractCodeId, 10),
Chain: wasmd,
}

icaQueryClient, err := icacontroller.NewQueryClient(icaContract.Chain.GetHostGRPCAddress(), icaContract.Address)
s.Require().NoError(err)
icaContract.SetQueryClient(icaQueryClient)

s.Run("TestChannelHandshakeSuccess", func() {
// Test if the handshake was successful
wasmdChannels, err := s.Relayer.GetChannels(ctx, s.ExecRep, wasmd.Config().ChainID)
Expand Down Expand Up @@ -126,12 +133,8 @@ func (s *OwnerTestSuite) TestOwnerCreateIcaContract() {
s.Require().Equal(channeltypes.OPEN.String(), simdChannel.State)

// Check contract's channel state
contractChannelState := &icacontroller.State{}
err = icaContract.Query(ctx, icacontroller.GetChannelRequest, contractChannelState)
contractChannelState, err := icaContract.QueryClient().GetChannel(ctx, &icacontroller.QueryMsg_GetChannel{})
s.Require().NoError(err)

s.T().Logf("contract's channel store after handshake: %s", toJSONString(contractChannelState))

s.Require().Equal(wasmdChannel.State, string(contractChannelState.ChannelStatus))
s.Require().Equal(wasmdChannel.Version, contractChannelState.Channel.Version)
s.Require().Equal(wasmdChannel.ConnectionHops[0], contractChannelState.Channel.ConnectionId)
Expand All @@ -142,14 +145,12 @@ func (s *OwnerTestSuite) TestOwnerCreateIcaContract() {
s.Require().Equal(wasmdChannel.Ordering, string(contractChannelState.Channel.Order))

// Check contract state
contractState := &icacontroller.State_2{}
err = icaContract.Query(ctx, icacontroller.GetContractStateRequest, contractState)
contractState, err := icaContract.QueryClient().GetContractState(ctx, &icacontroller.QueryMsg_GetContractState{})
s.Require().NoError(err)
s.Require().Equal(wasmdChannel.ChannelID, contractState.IcaInfo.ChannelId)

// Check contract's ownership
ownershipResponse := &icacontroller.Ownership_for_String{}
err = icaContract.Query(ctx, icacontroller.OwnershipRequest, ownershipResponse)
ownershipResponse, err := icaContract.QueryClient().Ownership(ctx, &icacontroller.QueryMsg_Ownership{})
s.Require().NoError(err)
s.Require().Equal(s.OwnerContract.Address, *ownershipResponse.Owner)
s.Require().Nil(ownershipResponse.PendingOwner)
Expand All @@ -166,20 +167,21 @@ func (s *OwnerTestSuite) TestOwnerPredefinedAction() {
wasmd, simd := s.ChainA, s.ChainB
wasmdUser, simdUser := s.UserA, s.UserB

icaStateRequest := owner.QueryMsg{GetIcaContractState: &owner.QueryMsg_GetIcaContractState{IcaId: 0}}
icaState := &owner.IcaContractState{}
err := s.OwnerContract.Query(ctx, icaStateRequest, &icaState)
icaState, err := s.OwnerContract.QueryClient().GetIcaContractState(ctx, &owner.QueryMsg_GetIcaContractState{IcaId: 0})
s.Require().NoError(err)

icaContract := types.Contract[icacontroller.InstantiateMsg, icacontroller.ExecuteMsg, icacontroller.QueryMsg]{
icaContract := types.Contract[icacontroller.InstantiateMsg, icacontroller.ExecuteMsg, icacontroller.QueryMsg, icacontroller.QueryClient]{
Address: string(icaState.ContractAddr),
CodeID: strconv.FormatInt(s.IcaContractCodeId, 10),
Chain: wasmd,
}

icaQueryClient, err := icacontroller.NewQueryClient(icaContract.Chain.GetHostGRPCAddress(), icaContract.Address)
s.Require().NoError(err)
icaContract.SetQueryClient(icaQueryClient)

// Check contract state
contractState := &icacontroller.State_2{}
err = icaContract.Query(ctx, icacontroller.GetContractStateRequest, contractState)
contractState, err := icaContract.QueryClient().GetContractState(ctx, &icacontroller.QueryMsg_GetContractState{})
s.Require().NoError(err)

icaAddress := contractState.IcaInfo.IcaAddress
Expand Down
81 changes: 81 additions & 0 deletions e2e/interchaintest/types/callback-counter/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/* Code generated by github.com/srdtrk/go-codegen, DO NOT EDIT. */
package callbackcounter

import (
"context"
"encoding/json"
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
grpc "google.golang.org/grpc"
insecure "google.golang.org/grpc/credentials/insecure"
)

// 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 {
// GetCallbackCounter is the client API for the QueryMsg_GetCallbackCounter query message
GetCallbackCounter(ctx context.Context, req *QueryMsg_GetCallbackCounter, opts ...grpc.CallOption) (*CallbackCounter, error)
}

type queryClient struct {
cc *grpc.ClientConn
address string
}

var _ QueryClient = (*queryClient)(nil)

// NewQueryClient creates a new QueryClient
func NewQueryClient(gRPCAddress, contractAddress string, opts ...grpc.DialOption) (QueryClient, error) {
if len(opts) == 0 {
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
}

// Create a connection to the gRPC server
grpcConn, err := grpc.Dial(gRPCAddress, opts...)
if err != nil {
return nil, err
}

return &queryClient{
address: contractAddress,
cc: grpcConn,
}, nil
}

// Close closes the gRPC connection to the server
func (q *queryClient) Close() error {
return q.cc.Close()
}

// queryContract is a helper function to query the contract with raw query data
func (q *queryClient) queryContract(ctx context.Context, rawQueryData []byte, opts ...grpc.CallOption) ([]byte, error) {
in := &wasmtypes.QuerySmartContractStateRequest{
Address: q.address,
QueryData: rawQueryData,
}
out := new(wasmtypes.QuerySmartContractStateResponse)
err := q.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/SmartContractState", in, out, opts...)
if err != nil {
return nil, err
}
return out.Data, nil
}

func (q *queryClient) GetCallbackCounter(ctx context.Context, req *QueryMsg_GetCallbackCounter, opts ...grpc.CallOption) (*CallbackCounter, error) {
rawQueryData, err := json.Marshal(&QueryMsg{GetCallbackCounter: req})
if err != nil {
return nil, err
}

rawResponseData, err := q.queryContract(ctx, rawQueryData, opts...)
if err != nil {
return nil, err
}

var response CallbackCounter
if err := json.Unmarshal(rawResponseData, &response); err != nil {
return nil, err
}

return &response, nil
}
53 changes: 26 additions & 27 deletions e2e/interchaintest/types/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@ import (
// I is the instantiate message type
// E is the execute message type
// Q is the query message type
type Contract[I, E, Q any] struct {
// QC is the query client type
type Contract[I, E, Q, QC any] struct {
Address string
CodeID string
Chain *cosmos.CosmosChain
qc QC
qcSet bool
}

// newContract creates a new Contract instance
func newContract[I, E, Q any](address string, codeId string, chain *cosmos.CosmosChain) *Contract[I, E, Q] {
return &Contract[I, E, Q]{
func newContract[I, E, Q, QC any](address, codeId string, chain *cosmos.CosmosChain) *Contract[I, E, Q, QC] {
return &Contract[I, E, Q, QC]{
Address: address,
CodeID: codeId,
Chain: chain,
Expand All @@ -32,45 +35,41 @@ func newContract[I, E, Q any](address string, codeId string, chain *cosmos.Cosmo
// I is the instantiate message type
// E is the execute message type
// Q is the query message type
func Instantiate[I, E, Q any](ctx context.Context, callerKeyName string, codeId string, chain *cosmos.CosmosChain, msg I, extraExecTxArgs ...string) (*Contract[I, E, Q], error) {
func Instantiate[I, E, Q, QC any](ctx context.Context, callerKeyName, codeId string, chain *cosmos.CosmosChain, msg I, extraExecTxArgs ...string) (*Contract[I, E, Q, QC], error) {
contractAddr, err := chain.InstantiateContract(ctx, callerKeyName, codeId, toString(msg), true, extraExecTxArgs...)
if err != nil {
return nil, err
}

return newContract[I, E, Q](contractAddr, codeId, chain), nil
return newContract[I, E, Q, QC](contractAddr, codeId, chain), nil
}

func (c *Contract[I, E, Q]) Port() string {
func (c *Contract[I, E, Q, QC]) Port() string {
return "wasm." + c.Address
}

// Execute executes the contract with the given execute message and returns the transaction response
func (c *Contract[I, E, Q]) Execute(ctx context.Context, callerKeyName string, msg E, extraExecTxArgs ...string) (*sdk.TxResponse, error) {
return c.Chain.ExecuteContract(ctx, callerKeyName, c.Address, toString(msg), extraExecTxArgs...)
}

// Query queries the contract with the given query message
// and unmarshals the response into the given response object
func (c *Contract[I, E, Q]) Query(ctx context.Context, queryMsg Q, resp any) error {
// queryResponse is used to represent the response of a query.
// It may contain different types of data, so we need to unmarshal it
type queryResponse struct {
Response json.RawMessage `json:"data"`
// QueryClient returns the query client for the contract
func (c *Contract[I, E, Q, QC]) QueryClient() QC {
if !c.qcSet {
panic("QueryClient not set")
}

queryResp := queryResponse{}
err := c.Chain.QueryContract(ctx, c.Address, queryMsg, &queryResp)
if err != nil {
return err
}
return c.qc
}

err = json.Unmarshal(queryResp.Response, resp)
if err != nil {
return err
// SetQueryClient sets the query client for the contract
func (c *Contract[I, E, Q, QC]) SetQueryClient(qc QC) {
if c.qcSet {
panic("QueryClient already set")
}

return nil
c.qc = qc
c.qcSet = true
}

// Execute executes the contract with the given execute message and returns the transaction response
func (c *Contract[I, E, Q, QC]) Execute(ctx context.Context, callerKeyName string, msg E, extraExecTxArgs ...string) (*sdk.TxResponse, error) {
return c.Chain.ExecuteContract(ctx, callerKeyName, c.Address, toString(msg), extraExecTxArgs...)
}

// toString converts the message to a string using json
Expand Down
Loading

0 comments on commit f1ee2dc

Please sign in to comment.