Merge pull request #218 from CosmWasm/update-go-cosmwasm

Update go cosmwasm
This commit is contained in:
Ethan Frey
2020-07-24 13:55:33 +02:00
committed by GitHub
12 changed files with 81 additions and 34 deletions

3
go.mod
View File

@@ -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

2
go.sum
View File

@@ -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=

View File

@@ -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{

View File

@@ -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",
@@ -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",

View File

@@ -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
@@ -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())
@@ -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())
@@ -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())
@@ -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())
@@ -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
@@ -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(),
}
}

View File

@@ -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)
@@ -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)
@@ -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) {
@@ -747,7 +754,7 @@ 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())
@@ -755,7 +762,6 @@ func TestExecuteWithStorageLoop(t *testing.T) {
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)
}()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -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