Skip to content

Commit

Permalink
add wasm testcode
Browse files Browse the repository at this point in the history
  • Loading branch information
Yun committed May 26, 2020
1 parent 7ba803e commit abf239b
Show file tree
Hide file tree
Showing 19 changed files with 405 additions and 59 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.13

require (
github.com/CosmWasm/go-cosmwasm v0.8.0
github.com/cosmos/cosmos-sdk v0.38.3
github.com/cosmos/cosmos-sdk v0.38.4
github.com/gorilla/mux v1.7.3
github.com/otiai10/copy v1.0.2
github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosmos/cosmos-sdk v0.38.3 h1:qIBTiw+2T9POaSUJ5rvbBbXeq8C8btBlJxnSegPBd3Y=
github.com/cosmos/cosmos-sdk v0.38.3/go.mod h1:rzWOofbKfRt3wxiylmYWEFHnxxGj0coyqgWl2I9obAw=
github.com/cosmos/cosmos-sdk v0.38.4 h1:jPZOvhMQkm7wwwzcLxuluhVpKfuIgddNGt999pAiz/Y=
github.com/cosmos/cosmos-sdk v0.38.4/go.mod h1:rzWOofbKfRt3wxiylmYWEFHnxxGj0coyqgWl2I9obAw=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4=
Expand Down
1 change: 0 additions & 1 deletion x/wasm/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const (
TStoreKey = types.TStoreKey
QuerierRoute = types.QuerierRoute
RouterKey = types.RouterKey
MaxWasmSize = types.MaxWasmSize
WasmMsgParserRouteBank = types.WasmMsgParserRouteBank
WasmMsgParserRouteStaking = types.WasmMsgParserRouteStaking
WasmMsgParserRouteWasm = types.WasmMsgParserRouteWasm
Expand Down
26 changes: 19 additions & 7 deletions x/wasm/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ func StoreCodeCmd(cdc *codec.Codec) *cobra.Command {
}

// limit the input size
if len(wasm) > types.MaxWasmSize {
return fmt.Errorf("input size exceeds the max size hard-cap (allowed:%d, actual: %d)",
types.MaxWasmSize, len(wasm))
if wasmLen := uint64(len(wasm)); wasmLen > types.EnforcedMaxContractSize {
return fmt.Errorf("wasm code size exceeds the max size hard-cap (allowed:%d, actual: %d)",
types.EnforcedMaxContractSize, wasmLen)
}

// gzip the wasm file
Expand Down Expand Up @@ -124,7 +124,13 @@ $ terracli instantiate 1 '{"arbiter": "terra~~"}' "1000000uluna"
return err
}

initMsg := args[1]
initMsgBz := []byte(args[1])

// limit the input size
if initMsgLen := uint64(len(initMsgBz)); initMsgLen > types.EnforcedMaxContractMsgSize {
return fmt.Errorf("init msg size exceeds the max size hard-cap (allowed:%d, actual: %d)",
types.EnforcedMaxContractMsgSize, initMsgLen)
}

var coins sdk.Coins
if len(args) == 3 {
Expand All @@ -139,7 +145,7 @@ $ terracli instantiate 1 '{"arbiter": "terra~~"}' "1000000uluna"
Sender: fromAddr,
CodeID: codeID,
InitCoins: coins,
InitMsg: []byte(initMsg),
InitMsg: initMsgBz,
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
Expand Down Expand Up @@ -170,7 +176,13 @@ func ExecuteContractCmd(cdc *codec.Codec) *cobra.Command {
return err
}

execMsg := args[1]
execMsgBz := []byte(args[1])

// limit the input size
if execMsgLen := uint64(len(execMsgBz)); execMsgLen > types.EnforcedMaxContractMsgSize {
return fmt.Errorf("exec msg size exceeds the max size hard-cap (allowed:%d, actual: %d)",
types.EnforcedMaxContractMsgSize, execMsgLen)
}

var coins sdk.Coins
if len(args) == 3 {
Expand All @@ -185,7 +197,7 @@ func ExecuteContractCmd(cdc *codec.Codec) *cobra.Command {
Sender: fromAddr,
Contract: contractAddr,
Coins: coins,
Msg: []byte(execMsg),
Msg: execMsgBz,
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
Expand Down
6 changes: 0 additions & 6 deletions x/wasm/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,10 @@ func NewHandler(k Keeper) sdk.Handler {
switch msg := msg.(type) {
case MsgStoreCode:
return handleStoreCode(ctx, k, &msg)
case *MsgStoreCode:
return handleStoreCode(ctx, k, msg)
case MsgInstantiateContract:
return handleInstantiate(ctx, k, &msg)
case *MsgInstantiateContract:
return handleInstantiate(ctx, k, msg)
case MsgExecuteContract:
return handleExecute(ctx, k, &msg)
case *MsgExecuteContract:
return handleExecute(ctx, k, msg)

default:
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized distribution message type: %T", msg)
Expand Down
2 changes: 1 addition & 1 deletion x/wasm/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ func TestHandleExecuteEscrow(t *testing.T) {
Sender: creator,
WASMByteCode: testContract,
}
_, err := h(data.ctx, &msg)
_, err := h(data.ctx, msg)
require.NoError(t, err)

bytecode, sdkErr := data.keeper.GetByteCode(data.ctx, 1)
Expand Down
16 changes: 14 additions & 2 deletions x/wasm/internal/keeper/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import (

// StoreCode uploads and compiles a WASM contract bytecode, returning a short identifier for the stored code
func (k Keeper) StoreCode(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte) (codeID uint64, err error) {
if uint64(len(wasmCode)) > k.MaxContractSize(ctx) {
return 0, sdkerrors.Wrap(types.ErrStoreCodeFailed, "contract size is too huge")
}

wasmCode, err = k.uncompress(ctx, wasmCode)
if err != nil {
return 0, sdkerrors.Wrap(types.ErrStoreCodeFailed, err.Error())
Expand All @@ -38,6 +42,10 @@ func (k Keeper) StoreCode(ctx sdk.Context, creator sdk.AccAddress, wasmCode []by

// InstantiateContract creates an instance of a WASM contract
func (k Keeper) InstantiateContract(ctx sdk.Context, codeID uint64, creator sdk.AccAddress, initMsg []byte, deposit sdk.Coins) (contractAddress sdk.AccAddress, err error) {
if uint64(len(initMsg)) > k.MaxContractMsgSize(ctx) {
return nil, sdkerrors.Wrap(types.ErrInstantiateFailed, "init msg size is too huge")
}

instanceID, err := k.GetLastInstanceID(ctx)
if err != nil {
return nil, err
Expand Down Expand Up @@ -107,7 +115,11 @@ func (k Keeper) InstantiateContract(ctx sdk.Context, codeID uint64, creator sdk.
}

// ExecuteContract executes the contract instance
func (k Keeper) ExecuteContract(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) (sdk.Result, error) {
func (k Keeper) ExecuteContract(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, exeMsg []byte, coins sdk.Coins) (sdk.Result, error) {
if uint64(len(exeMsg)) > k.MaxContractMsgSize(ctx) {
return sdk.Result{}, sdkerrors.Wrap(types.ErrInstantiateFailed, "execute msg size is too huge")
}

codeInfo, storePrefix, sdkerr := k.getContractDetails(ctx, contractAddress)
if sdkerr != nil {
return sdk.Result{}, sdkerr
Expand All @@ -124,7 +136,7 @@ func (k Keeper) ExecuteContract(ctx sdk.Context, contractAddress sdk.AccAddress,
apiParams := types.NewWasmAPIParams(ctx, caller, coins, contractAddress)

gas := k.gasForContract(ctx)
res, err := k.wasmer.Execute(codeInfo.CodeHash.Bytes(), apiParams, msg, storePrefix, cosmwasmAPI, k.querier.WithCtx(ctx), gas)
res, err := k.wasmer.Execute(codeInfo.CodeHash.Bytes(), apiParams, exeMsg, storePrefix, cosmwasmAPI, k.querier.WithCtx(ctx), gas)
if err != nil {
// TODO: wasmer doesn't return wasm gas used on error. we should consume it (for error on metering failure)
// Note: OutOfGas panics (from storage) are caught by go-cosmwasm, subtract one more gas to check if
Expand Down
83 changes: 82 additions & 1 deletion x/wasm/internal/keeper/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,24 @@ func TestStoreCode(t *testing.T) {
require.Equal(t, wasmCode, storedCode)
}

func TestStoreCodeWithHugeCode(t *testing.T) {
// Create & set temp as home
tempDir, err := ioutil.TempDir("", "wasmtest")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
viper.Set(flags.FlagHome, tempDir)

input := CreateTestInput(t)
ctx, keeper := input.Ctx, input.WasmKeeper

_, _, creator := keyPubAddr()
wasmCode := make([]byte, keeper.MaxContractSize(ctx)+1)
_, err = keeper.StoreCode(ctx, creator, wasmCode)

require.Error(t, err)
require.Contains(t, err.Error(), "contract size is too huge")
}

func TestCreateWithGzippedPayload(t *testing.T) {
// Create & set temp as home
tempDir, err := ioutil.TempDir("", "wasmtest")
Expand Down Expand Up @@ -127,6 +145,31 @@ func TestInstantiateWithNonExistingCodeID(t *testing.T) {
require.Error(t, err, sdkerrors.Wrapf(types.ErrNotFound, "codeID %d", nonExistingCodeID))
}

func TestInstantiateWithBigInitMsg(t *testing.T) {
// Create & set temp as home
tempDir, err := ioutil.TempDir("", "wasmtest")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
viper.Set(flags.FlagHome, tempDir)
input := CreateTestInput(t)
ctx, accKeeper, keeper := input.Ctx, input.AccKeeper, input.WasmKeeper

deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit)

wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
require.NoError(t, err)

codeID, err := keeper.StoreCode(ctx, creator, wasmCode)
require.NoError(t, err)

// test max init msg size
initMsgBz := make([]byte, keeper.MaxContractMsgSize(ctx)+1)
_, err = keeper.InstantiateContract(ctx, codeID, creator, initMsgBz, deposit)
require.Error(t, err)
require.Contains(t, err.Error(), "init msg size is too huge")
}

func TestExecute(t *testing.T) {
// Create & set temp as home
tempDir, err := ioutil.TempDir("", "wasmtest")
Expand Down Expand Up @@ -191,7 +234,7 @@ func TestExecute(t *testing.T) {

// make sure gas is properly deducted from ctx
gasAfter := ctx.GasMeter().GasConsumed()
require.Equal(t, uint64(0x8b2d), gasAfter-gasBefore)
require.Equal(t, uint64(0x8f21), gasAfter-gasBefore)

// ensure bob now exists and got both payments released
bobAcct = accKeeper.GetAccount(ctx, bob)
Expand Down Expand Up @@ -225,6 +268,44 @@ func TestExecuteWithNonExistingContractAddress(t *testing.T) {
require.Error(t, err, sdkerrors.Wrapf(types.ErrNotFound, "contract %s", nonExistingContractAddress))
}

func TestExecuteWithHugeMsg(t *testing.T) {
// Create & set temp as home
tempDir, err := ioutil.TempDir("", "wasmtest")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
viper.Set(flags.FlagHome, tempDir)
input := CreateTestInput(t)
ctx, accKeeper, keeper := input.Ctx, input.AccKeeper, input.WasmKeeper

deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit.Add(deposit...))
fred := createFakeFundedAccount(ctx, accKeeper, topUp)

wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
require.NoError(t, err)

codeID, err := keeper.StoreCode(ctx, creator, wasmCode)
require.NoError(t, err)

_, _, bob := keyPubAddr()
initMsg := InitMsg{
Verifier: fred,
Beneficiary: bob,
}
initMsgBz, err := json.Marshal(initMsg)
require.NoError(t, err)

addr, err := keeper.InstantiateContract(ctx, codeID, creator, initMsgBz, deposit)
require.NoError(t, err)
require.Equal(t, "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", addr.String())

msgBz := make([]byte, keeper.MaxContractMsgSize(ctx)+1)
_, err = keeper.ExecuteContract(ctx, addr, fred, msgBz, topUp)
require.Error(t, err)
require.Contains(t, err.Error(), "execute msg size is too huge")
}

func TestExecuteWithPanic(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
Expand Down
2 changes: 1 addition & 1 deletion x/wasm/internal/keeper/ioutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ func (k Keeper) uncompress(ctx sdk.Context, src []byte) ([]byte, error) {
}
zr.Multistream(false)

return ioutil.ReadAll(io.LimitReader(zr, k.MaxContractSize(ctx)))
return ioutil.ReadAll(io.LimitReader(zr, int64(k.MaxContractSize(ctx))))
}
8 changes: 7 additions & 1 deletion x/wasm/internal/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

// MaxContractSize defines maximum bytes size of a contract
func (k Keeper) MaxContractSize(ctx sdk.Context) (res int64) {
func (k Keeper) MaxContractSize(ctx sdk.Context) (res uint64) {
k.paramSpace.Get(ctx, types.ParamStoreKeyMaxContractSize, &res)
return
}
Expand All @@ -17,6 +17,12 @@ func (k Keeper) MaxContractGas(ctx sdk.Context) (res uint64) {
return
}

// MaxContractMsgSize defines maximum bytes size of a contract
func (k Keeper) MaxContractMsgSize(ctx sdk.Context) (res uint64) {
k.paramSpace.Get(ctx, types.ParamStoreKeyMaxContractMsgSize, &res)
return
}

// GasMultiplier defines how many cosmwasm gas points = 1 sdk gas point
func (k Keeper) GasMultiplier(ctx sdk.Context) (res uint64) {
k.paramSpace.Get(ctx, types.ParamStoreKeyGasMultiplier, &res)
Expand Down
1 change: 1 addition & 0 deletions x/wasm/internal/keeper/test_utils.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// nolint:deadcode unused noalias
package keeper

import (
Expand Down
30 changes: 29 additions & 1 deletion x/wasm/internal/types/genesis.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package types

import (
"bytes"

sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

// GenesisState is the struct representation of the export genesis
type GenesisState struct {
Params Params `json:"params" yaml:"params"`
Expand Down Expand Up @@ -46,5 +52,27 @@ func DefaultGenesisState() GenesisState {
// ValidateGenesis performs basic validation of wasm genesis data returning an
// error for any failed validation criteria.
func ValidateGenesis(data GenesisState) error {
return nil

if uint64(len(data.Codes)) != data.LastCodeID {
return sdkerrors.Wrap(ErrInvalidGenesis, "the number of codes is not met with LastCodeID")
}

if uint64(len(data.Contracts)) != data.LastInstanceID {
return sdkerrors.Wrap(ErrInvalidGenesis, "the number of contracts is not met with LastInstanceID")
}

return data.Params.Validate()
}

// Equal checks whether 2 GenesisState structs are equivalent.
func (data GenesisState) Equal(data2 GenesisState) bool {
b1 := ModuleCdc.MustMarshalBinaryBare(data)
b2 := ModuleCdc.MustMarshalBinaryBare(data2)
return bytes.Equal(b1, b2)
}

// IsEmpty returns if a GenesisState is empty or has data in it
func (data GenesisState) IsEmpty() bool {
emptyGenState := GenesisState{}
return data.Equal(emptyGenState)
}
Loading

0 comments on commit abf239b

Please sign in to comment.