diff --git a/.github/workflows/lint-go.yml b/.github/workflows/lint-go.yml index 1c9ad642d..ba7bd6c4d 100644 --- a/.github/workflows/lint-go.yml +++ b/.github/workflows/lint-go.yml @@ -20,8 +20,11 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: +<<<<<<< HEAD +======= +>>>>>>> faddat/errcheck go-version: "1.23.4" cache: false - name: golangci-lint diff --git a/README.md b/README.md index cb27f61bd..dc7320f45 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ library that can be used via FFI. It is compiled like this: # Run unit tests (cd libwasmvm && cargo test) -# Create release build for your current system. Uses whatever default Rust +# Create a release build for your current system. Uses whatever default Rust # version you have installed. make build-libwasmvm @@ -107,11 +107,11 @@ go build -tags "nolink_libwasmvm" See [COMPILER_VERSIONS.md](docs/COMPILER_VERSIONS.md) for information on Go and Rust compiler support. -The Rust implementation of the VM is compiled to a library called libwasmvm. +The Rust implementation of the VM is compiled into a library called libwasmvm. This is then linked to the Go code when the final binary is built. For that reason not all systems supported by Go are supported by this project. -Linux (tested on Ubuntu, Debian, Alpine) and macOS is supported. We are working +Linux (tested on Ubuntu, Debian, Alpine) and macOS are supported. We are working on Windows support with very low priority (#288). [#288]: https://github.com/CosmWasm/wasmvm/pull/288 diff --git a/docs/COMPILER_VERSIONS.md b/docs/COMPILER_VERSIONS.md index 55f9c2159..4e13411ac 100644 --- a/docs/COMPILER_VERSIONS.md +++ b/docs/COMPILER_VERSIONS.md @@ -15,7 +15,7 @@ The Go version here has the following goals: versions reasonably wide to avoid unnecessary friction for users. I.e. just because Cosmos SDK now uses Go 1.19 does not mean we make 1.19 the minimal supported version here. However, the project should work with the latest - stable Go version. When the majority of our users is between 1.18 and 1.19, we + stable Go version. When the majority of our users are between 1.18 and 1.19, we can slowly remove 1.17 support by bumping the min version to 1.18. - Be stable enough to test Go code. We always pin the patch version to ensure CI runs are reproducible. Those versions will contain security issues from time @@ -31,10 +31,10 @@ Go version locations: ## Rust In contrast to Go, the Rust compiler used here produces actual artifacts used -directly by consumer projects. This are the shared .dylib, .so, .dll libraries +directly by consumer projects. These are the shared .dylib, .so, .dll libraries as well as the static .a libraries. Those libwasmvm builds contain all the Rust code executing contracts, especially cosmwasm-vm. New Rust versions usually add -features which are not necessarily used or needed. But we should move with the +features that are not necessarily used or needed. But we should move with the ecosystem to keep the dependency tree compiling. Also new Rust versions tend to increase runtime speed through optimizer improvements, which never hurts. diff --git a/docs/MIGRATING.md b/docs/MIGRATING.md index 1378fe5e2..7425f2327 100644 --- a/docs/MIGRATING.md +++ b/docs/MIGRATING.md @@ -27,7 +27,7 @@ - `QueryRequest.Grpc` was added. It is similar to `QueryRequest.Stargate` but unlike that, it should always return protobuf encoded responses on all chains. - `VM.StoreCode` now returns a `uint64` containing the gas cost in CosmWasm gas - and takes a gas limit as argument. This was previously calculated in wasmd. + and takes a gas limit as an argument. This was previously calculated in wasmd. The change brings consistency with the other functions that cause gas usage. - `GoAPI` now requires an additional `ValidateAddress` function that validates whether the given string is a valid address. This was previously done diff --git a/internal/api/lib.go b/internal/api/lib.go index 3531f8164..45802bbd2 100644 --- a/internal/api/lib.go +++ b/internal/api/lib.go @@ -104,7 +104,7 @@ func StoreCodeUnchecked(cache Cache, wasm []byte) ([]byte, error) { w := makeView(wasm) defer runtime.KeepAlive(wasm) errmsg := uninitializedUnmanagedVector() - checksum, err := C.store_code(cache.ptr, w, cbool(true), cbool(true), &errmsg) + checksum, err := C.store_code(cache.ptr, w, cbool(false), cbool(true), &errmsg) if err != nil { return nil, errorWithMessage(err, errmsg) } diff --git a/internal/api/lib_test.go b/internal/api/lib_test.go index 0e8854cf7..1972f4a72 100644 --- a/internal/api/lib_test.go +++ b/internal/api/lib_test.go @@ -305,6 +305,28 @@ func TestStoreCodeUnchecked(t *testing.T) { require.Equal(t, wasm, code) } +func TestStoreCodeUncheckedWorksWithInvalidWasm(t *testing.T) { + cache, cleanup := withCache(t) + defer cleanup() + + wasm, err := os.ReadFile("../../testdata/hackatom.wasm") + require.NoError(t, err) + + // Look for "interface_version_8" in the wasm file and replace it with "interface_version_9". + // This makes the wasm file invalid. + wasm = bytes.Replace(wasm, []byte("interface_version_8"), []byte("interface_version_9"), 1) + + // StoreCode should fail + _, err = StoreCode(cache, wasm, true) + require.ErrorContains(t, err, "Wasm contract has unknown interface_version_* marker export") + + // StoreCodeUnchecked should not fail + checksum, err := StoreCodeUnchecked(cache, wasm) + require.NoError(t, err) + expectedChecksum := sha256.Sum256(wasm) + assert.Equal(t, expectedChecksum[:], checksum) +} + func TestPin(t *testing.T) { cache, cleanup := withCache(t) defer cleanup() @@ -866,6 +888,8 @@ func Benchmark100ConcurrentContractCalls(b *testing.B) { require.NoError(b, err) requireOkResponse(b, res, 0) + info = MockInfoBin(b, "fred") + const callCount = 100 // Calls per benchmark iteration b.ResetTimer() @@ -874,7 +898,9 @@ func Benchmark100ConcurrentContractCalls(b *testing.B) { errChan := make(chan error, callCount) resChan := make(chan []byte, callCount) wg.Add(callCount) + info = mockInfoBinNoAssert("fred") + for i := 0; i < callCount; i++ { go func() { defer wg.Done() @@ -1358,6 +1384,10 @@ func TestCustomReflectQuerier(t *testing.T) { // https://github.com/CosmWasm/cosmwasm/blob/v0.11.0-alpha3/contracts/reflect/src/msg.rs#L18-L28 } + type CapitalizedResponse struct { + Text string `json:"text"` + } + cache, cleanup := withCache(t) defer cleanup() checksum := createReflectContract(t, cache) diff --git a/types/eureka.go b/types/eureka.go new file mode 100644 index 000000000..a3d919e42 --- /dev/null +++ b/types/eureka.go @@ -0,0 +1,16 @@ +package types + +// EurekaPayload defines a single packet sent in the EurekaSendPacketMsg. +// +// Payload value should be encoded using the method specified in the Encoding field, +// and the module on the other side should know how to parse this. +type EurekaPayload struct { + // The port id on the chain where the packet is sent to (external chain). + DestinationPort string `json:"destination_port"` + // Version of the receiving contract. + Version string `json:"version"` + // Encoding used to serialize the Value. + Encoding string `json:"encoding"` + // Encoded payload data + Value []byte `json:"value"` +} diff --git a/types/msg.go b/types/msg.go index 677f96ab4..394a67dd9 100644 --- a/types/msg.go +++ b/types/msg.go @@ -60,6 +60,7 @@ type CosmosMsg struct { Staking *StakingMsg `json:"staking,omitempty"` Any *AnyMsg `json:"any,omitempty"` Wasm *WasmMsg `json:"wasm,omitempty"` + Eureka *EurekaMsg `json:"eureka,omitempty"` } func (m *CosmosMsg) UnmarshalJSON(data []byte) error { @@ -74,6 +75,7 @@ func (m *CosmosMsg) UnmarshalJSON(data []byte) error { Any *AnyMsg `json:"any,omitempty"` Wasm *WasmMsg `json:"wasm,omitempty"` Stargate *AnyMsg `json:"stargate,omitempty"` + Eureka *EurekaMsg `json:"eureka,omitempty"` } var tmp InternalCosmosMsg err := json.Unmarshal(data, &tmp) @@ -97,6 +99,7 @@ func (m *CosmosMsg) UnmarshalJSON(data []byte) error { Staking: tmp.Staking, Any: tmp.Any, Wasm: tmp.Wasm, + Eureka: tmp.Eureka, } return nil } @@ -350,6 +353,18 @@ type WasmMsg struct { ClearAdmin *ClearAdminMsg `json:"clear_admin,omitempty"` } +// These are messages in the IBC lifecycle using the new Eureka approach. Only usable by IBC-enabled contracts +type EurekaMsg struct { + SendPacket *EurekaSendPacketMsg `json:"send_packet,omitempty"` +} + +// Sends an IBC packet with given payloads over the existing channel. +type EurekaSendPacketMsg struct { + ChannelID string `json:"channel_id"` + Payloads []EurekaPayload `json:"payloads"` + Timeout uint64 `json:"timeout,string,omitempty"` +} + // ExecuteMsg is used to call another defined contract on this chain. // The calling contract requires the callee to be defined beforehand, // and the address should have been defined in initialization. diff --git a/types/msg_test.go b/types/msg_test.go index fa0c7061b..b3bc271b6 100644 --- a/types/msg_test.go +++ b/types/msg_test.go @@ -161,3 +161,20 @@ func TestMsgFundCommunityPoolSerialization(t *testing.T) { require.Equal(t, Array[Coin]{{"adenom", "300"}, {"bdenom", "400"}}, msg.FundCommunityPool.Amount) } + +func TestMsgEurekaSendPacketSerialization(t *testing.T) { + document := []byte(`{"send_packet":{"channel_id":"channel-432", "payloads": [{"destination_port": "wasm.123", "version": "random_version", "encoding": "json", "value": ""}], "timeout": "0"}}`) + + var msg EurekaMsg + err := json.Unmarshal(document, &msg) + require.NoError(t, err) + + require.Equal(t, "channel-432", msg.SendPacket.ChannelID) + require.Equal(t, []EurekaPayload{{ + DestinationPort: "wasm.123", + Version: "random_version", + Encoding: "json", + Value: []byte(""), + }}, msg.SendPacket.Payloads) + require.Equal(t, uint64(0), msg.SendPacket.Timeout) +}