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 Rust and Types #197

Merged
merged 3 commits into from
Mar 3, 2021
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
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ jobs:
# All checks on the codebase that can run in parallel to build_library
sanity:
docker:
- image: circleci/rust:1.49.0-buster
- image: circleci/rust:1.50.0-buster
steps:
- checkout
- run:
Expand Down Expand Up @@ -39,7 +39,7 @@ jobs:

build_library:
docker:
- image: circleci/rust:1.49.0-buster
- image: circleci/rust:1.50.0-buster
steps:
- checkout
- run:
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ and this project adheres to

### Added

- Add Submessages and Subcall types ([#197])
- Add WasmMsg::Migrate message type ([#197])
- Add IBC and Stargate message types ([#167], [#174])
- Expose IBC entry points and AnalyzeCode ([#167], [#174])

[#167]: https://github.com/CosmWasm/wasmvm/pull/167
[#174]: https://github.com/CosmWasm/wasmvm/pull/174
[#197]: https://github.com/CosmWasm/wasmvm/pull/197

### Changed

- Renamed the Go type `CodeID` to `Checksum` to clarify the difference between
the numeric code ID assigned by x/wasm and the hash used to identify it in the cache.
- Update required Rust version in build scripts to 1.50 ([#197])

## 0.13.0

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.PHONY: all build build-rust build-go test

BUILDERS_PREFIX := cosmwasm/go-ext-builder:0004
BUILDERS_PREFIX := cosmwasm/go-ext-builder:0005
USER_ID := $(shell id -u)
USER_GROUP = $(shell id -g)

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ link with, and Go developers should just be able to import this directly.

## Supported Platforms

Requires Rust 1.50+, Requires Go 1.15+

Since this package includes a rust prebuilt dll, you cannot just import the go code,
but need to be on a system that works with an existing dll. Currently this is Linux
(tested on Ubuntu, Debian, and CentOS7) and MacOS. We have a build system for Windows,
Expand Down
18 changes: 9 additions & 9 deletions api/lib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func TestInstantiate(t *testing.T) {
res, cost, err := Instantiate(cache, checksum, env, info, msg, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG)
require.NoError(t, err)
requireOkResponse(t, res, 0)
assert.Equal(t, uint64(0xd830), cost)
assert.Equal(t, uint64(0xdb95), cost)

var result types.ContractResult
err = json.Unmarshal(res, &result)
Expand Down Expand Up @@ -215,7 +215,7 @@ func TestHandle(t *testing.T) {
diff := time.Now().Sub(start)
require.NoError(t, err)
requireOkResponse(t, res, 0)
assert.Equal(t, uint64(0xd830), cost)
assert.Equal(t, uint64(0xdb95), cost)
t.Logf("Time (%d gas): %s\n", cost, diff)

// execute with the same store
Expand All @@ -228,7 +228,7 @@ func TestHandle(t *testing.T) {
res, cost, err = Handle(cache, checksum, env, info, []byte(`{"release":{}}`), &igasMeter2, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG)
diff = time.Now().Sub(start)
require.NoError(t, err)
assert.Equal(t, uint64(0x112a4), cost)
assert.Equal(t, uint64(0x12168), cost)
t.Logf("Time (%d gas): %s\n", cost, diff)

// make sure it read the balance properly and we got 250 atoms
Expand Down Expand Up @@ -270,7 +270,7 @@ func TestHandleCpuLoop(t *testing.T) {
diff := time.Now().Sub(start)
require.NoError(t, err)
requireOkResponse(t, res, 0)
assert.Equal(t, uint64(0xd830), cost)
assert.Equal(t, uint64(0xdb95), cost)
t.Logf("Time (%d gas): %s\n", cost, diff)

// execute a cpu loop
Expand Down Expand Up @@ -421,7 +421,7 @@ func TestMultipleInstances(t *testing.T) {
require.NoError(t, err)
requireOkResponse(t, res, 0)
// we now count wasm gas charges and db writes
assert.Equal(t, uint64(0xd7ae), cost)
assert.Equal(t, uint64(0xdb2c), cost)

// instance2 controlled by mary
gasMeter2 := NewMockGasMeter(TESTING_GAS_LIMIT)
Expand All @@ -432,14 +432,14 @@ func TestMultipleInstances(t *testing.T) {
res, cost, err = Instantiate(cache, checksum, env, info, msg, &igasMeter2, store2, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG)
require.NoError(t, err)
requireOkResponse(t, res, 0)
assert.Equal(t, uint64(0xd7f7), cost)
assert.Equal(t, uint64(0xdb75), cost)

// fail to execute store1 with mary
resp := exec(t, cache, checksum, "mary", store1, api, querier, 0x9a35)
resp := exec(t, cache, checksum, "mary", store1, api, querier, 0xa6c3)
require.Equal(t, "Unauthorized", resp.Err)

// succeed to execute store1 with fred
resp = exec(t, cache, checksum, "fred", store1, api, querier, 0x112a4)
resp = exec(t, cache, checksum, "fred", store1, api, querier, 0x12168)
require.Equal(t, "", resp.Err)
require.Equal(t, 1, len(resp.Ok.Messages))
attributes := resp.Ok.Attributes
Expand All @@ -448,7 +448,7 @@ func TestMultipleInstances(t *testing.T) {
require.Equal(t, "bob", attributes[1].Value)

// succeed to execute store2 with mary
resp = exec(t, cache, checksum, "mary", store2, api, querier, 0x112a4)
resp = exec(t, cache, checksum, "mary", store2, api, querier, 0x12168)
require.Equal(t, "", resp.Err)
require.Equal(t, 1, len(resp.Ok.Messages))
attributes = resp.Ok.Attributes
Expand Down
Binary file modified api/testdata/hackatom.wasm
Binary file not shown.
Binary file modified api/testdata/ibc_reflect.wasm
Binary file not shown.
Binary file modified api/testdata/queue.wasm
Binary file not shown.
Binary file modified api/testdata/reflect.wasm
Binary file not shown.
4 changes: 2 additions & 2 deletions builders/Dockerfile.alpine
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ RUN set -eux; \

RUN wget "https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-musl/rustup-init"
RUN chmod +x rustup-init
RUN ./rustup-init -y --no-modify-path --default-toolchain 1.49.0; rm rustup-init
RUN ./rustup-init -y --no-modify-path --default-toolchain 1.50.0; rm rustup-init
RUN chmod -R a+w $RUSTUP_HOME $CARGO_HOME

# needed for
# /usr/lib/gcc/x86_64-alpine-linux-musl/9.3.0/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find crti.o: No such file or directory
ENV LIBRARY_PATH=/usr/local/rustup/toolchains/1.49.0-x86_64-unknown-linux-musl/lib/rustlib/x86_64-unknown-linux-musl/lib:$LIBRARY_PATH
ENV LIBRARY_PATH=/usr/local/rustup/toolchains/1.50.0-x86_64-unknown-linux-musl/lib/rustlib/x86_64-unknown-linux-musl/lib:$LIBRARY_PATH

# prepare go cache dirs
RUN mkdir -p /.cache/go-build
Expand Down
2 changes: 1 addition & 1 deletion builders/Dockerfile.centos7
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ENV RUSTUP_HOME=/usr/local/rustup \
RUN url="https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init"; \
wget "$url"; \
chmod +x rustup-init; \
./rustup-init -y --no-modify-path --default-toolchain 1.49.0; \
./rustup-init -y --no-modify-path --default-toolchain 1.50.0; \
rm rustup-init; \
chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \
rustup --version; \
Expand Down
2 changes: 1 addition & 1 deletion builders/Dockerfile.cross
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM rust:1.49.0-buster
FROM rust:1.50.0-buster

# Install build dependencies
RUN apt-get update
Expand Down
2 changes: 1 addition & 1 deletion builders/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Versioned by a simple counter that is not bound to a specific CosmWasm version
# See builders/README.md
BUILDERS_PREFIX := cosmwasm/go-ext-builder:0004
BUILDERS_PREFIX := cosmwasm/go-ext-builder:0005

.PHONY: docker-image-centos7
docker-image-centos7:
Expand Down
4 changes: 4 additions & 0 deletions builders/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ can do the cross-compilation.

## Changelog

**Version 0005:**

- Update Rust to 1.50.0.

**Version 0004:**

- Update Rust to 1.49.0.
Expand Down
47 changes: 46 additions & 1 deletion types/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,41 @@ type ContractResult struct {
type Response struct {
// Messages comes directly from the contract and is it's request for action
Messages []CosmosMsg `json:"messages"`
// Submessages are like Messages, but they guarantee a reply to the calling contract
// after their execution, and return both success and error rather than auto-failing on error
Submessages []SubMsg `json:"submessages"`
// base64-encoded bytes to return as ABCI.Data field
Data []byte `json:"data"`
// attributes for a log event to return over abci interface
Attributes []EventAttribute `json:"attributes"`
}

// EventAttributes must encode empty array as []
type EventAttributes []EventAttribute

// MarshalJSON ensures that we get [] for empty arrays
func (a EventAttributes) MarshalJSON() ([]byte, error) {
if len(a) == 0 {
return []byte("[]"), nil
}
var raw []EventAttribute = a
return json.Marshal(raw)
}

// UnmarshalJSON ensures that we get [] for empty arrays
func (a *EventAttributes) UnmarshalJSON(data []byte) error {
// make sure we deserialize [] back to null
if string(data) == "[]" || string(data) == "null" {
return nil
}
var raw []EventAttribute
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
*a = raw
return nil
}

// EventAttribute
type EventAttribute struct {
Key string `json:"key"`
Expand Down Expand Up @@ -125,6 +154,7 @@ type StargateMsg struct {
type WasmMsg struct {
Execute *ExecuteMsg `json:"execute,omitempty"`
Instantiate *InstantiateMsg `json:"instantiate,omitempty"`
Migrate *MigrateMsg `json:"migrate,omitempty"`
}

// ExecuteMsg is used to call another defined contract on this chain.
Expand All @@ -145,12 +175,27 @@ type ExecuteMsg struct {
Send Coins `json:"send"`
}

// InstantiateMsg will create a new contract instance from a previously uploaded CodeID.
// This allows one contract to spawn "sub-contracts".
type InstantiateMsg struct {
// CodeID is the reference to the wasm byte code as used by the Cosmos-SDK
CodeID uint64 `json:"code_id"`
// Msg is assumed to be a json-encoded message, which will be passed directly
// as `userMsg` when calling `Handle` on the above-defined contract
// as `userMsg` when calling `Init` on a new contract with the above-defined CodeID
Msg []byte `json:"msg"`
// Send is an optional amount of coins this contract sends to the called contract
Send Coins `json:"send"`
}

// MigrateMsg will migrate an existing contract from it's current wasm code (logic)
// to another previously uploaded wasm code. It requires the calling contract to be
// listed as "admin" of the contract to be migrated.
type MigrateMsg struct {
// ContractAddr is the sdk.AccAddress of the target contract, to migrate.
ContractAddr string `json:"contract_addr"`
// NewCodeID is the reference to the wasm byte code for the new logic to migrate to
NewCodeID uint64 `json:"new_code_id"`
// Msg is assumed to be a json-encoded message, which will be passed directly
// as `userMsg` when calling `Migrate` on the above-defined contract
Msg []byte `json:"msg"`
}
59 changes: 59 additions & 0 deletions types/subcall.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package types

import "encoding/json"

// SubMsg wraps a CosmosMsg with some metadata for handling replies (ID) and optionally
// limiting the gas usage (GasLimit)
type SubMsg struct {
ID uint64 `json:"id"`
Msg CosmosMsg `json:"msg"`
GasLimit *uint64 `json:"gas_limit,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSON schema says this is null or an integer:

    "SubMsg_for_CustomMsg": {
      "description": "A sub-message that will guarantee a subcall_response callback on success or error Note on error the subcall will revert any partial state changes due to this message, but not revert any state changes in the calling contract (that must be done in the subcall_response entry point)",
      "type": "object",
      "required": [
        "id",
        "msg"
      ],
      "properties": {
        "gas_limit": {
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0.0
        },
        "id": {
          "type": "integer",
          "format": "uint64",
          "minimum": 0.0
        },
        "msg": {
          "$ref": "#/definitions/CosmosMsg_for_CustomMsg"
        }
      }
    },

Are you sure it works with *uint64 and omitempty?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not a required field. This works fine

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, and it only needs to work from Rust to Go. Then we receive a number of null in Go.

}

type Reply struct {
ID uint64 `json:"id"`
Result SubcallResult `json:"result"`
}

// SubcallResult is the raw response we return from the sdk -> reply after executing a SubMsg.
// This is mirrors Rust's ContractResult<SubcallResponse>.
type SubcallResult struct {
Ok *SubcallResponse `json:"ok,omitempty"`
Err string `json:"error,omitempty"`
}

type SubcallResponse struct {
Events Events `json:"events"`
Data []byte `json:"data,omitempty"`
}

// Events must encode empty array as []
type Events []Event

// MarshalJSON ensures that we get [] for empty arrays
func (e Events) MarshalJSON() ([]byte, error) {
if len(e) == 0 {
return []byte("[]"), nil
}
var raw []Event = e
return json.Marshal(raw)
}

// UnmarshalJSON ensures that we get [] for empty arrays
func (e *Events) UnmarshalJSON(data []byte) error {
// make sure we deserialize [] back to null
if string(data) == "[]" || string(data) == "null" {
return nil
}
var raw []Event
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
*e = raw
return nil
}

type Event struct {
Type string `json:"type"`
Attributes EventAttributes `json:"attributes"`
}