Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup query api #50

Merged
merged 4 commits into from
Jan 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ This code was forked from the `cosmos/gaia` repository and the majority of the c

**Compatibility**: Last merge from `cosmos/gaia` was `090c545347b03e59415a18107a0a279c703c8f40` (Jan 23, 2020)

## Stability

**This is alpha software, do not run on a production system.** Notably, we currently provide **no migration path** not even "dump state and restart" to move to future versions. At **beta** we will begin to offer migrations and better backwards compatibility guarantees.

With the `v0.6.0` tag, we are entering semver. That means anything with `v0.6.x` tags is compatible. We will have a series of minor version updates prior to `v1.0.0`, where we offer strong backwards compatibility guarantees. In particular, work has begun in the `cosmwasm` library on `v0.7`, which will change many internal APIs, in order to allow adding other languages for writing smart contracts. We hope to stabilize much of this well before `v1`, but we are still in the process of learning from real-world use-cases

## Encoding

We use standard cosmos-sdk encoding (amino) for all sdk Messages. However, the message body sent to all contracts, as well as the internal state is encoded using JSON. Cosmwasm allows arbitrary bytes with the contract itself responsible for decodng. For better UX, we often use `json.RawMessage` to contain these bytes, which enforces that it is valid json, but also give a much more readable interface. If you want to use another encoding in the contracts, that is a relatively minor change to wasmd but would currently require a fork. Please open in issue if this is important for your use case.

## Quick Start

```
Expand Down
4 changes: 2 additions & 2 deletions x/wasm/internal/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
var state []types.Model
for ; contractStateIterator.Valid(); contractStateIterator.Next() {
m := types.Model{
Key: string(contractStateIterator.Key()),
Value: string(contractStateIterator.Value()),
Key: contractStateIterator.Key(),
Value: contractStateIterator.Value(),
}
state = append(state, m)
}
Expand Down
6 changes: 3 additions & 3 deletions x/wasm/internal/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func (k Keeper) Instantiate(ctx sdk.Context, codeID uint64, creator sdk.AccAddre
}

// persist instance
instance := types.NewContractInfo(codeID, creator, string(initMsg))
instance := types.NewContractInfo(codeID, creator, initMsg)
// 0x02 | contractAddress (sdk.AccAddress) -> Instance
store.Set(types.GetContractAddressKey(contractAddress), k.cdc.MustMarshalBinaryBare(instance))

Expand Down Expand Up @@ -193,8 +193,8 @@ func (k Keeper) QueryRaw(ctx sdk.Context, contractAddress sdk.AccAddress, key []

if val := prefixStore.Get(key); val != nil {
return append(result, types.Model{
Key: string(key),
Value: string(val),
Key: key,
Value: val,
})
}
return result
Expand Down
6 changes: 3 additions & 3 deletions x/wasm/internal/keeper/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ func queryContractState(ctx sdk.Context, bech, queryMethod string, req abci.Requ
case QueryMethodContractStateAll:
for iter := keeper.GetContractState(ctx, contractAddr); iter.Valid(); iter.Next() {
resultData = append(resultData, types.Model{
Key: string(iter.Key()),
Value: string(iter.Value()),
Key: iter.Key(),
Value: iter.Value(),
})
}
if resultData == nil {
Expand All @@ -104,7 +104,7 @@ func queryContractState(ctx sdk.Context, bech, queryMethod string, req abci.Requ
default:
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, queryMethod)
}
bz, err := json.MarshalIndent(resultData, "", " ")
bz, err := json.Marshal(resultData)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
Expand Down
27 changes: 11 additions & 16 deletions x/wasm/internal/keeper/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ import (
)

func TestQueryContractState(t *testing.T) {
type model struct {
Key string `json:"key"`
Value string `json:"val"`
}

tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
Expand Down Expand Up @@ -48,8 +43,8 @@ func TestQueryContractState(t *testing.T) {
require.NoError(t, err)

contractModel := []types.Model{
{Key: "foo", Value: "bar"},
{Key: string([]byte{0x0, 0x1}), Value: string([]byte{0x2, 0x3})},
{Key: []byte("foo"), Value: []byte(`"bar"`)},
{Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)},
}
keeper.setContractState(ctx, addr, contractModel)

Expand All @@ -58,33 +53,33 @@ func TestQueryContractState(t *testing.T) {
specs := map[string]struct {
srcPath []string
srcReq abci.RequestQuery
// smart queries return raw bytes from contract not []model
// smart queries return raw bytes from contract not []types.Model
// if this is set, then we just compare - (should be json encoded string)
expSmartRes string
// if success and expSmartRes is not set, we parse into []model and compare
// if success and expSmartRes is not set, we parse into []types.Model and compare
expModelLen int
expModelContains []model
expModelContains []types.Model
expErr *sdkErrors.Error
}{
"query all": {
srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateAll},
expModelLen: 3,
expModelContains: []model{
{Key: "foo", Value: "bar"},
{Key: string([]byte{0x0, 0x1}), Value: string([]byte{0x2, 0x3})},
expModelContains: []types.Model{
{Key: []byte("foo"), Value: []byte(`"bar"`)},
{Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)},
},
},
"query raw key": {
srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateRaw},
srcReq: abci.RequestQuery{Data: []byte("foo")},
expModelLen: 1,
expModelContains: []model{{Key: "foo", Value: "bar"}},
expModelContains: []types.Model{{Key: []byte("foo"), Value: []byte(`"bar"`)}},
},
"query raw binary key": {
srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateRaw},
srcReq: abci.RequestQuery{Data: []byte{0x0, 0x1}},
expModelLen: 1,
expModelContains: []model{{Key: string([]byte{0x0, 0x1}), Value: string([]byte{0x2, 0x3})}},
expModelContains: []types.Model{{Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)}},
},
"query smart": {
srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateSmart},
Expand Down Expand Up @@ -133,7 +128,7 @@ func TestQueryContractState(t *testing.T) {
}

// otherwise, check returned models
var r []model
var r []types.Model
if spec.expErr == nil {
require.NoError(t, json.Unmarshal(binResult, &r))
require.NotNil(t, r)
Expand Down
15 changes: 9 additions & 6 deletions x/wasm/internal/types/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package types

import (
"encoding/json"
tmBytes "github.com/tendermint/tendermint/libs/bytes"

wasmTypes "github.com/confio/go-cosmwasm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
auth "github.com/cosmos/cosmos-sdk/x/auth/exported"
Expand All @@ -11,8 +14,8 @@ const defaultQueryGasLimit = uint64(3000000)

// Model is a struct that holds a KV pair
type Model struct {
Key string `json:"key"`
Value string `json:"val"`
Key tmBytes.HexBytes `json:"key"`
Value json.RawMessage `json:"val"`
}

// CodeInfo is data for the uploaded contract WASM code
Expand All @@ -35,9 +38,9 @@ func NewCodeInfo(codeHash []byte, creator sdk.AccAddress, source string, builder

// ContractInfo stores a WASM contract instance
type ContractInfo struct {
CodeID uint64 `json:"code_id"`
Creator sdk.AccAddress `json:"creator"`
InitMsg string `json:"init_msg"`
CodeID uint64 `json:"code_id"`
Creator sdk.AccAddress `json:"creator"`
InitMsg json.RawMessage `json:"init_msg"`
}

// NewParams initializes params for a contract instance
Expand Down Expand Up @@ -72,7 +75,7 @@ func NewWasmCoins(cosmosCoins sdk.Coins) (wasmCoins []wasmTypes.Coin) {
}

// NewContractInfo creates a new instance of a given WASM contract info
func NewContractInfo(codeID uint64, creator sdk.AccAddress, initMsg string) ContractInfo {
func NewContractInfo(codeID uint64, creator sdk.AccAddress, initMsg []byte) ContractInfo {
return ContractInfo{
CodeID: codeID,
Creator: creator,
Expand Down
11 changes: 3 additions & 8 deletions x/wasm/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,25 +398,20 @@ func assertContractList(t *testing.T, q sdk.Querier, ctx sdk.Context, addrs []st
assert.Equal(t, addrs, res)
}

type model struct {
Key string `json:"key"`
Value string `json:"val"`
}

func assertContractState(t *testing.T, q sdk.Querier, ctx sdk.Context, addr sdk.AccAddress, expected state) {
path := []string{QueryGetContractState, addr.String(), keeper.QueryMethodContractStateAll}
bz, sdkerr := q(ctx, path, abci.RequestQuery{})
require.NoError(t, sdkerr)

var res []model
var res []Model
err := json.Unmarshal(bz, &res)
require.NoError(t, err)
require.Equal(t, 1, len(res), "#v", res)
require.Equal(t, "config", res[0].Key)
require.Equal(t, []byte("config"), []byte(res[0].Key))

expectedBz, err := json.Marshal(expected)
require.NoError(t, err)
assert.Equal(t, string(expectedBz), res[0].Value)
assert.Equal(t, json.RawMessage(expectedBz), res[0].Value)
}

func assertContractInfo(t *testing.T, q sdk.Querier, ctx sdk.Context, addr sdk.AccAddress, codeID uint64, creator sdk.AccAddress) {
Expand Down