Merge branch 'master' of https://github.com/cosmwasm/wasmd into vw/add_source_ref

This commit is contained in:
Sahith Reddy Narahari 2020-01-17 19:32:58 +05:30
commit 872a40eaa3
17 changed files with 270 additions and 221 deletions

View File

@ -13,6 +13,7 @@ This code was forked from the `cosmos/gaia` repository and the majority of the c
**Note**: Requires [Go 1.13+](https://golang.org/dl/)
**Compatibility**: Last merge from `cosmos/gaia` was `d6dfa141e2ae38a1ff9f53fca8078c0822671b95`
## Quick Start

2
go.mod
View File

@ -4,7 +4,7 @@ go 1.13
require (
github.com/btcsuite/btcd v0.0.0-20190807005414-4063feeff79a // indirect
github.com/confio/go-cosmwasm v0.4.1
github.com/confio/go-cosmwasm v0.6.0
github.com/cosmos/cosmos-sdk v0.34.4-0.20191114141721-d4c831e63ad3
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect
github.com/golang/mock v1.3.1 // indirect

4
go.sum
View File

@ -34,8 +34,8 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/confio/go-cosmwasm v0.4.1 h1:ZqqGlK5MA6iJlYU8LtV0VPmv4mMI1s1cx2xWnDSEzH0=
github.com/confio/go-cosmwasm v0.4.1/go.mod h1:pHipRby+f3cv97QPLELkzOAlNs/s87uDyhc+SnMn7L4=
github.com/confio/go-cosmwasm v0.6.0 h1:6MsfozR4IWb+V9TgVhDoGvcEs0ItBCqHg4pGbMafX1A=
github.com/confio/go-cosmwasm v0.6.0/go.mod h1:pHipRby+f3cv97QPLELkzOAlNs/s87uDyhc+SnMn7L4=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=

View File

@ -1,4 +1,8 @@
// nolint
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/cosmwasm/wasmd/x/wasm/internal/types
// ALIASGEN: github.com/cosmwasm/wasmd/x/wasm/internal/keeper
package wasm
import (
@ -6,46 +10,29 @@ import (
"github.com/cosmwasm/wasmd/x/wasm/internal/types"
)
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/cosmwasm/wasmd/x/wasm/internal/keeper/
// ALIASGEN: github.com/cosmwasm/wasmd/x/wasm/internal/types/
const (
GasMultiplier = keeper.GasMultiplier
MaxGas = keeper.MaxGas
QueryListContracts = keeper.QueryListContracts
QueryGetContract = keeper.QueryGetContract
QueryGetContractState = keeper.QueryGetContractState
QueryGetCode = keeper.QueryGetCode
QueryListCode = keeper.QueryListCode
DefaultCodespace = types.DefaultCodespace
CodeCreatedFailed = types.CodeCreatedFailed
CodeAccountExists = types.CodeAccountExists
CodeInstantiateFailed = types.CodeInstantiateFailed
CodeExecuteFailed = types.CodeExecuteFailed
CodeGasLimit = types.CodeGasLimit
ModuleName = types.ModuleName
StoreKey = types.StoreKey
TStoreKey = types.TStoreKey
QuerierRoute = types.QuerierRoute
RouterKey = types.RouterKey
MaxWasmSize = types.MaxWasmSize
ModuleName = types.ModuleName
StoreKey = types.StoreKey
TStoreKey = types.TStoreKey
QuerierRoute = types.QuerierRoute
RouterKey = types.RouterKey
MaxWasmSize = types.MaxWasmSize
GasMultiplier = keeper.GasMultiplier
MaxGas = keeper.MaxGas
QueryListContracts = keeper.QueryListContracts
QueryGetContract = keeper.QueryGetContract
QueryGetContractState = keeper.QueryGetContractState
QueryGetCode = keeper.QueryGetCode
QueryListCode = keeper.QueryListCode
QueryMethodContractStateSmart = keeper.QueryMethodContractStateSmart
QueryMethodContractStateAll = keeper.QueryMethodContractStateAll
QueryMethodContractStateRaw = keeper.QueryMethodContractStateRaw
)
var (
// functions aliases
NewKeeper = keeper.NewKeeper
NewQuerier = keeper.NewQuerier
MakeTestCodec = keeper.MakeTestCodec
CreateTestInput = keeper.CreateTestInput
RegisterCodec = types.RegisterCodec
ErrCreateFailed = types.ErrCreateFailed
ErrAccountExists = types.ErrAccountExists
ErrInstantiateFailed = types.ErrInstantiateFailed
ErrExecuteFailed = types.ErrExecuteFailed
ErrGasLimit = types.ErrGasLimit
ErrInvalidGenesis = types.ErrInvalidGenesis
ValidateGenesis = types.ValidateGenesis
GetCodeKey = types.GetCodeKey
GetContractAddressKey = types.GetContractAddressKey
GetContractStorePrefixKey = types.GetContractStorePrefixKey
@ -54,29 +41,42 @@ var (
NewWasmCoins = types.NewWasmCoins
NewContractInfo = types.NewContractInfo
CosmosResult = types.CosmosResult
// genesis aliases
ValidateGenesis = types.ValidateGenesis
InitGenesis = keeper.InitGenesis
ExportGenesis = keeper.ExportGenesis
InitGenesis = keeper.InitGenesis
ExportGenesis = keeper.ExportGenesis
NewKeeper = keeper.NewKeeper
NewQuerier = keeper.NewQuerier
MakeTestCodec = keeper.MakeTestCodec
CreateTestInput = keeper.CreateTestInput
// variable aliases
ModuleCdc = types.ModuleCdc
KeyLastCodeID = types.KeyLastCodeID
KeyLastInstanceID = types.KeyLastInstanceID
CodeKeyPrefix = types.CodeKeyPrefix
ContractKeyPrefix = types.ContractKeyPrefix
ContractStorePrefix = types.ContractStorePrefix
ModuleCdc = types.ModuleCdc
DefaultCodespace = types.DefaultCodespace
ErrCreateFailed = types.ErrCreateFailed
ErrAccountExists = types.ErrAccountExists
ErrInstantiateFailed = types.ErrInstantiateFailed
ErrExecuteFailed = types.ErrExecuteFailed
ErrGasLimit = types.ErrGasLimit
ErrInvalidGenesis = types.ErrInvalidGenesis
ErrNotFound = types.ErrNotFound
ErrQueryFailed = types.ErrQueryFailed
KeyLastCodeID = types.KeyLastCodeID
KeyLastInstanceID = types.KeyLastInstanceID
CodeKeyPrefix = types.CodeKeyPrefix
ContractKeyPrefix = types.ContractKeyPrefix
ContractStorePrefix = types.ContractStorePrefix
)
type (
Keeper = keeper.Keeper
GetCodeResponse = keeper.GetCodeResponse
GenesisState = types.GenesisState
Code = types.Code
Contract = types.Contract
MsgStoreCode = types.MsgStoreCode
MsgInstantiateContract = types.MsgInstantiateContract
MsgExecuteContract = types.MsgExecuteContract
Model = types.Model
CodeInfo = types.CodeInfo
ContractInfo = types.ContractInfo
GenesisState = types.GenesisState
Keeper = keeper.Keeper
GetCodeResponse = keeper.GetCodeResponse
ListCodeResponse = keeper.ListCodeResponse
)

View File

@ -9,6 +9,9 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
type contractState struct {
}
func TestInitGenesis(t *testing.T) {
data, cleanup := setupTest(t)
defer cleanup()
@ -31,8 +34,8 @@ func TestInitGenesis(t *testing.T) {
_, _, bob := keyPubAddr()
initMsg := initMsg{
Verifier: fred.String(),
Beneficiary: bob.String(),
Verifier: fred,
Beneficiary: bob,
}
initMsgBz, err := json.Marshal(initMsg)
require.NoError(t, err)
@ -63,9 +66,9 @@ func TestInitGenesis(t *testing.T) {
assertContractList(t, q, data.ctx, []string{contractAddr.String()})
assertContractInfo(t, q, data.ctx, contractAddr, 1, creator)
assertContractState(t, q, data.ctx, contractAddr, state{
Verifier: fred.String(),
Beneficiary: bob.String(),
Funder: creator.String(),
Verifier: []byte(fred),
Beneficiary: []byte(bob),
Funder: []byte(creator),
})
// export into genstate
@ -86,8 +89,8 @@ func TestInitGenesis(t *testing.T) {
assertContractList(t, q2, newData.ctx, []string{contractAddr.String()})
assertContractInfo(t, q2, newData.ctx, contractAddr, 1, creator)
assertContractState(t, q2, newData.ctx, contractAddr, state{
Verifier: fred.String(),
Beneficiary: bob.String(),
Funder: creator.String(),
Verifier: []byte(fred),
Beneficiary: []byte(bob),
Funder: []byte(creator),
})
}

View File

@ -40,10 +40,9 @@ func NewHandler(k Keeper) sdk.Handler {
}
func handleStoreCode(ctx sdk.Context, k Keeper, msg *MsgStoreCode) sdk.Result {
err := msg.ValidateBasic()
codeID, err := k.Create(ctx, msg.Sender, msg.WASMByteCode, msg.Source, msg.Builder)
if err != nil {
return err.Result()
return sdk.ResultFromError(err)
}
ctx.EventManager().EmitEvent(
@ -65,7 +64,7 @@ func handleStoreCode(ctx sdk.Context, k Keeper, msg *MsgStoreCode) sdk.Result {
func handleInstantiate(ctx sdk.Context, k Keeper, msg *MsgInstantiateContract) sdk.Result {
contractAddr, err := k.Instantiate(ctx, msg.Sender, msg.Code, msg.InitMsg, msg.InitFunds)
if err != nil {
return err.Result()
return sdk.ResultFromError(err)
}
ctx.EventManager().EmitEvent(
@ -88,7 +87,7 @@ func handleInstantiate(ctx sdk.Context, k Keeper, msg *MsgInstantiateContract) s
func handleExecute(ctx sdk.Context, k Keeper, msg *MsgExecuteContract) sdk.Result {
res, err := k.Execute(ctx, msg.Contract, msg.Sender, msg.SentFunds, msg.Msg)
if err != nil {
return err.Result()
return sdk.ResultFromError(err)
}
ctx.EventManager().EmitEvent(

View File

@ -0,0 +1,23 @@
package keeper
import (
"fmt"
cosmwasm "github.com/confio/go-cosmwasm"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func humanAddress(canon []byte) (string, error) {
if len(canon) != sdk.AddrLen {
return "", fmt.Errorf("Expected %d byte address", sdk.AddrLen)
}
return sdk.AccAddress(canon).String(), nil
}
func canonicalAddress(human string) ([]byte, error) {
return sdk.AccAddressFromBech32(human)
}
var cosmwasmAPI = cosmwasm.GoAPI{
HumanAddress: humanAddress,
CanonicalAddress: canonicalAddress,
}

View File

@ -10,6 +10,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkErrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/exported"
"github.com/cosmos/cosmos-sdk/x/bank"
@ -45,7 +46,7 @@ type Keeper struct {
// NewKeeper creates a new contract Keeper instance
func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, accountKeeper auth.AccountKeeper, bankKeeper bank.Keeper, router sdk.Router, homeDir string) Keeper {
wasmer, err := wasm.NewWasmer(filepath.Join(homeDir, "wasm"), 3)
wasmer, err := wasm.NewWasmer(filepath.Join(homeDir, "wasm"), 0)
if err != nil {
panic(err)
}
@ -62,14 +63,15 @@ func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, accountKeeper auth.Accou
}
// Create uploads and compiles a WASM contract, returning a short identifier for the contract
func (k Keeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, source string, builder string) (codeID uint64, sdkErr sdk.Error) {
wasmCode, err := uncompress(wasmCode)
func (k Keeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, source string, builder string) (codeID uint64, err error) {
wasmCode, err = uncompress(wasmCode)
if err != nil {
return 0, types.ErrCreateFailed(err)
return 0, sdkErrors.Wrap(types.ErrCreateFailed, err.Error())
}
codeHash, err := k.wasmer.Create(wasmCode)
if err != nil {
return 0, types.ErrCreateFailed(err)
// return 0, sdkErrors.Wrap(err, "cosmwasm create")
return 0, sdkErrors.Wrap(types.ErrCreateFailed, err.Error())
}
store := ctx.KVStore(k.storeKey)
@ -82,12 +84,12 @@ func (k Keeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte,
}
// Instantiate creates an instance of a WASM contract
func (k Keeper) Instantiate(ctx sdk.Context, creator sdk.AccAddress, codeID uint64, initMsg []byte, deposit sdk.Coins) (sdk.AccAddress, sdk.Error) {
func (k Keeper) Instantiate(ctx sdk.Context, creator sdk.AccAddress, codeID uint64, initMsg []byte, deposit sdk.Coins) (sdk.AccAddress, error) {
// create contract address
contractAddress := k.generateContractAddress(ctx, codeID)
existingAccnt := k.accountKeeper.GetAccount(ctx, contractAddress)
if existingAccnt != nil {
return nil, types.ErrAccountExists(existingAccnt.GetAddress())
existingAcct := k.accountKeeper.GetAccount(ctx, contractAddress)
if existingAcct != nil {
return nil, sdkErrors.Wrap(types.ErrAccountExists, existingAcct.GetAddress().String())
}
// deposit initial contract funds
@ -101,7 +103,7 @@ func (k Keeper) Instantiate(ctx sdk.Context, creator sdk.AccAddress, codeID uint
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.GetCodeKey(codeID))
if bz == nil {
return nil, types.ErrNotFound("contract")
return nil, sdkErrors.Wrap(types.ErrNotFound, "contract")
}
var codeInfo types.CodeInfo
k.cdc.MustUnmarshalBinaryBare(bz, &codeInfo)
@ -116,15 +118,16 @@ func (k Keeper) Instantiate(ctx sdk.Context, creator sdk.AccAddress, codeID uint
// instantiate wasm contract
gas := gasForContract(ctx)
res, err := k.wasmer.Instantiate(codeInfo.CodeHash, params, initMsg, prefixStore, gas)
res, err := k.wasmer.Instantiate(codeInfo.CodeHash, params, initMsg, prefixStore, cosmwasmAPI, gas)
if err != nil {
return contractAddress, types.ErrInstantiateFailed(err)
return contractAddress, sdkErrors.Wrap(types.ErrInstantiateFailed, err.Error())
// return contractAddress, sdkErrors.Wrap(err, "cosmwasm instantiate")
}
consumeGas(ctx, res.GasUsed)
sdkerr = k.dispatchMessages(ctx, contractAccount, res.Messages)
if sdkerr != nil {
return nil, sdkerr
err = k.dispatchMessages(ctx, contractAccount, res.Messages)
if err != nil {
return nil, err
}
// persist instance
@ -136,7 +139,7 @@ func (k Keeper) Instantiate(ctx sdk.Context, creator sdk.AccAddress, codeID uint
}
// Execute executes the contract instance
func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, coins sdk.Coins, msgs []byte) (sdk.Result, sdk.Error) {
func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, coins sdk.Coins, msg []byte) (sdk.Result, error) {
codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress)
if err != nil {
return sdk.Result{}, err
@ -150,41 +153,34 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller
params := types.NewParams(ctx, caller, coins, contractAccount)
gas := gasForContract(ctx)
res, execErr := k.wasmer.Execute(codeInfo.CodeHash, params, msgs, prefixStore, gas)
res, execErr := k.wasmer.Execute(codeInfo.CodeHash, params, msg, prefixStore, cosmwasmAPI, gas)
if execErr != nil {
return sdk.Result{}, types.ErrExecuteFailed(execErr)
return sdk.Result{}, sdkErrors.Wrap(types.ErrExecuteFailed, execErr.Error())
}
consumeGas(ctx, res.GasUsed)
sdkerr = k.dispatchMessages(ctx, contractAccount, res.Messages)
if sdkerr != nil {
return sdk.Result{}, sdkerr
err = k.dispatchMessages(ctx, contractAccount, res.Messages)
if err != nil {
return sdk.Result{}, err
}
return types.CosmosResult(*res), nil
}
// QuerySmart queries the smart contract itself.
func (k Keeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]types.Model, sdk.Error) {
func (k Keeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error) {
ctx = ctx.WithGasMeter(sdk.NewGasMeter(k.queryGasLimit))
codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr)
if err != nil {
return nil, err
}
queryResult, gasUsed, qErr := k.wasmer.Query(codeInfo.CodeHash, req, prefixStore, gasForContract(ctx))
queryResult, gasUsed, qErr := k.wasmer.Query(codeInfo.CodeHash, req, prefixStore, cosmwasmAPI, gasForContract(ctx))
if qErr != nil {
return nil, types.ErrExecuteFailed(qErr)
return nil, sdkErrors.Wrap(types.ErrQueryFailed, qErr.Error())
}
consumeGas(ctx, gasUsed)
models := make([]types.Model, len(queryResult.Results))
for i := range queryResult.Results {
models[i] = types.Model{
Key: queryResult.Results[i].Key,
Value: string(queryResult.Results[i].Value),
}
}
return models, nil
return queryResult, nil
}
// QueryRaw returns the contract's state for give key. For a `nil` key a empty slice` result is returned.
@ -205,19 +201,19 @@ func (k Keeper) QueryRaw(ctx sdk.Context, contractAddress sdk.AccAddress, key []
return result
}
func (k Keeper) contractInstance(ctx sdk.Context, contractAddress sdk.AccAddress) (types.CodeInfo, prefix.Store, sdk.Error) {
func (k Keeper) contractInstance(ctx sdk.Context, contractAddress sdk.AccAddress) (types.CodeInfo, prefix.Store, error) {
store := ctx.KVStore(k.storeKey)
contractBz := store.Get(types.GetContractAddressKey(contractAddress))
if contractBz == nil {
return types.CodeInfo{}, prefix.Store{}, types.ErrNotFound("contract")
return types.CodeInfo{}, prefix.Store{}, sdkErrors.Wrap(types.ErrNotFound, "contract")
}
var contract types.ContractInfo
k.cdc.MustUnmarshalBinaryBare(contractBz, &contract)
contractInfoBz := store.Get(types.GetCodeKey(contract.CodeID))
if contractInfoBz == nil {
return types.CodeInfo{}, prefix.Store{}, types.ErrNotFound("contract info")
return types.CodeInfo{}, prefix.Store{}, sdkErrors.Wrap(types.ErrNotFound, "contract info")
}
var codeInfo types.CodeInfo
k.cdc.MustUnmarshalBinaryBare(contractInfoBz, &codeInfo)
@ -291,7 +287,7 @@ func (k Keeper) GetByteCode(ctx sdk.Context, codeID uint64) ([]byte, error) {
return k.wasmer.GetCode(codeInfo.CodeHash)
}
func (k Keeper) dispatchMessages(ctx sdk.Context, contract exported.Account, msgs []wasmTypes.CosmosMsg) sdk.Error {
func (k Keeper) dispatchMessages(ctx sdk.Context, contract exported.Account, msgs []wasmTypes.CosmosMsg) error {
for _, msg := range msgs {
if err := k.dispatchMessage(ctx, contract, msg); err != nil {
return err
@ -300,7 +296,7 @@ func (k Keeper) dispatchMessages(ctx sdk.Context, contract exported.Account, msg
return nil
}
func (k Keeper) dispatchMessage(ctx sdk.Context, contract exported.Account, msg wasmTypes.CosmosMsg) sdk.Error {
func (k Keeper) dispatchMessage(ctx sdk.Context, contract exported.Account, msg wasmTypes.CosmosMsg) error {
// we check each type (pointers would make it easier to test if set)
if msg.Send.FromAddress != "" {
sendMsg, err := convertCosmosSendMsg(msg.Send)
@ -356,23 +352,23 @@ func convertCosmosSendMsg(msg wasmTypes.SendMsg) (bank.MsgSend, sdk.Error) {
return sendMsg, nil
}
func (k Keeper) handleSdkMessage(ctx sdk.Context, contract exported.Account, msg sdk.Msg) sdk.Error {
func (k Keeper) handleSdkMessage(ctx sdk.Context, contract exported.Account, msg sdk.Msg) error {
// make sure this account can send it
contractAddr := contract.GetAddress()
for _, acct := range msg.GetSigners() {
if !acct.Equals(contractAddr) {
return sdk.ErrUnauthorized("contract doesn't have permission")
return sdkErrors.Wrap(sdkErrors.ErrUnauthorized, "contract doesn't have permission")
}
}
// find the handler and execute it
h := k.router.Route(msg.Route())
if h == nil {
return sdk.ErrUnknownRequest(msg.Route())
return sdkErrors.Wrap(sdkErrors.ErrUnknownRequest, msg.Route())
}
res := h(ctx, msg)
if !res.IsOK() {
return sdk.NewError(res.Codespace, res.Code, res.Log)
return sdkErrors.ABCIError(string(res.Codespace), uint32(res.Code), res.Log)
}
return nil
}

View File

@ -1,6 +1,7 @@
package keeper
import (
"encoding/binary"
"encoding/json"
"io/ioutil"
"os"
@ -84,9 +85,12 @@ func TestInstantiate(t *testing.T) {
contractID, err := keeper.Create(ctx, creator, wasmCode, "", "")
require.NoError(t, err)
_, _, bob := keyPubAddr()
_, _, fred := keyPubAddr()
initMsg := InitMsg{
Verifier: "fred",
Beneficiary: "bob",
Verifier: fred,
Beneficiary: bob,
}
initMsgBz, err := json.Marshal(initMsg)
require.NoError(t, err)
@ -99,8 +103,7 @@ func TestInstantiate(t *testing.T) {
require.Equal(t, "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", addr.String())
gasAfter := ctx.GasMeter().GasConsumed()
kvStoreGas := uint64(28757) // calculated by disabling contract gas reduction and running test
require.Equal(t, kvStoreGas+288, gasAfter-gasBefore)
require.Equal(t, uint64(36698), gasAfter-gasBefore)
}
func TestInstantiateWithNonExistingCodeID(t *testing.T) {
@ -120,7 +123,7 @@ func TestInstantiateWithNonExistingCodeID(t *testing.T) {
const nonExistingCodeID = 9999
addr, err := keeper.Instantiate(ctx, creator, nonExistingCodeID, initMsgBz, nil)
require.Error(t, err, types.ErrNotFound("contract"))
require.True(t, types.ErrNotFound.Is(err), err)
require.Nil(t, addr)
}
@ -143,8 +146,8 @@ func TestExecute(t *testing.T) {
_, _, bob := keyPubAddr()
initMsg := InitMsg{
Verifier: fred.String(),
Beneficiary: bob.String(),
Verifier: fred,
Beneficiary: bob,
}
initMsgBz, err := json.Marshal(initMsg)
require.NoError(t, err)
@ -182,12 +185,11 @@ func TestExecute(t *testing.T) {
diff := time.Now().Sub(start)
require.NoError(t, err)
require.NotNil(t, res)
assert.Equal(t, uint64(81778), res.GasUsed)
assert.Equal(t, uint64(119513), res.GasUsed)
// make sure gas is properly deducted from ctx
gasAfter := ctx.GasMeter().GasConsumed()
kvStoreGas := uint64(30321) // calculated by disabling contract gas reduction and running test
require.Equal(t, kvStoreGas+814, gasAfter-gasBefore)
require.Equal(t, uint64(31723), gasAfter-gasBefore)
// ensure bob now exists and got both payments released
bobAcct = accKeeper.GetAccount(ctx, bob)
@ -215,12 +217,12 @@ func TestExecuteWithNonExistingAddress(t *testing.T) {
// unauthorized - trialCtx so we don't change state
nonExistingAddress := addrFromUint64(9999)
_, err = keeper.Execute(ctx, nonExistingAddress, creator, nil, []byte(`{}`))
require.Error(t, err, types.ErrNotFound("contract info"))
require.True(t, types.ErrNotFound.Is(err), err)
}
type InitMsg struct {
Verifier string `json:"verifier"`
Beneficiary string `json:"beneficiary"`
Verifier sdk.AccAddress `json:"verifier"`
Beneficiary sdk.AccAddress `json:"beneficiary"`
}
func createFakeFundedAccount(ctx sdk.Context, am auth.AccountKeeper, coins sdk.Coins) sdk.AccAddress {
@ -232,8 +234,16 @@ func createFakeFundedAccount(ctx sdk.Context, am auth.AccountKeeper, coins sdk.C
return addr
}
var keyCounter uint64 = 0
// we need to make this deterministic (same every test run), as encoded address size and thus gas cost,
// depends on the actual bytes (due to ugly CanonicalAddress encoding)
func keyPubAddr() (crypto.PrivKey, crypto.PubKey, sdk.AccAddress) {
key := ed25519.GenPrivKey()
keyCounter++
seed := make([]byte, 8)
binary.BigEndian.PutUint64(seed, keyCounter)
key := ed25519.GenPrivKeyFromSecret(seed)
pub := key.PubKey()
addr := sdk.AccAddress(pub.Address())
return key, pub, addr

View File

@ -5,6 +5,7 @@ import (
"strconv"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkErrors "github.com/cosmos/cosmos-sdk/types/errors"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
@ -26,9 +27,28 @@ const (
QueryMethodContractStateRaw = "raw"
)
// controls error output on querier - set true when testing/debugging
const debug = false
// NewQuerier creates a new querier
func NewQuerier(keeper Keeper) sdk.Querier {
q := newQuerier(keeper)
return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) {
res, err := q(ctx, path, req)
// convert returned errors
if err != nil {
space, code, log := sdkErrors.ABCIInfo(err, debug)
sdkErr := sdk.NewError(sdk.CodespaceType(space), sdk.CodeType(code), log)
return nil, sdkErr
}
return res, nil
}
}
// pull this out as a separate function for testing.
// this returns proper error before redacting, NewQuerier is adapting to 0.37 style
func newQuerier(keeper Keeper) func(sdk.Context, []string, abci.RequestQuery) ([]byte, error) {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) {
switch path[0] {
case QueryGetContract:
return queryContractInfo(ctx, path[1], req, keeper)
@ -36,7 +56,7 @@ func NewQuerier(keeper Keeper) sdk.Querier {
return queryContractList(ctx, req, keeper)
case QueryGetContractState:
if len(path) < 3 {
return nil, sdk.ErrUnknownRequest("unknown data query endpoint")
return nil, sdkErrors.Wrap(sdkErrors.ErrUnknownRequest, "unknown data query endpoint")
}
return queryContractState(ctx, path[1], path[2], req, keeper)
case QueryGetCode:
@ -44,7 +64,7 @@ func NewQuerier(keeper Keeper) sdk.Querier {
case QueryListCode:
return queryCodeList(ctx, req, keeper)
default:
return nil, sdk.ErrUnknownRequest("unknown data query endpoint")
return nil, sdkErrors.Wrap(sdkErrors.ErrUnknownRequest, "unknown data query endpoint")
}
}
}
@ -63,7 +83,7 @@ func queryContractInfo(ctx sdk.Context, bech string, req abci.RequestQuery, keep
return bz, nil
}
func queryContractList(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) {
func queryContractList(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
var addrs []string
keeper.ListContractInfo(ctx, func(addr sdk.AccAddress, _ types.ContractInfo) bool {
addrs = append(addrs, addr.String())
@ -71,15 +91,15 @@ func queryContractList(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([
})
bz, err := json.MarshalIndent(addrs, "", " ")
if err != nil {
return nil, sdk.ErrInvalidAddress(err.Error())
return nil, sdkErrors.Wrap(sdkErrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryContractState(ctx sdk.Context, bech, queryMethod string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) {
func queryContractState(ctx sdk.Context, bech, queryMethod string, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
contractAddr, err := sdk.AccAddressFromBech32(bech)
if err != nil {
return nil, sdk.ErrUnknownRequest(err.Error())
return nil, sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, bech)
}
var resultData []types.Model
@ -97,39 +117,35 @@ func queryContractState(ctx sdk.Context, bech, queryMethod string, req abci.Requ
case QueryMethodContractStateRaw:
resultData = keeper.QueryRaw(ctx, contractAddr, req.Data)
case QueryMethodContractStateSmart:
res, err := keeper.QuerySmart(ctx, contractAddr, req.Data)
if err != nil {
return nil, err
}
resultData = res
return keeper.QuerySmart(ctx, contractAddr, req.Data)
default:
return nil, sdk.ErrUnknownRequest("unsupported data query method for contract-state")
return nil, sdkErrors.Wrap(sdkErrors.ErrUnknownRequest, queryMethod)
}
bz, err := json.MarshalIndent(resultData, "", " ")
if err != nil {
return nil, sdk.ErrUnknownRequest(err.Error())
return nil, sdkErrors.Wrap(sdkErrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
type GetCodeResponse struct {
Code []byte `json:"code", yaml:"code"`
Code []byte `json:"code" yaml:"code"`
}
func queryCode(ctx sdk.Context, codeIDstr string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) {
func queryCode(ctx sdk.Context, codeIDstr string, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
codeID, err := strconv.ParseUint(codeIDstr, 10, 64)
if err != nil {
return nil, sdk.ErrUnknownRequest("invalid codeID: " + err.Error())
return nil, sdkErrors.Wrap(sdkErrors.ErrUnknownRequest, "invalid codeID: "+err.Error())
}
code, err := keeper.GetByteCode(ctx, codeID)
if err != nil {
return nil, sdk.ErrUnknownRequest("loading wasm code: " + err.Error())
return nil, sdkErrors.Wrap(err, "loading wasm code")
}
bz, err := json.MarshalIndent(GetCodeResponse{code}, "", " ")
if err != nil {
return nil, sdk.ErrUnknownRequest(err.Error())
return nil, sdkErrors.Wrap(sdkErrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
@ -140,7 +156,7 @@ type ListCodeResponse struct {
CodeHash cmn.HexBytes `json:"code_hash"`
}
func queryCodeList(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) {
func queryCodeList(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
var info []ListCodeResponse
var i uint64
@ -159,7 +175,7 @@ func queryCodeList(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byt
bz, err := json.MarshalIndent(info, "", " ")
if err != nil {
return nil, sdk.ErrUnknownRequest(err.Error())
return nil, sdkErrors.Wrap(sdkErrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}

View File

@ -7,6 +7,7 @@ import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkErrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmwasm/wasmd/x/wasm/internal/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -37,8 +38,8 @@ func TestQueryContractState(t *testing.T) {
_, _, bob := keyPubAddr()
initMsg := InitMsg{
Verifier: anyAddr.String(),
Beneficiary: bob.String(),
Verifier: anyAddr,
Beneficiary: bob,
}
initMsgBz, err := json.Marshal(initMsg)
require.NoError(t, err)
@ -53,13 +54,18 @@ func TestQueryContractState(t *testing.T) {
}
keeper.setContractState(ctx, addr, contractModel)
q := NewQuerier(keeper)
// this gets us full error, not redacted sdk.Error
q := newQuerier(keeper)
specs := map[string]struct {
srcPath []string
srcReq abci.RequestQuery
srcPath []string
srcReq abci.RequestQuery
// smart queries return raw bytes from contract not []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
expModelLen int
expModelContains []model
expErr sdk.Error
expErr *sdkErrors.Error
}{
"query all": {
srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateAll},
@ -83,9 +89,13 @@ func TestQueryContractState(t *testing.T) {
},
"query smart": {
srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateSmart},
srcReq: abci.RequestQuery{Data: []byte(`{"raw":{"key":"config"}}`)},
expModelLen: 1,
//expModelContains: []model{}, // stopping here as contract internals are not stable
srcReq: abci.RequestQuery{Data: []byte(`{"verifier":{}}`)},
expSmartRes: "cosmos1uf348t8j0h06ghr5udaw0hvlj9fhemhlsvve0f",
},
"query smart invalid request": {
srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateSmart},
srcReq: abci.RequestQuery{Data: []byte(`{"raw":{"key":"config"}}`)},
expErr: types.ErrQueryFailed,
},
"query unknown raw key": {
srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateRaw},
@ -107,15 +117,23 @@ func TestQueryContractState(t *testing.T) {
"query smart with unknown address": {
srcPath: []string{QueryGetContractState, anyAddr.String(), QueryMethodContractStateSmart},
expModelLen: 0,
expErr: types.ErrNotFound("contract"),
expErr: types.ErrNotFound,
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
binResult, err := q(ctx, spec.srcPath, spec.srcReq)
require.Equal(t, spec.expErr, err)
// then
// require.True(t, spec.expErr.Is(err), "unexpected error")
require.True(t, spec.expErr.Is(err), err)
// if smart query, check custom response
if spec.expSmartRes != "" {
require.Equal(t, spec.expSmartRes, string(binResult))
return
}
// otherwise, check returned models
var r []model
if spec.expErr == nil {
require.NoError(t, json.Unmarshal(binResult, &r))

Binary file not shown.

View File

@ -1,55 +1,34 @@
package types
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkErrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// Codes for wasm contract errors
const (
DefaultCodespace sdk.CodespaceType = ModuleName
var (
DefaultCodespace = ModuleName
CodeCreatedFailed sdk.CodeType = 1
CodeAccountExists sdk.CodeType = 2
CodeInstantiateFailed sdk.CodeType = 3
CodeExecuteFailed sdk.CodeType = 4
CodeGasLimit sdk.CodeType = 5
CodeInvalidGenesis sdk.CodeType = 6
CodeNotFound sdk.CodeType = 7
// ErrCreateFailed error for wasm code that has already been uploaded or failed
ErrCreateFailed = sdkErrors.Register(DefaultCodespace, 1, "create wasm contract failed")
// ErrAccountExists error for a contract account that already exists
ErrAccountExists = sdkErrors.Register(DefaultCodespace, 2, "contract account already exists")
// ErrInstantiateFailed error for rust instantiate contract failure
ErrInstantiateFailed = sdkErrors.Register(DefaultCodespace, 3, "instantiate wasm contract failed")
// ErrExecuteFailed error for rust execution contract failure
ErrExecuteFailed = sdkErrors.Register(DefaultCodespace, 4, "execute wasm contract failed")
// ErrGasLimit error for out of gas
ErrGasLimit = sdkErrors.Register(DefaultCodespace, 5, "insufficient gas")
// ErrInvalidGenesis error for invalid genesis file syntax
ErrInvalidGenesis = sdkErrors.Register(DefaultCodespace, 6, "invalid genesis")
// ErrNotFound error for an entry not found in the store
ErrNotFound = sdkErrors.Register(DefaultCodespace, 7, "not found")
// ErrQueryFailed error for rust smart query contract failure
ErrQueryFailed = sdkErrors.Register(DefaultCodespace, 8, "query wasm contract failed")
)
// ErrCreateFailed error for wasm code that has already been uploaded or failed
func ErrCreateFailed(err error) sdk.Error {
return sdk.NewError(DefaultCodespace, CodeCreatedFailed, fmt.Sprintf("create wasm contract failed: %s", err.Error()))
}
// ErrAccountExists error for a contract account that already exists
func ErrAccountExists(addr sdk.AccAddress) sdk.Error {
return sdk.NewError(DefaultCodespace, CodeAccountExists, fmt.Sprintf("contract account %s already exists", addr.String()))
}
// ErrInstantiateFailed error for rust instantiate contract failure
func ErrInstantiateFailed(err error) sdk.Error {
return sdk.NewError(DefaultCodespace, CodeInstantiateFailed, fmt.Sprintf("instantiate wasm contract failed: %s", err.Error()))
}
// ErrExecuteFailed error for rust execution contract failure
func ErrExecuteFailed(err error) sdk.Error {
return sdk.NewError(DefaultCodespace, CodeExecuteFailed, fmt.Sprintf("execute wasm contract failed: %s", err.Error()))
}
// ErrGasLimit error for out of gas
func ErrGasLimit(msg string) sdk.Error {
return sdk.NewError(DefaultCodespace, CodeGasLimit, fmt.Sprintf("insufficient gas: %s", msg))
}
// ErrInvalidGenesis error for out of gas
func ErrInvalidGenesis(msg string) sdk.Error {
return sdk.NewError(DefaultCodespace, CodeInvalidGenesis, fmt.Sprintf("invalid genesis: %s", msg))
}
// ErrNotFound error for an entry not found in the stoe
func ErrNotFound(msg string) sdk.Error {
return sdk.NewError(DefaultCodespace, CodeNotFound, fmt.Sprintf("not found: %s", msg))
}

View File

@ -46,11 +46,11 @@ func NewParams(ctx sdk.Context, creator sdk.AccAddress, deposit sdk.Coins, contr
ChainID: ctx.ChainID(),
},
Message: wasmTypes.MessageInfo{
Signer: creator.String(),
Signer: wasmTypes.CanonicalAddress(creator),
SentFunds: NewWasmCoins(deposit),
},
Contract: wasmTypes.ContractInfo{
Address: contractAcct.GetAddress().String(),
Address: wasmTypes.CanonicalAddress(contractAcct.GetAddress()),
Balance: NewWasmCoins(contractAcct.GetCoins()),
},
}

View File

@ -7,17 +7,18 @@ import (
"os"
"testing"
"github.com/cosmwasm/wasmd/x/wasm/internal/keeper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
wasmTypes "github.com/confio/go-cosmwasm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmwasm/wasmd/x/wasm/internal/keeper"
)
type testData struct {
@ -119,14 +120,14 @@ func TestHandleCreate(t *testing.T) {
}
type initMsg struct {
Verifier string `json:"verifier"`
Beneficiary string `json:"beneficiary"`
Verifier sdk.AccAddress `json:"verifier"`
Beneficiary sdk.AccAddress `json:"beneficiary"`
}
type state struct {
Verifier string `json:"verifier"`
Beneficiary string `json:"beneficiary"`
Funder string `json:"funder"`
Verifier wasmTypes.CanonicalAddress `json:"verifier"`
Beneficiary wasmTypes.CanonicalAddress `json:"beneficiary"`
Funder wasmTypes.CanonicalAddress `json:"funder"`
}
func TestHandleInstantiate(t *testing.T) {
@ -147,9 +148,12 @@ func TestHandleInstantiate(t *testing.T) {
require.True(t, res.IsOK())
require.Equal(t, res.Data, []byte("1"))
_, _, bob := keyPubAddr()
_, _, fred := keyPubAddr()
initMsg := initMsg{
Verifier: "fred",
Beneficiary: "bob",
Verifier: fred,
Beneficiary: bob,
}
initMsgBz, err := json.Marshal(initMsg)
require.NoError(t, err)
@ -162,7 +166,7 @@ func TestHandleInstantiate(t *testing.T) {
InitFunds: nil,
}
res = h(data.ctx, initCmd)
require.True(t, res.IsOK())
require.True(t, res.IsOK(), res.Log)
contractAddr := sdk.AccAddress(res.Data)
require.Equal(t, "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", contractAddr.String())
@ -172,9 +176,9 @@ func TestHandleInstantiate(t *testing.T) {
assertContractList(t, q, data.ctx, []string{contractAddr.String()})
assertContractInfo(t, q, data.ctx, contractAddr, 1, creator)
assertContractState(t, q, data.ctx, contractAddr, state{
Verifier: "fred",
Beneficiary: "bob",
Funder: creator.String(),
Verifier: []byte(fred),
Beneficiary: []byte(bob),
Funder: []byte(creator),
})
}
@ -200,8 +204,8 @@ func TestHandleExecute(t *testing.T) {
_, _, bob := keyPubAddr()
initMsg := initMsg{
Verifier: fred.String(),
Beneficiary: bob.String(),
Verifier: fred,
Beneficiary: bob,
}
initMsgBz, err := json.Marshal(initMsg)
require.NoError(t, err)
@ -259,9 +263,9 @@ func TestHandleExecute(t *testing.T) {
assertContractList(t, q, data.ctx, []string{contractAddr.String()})
assertContractInfo(t, q, data.ctx, contractAddr, 1, creator)
assertContractState(t, q, data.ctx, contractAddr, state{
Verifier: fred.String(),
Beneficiary: bob.String(),
Funder: creator.String(),
Verifier: []byte(fred),
Beneficiary: []byte(bob),
Funder: []byte(creator),
})
}
@ -281,7 +285,7 @@ func TestHandleExecuteEscrow(t *testing.T) {
WASMByteCode: escrowContract,
}
res := h(data.ctx, &msg)
require.True(t, res.IsOK())
require.True(t, res.IsOK(), res.Log)
require.Equal(t, res.Data, []byte("1"))
_, _, bob := keyPubAddr()

Binary file not shown.