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

Update go cosmwasm #218

Merged
merged 5 commits into from
Jul 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
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ module github.com/CosmWasm/wasmd
go 1.13

require (
// Note: update ENV GO_COSMWASM in Dockerfile when updating this
github.com/CosmWasm/go-cosmwasm v0.9.1
github.com/CosmWasm/go-cosmwasm v0.10.0-alpha2
github.com/cosmos/cosmos-sdk v0.39.0
github.com/golang/mock v1.4.3 // indirect
github.com/google/gofuzz v1.0.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQ
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4=
github.com/CosmWasm/go-cosmwasm v0.9.1 h1:w5s2o7H3cmNexct9yv8F6OLXwgxbdfVApwam7DibPqI=
github.com/CosmWasm/go-cosmwasm v0.9.1/go.mod h1:gAFCwllx97ejI+m9SqJQrmd2SBW7HA0fOjvWWJjM2uc=
github.com/CosmWasm/go-cosmwasm v0.10.0-alpha2 h1:k069wQF0f24w3A52mjR3AK6AfkuvQ5d0Mdu/rpB5nEk=
github.com/CosmWasm/go-cosmwasm v0.10.0-alpha2/go.mod h1:gAFCwllx97ejI+m9SqJQrmd2SBW7HA0fOjvWWJjM2uc=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
Expand Down
16 changes: 11 additions & 5 deletions x/wasm/internal/keeper/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,21 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

func humanAddress(canon []byte) (string, error) {
var (
CostHumanize = 5 * GasMultiplier
CostCanonical = 4 * GasMultiplier
)

func humanAddress(canon []byte) (string, uint64, error) {
if len(canon) != sdk.AddrLen {
return "", fmt.Errorf("Expected %d byte address", sdk.AddrLen)
return "", CostHumanize, fmt.Errorf("Expected %d byte address", sdk.AddrLen)
}
return sdk.AccAddress(canon).String(), nil
return sdk.AccAddress(canon).String(), CostHumanize, nil
}

func canonicalAddress(human string) ([]byte, error) {
return sdk.AccAddressFromBech32(human)
func canonicalAddress(human string) ([]byte, uint64, error) {
bz, err := sdk.AccAddressFromBech32(human)
return bz, CostCanonical, err
}

var cosmwasmAPI = cosmwasm.GoAPI{
Expand Down
35 changes: 23 additions & 12 deletions x/wasm/internal/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,9 +369,9 @@ func TestImportContractWithCodeHistoryReset(t *testing.T) {
},
"codes": [
{
"code_id": 1,
"code_id": "1",
"code_info": {
"code_hash": "mrFpzGE5s+Qfn9Xe7OikXc0q169m7sMm4ZuV6pVA8Mc=",
"code_hash": %q,
"creator": "cosmos1qtu5n0cnhfkjj6l2rq97hmky9fd89gwca9yarx",
"source": "https://example.com",
"builder": "foo/bar:tag",
Expand All @@ -387,41 +387,52 @@ func TestImportContractWithCodeHistoryReset(t *testing.T) {
{
"contract_address": "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5",
"contract_info": {
"code_id": 1,
"code_id": "1",
"creator": "cosmos13x849jzd03vne42ynpj25hn8npjecxqrjghd8x",
"admin": "cosmos1h5t8zxmjr30e9dqghtlpl40f2zz5cgey6esxtn",
"label": "ȀĴnZV芢毤"
}
}
],
"sequences": [
{"id_key": %q, "value": "2"},
{"id_key": %q, "value": "2"}
]
}`
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
require.NoError(t, err)

keeper, ctx, _, dstCleanup := setupKeeper(t)
defer dstCleanup()

ctx = ctx.WithBlockHeight(0).WithGasMeter(sdk.NewInfiniteGasMeter())
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
require.NoError(t, err)

wasmCodeHash := sha256.Sum256(wasmCode)
enc64 := base64.StdEncoding.EncodeToString
var importState wasmTypes.GenesisState
err = json.Unmarshal([]byte(fmt.Sprintf(genesis, base64.StdEncoding.EncodeToString(wasmCode))), &importState)
err = keeper.cdc.UnmarshalJSON([]byte(
fmt.Sprintf(genesis, enc64(wasmCodeHash[:]), enc64(wasmCode),
enc64(append([]byte{0x04}, []byte("lastCodeId")...)),
enc64(append([]byte{0x04}, []byte("lastContractId")...))),
), &importState)
require.NoError(t, err)
require.NoError(t, importState.ValidateBasic())

ctx = ctx.WithBlockHeight(0).WithGasMeter(sdk.NewInfiniteGasMeter())

// when
InitGenesis(ctx, keeper, importState)
err = InitGenesis(ctx, keeper, importState)
require.NoError(t, err)

// verify wasm code
gotWasmCode, err := keeper.GetByteCode(ctx, 1)
require.NoError(t, err)
assert.Equal(t, wasmCode, gotWasmCode)
assert.Equal(t, wasmCode, gotWasmCode, "byte code does not match")

// verify code info
gotCodeInfo := keeper.GetCodeInfo(ctx, 1)
require.NotNil(t, gotCodeInfo)
codeCreatorAddr, _ := sdk.AccAddressFromBech32("cosmos1qtu5n0cnhfkjj6l2rq97hmky9fd89gwca9yarx")
codeHash := sha256.Sum256(wasmCode)
expCodeInfo := types.CodeInfo{
CodeHash: codeHash[:],
CodeHash: wasmCodeHash[:],
Creator: codeCreatorAddr,
Source: "https://example.com",
Builder: "foo/bar:tag",
Expand Down
33 changes: 28 additions & 5 deletions x/wasm/internal/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import (
// SDK reference costs can be found here: https://github.com/cosmos/cosmos-sdk/blob/02c6c9fafd58da88550ab4d7d494724a477c8a68/store/types/gas.go#L153-L164
// A write at ~3000 gas and ~200us = 10 gas per us (microsecond) cpu/io
// Rough timing have 88k gas at 90us, which is equal to 1k sdk gas... (one read)
const GasMultiplier = 100
//
// Please not that all gas prices returned to the wasmer engine should have this multiplied
const GasMultiplier uint64 = 100

// MaxGas for a contract is 10 billion wasmer gas (enforced in rust to prevent overflow)
// The limit for v0.9.3 is defined here: https://github.com/CosmWasm/cosmwasm/blob/v0.9.3/packages/vm/src/backends/singlepass.rs#L15-L23
Expand Down Expand Up @@ -225,7 +227,7 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A

// instantiate wasm contract
gas := gasForContract(ctx)
res, gasUsed, err := k.wasmer.Instantiate(codeInfo.CodeHash, params, initMsg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
res, gasUsed, err := k.wasmer.Instantiate(codeInfo.CodeHash, params, initMsg, prefixStore, cosmwasmAPI, querier, gasMeter(ctx), gas)
consumeGas(ctx, gasUsed)
if err != nil {
return contractAddress, sdkerrors.Wrap(types.ErrInstantiateFailed, err.Error())
Expand Down Expand Up @@ -278,7 +280,7 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller
}

gas := gasForContract(ctx)
res, gasUsed, execErr := k.wasmer.Execute(codeInfo.CodeHash, params, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
res, gasUsed, execErr := k.wasmer.Execute(codeInfo.CodeHash, params, msg, prefixStore, cosmwasmAPI, querier, gasMeter(ctx), gas)
consumeGas(ctx, gasUsed)
if execErr != nil {
return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error())
Expand Down Expand Up @@ -331,7 +333,7 @@ func (k Keeper) migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller
prefixStoreKey := types.GetContractStorePrefixKey(contractAddress)
prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey)
gas := gasForContract(ctx)
res, gasUsed, err := k.wasmer.Migrate(newCodeInfo.CodeHash, params, msg, &prefixStore, cosmwasmAPI, &querier, ctx.GasMeter(), gas)
res, gasUsed, err := k.wasmer.Migrate(newCodeInfo.CodeHash, params, msg, &prefixStore, cosmwasmAPI, &querier, gasMeter(ctx), gas)
consumeGas(ctx, gasUsed)
if err != nil {
return nil, sdkerrors.Wrap(types.ErrMigrationFailed, err.Error())
Expand Down Expand Up @@ -408,7 +410,7 @@ func (k Keeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []b
Ctx: ctx,
Plugins: k.queryPlugins,
}
queryResult, gasUsed, qErr := k.wasmer.Query(codeInfo.CodeHash, req, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gasForContract(ctx))
queryResult, gasUsed, qErr := k.wasmer.Query(codeInfo.CodeHash, req, prefixStore, cosmwasmAPI, querier, gasMeter(ctx), gasForContract(ctx))
consumeGas(ctx, gasUsed)
if qErr != nil {
return nil, sdkerrors.Wrap(types.ErrQueryFailed, qErr.Error())
Expand Down Expand Up @@ -571,6 +573,10 @@ func gasForContract(ctx sdk.Context) uint64 {
func consumeGas(ctx sdk.Context, gas uint64) {
consumed := gas / GasMultiplier
ctx.GasMeter().ConsumeGas(consumed, "wasm contract")
// throw OutOfGas error if we ran out (got exactly to zero due to better limit enforcing)
if ctx.GasMeter().IsOutOfGas() {
panic(sdk.ErrorOutOfGas{"Wasmer function execution"})
}
}

// generates a contract address from codeID + instanceID
Expand Down Expand Up @@ -650,3 +656,20 @@ func addrFromUint64(id uint64) sdk.AccAddress {
binary.PutUvarint(addr[1:], id)
return sdk.AccAddress(crypto.AddressHash(addr))
}

// MultipliedGasMeter wraps the GasMeter from context and multiplies all reads by out defined multiplier
type MultipiedGasMeter struct {
originalMeter sdk.GasMeter
}

var _ wasm.GasMeter = MultipiedGasMeter{}

func (m MultipiedGasMeter) GasConsumed() sdk.Gas {
return m.originalMeter.GasConsumed() * GasMultiplier
}

func gasMeter(ctx sdk.Context) MultipiedGasMeter {
return MultipiedGasMeter{
originalMeter: ctx.GasMeter(),
}
}
22 changes: 14 additions & 8 deletions x/wasm/internal/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ func TestInstantiate(t *testing.T) {
require.Equal(t, "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", contractAddr.String())

gasAfter := ctx.GasMeter().GasConsumed()
require.Equal(t, uint64(0x12313), gasAfter-gasBefore)
require.Equal(t, uint64(0x10c43), gasAfter-gasBefore)

// ensure it is stored properly
info := keeper.GetContractInfo(ctx, contractAddr)
Expand Down Expand Up @@ -534,7 +534,7 @@ func TestExecute(t *testing.T) {

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

// ensure bob now exists and got both payments released
bobAcct = accKeeper.GetAccount(ctx, bob)
Expand Down Expand Up @@ -710,11 +710,18 @@ func TestExecuteWithCpuLoop(t *testing.T) {
ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimit))
require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed())

// this must fail
// ensure we get an out of gas panic
defer func() {
r := recover()
require.NotNil(t, r)
_, ok := r.(sdk.ErrorOutOfGas)
require.True(t, ok, "%v", r)
}()

// this should throw out of gas exception (panic)
_, err = keeper.Execute(ctx, addr, fred, []byte(`{"cpu_loop":{}}`), nil)
assert.Error(t, err)
// make sure gas ran out
require.Equal(t, gasLimit, ctx.GasMeter().GasConsumed())
require.True(t, false, "We must panic before this line")

}

func TestExecuteWithStorageLoop(t *testing.T) {
Expand Down Expand Up @@ -747,15 +754,14 @@ func TestExecuteWithStorageLoop(t *testing.T) {
require.NoError(t, err)

// make sure we set a limit before calling
var gasLimit uint64 = 400_000
var gasLimit uint64 = 400_002
ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimit))
require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed())

// ensure we get an out of gas panic
defer func() {
r := recover()
require.NotNil(t, r)
// TODO: ensure it is out of gas error
_, ok := r.(sdk.ErrorOutOfGas)
require.True(t, ok, "%v", r)
}()
Expand Down
Binary file modified x/wasm/internal/keeper/testdata/burner.wasm
Binary file not shown.
Binary file modified x/wasm/internal/keeper/testdata/contract.wasm
Binary file not shown.
Binary file modified x/wasm/internal/keeper/testdata/contract.wasm.gzip
Binary file not shown.
Binary file modified x/wasm/internal/keeper/testdata/reflect.wasm
Binary file not shown.
Binary file modified x/wasm/internal/keeper/testdata/staking.wasm
Binary file not shown.
4 changes: 2 additions & 2 deletions x/wasm/internal/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,11 @@ func NewEnv(ctx sdk.Context, creator sdk.AccAddress, deposit sdk.Coins, contract
ChainID: ctx.ChainID(),
},
Message: wasmTypes.MessageInfo{
Sender: wasmTypes.CanonicalAddress(creator),
Sender: creator.String(),
SentFunds: NewWasmCoins(deposit),
},
Contract: wasmTypes.ContractInfo{
Address: wasmTypes.CanonicalAddress(contractAddr),
Address: contractAddr.String(),
},
}
return env
Expand Down