Skip to content

Commit

Permalink
[Feature] contract info query wasm interface (#520)
Browse files Browse the repository at this point in the history
* add contract info query interface

* add testing code for contract info query wasm interface

* remove print
  • Loading branch information
yys authored and yun-yeo committed Aug 11, 2021
1 parent 2e72678 commit 83b1599
Show file tree
Hide file tree
Showing 4 changed files with 327 additions and 2 deletions.
37 changes: 37 additions & 0 deletions x/wasm/keeper/custom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ type bindingsTesterTaxCapQueryMsg struct {
type bindingsTesterExchangeRatesQueryMsg struct {
ExchangeRates exchangeRatesQueryMsg `json:"exchange_rates"`
}
type bindingsTesterContractInfoQuerymsg struct {
ContractInfo contractInfoQueryMsg `json:"contract_info"`
}
type swapQueryMsg struct {
OfferCoin wasmvmtypes.Coin `json:"offer_coin"`
AskDenom string `json:"ask_denom"`
Expand All @@ -100,6 +103,9 @@ type exchangeRatesQueryMsg struct {
BaseDenom string `json:"base_denom"`
QuoteDenoms []string `json:"quote_denoms"`
}
type contractInfoQueryMsg struct {
ContractAddress string `json:"contract_address"`
}

func TestInstantiateMaker(t *testing.T) {
input := CreateTestInput(t)
Expand Down Expand Up @@ -240,6 +246,37 @@ func TestExchangeRatesQuerier(t *testing.T) {
require.Equal(t, KRWExchangeRate, exchangeRateDec)
}

func TestContractInfoQuerier(t *testing.T) {
input, _, testerAddr, _ := setupBindingsTesterContract(t)

ctx, keeper := input.Ctx, input.WasmKeeper

contractInfoQueryMsg := bindingsTesterContractInfoQuerymsg{
ContractInfo: contractInfoQueryMsg{
ContractAddress: testerAddr.String(),
},
}

bz, err := json.Marshal(contractInfoQueryMsg)
require.NoError(t, err)

res, err := keeper.queryToContract(ctx, testerAddr, bz)
require.NoError(t, err)

var contractInfoResponse ContractInfoQueryResponse
err = json.Unmarshal(res, &contractInfoResponse)
require.NoError(t, err)

contractInfo, err := keeper.GetContractInfo(ctx, testerAddr)
require.NoError(t, err)
require.Equal(t, contractInfoResponse, ContractInfoQueryResponse{
CodeID: contractInfo.CodeID,
Address: contractInfo.Address,
Creator: contractInfo.Creator,
Admin: contractInfo.Admin,
})
}

func TestBuyMsg(t *testing.T) {
input, creatorAddr, makerAddr, offerCoin := setupMakerContract(t)

Expand Down
Binary file modified x/wasm/keeper/testdata/bindings_tester.wasm
Binary file not shown.
54 changes: 52 additions & 2 deletions x/wasm/keeper/wasm_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,57 @@ func (querier WasmQuerier) Query(ctx sdk.Context, request wasmvmtypes.QueryReque
return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown WasmQuery variant"}
}

// ContractInfoQueryParams query request params for contract info
type ContractInfoQueryParams struct {
ContractAddress string `json:"contract_address"`
}

// CosmosQuery custom query interface for oracle querier
type CosmosQuery struct {
ContractInfo *ContractInfoQueryParams `json:"contract_info,omitempty"`
}

// ContractInfoQueryResponse - exchange rates query response for wasm module
type ContractInfoQueryResponse struct {
Address string `json:"address"`
Creator string `json:"creator"`
Admin string `json:"admin,omitempty"`
CodeID uint64 `json:"code_id"`
}

// QueryCustom implements custom query interface
func (WasmQuerier) QueryCustom(ctx sdk.Context, data json.RawMessage) ([]byte, error) {
return nil, nil
func (querier WasmQuerier) QueryCustom(ctx sdk.Context, data json.RawMessage) ([]byte, error) {
var params CosmosQuery
err := json.Unmarshal(data, &params)

if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}

if params.ContractInfo != nil {
contractAddress, err := sdk.AccAddressFromBech32(params.ContractInfo.ContractAddress)
if err != nil {
return nil, err
}

contractInfo, err := querier.keeper.GetContractInfo(ctx, contractAddress)
if err != nil {
return nil, err
}

bz, err := json.Marshal(ContractInfoQueryResponse{
Address: contractInfo.Address,
Creator: contractInfo.Creator,
Admin: contractInfo.Admin,
CodeID: contractInfo.CodeID,
})

if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}

return bz, nil
}

return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown Wasm variant"}
}
238 changes: 238 additions & 0 deletions x/wasm/keeper/wasm_interface_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
package keeper

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/secp256k1"

wasmvmtypes "github.com/CosmWasm/wasmvm/types"

sdk "github.com/cosmos/cosmos-sdk/types"

core "github.com/terra-money/core/types"
"github.com/terra-money/core/x/wasm/types"
)

func TestEcoding(t *testing.T) {
pubKeys := []crypto.PubKey{
secp256k1.GenPrivKey().PubKey(),
secp256k1.GenPrivKey().PubKey(),
secp256k1.GenPrivKey().PubKey(),
}

addrs := []sdk.AccAddress{
sdk.AccAddress(pubKeys[0].Address()),
sdk.AccAddress(pubKeys[1].Address()),
sdk.AccAddress(pubKeys[2].Address()),
}

invalidAddr := "xrnd1d02kd90n38qvr3qb9qof83fn2d2"
cases := map[string]struct {
sender sdk.AccAddress
input wasmvmtypes.CosmosMsg
// set if valid
output sdk.Msg
// set if invalid
isError bool
}{
"simple execute": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
Execute: &wasmvmtypes.ExecuteMsg{
ContractAddr: addrs[1].String(),
Msg: []byte("{}"),
Funds: wasmvmtypes.Coins{wasmvmtypes.NewCoin(1234, core.MicroLunaDenom)},
},
},
},
output: &types.MsgExecuteContract{
Sender: addrs[0].String(),
Contract: addrs[1].String(),
Coins: sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 1234)),
ExecuteMsg: []byte("{}"),
},
},
"simple instantiate without admin": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
Instantiate: &wasmvmtypes.InstantiateMsg{
CodeID: 1,
Msg: []byte("{}"),
Funds: wasmvmtypes.Coins{wasmvmtypes.NewCoin(1234, core.MicroLunaDenom)},
},
},
},
output: &types.MsgInstantiateContract{
Sender: addrs[0].String(),
CodeID: 1,
InitCoins: sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 1234)),
InitMsg: []byte("{}"),
},
},
"simple instantiate with admin": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
Instantiate: &wasmvmtypes.InstantiateMsg{
CodeID: 1,
Msg: []byte("{}"),
Funds: wasmvmtypes.Coins{wasmvmtypes.NewCoin(1234, core.MicroLunaDenom)},
Admin: addrs[0].String(),
},
},
},
output: &types.MsgInstantiateContract{
Sender: addrs[0].String(),
CodeID: 1,
InitCoins: sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 1234)),
InitMsg: []byte("{}"),
Admin: addrs[0].String(),
},
},
"simple migrate": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
Migrate: &wasmvmtypes.MigrateMsg{
ContractAddr: addrs[1].String(),
Msg: []byte("{}"),
NewCodeID: 1,
},
},
},
output: &types.MsgMigrateContract{
Admin: addrs[0].String(),
NewCodeID: 1,
Contract: addrs[1].String(),
MigrateMsg: []byte("{}"),
},
},
"simple update admin": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
UpdateAdmin: &wasmvmtypes.UpdateAdminMsg{
ContractAddr: addrs[1].String(),
Admin: addrs[2].String(),
},
},
},
output: &types.MsgUpdateContractAdmin{
Admin: addrs[0].String(),
Contract: addrs[1].String(),
NewAdmin: addrs[2].String(),
},
},
"simple clear admin": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
ClearAdmin: &wasmvmtypes.ClearAdminMsg{
ContractAddr: addrs[1].String(),
},
},
},
output: &types.MsgClearContractAdmin{
Admin: addrs[0].String(),
Contract: addrs[1].String(),
},
},
"invalid address execute": {
sender: addrs[0],
input: wasmvmtypes.CosmosMsg{
Wasm: &wasmvmtypes.WasmMsg{
Execute: &wasmvmtypes.ExecuteMsg{
ContractAddr: invalidAddr,
Msg: []byte("{}"),
Funds: wasmvmtypes.Coins{wasmvmtypes.NewCoin(1234, core.MicroLunaDenom)},
},
},
},
isError: true,
},
}

parser := NewWasmMsgParser()
for name, tc := range cases {
tc := tc
t.Run(name, func(t *testing.T) {
res, err := parser.Parse(tc.sender, tc.input)
if tc.isError {
require.Error(t, err)
} else {
require.NoError(t, err)
assert.Equal(t, tc.output, res)
}
})
}
}

func TestQueryRaw(t *testing.T) {
input := CreateTestInput(t)

input.WasmKeeper.SetContractStore(input.Ctx, Addrs[0], []types.Model{
{
Key: []byte("key1"),
Value: []byte("value1"),
},
{
Key: []byte("key2"),
Value: []byte("value2"),
},
{
Key: []byte("key3"),
Value: []byte("value3"),
},
{
Key: []byte("key4"),
Value: []byte("value4"),
},
})

querier := NewWasmQuerier(input.WasmKeeper)
res, err := querier.Query(input.Ctx, wasmvmtypes.QueryRequest{
Wasm: &wasmvmtypes.WasmQuery{
Raw: &wasmvmtypes.RawQuery{
ContractAddr: Addrs[0].String(),
Key: []byte("key1"),
},
},
})

require.NoError(t, err)
require.Equal(t, res, []byte("value1"))
}

func TestQueryContractInfo(t *testing.T) {
input := CreateTestInput(t)

input.WasmKeeper.SetContractInfo(input.Ctx, Addrs[0], types.NewContractInfo(1, Addrs[0], Addrs[1], sdk.AccAddress{}, []byte{}))

bz, err := json.Marshal(CosmosQuery{
ContractInfo: &ContractInfoQueryParams{
ContractAddress: Addrs[0].String(),
},
})
require.NoError(t, err)

querier := NewWasmQuerier(input.WasmKeeper)
res, err := querier.QueryCustom(input.Ctx, bz)
require.NoError(t, err)

var contractInfoResponse ContractInfoQueryResponse
err = json.Unmarshal(res, &contractInfoResponse)
require.NoError(t, err)

require.Equal(t, contractInfoResponse, ContractInfoQueryResponse{
Address: Addrs[0].String(),
Creator: Addrs[1].String(),
Admin: "",
CodeID: 1,
})
}

0 comments on commit 83b1599

Please sign in to comment.