Merge branch 'master' into vw/modify-cli

This commit is contained in:
Ethan Frey 2020-01-20 10:40:54 +01:00
commit 37ec9df047
11 changed files with 145 additions and 32 deletions

2
go.sum
View File

@ -34,8 +34,6 @@ 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=

View File

@ -21,13 +21,12 @@ import (
)
const (
flagTo = "to"
flagAmount = "amount"
flagTo = "to"
flagAmount = "amount"
flagSource = "source"
flagBuilder = "builder"
)
// limit max bytes read to prevent gzip bombs
const maxSize = 400 * 1024
// GetTxCmd returns the transaction commands for this module
func GetTxCmd(cdc *codec.Codec) *cobra.Command {
txCmd := &cobra.Command{
@ -48,7 +47,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
// StoreCodeCmd will upload code to be reused.
func StoreCodeCmd(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "store [wasm file]",
Use: "store [wasm file] --source [source] --builder [builder]",
Short: "Upload a wasm binary",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
@ -62,11 +61,9 @@ func StoreCodeCmd(cdc *codec.Codec) *cobra.Command {
return err
}
// limit the input size
if len(wasm) > maxSize {
return fmt.Errorf("input size exceeds the max size allowed (allowed:%d, actual: %d)",
maxSize, len(wasm))
}
source := viper.GetString(flagSource)
builder := viper.GetString(flagBuilder)
// gzip the wasm file
if wasmUtils.IsWasm(wasm) {
@ -83,10 +80,22 @@ func StoreCodeCmd(cdc *codec.Codec) *cobra.Command {
msg := types.MsgStoreCode{
Sender: cliCtx.GetFromAddress(),
WASMByteCode: wasm,
Source: source,
Builder: builder,
}
err = msg.ValidateBasic()
if err != nil {
return err
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
cmd.Flags().String(flagSource, "", "A valid URI reference to the contract's source code, optional")
cmd.Flags().String(flagBuilder, "", "A valid docker tag for the build system, optional")
return cmd
}

View File

@ -6,7 +6,7 @@ import (
"testing"
)
func GetTestData() ([]byte, []byte, []byte, error){
func GetTestData() ([]byte, []byte, []byte, error) {
wasmCode, err := ioutil.ReadFile("../../internal/keeper/testdata/contract.wasm")
if err != nil {
@ -23,7 +23,7 @@ func GetTestData() ([]byte, []byte, []byte, error){
return wasmCode, someRandomStr, gzipData, nil
}
func TestIsWasm (t *testing.T) {
func TestIsWasm(t *testing.T) {
wasmCode, someRandomStr, gzipData, err := GetTestData()
require.NoError(t, err)
@ -35,7 +35,7 @@ func TestIsWasm (t *testing.T) {
require.True(t, IsWasm(wasmCode))
}
func TestIsGzip (t *testing.T) {
func TestIsGzip(t *testing.T) {
wasmCode, someRandomStr, gzipData, err := GetTestData()
require.NoError(t, err)
@ -44,7 +44,7 @@ func TestIsGzip (t *testing.T) {
require.True(t, IsGzip(gzipData))
}
func TestGzipIt (t *testing.T) {
func TestGzipIt(t *testing.T) {
wasmCode, someRandomStr, _, err := GetTestData()
originalGzipData := []byte{31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 202, 72, 205, 201, 201, 87, 40, 207, 47, 202, 73, 1,
4, 0, 0, 255, 255, 133, 17, 74, 13, 11, 0, 0, 0}
@ -61,4 +61,4 @@ func TestGzipIt (t *testing.T) {
require.True(t, IsGzip(strToGzip))
require.NoError(t, err)
require.Equal(t, originalGzipData, strToGzip)
}
}

View File

@ -24,11 +24,73 @@ func TestInitGenesis(t *testing.T) {
h := data.module.NewHandler()
q := data.module.NewQuerierHandler()
t.Log("fail with invalid source url")
msg := MsgStoreCode{
Sender: creator,
WASMByteCode: testContract,
Source: "someinvalidurl",
Builder: "",
}
sdkerr := msg.ValidateBasic()
require.Error(t, sdkerr)
res := h(data.ctx, msg)
require.False(t, res.IsOK())
t.Log("fail with relative source url")
msg = MsgStoreCode{
Sender: creator,
WASMByteCode: testContract,
Source: "./testdata/escrow.wasm",
Builder: "",
}
sdkerr = msg.ValidateBasic()
require.Error(t, sdkerr)
res = h(data.ctx, msg)
require.False(t, res.IsOK())
t.Log("fail with unreachable source url")
msg = MsgStoreCode{
Sender: creator,
WASMByteCode: testContract,
Source: "https://github.com/cosmwasm/wasmddddddrandom",
Builder: "",
}
sdkerr = msg.ValidateBasic()
require.Error(t, sdkerr)
res = h(data.ctx, msg)
require.False(t, res.IsOK())
t.Log("fail with invalid build tag")
msg = MsgStoreCode{
Sender: creator,
WASMByteCode: testContract,
Source: "",
Builder: "somerandombuildtag-0.6.2",
}
sdkerr = msg.ValidateBasic()
require.Error(t, sdkerr)
res = h(data.ctx, msg)
require.False(t, res.IsOK())
t.Log("no error with valid source and build tag")
msg = MsgStoreCode{
Sender: creator,
WASMByteCode: testContract,
Source: "https://github.com/cosmwasm/wasmd/blob/master/x/wasm/testdata/escrow.wasm",
Builder: "cosmwasm-opt:0.5.2",
}
sdkerr = msg.ValidateBasic()
require.NoError(t, sdkerr)
res = h(data.ctx, msg)
require.True(t, res.IsOK())
require.Equal(t, res.Data, []byte("1"))

View File

@ -40,7 +40,12 @@ func NewHandler(k Keeper) sdk.Handler {
}
func handleStoreCode(ctx sdk.Context, k Keeper, msg *MsgStoreCode) sdk.Result {
codeID, err := k.Create(ctx, msg.Sender, msg.WASMByteCode)
sdkerr := msg.ValidateBasic()
if sdkerr != nil {
return sdk.ResultFromError(sdkerr)
}
codeID, err := k.Create(ctx, msg.Sender, msg.WASMByteCode, msg.Source, msg.Builder)
if err != nil {
return sdk.ResultFromError(err)
}

View File

@ -14,7 +14,7 @@ import (
// CONTRACT: all types of accounts must have been already initialized/created
func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
for _, code := range data.Codes {
newId, err := keeper.Create(ctx, code.CodeInfo.Creator, code.CodesBytes)
newId, err := keeper.Create(ctx, code.CodeInfo.Creator, code.CodesBytes, code.CodeInfo.Source, code.CodeInfo.Builder)
if err != nil {
panic(err)
}

View File

@ -63,8 +63,8 @@ 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) (uint64, 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, sdkErrors.Wrap(types.ErrCreateFailed, err.Error())
}
@ -75,8 +75,8 @@ func (k Keeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte)
}
store := ctx.KVStore(k.storeKey)
codeID := k.autoIncrementID(ctx, types.KeyLastCodeID)
contractInfo := types.NewCodeInfo(codeHash, creator)
codeID = k.autoIncrementID(ctx, types.KeyLastCodeID)
contractInfo := types.NewCodeInfo(codeHash, creator, source, builder)
// 0x01 | codeID (uint64) -> ContractInfo
store.Set(types.GetCodeKey(codeID), k.cdc.MustMarshalBinaryBare(contractInfo))

View File

@ -38,7 +38,7 @@ func TestCreate(t *testing.T) {
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
require.NoError(t, err)
contractID, err := keeper.Create(ctx, creator, wasmCode)
contractID, err := keeper.Create(ctx, creator, wasmCode, "https://github.com/cosmwasm/wasmd/blob/master/x/wasm/testdata/escrow.wasm", "cosmwasm-opt:0.5.2")
require.NoError(t, err)
require.Equal(t, uint64(1), contractID)
// and verify content
@ -59,7 +59,7 @@ func TestCreateWithGzippedPayload(t *testing.T) {
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm.gzip")
require.NoError(t, err)
contractID, err := keeper.Create(ctx, creator, wasmCode)
contractID, err := keeper.Create(ctx, creator, wasmCode, "https://github.com/cosmwasm/wasmd/blob/master/x/wasm/testdata/escrow.wasm", "")
require.NoError(t, err)
require.Equal(t, uint64(1), contractID)
// and verify content
@ -82,7 +82,7 @@ func TestInstantiate(t *testing.T) {
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
require.NoError(t, err)
contractID, err := keeper.Create(ctx, creator, wasmCode)
contractID, err := keeper.Create(ctx, creator, wasmCode, "https://github.com/cosmwasm/wasmd/blob/master/x/wasm/testdata/escrow.wasm", "")
require.NoError(t, err)
_, _, bob := keyPubAddr()
@ -103,7 +103,7 @@ func TestInstantiate(t *testing.T) {
require.Equal(t, "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", addr.String())
gasAfter := ctx.GasMeter().GasConsumed()
require.Equal(t, uint64(36698), gasAfter-gasBefore)
require.Equal(t, uint64(36923), gasAfter-gasBefore)
}
func TestInstantiateWithNonExistingCodeID(t *testing.T) {
@ -141,7 +141,7 @@ func TestExecute(t *testing.T) {
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
require.NoError(t, err)
contractID, err := keeper.Create(ctx, creator, wasmCode)
contractID, err := keeper.Create(ctx, creator, wasmCode, "", "")
require.NoError(t, err)
_, _, bob := keyPubAddr()

View File

@ -33,7 +33,7 @@ func TestQueryContractState(t *testing.T) {
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm")
require.NoError(t, err)
contractID, err := keeper.Create(ctx, creator, wasmCode)
contractID, err := keeper.Create(ctx, creator, wasmCode, "", "")
require.NoError(t, err)
_, _, bob := keyPubAddr()

View File

@ -1,17 +1,26 @@
package types
import (
"net/http"
"net/url"
"regexp"
sdk "github.com/cosmos/cosmos-sdk/types"
)
const (
MaxWasmSize = 500 * 1024
MaxWasmSize = 500 * 1024
BuildTagRegex = "^cosmwasm-opt:"
)
type MsgStoreCode struct {
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
// WASMByteCode can be raw or gzip compressed
WASMByteCode []byte `json:"wasm_byte_code" yaml:"wasm_byte_code"`
// Source is a valid URI reference to the contract's source code, optional
Source string `json:"source" yaml:"source"`
// Builder is a docker tag, optional
Builder string `json:"builder" yaml:"builder"`
}
func (msg MsgStoreCode) Route() string {
@ -26,9 +35,35 @@ func (msg MsgStoreCode) ValidateBasic() sdk.Error {
if len(msg.WASMByteCode) == 0 {
return sdk.ErrInternal("empty wasm code")
}
if len(msg.WASMByteCode) > MaxWasmSize {
return sdk.ErrInternal("wasm code too large")
}
if msg.Source != "" {
u, err := url.Parse(msg.Source)
if err != nil {
return sdk.ErrInternal("source should be a valid url")
}
if !u.IsAbs() {
return sdk.ErrInternal("source should be an absolute url")
}
// check if the source is reachable
resp, err := http.Get(msg.Source)
if err != nil || resp.StatusCode != 200 {
return sdk.ErrInternal("source url is not reachable")
}
}
if msg.Builder != "" {
ok, err := regexp.MatchString(BuildTagRegex, msg.Builder)
if err != nil || !ok {
return sdk.ErrInternal("invalid tag supplied for builder")
}
}
return nil
}

View File

@ -16,13 +16,17 @@ type Model struct {
type CodeInfo struct {
CodeHash []byte `json:"code_hash"`
Creator sdk.AccAddress `json:"creator"`
Source string `json:"source"`
Builder string `json:"builder"`
}
// NewCodeInfo fills a new Contract struct
func NewCodeInfo(codeHash []byte, creator sdk.AccAddress) CodeInfo {
func NewCodeInfo(codeHash []byte, creator sdk.AccAddress, source string, builder string) CodeInfo {
return CodeInfo{
CodeHash: codeHash,
Creator: creator,
Source: source,
Builder: builder,
}
}