diff --git a/Dockerfile b/Dockerfile index 7e3ac16423..634a75c671 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,6 +23,9 @@ WORKDIR /go/src/github.com/ChainSafe/gossamer COPY go.mod go.sum ./ RUN go mod download +# Prepare libwasmer.so for COPY +RUN cp /go/pkg/mod/github.com/wasmerio/go-ext-wasm@*/wasmer/libwasmer.so libwasmer.so + # Copy gossamer sources COPY . . diff --git a/README.md b/README.md index a1c7f01120..b80ba1191d 100644 --- a/README.md +++ b/README.md @@ -81,15 +81,22 @@ make install To install Gossamer -**Note**: Apple Silicon users running aarch64 might run into issues -with our wasm interpreter since wasmer is still working on supporting this architecture. -See their [README](https://github.com/wasmerio/wasmer-go) for me info on supported platforms. -Currently, there are no known issues regarding this within the Gossamer repo, but if you run into one please open an issue -on our GitHub. - -If you are an Apple Silicon user make sure the `GOARCH` env variable is -set to `arm64` by executing `go env`, if the variable contains another value you can change -by executing `go env -w GOARCH=arm64` +#### Troubleshooting for Apple Silicon users + +Apple Silicon users may encounter these errors: + +```sh +undefined: cWasmerImportObjectT +undefined: cWasmerImportFuncT +undefined: cWasmerValueTag +``` + +If so, set the following +[Golang environment variables](https://pkg.go.dev/cmd/go#hdr-Environment_variables): + +```sh +GOARCH="amd64" +``` ## Use Gossamer diff --git a/dot/core/service_test.go b/dot/core/service_test.go index 8c05697c71..b7dffb664e 100644 --- a/dot/core/service_test.go +++ b/dot/core/service_test.go @@ -252,7 +252,7 @@ func Test_Service_handleCodeSubstitution(t *testing.T) { }, blockHash: common.Hash{0x01}, errWrapped: wasmer.ErrWASMDecompress, - errMessage: "creating new runtime instance: " + + errMessage: "creating new runtime instance: setting up VM: " + "wasm decompression failed: unexpected EOF", }, "store_code_substitution_block_hash_error": { diff --git a/dot/state/block.go b/dot/state/block.go index 2c99881dac..f1002c4555 100644 --- a/dot/state/block.go +++ b/dot/state/block.go @@ -888,8 +888,6 @@ func (bs *BlockState) HandleRuntimeChanges(newState *rtstorage.TrieState, return err } - logger.Info("instantiated runtime!!!") - bs.StoreRuntime(bHash, instance) err = bs.baseState.StoreCodeSubstitutedBlockHash(common.Hash{}) diff --git a/go.mod b/go.mod index 50946c8a3d..af29803342 100644 --- a/go.mod +++ b/go.mod @@ -35,6 +35,7 @@ require ( github.com/spf13/cobra v1.2.1 github.com/spf13/viper v1.8.1 github.com/stretchr/testify v1.8.2 + github.com/wasmerio/go-ext-wasm v0.3.2-0.20200326095750-0a32be6068ec github.com/wasmerio/wasmer-go v1.0.4 github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 golang.org/x/crypto v0.9.0 @@ -164,6 +165,7 @@ require ( github.com/spf13/cast v1.3.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect diff --git a/go.sum b/go.sum index 4abbd1a0cd..ead4cacc60 100644 --- a/go.sum +++ b/go.sum @@ -718,6 +718,7 @@ github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -748,12 +749,15 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/vedhavyas/go-subkey v1.0.3 h1:iKR33BB/akKmcR2PMlXPBeeODjWLM90EL98OrOGs8CA= github.com/vedhavyas/go-subkey v1.0.3/go.mod h1:CloUaFQSSTdWnINfBRFjVMkWXZANW+nd8+TI5jYcl6Y= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/wasmerio/go-ext-wasm v0.3.2-0.20200326095750-0a32be6068ec h1:VElCeVyfCWNmCv6UisKQrr+P2/JRG0uf4/FIdCB4pL0= +github.com/wasmerio/go-ext-wasm v0.3.2-0.20200326095750-0a32be6068ec/go.mod h1:VGyarTzasuS7k5KhSIGpM3tciSZlkP31Mp9VJTHMMeI= github.com/wasmerio/wasmer-go v1.0.4 h1:MnqHoOGfiQ8MMq2RF6wyCeebKOe84G88h5yv+vmxJgs= github.com/wasmerio/wasmer-go v1.0.4/go.mod h1:0gzVdSfg6pysA6QVp6iVRPTagC6Wq9pOE8J86WKb2Fk= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= diff --git a/lib/runtime/mocks/instance.go b/lib/runtime/mocks/instance.go new file mode 100644 index 0000000000..d4d0d5e628 --- /dev/null +++ b/lib/runtime/mocks/instance.go @@ -0,0 +1,476 @@ +// Code generated by mockery v2.14.1. DO NOT EDIT. + +package mocks + +import ( + common "github.com/ChainSafe/gossamer/lib/common" + ed25519 "github.com/ChainSafe/gossamer/lib/crypto/ed25519" + + keystore "github.com/ChainSafe/gossamer/lib/keystore" + + mock "github.com/stretchr/testify/mock" + + runtime "github.com/ChainSafe/gossamer/lib/runtime" + + transaction "github.com/ChainSafe/gossamer/lib/transaction" + + types "github.com/ChainSafe/gossamer/dot/types" +) + +// Instance is an autogenerated mock type for the Instance type +type Instance struct { + mock.Mock +} + +// ApplyExtrinsic provides a mock function with given fields: data +func (_m *Instance) ApplyExtrinsic(data types.Extrinsic) ([]byte, error) { + ret := _m.Called(data) + + var r0 []byte + if rf, ok := ret.Get(0).(func(types.Extrinsic) []byte); ok { + r0 = rf(data) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(types.Extrinsic) error); ok { + r1 = rf(data) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BabeConfiguration provides a mock function with given fields: +func (_m *Instance) BabeConfiguration() (*types.BabeConfiguration, error) { + ret := _m.Called() + + var r0 *types.BabeConfiguration + if rf, ok := ret.Get(0).(func() *types.BabeConfiguration); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.BabeConfiguration) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CheckInherents provides a mock function with given fields: +func (_m *Instance) CheckInherents() { + _m.Called() +} + +// DecodeSessionKeys provides a mock function with given fields: enc +func (_m *Instance) DecodeSessionKeys(enc []byte) ([]byte, error) { + ret := _m.Called(enc) + + var r0 []byte + if rf, ok := ret.Get(0).(func([]byte) []byte); ok { + r0 = rf(enc) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func([]byte) error); ok { + r1 = rf(enc) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Exec provides a mock function with given fields: function, data +func (_m *Instance) Exec(function string, data []byte) ([]byte, error) { + ret := _m.Called(function, data) + + var r0 []byte + if rf, ok := ret.Get(0).(func(string, []byte) []byte); ok { + r0 = rf(function, data) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, []byte) error); ok { + r1 = rf(function, data) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExecuteBlock provides a mock function with given fields: block +func (_m *Instance) ExecuteBlock(block *types.Block) ([]byte, error) { + ret := _m.Called(block) + + var r0 []byte + if rf, ok := ret.Get(0).(func(*types.Block) []byte); ok { + r0 = rf(block) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*types.Block) error); ok { + r1 = rf(block) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FinalizeBlock provides a mock function with given fields: +func (_m *Instance) FinalizeBlock() (*types.Header, error) { + ret := _m.Called() + + var r0 *types.Header + if rf, ok := ret.Get(0).(func() *types.Header); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Header) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GenerateSessionKeys provides a mock function with given fields: +func (_m *Instance) GenerateSessionKeys() { + _m.Called() +} + +// GetCodeHash provides a mock function with given fields: +func (_m *Instance) GetCodeHash() common.Hash { + ret := _m.Called() + + var r0 common.Hash + if rf, ok := ret.Get(0).(func() common.Hash); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(common.Hash) + } + } + + return r0 +} + +// GrandpaAuthorities provides a mock function with given fields: +func (_m *Instance) GrandpaAuthorities() ([]types.Authority, error) { + ret := _m.Called() + + var r0 []types.Authority + if rf, ok := ret.Get(0).(func() []types.Authority); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]types.Authority) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GrandpaGenerateKeyOwnershipProof provides a mock function with given fields: authSetID, authorityID +func (_m *Instance) GrandpaGenerateKeyOwnershipProof(authSetID uint64, authorityID ed25519.PublicKeyBytes) (types.GrandpaOpaqueKeyOwnershipProof, error) { + ret := _m.Called(authSetID, authorityID) + + var r0 types.GrandpaOpaqueKeyOwnershipProof + if rf, ok := ret.Get(0).(func(uint64, ed25519.PublicKeyBytes) types.GrandpaOpaqueKeyOwnershipProof); ok { + r0 = rf(authSetID, authorityID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.GrandpaOpaqueKeyOwnershipProof) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(uint64, ed25519.PublicKeyBytes) error); ok { + r1 = rf(authSetID, authorityID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GrandpaSubmitReportEquivocationUnsignedExtrinsic provides a mock function with given fields: equivocationProof, keyOwnershipProof +func (_m *Instance) GrandpaSubmitReportEquivocationUnsignedExtrinsic(equivocationProof types.GrandpaEquivocationProof, keyOwnershipProof types.GrandpaOpaqueKeyOwnershipProof) error { + ret := _m.Called(equivocationProof, keyOwnershipProof) + + var r0 error + if rf, ok := ret.Get(0).(func(types.GrandpaEquivocationProof, types.GrandpaOpaqueKeyOwnershipProof) error); ok { + r0 = rf(equivocationProof, keyOwnershipProof) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// InherentExtrinsics provides a mock function with given fields: data +func (_m *Instance) InherentExtrinsics(data []byte) ([]byte, error) { + ret := _m.Called(data) + + var r0 []byte + if rf, ok := ret.Get(0).(func([]byte) []byte); ok { + r0 = rf(data) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func([]byte) error); ok { + r1 = rf(data) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// InitializeBlock provides a mock function with given fields: header +func (_m *Instance) InitializeBlock(header *types.Header) error { + ret := _m.Called(header) + + var r0 error + if rf, ok := ret.Get(0).(func(*types.Header) error); ok { + r0 = rf(header) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Keystore provides a mock function with given fields: +func (_m *Instance) Keystore() *keystore.GlobalKeystore { + ret := _m.Called() + + var r0 *keystore.GlobalKeystore + if rf, ok := ret.Get(0).(func() *keystore.GlobalKeystore); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*keystore.GlobalKeystore) + } + } + + return r0 +} + +// Metadata provides a mock function with given fields: +func (_m *Instance) Metadata() ([]byte, error) { + ret := _m.Called() + + var r0 []byte + if rf, ok := ret.Get(0).(func() []byte); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NetworkService provides a mock function with given fields: +func (_m *Instance) NetworkService() runtime.BasicNetwork { + ret := _m.Called() + + var r0 runtime.BasicNetwork + if rf, ok := ret.Get(0).(func() runtime.BasicNetwork); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(runtime.BasicNetwork) + } + } + + return r0 +} + +// NodeStorage provides a mock function with given fields: +func (_m *Instance) NodeStorage() runtime.NodeStorage { + ret := _m.Called() + + var r0 runtime.NodeStorage + if rf, ok := ret.Get(0).(func() runtime.NodeStorage); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(runtime.NodeStorage) + } + + return r0 +} + +// OffchainWorker provides a mock function with given fields: +func (_m *Instance) OffchainWorker() { + _m.Called() +} + +// PaymentQueryInfo provides a mock function with given fields: ext +func (_m *Instance) PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error) { + ret := _m.Called(ext) + + var r0 *types.RuntimeDispatchInfo + if rf, ok := ret.Get(0).(func([]byte) *types.RuntimeDispatchInfo); ok { + r0 = rf(ext) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.RuntimeDispatchInfo) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func([]byte) error); ok { + r1 = rf(ext) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RandomSeed provides a mock function with given fields: +func (_m *Instance) RandomSeed() { + _m.Called() +} + +// SetContextStorage provides a mock function with given fields: s +func (_m *Instance) SetContextStorage(s runtime.Storage) { + _m.Called(s) +} + +// Stop provides a mock function with given fields: +func (_m *Instance) Stop() { + _m.Called() +} + +// UpdateRuntimeCode provides a mock function with given fields: _a0 +func (_m *Instance) UpdateRuntimeCode(_a0 []byte) error { + ret := _m.Called(_a0) + + var r0 error + if rf, ok := ret.Get(0).(func([]byte) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ValidateTransaction provides a mock function with given fields: e +func (_m *Instance) ValidateTransaction(e types.Extrinsic) (*transaction.Validity, error) { + ret := _m.Called(e) + + var r0 *transaction.Validity + if rf, ok := ret.Get(0).(func(types.Extrinsic) *transaction.Validity); ok { + r0 = rf(e) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*transaction.Validity) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(types.Extrinsic) error); ok { + r1 = rf(e) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Validator provides a mock function with given fields: +func (_m *Instance) Validator() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// Version provides a mock function with given fields: +func (_m *Instance) Version() runtime.Version { + ret := _m.Called() + + var r0 runtime.Version + if rf, ok := ret.Get(0).(func() runtime.Version); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(runtime.Version) + } + + return r0 +} + +type mockConstructorTestingTNewInstance interface { + mock.TestingT + Cleanup(func()) +} + +// NewInstance creates a new instance of Instance. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewInstance(t mockConstructorTestingTNewInstance) *Instance { + mock := &Instance{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/lib/runtime/types.go b/lib/runtime/types.go index cd3a15caa3..0a16ffa165 100644 --- a/lib/runtime/types.go +++ b/lib/runtime/types.go @@ -57,5 +57,4 @@ type Context struct { SigVerifier *crypto.SignatureVerifier OffchainHTTPSet *offchain.HTTPSet Version *Version - Memory Memory } diff --git a/lib/runtime/wasmer/exports_test.go b/lib/runtime/wasmer/exports_test.go index a00074b5ab..6e7e709bdb 100644 --- a/lib/runtime/wasmer/exports_test.go +++ b/lib/runtime/wasmer/exports_test.go @@ -22,6 +22,7 @@ import ( "github.com/ChainSafe/gossamer/lib/utils" "github.com/ChainSafe/gossamer/pkg/scale" "github.com/centrifuge/go-substrate-rpc-client/v4/signature" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -31,6 +32,8 @@ import ( var testKeyOwnershipProof types.OpaqueKeyOwnershipProof = types.OpaqueKeyOwnershipProof([]byte{64, 138, 252, 29, 127, 102, 189, 129, 207, 47, 157, 60, 17, 138, 194, 121, 139, 92, 176, 175, 224, 16, 185, 93, 175, 251, 224, 81, 209, 61, 0, 71}) //nolint:lll func Test_Instance_Version(t *testing.T) { + t.Parallel() + type instanceVersioner interface { Version() (runtime.Version, error) } @@ -144,6 +147,8 @@ func Test_Instance_Version(t *testing.T) { for name, testCase := range testCases { testCase := testCase t.Run(name, func(t *testing.T) { + t.Parallel() + instance := testCase.instanceBuilder(t) version, err := instance.Version() require.NoError(t, err) @@ -227,6 +232,7 @@ func TestWestendRuntime_ValidateTransaction(t *testing.T) { func TestInstance_GrandpaAuthorities_NodeRuntime(t *testing.T) { tt := trie.NewEmptyTrie() + value, err := common.HexToBytes("0x0108eea1eabcac7d2c8a6459b7322cf997874482bfc3d2ec7a80888a3a7d714103640100000000000000b64994460e59b30364cad3c92e3df6052f9b0ebbb8f88460c194dc5794d6d7170100000000000000") //nolint:lll require.NoError(t, err) @@ -254,6 +260,7 @@ func TestInstance_GrandpaAuthorities_NodeRuntime(t *testing.T) { func TestInstance_GrandpaAuthorities_PolkadotRuntime(t *testing.T) { tt := trie.NewEmptyTrie() + value, err := common.HexToBytes("0x0108eea1eabcac7d2c8a6459b7322cf997874482bfc3d2ec7a80888a3a7d714103640100000000000000b64994460e59b30364cad3c92e3df6052f9b0ebbb8f88460c194dc5794d6d7170100000000000000") //nolint:lll require.NoError(t, err) @@ -275,10 +282,13 @@ func TestInstance_GrandpaAuthorities_PolkadotRuntime(t *testing.T) { {Key: authA, Weight: 1}, {Key: authB, Weight: 1}, } + require.Equal(t, expected, auths) } func TestInstance_BabeGenerateKeyOwnershipProof(t *testing.T) { + t.Parallel() + testCases := []struct { name string targetRuntime string @@ -295,7 +305,10 @@ func TestInstance_BabeGenerateKeyOwnershipProof(t *testing.T) { for _, testCase := range testCases { testCase := testCase t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + tt := trie.NewEmptyTrie() + randomnessValue, err := common.HexToHash("0x01") require.NoError(t, err) key := common.MustHexToBytes(genesis.BABERandomnessKeyHex) @@ -325,6 +338,8 @@ func TestInstance_BabeGenerateKeyOwnershipProof(t *testing.T) { } func TestInstance_BabeSubmitReportEquivocationUnsignedExtrinsic(t *testing.T) { + t.Parallel() + testCases := []struct { name string targetRuntime string @@ -341,6 +356,8 @@ func TestInstance_BabeSubmitReportEquivocationUnsignedExtrinsic(t *testing.T) { for _, testCase := range testCases { testCase := testCase t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + tt := trie.NewEmptyTrie() rt := NewTestInstanceWithTrie(t, testCase.targetRuntime, tt) authorityID := types.AuthorityID{1} @@ -412,6 +429,7 @@ func TestInstance_BabeConfiguration_WestendRuntime_WithAuthorities(t *testing.T) Randomness: [32]byte{1}, SecondarySlots: 2, } + require.Equal(t, expected, cfg) } @@ -927,13 +945,15 @@ func TestInstance_PaymentQueryInfo(t *testing.T) { }, { // incomplete extrinsic - ext: "0x4ccde39a5684e7a56da23b22d4d9fbadb023baa19c56495432884d0640000000000000000000000000000000", - errMessage: "running runtime function: unreachable", + ext: "0x4ccde39a5684e7a56da23b22d4d9fbadb023baa19c56495432884d0640000000000000000000000000000000", + errMessage: "running runtime function: " + + "Failed to call the `TransactionPaymentApi_query_info` exported function.", }, { // incomplete extrinsic - extB: nil, - errMessage: "running runtime function: unreachable", + extB: nil, + errMessage: "running runtime function: " + + "Failed to call the `TransactionPaymentApi_query_info` exported function.", }, } @@ -956,6 +976,7 @@ func TestInstance_PaymentQueryInfo(t *testing.T) { continue } require.NoError(t, err) + require.NoError(t, err) require.NotNil(t, info) require.Equal(t, test.expect, info) @@ -983,6 +1004,7 @@ func newTrieFromPairs(t *testing.T, filename string) *trie.Trie { } func TestInstance_TransactionPaymentCallApi_QueryCallInfo(t *testing.T) { + t.Parallel() ins := NewTestInstance(t, runtime.WESTEND_RUNTIME_v0929) tests := []struct { callHex string @@ -1007,15 +1029,17 @@ func TestInstance_TransactionPaymentCallApi_QueryCallInfo(t *testing.T) { // polkadot.js/api returns error: RPC-CORE: call(method: Text, data: Bytes, at?: BlockHash): // Bytes:: -32000: Client error: Execution failed: Execution aborted due to trap: wasm trap: wasm //`unreachable` instruction executed - callHex: "0x040001084564", - errMessage: "running runtime function: unreachable", + callHex: "0x040001084564", + errMessage: "running runtime function: " + + "Failed to call the `TransactionPaymentCallApi_query_call_info` exported function.", }, { // call without removing any bytes, polkadot.js/api v9.5.1: api.tx.system.remark("Ed test") // polkadot.js/api returns error: Error: createType(Call):: findMetaCall: Unable to find Call with index // [44, 4]/[44,4] - callHex: "0x2c0400011c45642074657374", - errMessage: "running runtime function: unreachable", + callHex: "0x2c0400011c45642074657374", + errMessage: "running runtime function: " + + "Failed to call the `TransactionPaymentCallApi_query_call_info` exported function.", }, } @@ -1040,6 +1064,7 @@ func TestInstance_TransactionPaymentCallApi_QueryCallInfo(t *testing.T) { } func TestInstance_TransactionPaymentCallApi_QueryCallFeeDetails(t *testing.T) { + t.Parallel() ins := NewTestInstance(t, runtime.WESTEND_RUNTIME_v0929) tests := []struct { callHex string @@ -1070,15 +1095,17 @@ func TestInstance_TransactionPaymentCallApi_QueryCallFeeDetails(t *testing.T) { // when calling polkadot node (v0.9.29) with polkadot.js/api the node returns error: RPC-CORE: call( // method: Text, data: Bytes, at?: BlockHash): Bytes:: -32000: Client error: Execution failed: // Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed - callHex: "0x040001084564", - errMessage: "running runtime function: unreachable", + callHex: "0x040001084564", + errMessage: "running runtime function: " + + "Failed to call the `TransactionPaymentCallApi_query_call_fee_details` exported function.", }, { // call without removing any bytes, polkadot.js/api v9.5.1: api.tx.system.remark("Ed test") // when calling polkadot (v0.9.29) with polkadot.js/api the node returns error: Error: createType( //Call):: findMetaCall: Unable to find Call with index [44, 4]/[44,4] - callHex: "0x18040001084564", - errMessage: "running runtime function: unreachable", + callHex: "0x18040001084564", + errMessage: "running runtime function: " + + "Failed to call the `TransactionPaymentCallApi_query_call_fee_details` exported function.", }, } @@ -1100,6 +1127,7 @@ func TestInstance_TransactionPaymentCallApi_QueryCallFeeDetails(t *testing.T) { } func TestInstance_GrandpaGenerateKeyOwnershipProof(t *testing.T) { + t.Parallel() instance := NewTestInstance(t, runtime.WESTEND_RUNTIME_v0929) identity := common.MustHexToBytes("0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee") identityPubKey, _ := ed25519.NewPublicKey(identity) @@ -1112,6 +1140,7 @@ func TestInstance_GrandpaGenerateKeyOwnershipProof(t *testing.T) { } func TestInstance_GrandpaSubmitReportEquivocationUnsignedExtrinsic(t *testing.T) { + t.Parallel() identity := common.MustHexToBytes("0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee") identityPubKey, _ := ed25519.NewPublicKey(identity) runtime := NewTestInstance(t, runtime.WESTEND_RUNTIME_v0929) diff --git a/lib/runtime/wasmer/genesis_test.go b/lib/runtime/wasmer/genesis_test.go index b5e93df355..b261f4e397 100644 --- a/lib/runtime/wasmer/genesis_test.go +++ b/lib/runtime/wasmer/genesis_test.go @@ -13,6 +13,8 @@ import ( ) func Test_NewTrieFromGenesis(t *testing.T) { + t.Parallel() + testCases := map[string]struct { genesis genesis.Genesis expectedKV map[string]string @@ -62,6 +64,8 @@ func Test_NewTrieFromGenesis(t *testing.T) { for name, testCase := range testCases { testCase := testCase t.Run(name, func(t *testing.T) { + t.Parallel() + tr, err := NewTrieFromGenesis(testCase.genesis) require.ErrorIs(t, err, testCase.errSentinel) diff --git a/lib/runtime/wasmer/helpers.go b/lib/runtime/wasmer/helpers.go index c64c533256..f8eb008415 100644 --- a/lib/runtime/wasmer/helpers.go +++ b/lib/runtime/wasmer/helpers.go @@ -3,24 +3,19 @@ package wasmer +// #include +import "C" //skipcq: SCC-compile + import ( "fmt" - "math" "math/big" "github.com/ChainSafe/gossamer/lib/common/types" "github.com/ChainSafe/gossamer/lib/runtime" "github.com/ChainSafe/gossamer/pkg/scale" - "github.com/wasmerio/wasmer-go/wasmer" + "github.com/wasmerio/go-ext-wasm/wasmer" ) -func safeCastInt32(value uint32) (int32, error) { - if value > math.MaxInt32 { - return 0, fmt.Errorf("%w", errMemoryValueOutOfBounds) - } - return int32(value), nil -} - // toPointerSize converts an uint32 pointer and uint32 size // to an int64 pointer size. func toPointerSize(ptr, size uint32) (pointerSize int64) { @@ -34,17 +29,17 @@ func splitPointerSize(pointerSize int64) (ptr, size uint32) { } // asMemorySlice converts a 64 bit pointer size to a Go byte slice. -func asMemorySlice(context *runtime.Context, pointerSize int64) (data []byte) { - memory := context.Memory.Data() - ptr, size := splitPointerSize(pointerSize) +func asMemorySlice(context wasmer.InstanceContext, pointerSize C.int64_t) (data []byte) { + memory := context.Memory().Data() + ptr, size := splitPointerSize(int64(pointerSize)) return memory[ptr : ptr+size] } // toWasmMemory copies a Go byte slice to wasm memory and returns the corresponding // 64 bit pointer size. -func toWasmMemory(context *runtime.Context, data []byte) ( +func toWasmMemory(context wasmer.InstanceContext, data []byte) ( pointerSize int64, err error) { - allocator := context.Allocator + allocator := context.Data().(*runtime.Context).Allocator size := uint32(len(data)) ptr, err := allocator.Allocate(size) @@ -52,7 +47,7 @@ func toWasmMemory(context *runtime.Context, data []byte) ( return 0, fmt.Errorf("allocating: %w", err) } - memory := context.Memory.Data() + memory := context.Memory().Data() if uint32(len(memory)) < ptr+size { panic(fmt.Sprintf("length of memory is less than expected, want %d have %d", ptr+size, len(memory))) @@ -65,9 +60,9 @@ func toWasmMemory(context *runtime.Context, data []byte) ( // toWasmMemorySized copies a Go byte slice to wasm memory and returns the corresponding // 32 bit pointer. Note the data must have a well known fixed length in the runtime. -func toWasmMemorySized(context *runtime.Context, data []byte) ( +func toWasmMemorySized(context wasmer.InstanceContext, data []byte) ( pointer uint32, err error) { - allocator := context.Allocator + allocator := context.Data().(*runtime.Context).Allocator size := uint32(len(data)) pointer, err = allocator.Allocate(size) @@ -75,7 +70,7 @@ func toWasmMemorySized(context *runtime.Context, data []byte) ( return 0, fmt.Errorf("allocating: %w", err) } - memory := context.Memory.Data() + memory := context.Memory().Data() copy(memory[pointer:pointer+size], data) return pointer, nil @@ -83,7 +78,7 @@ func toWasmMemorySized(context *runtime.Context, data []byte) ( // toWasmMemoryOptional scale encodes the byte slice `data`, writes it to wasm memory // and returns the corresponding 64 bit pointer size. -func toWasmMemoryOptional(context *runtime.Context, data []byte) ( +func toWasmMemoryOptional(context wasmer.InstanceContext, data []byte) ( pointerSize int64, err error) { var optionalSlice *[]byte if data != nil { @@ -97,43 +92,10 @@ func toWasmMemoryOptional(context *runtime.Context, data []byte) ( return toWasmMemory(context, encoded) } -func toWasmMemoryOptionalNil(context *runtime.Context) ( - cPointerSize []wasmer.Value, err error) { - pointerSize, err := toWasmMemoryOptional(context, nil) - if err != nil { - return []wasmer.Value{wasmer.NewI64(0)}, err - } - - return []wasmer.Value{wasmer.NewI64(pointerSize)}, nil -} - -func mustToWasmMemoryOptionalNil(context *runtime.Context) ( - cPointerSize []wasmer.Value) { - cPointerSize, err := toWasmMemoryOptionalNil(context) - if err != nil { - panic(err) - } - - return cPointerSize -} - -// toWasmMemoryFixedSizeOptional copies the `data` byte slice to a 64B array, -// scale encodes the pointer to the resulting array, writes it to wasm memory -// and returns the corresponding 64 bit pointer size. -func toWasmMemoryFixedSizeOptional(context *runtime.Context, data []byte) ( - pointerSize int64, err error) { - var optionalFixedSize [64]byte - copy(optionalFixedSize[:], data) - encodedOptionalFixedSize, err := scale.Marshal(&optionalFixedSize) - if err != nil { - return 0, fmt.Errorf("scale encoding: %w", err) - } - return toWasmMemory(context, encodedOptionalFixedSize) -} // toWasmMemoryResult wraps the data byte slice in a Result type, scale encodes it, // copies it to wasm memory and returns the corresponding 64 bit pointer size. -func toWasmMemoryResult(context *runtime.Context, data []byte) ( +func toWasmMemoryResult(context wasmer.InstanceContext, data []byte) ( pointerSize int64, err error) { var result *types.Result if len(data) == 0 { @@ -150,45 +112,64 @@ func toWasmMemoryResult(context *runtime.Context, data []byte) ( return toWasmMemory(context, encodedResult) } -func toWasmMemoryResultEmpty(context *runtime.Context) ( - cPointerSize []wasmer.Value, err error) { - pointerSize, err := toWasmMemoryResult(context, nil) +// toWasmMemoryOptional scale encodes the uint32 pointer `data`, writes it to wasm memory +// and returns the corresponding 64 bit pointer size. +func toWasmMemoryOptionalUint32(context wasmer.InstanceContext, data *uint32) ( + pointerSize int64, err error) { + enc, err := scale.Marshal(data) if err != nil { - return []wasmer.Value{wasmer.NewI64(0)}, err + return 0, fmt.Errorf("scale encoding: %w", err) } - return []wasmer.Value{wasmer.NewI64(pointerSize)}, nil + return toWasmMemory(context, enc) } -func mustToWasmMemoryResultEmpty(context *runtime.Context) ( - cPointerSize []wasmer.Value) { - cPointerSize, err := toWasmMemoryResultEmpty(context) +func mustToWasmMemoryNil(context wasmer.InstanceContext) ( + cPointerSize C.int64_t) { + allocator := context.Data().(*runtime.Context).Allocator + ptr, err := allocator.Allocate(0) + if err != nil { + // we allocate 0 byte, this should never fail + panic(err) + } + pointerSize := toPointerSize(ptr, 0) + return C.int64_t(pointerSize) +} + +func toWasmMemoryOptionalNil(context wasmer.InstanceContext) ( + cPointerSize C.int64_t, err error) { + pointerSize, err := toWasmMemoryOptional(context, nil) + if err != nil { + return 0, err + } + + return C.int64_t(pointerSize), nil +} + +func mustToWasmMemoryOptionalNil(context wasmer.InstanceContext) ( + cPointerSize C.int64_t) { + cPointerSize, err := toWasmMemoryOptionalNil(context) if err != nil { panic(err) } return cPointerSize } -// toWasmMemoryOptional scale encodes the uint32 pointer `data`, writes it to wasm memory -// and returns the corresponding 64 bit pointer size. -func toWasmMemoryOptionalUint32(context *runtime.Context, data *uint32) ( - pointerSize int64, err error) { - enc, err := scale.Marshal(data) +func toWasmMemoryResultEmpty(context wasmer.InstanceContext) ( + cPointerSize C.int64_t, err error) { + pointerSize, err := toWasmMemoryResult(context, nil) if err != nil { - return 0, fmt.Errorf("scale encoding: %w", err) + return 0, err } - return toWasmMemory(context, enc) + return C.int64_t(pointerSize), nil } -func mustToWasmMemoryNil(context *runtime.Context) ( - cPointerSize []wasmer.Value) { - allocator := context.Allocator - ptr, err := allocator.Allocate(0) +func mustToWasmMemoryResultEmpty(context wasmer.InstanceContext) ( + cPointerSize C.int64_t) { + cPointerSize, err := toWasmMemoryResultEmpty(context) if err != nil { - // we allocate 0 byte, this should never fail panic(err) } - pointerSize := toPointerSize(ptr, 0) - return []wasmer.Value{wasmer.NewI64(pointerSize)} + return cPointerSize } // toKillStorageResultEnum encodes the `allRemoved` flag and @@ -213,6 +194,20 @@ func toKillStorageResultEnum(allRemoved bool, numRemoved uint32) ( return encodedEnumValue, nil } +// toWasmMemoryFixedSizeOptional copies the `data` byte slice to a 64B array, +// scale encodes the pointer to the resulting array, writes it to wasm memory +// and returns the corresponding 64 bit pointer size. +func toWasmMemoryFixedSizeOptional(context wasmer.InstanceContext, data []byte) ( + pointerSize int64, err error) { + var optionalFixedSize [64]byte + copy(optionalFixedSize[:], data) + encodedOptionalFixedSize, err := scale.Marshal(&optionalFixedSize) + if err != nil { + return 0, fmt.Errorf("scale encoding: %w", err) + } + return toWasmMemory(context, encodedOptionalFixedSize) +} + func storageAppend(storage GetSetter, key, valueToAppend []byte) (err error) { // this function assumes the item in storage is a SCALE encoded array of items // the valueToAppend is a new item, so it appends the item and increases the length prefix by 1 diff --git a/lib/runtime/wasmer/helpers_test.go b/lib/runtime/wasmer/helpers_test.go index 6e6f5fc941..191e4a7abb 100644 --- a/lib/runtime/wasmer/helpers_test.go +++ b/lib/runtime/wasmer/helpers_test.go @@ -6,7 +6,6 @@ package wasmer import ( "encoding/json" "errors" - "math" "os" "path/filepath" "testing" @@ -31,46 +30,6 @@ func genesisFromRawJSON(t *testing.T, jsonFilepath string) (gen genesis.Genesis) return gen } -func TestMemory_safeCastInt32(t *testing.T) { - t.Parallel() - testCases := []struct { - name string - value uint32 - exp int32 - expErr error - expErrMsg string - }{ - { - name: "valid cast", - value: uint32(0), - exp: int32(0), - }, - { - name: "max uint32", - value: uint32(math.MaxInt32), - exp: math.MaxInt32, - }, - { - name: "out of bounds", - value: uint32(math.MaxInt32 + 1), - expErr: errMemoryValueOutOfBounds, - expErrMsg: errMemoryValueOutOfBounds.Error(), - }, - } - for _, test := range testCases { - test := test - t.Run(test.name, func(t *testing.T) { - t.Parallel() - res, err := safeCastInt32(test.value) - assert.ErrorIs(t, err, test.expErr) - if test.expErr != nil { - assert.EqualError(t, err, test.expErrMsg) - } - assert.Equal(t, test.exp, res) - }) - } -} - func Test_pointerSize(t *testing.T) { t.Parallel() diff --git a/lib/runtime/wasmer/imports.go b/lib/runtime/wasmer/imports.go index 04943208ae..3d38cdfa0b 100644 --- a/lib/runtime/wasmer/imports.go +++ b/lib/runtime/wasmer/imports.go @@ -3,6 +3,103 @@ package wasmer +// #include +// +// extern void ext_logging_log_version_1(void *context, int32_t level, int64_t target, int64_t msg); +// extern int32_t ext_logging_max_level_version_1(void *context); +// +// extern void ext_sandbox_instance_teardown_version_1(void *context, int32_t a); +// extern int32_t ext_sandbox_instantiate_version_1(void *context, int32_t a, int64_t b, int64_t c, int32_t d); +// extern int32_t ext_sandbox_invoke_version_1(void *context, int32_t a, int64_t b, int64_t c, int32_t d, int32_t e, int32_t f); +// extern int32_t ext_sandbox_memory_get_version_1(void *context, int32_t a, int32_t b, int32_t c, int32_t d); +// extern int32_t ext_sandbox_memory_new_version_1(void *context, int32_t a, int32_t b); +// extern int32_t ext_sandbox_memory_set_version_1(void *context, int32_t a, int32_t b, int32_t c, int32_t d); +// extern void ext_sandbox_memory_teardown_version_1(void *context, int32_t a); +// +// extern int32_t ext_crypto_ed25519_generate_version_1(void *context, int32_t a, int64_t b); +// extern int64_t ext_crypto_ed25519_public_keys_version_1(void *context, int32_t a); +// extern int64_t ext_crypto_ed25519_sign_version_1(void *context, int32_t a, int32_t b, int64_t c); +// extern int32_t ext_crypto_ed25519_verify_version_1(void *context, int32_t a, int64_t b, int32_t c); +// extern int32_t ext_crypto_finish_batch_verify_version_1(void *context); +// extern int64_t ext_crypto_secp256k1_ecdsa_recover_version_1(void *context, int32_t a, int32_t b); +// extern int64_t ext_crypto_secp256k1_ecdsa_recover_version_2(void *context, int32_t a, int32_t b); +// extern int64_t ext_crypto_secp256k1_ecdsa_recover_compressed_version_1(void *context, int32_t a, int32_t b); +// extern int64_t ext_crypto_secp256k1_ecdsa_recover_compressed_version_2(void *context, int32_t a, int32_t b); +// extern int32_t ext_crypto_ecdsa_verify_version_2(void *context, int32_t a, int64_t b, int32_t c); +// extern int32_t ext_crypto_sr25519_generate_version_1(void *context, int32_t a, int64_t b); +// extern int64_t ext_crypto_sr25519_public_keys_version_1(void *context, int32_t a); +// extern int64_t ext_crypto_sr25519_sign_version_1(void *context, int32_t a, int32_t b, int64_t c); +// extern int32_t ext_crypto_sr25519_verify_version_1(void *context, int32_t a, int64_t b, int32_t c); +// extern int32_t ext_crypto_sr25519_verify_version_2(void *context, int32_t a, int64_t b, int32_t c); +// extern void ext_crypto_start_batch_verify_version_1(void *context); +// +// extern int32_t ext_trie_blake2_256_root_version_1(void *context, int64_t a); +// extern int32_t ext_trie_blake2_256_ordered_root_version_1(void *context, int64_t a); +// extern int32_t ext_trie_blake2_256_ordered_root_version_2(void *context, int64_t a, int32_t b); +// extern int32_t ext_trie_blake2_256_verify_proof_version_1(void *context, int32_t a, int64_t b, int64_t c, int64_t d); +// +// extern int64_t ext_misc_runtime_version_version_1(void *context, int64_t a); +// extern void ext_misc_print_hex_version_1(void *context, int64_t a); +// extern void ext_misc_print_num_version_1(void *context, int64_t a); +// extern void ext_misc_print_utf8_version_1(void *context, int64_t a); +// +// extern void ext_default_child_storage_clear_version_1(void *context, int64_t a, int64_t b); +// extern int64_t ext_default_child_storage_get_version_1(void *context, int64_t a, int64_t b); +// extern int64_t ext_default_child_storage_next_key_version_1(void *context, int64_t a, int64_t b); +// extern int64_t ext_default_child_storage_read_version_1(void *context, int64_t a, int64_t b, int64_t c, int32_t d); +// extern int64_t ext_default_child_storage_root_version_1(void *context, int64_t a); +// extern void ext_default_child_storage_set_version_1(void *context, int64_t a, int64_t b, int64_t c); +// extern void ext_default_child_storage_storage_kill_version_1(void *context, int64_t a); +// extern int32_t ext_default_child_storage_storage_kill_version_2(void *context, int64_t a, int64_t b); +// extern int64_t ext_default_child_storage_storage_kill_version_3(void *context, int64_t a, int64_t b); +// extern void ext_default_child_storage_clear_prefix_version_1(void *context, int64_t a, int64_t b); +// extern int32_t ext_default_child_storage_exists_version_1(void *context, int64_t a, int64_t b); +// +// extern void ext_allocator_free_version_1(void *context, int32_t a); +// extern int32_t ext_allocator_malloc_version_1(void *context, int32_t a); +// +// extern int32_t ext_hashing_blake2_128_version_1(void *context, int64_t a); +// extern int32_t ext_hashing_blake2_256_version_1(void *context, int64_t a); +// extern int32_t ext_hashing_keccak_256_version_1(void *context, int64_t a); +// extern int32_t ext_hashing_sha2_256_version_1(void *context, int64_t a); +// extern int32_t ext_hashing_twox_256_version_1(void *context, int64_t a); +// extern int32_t ext_hashing_twox_128_version_1(void *context, int64_t a); +// extern int32_t ext_hashing_twox_64_version_1(void *context, int64_t a); +// +// extern void ext_offchain_index_set_version_1(void *context, int64_t a, int64_t b); +// extern int32_t ext_offchain_is_validator_version_1(void *context); +// extern void ext_offchain_local_storage_clear_version_1(void *context, int32_t a, int64_t b); +// extern int32_t ext_offchain_local_storage_compare_and_set_version_1(void *context, int32_t a, int64_t b, int64_t c, int64_t d); +// extern int64_t ext_offchain_local_storage_get_version_1(void *context, int32_t a, int64_t b); +// extern void ext_offchain_local_storage_set_version_1(void *context, int32_t a, int64_t b, int64_t c); +// extern int64_t ext_offchain_network_state_version_1(void *context); +// extern int32_t ext_offchain_random_seed_version_1(void *context); +// extern int64_t ext_offchain_submit_transaction_version_1(void *context, int64_t a); +// extern int64_t ext_offchain_timestamp_version_1(void *context); +// extern void ext_offchain_sleep_until_version_1(void *context, int64_t a); +// extern int64_t ext_offchain_http_request_start_version_1(void *context, int64_t a, int64_t b, int64_t c); +// extern int64_t ext_offchain_http_request_add_header_version_1(void *context, int32_t a, int64_t k, int64_t v); +// +// extern void ext_storage_append_version_1(void *context, int64_t a, int64_t b); +// extern int64_t ext_storage_changes_root_version_1(void *context, int64_t a); +// extern void ext_storage_clear_version_1(void *context, int64_t a); +// extern void ext_storage_clear_prefix_version_1(void *context, int64_t a); +// extern int64_t ext_storage_clear_prefix_version_2(void *context, int64_t a, int64_t b); +// extern void ext_storage_commit_transaction_version_1(void *context); +// extern int32_t ext_storage_exists_version_1(void *context, int64_t a); +// extern int64_t ext_storage_get_version_1(void *context, int64_t a); +// extern int64_t ext_storage_next_key_version_1(void *context, int64_t a); +// extern int64_t ext_storage_read_version_1(void *context, int64_t a, int64_t b, int32_t c); +// extern void ext_storage_rollback_transaction_version_1(void *context); +// extern int64_t ext_storage_root_version_1(void *context); +// extern int64_t ext_storage_root_version_2(void *context, int32_t a); +// extern void ext_storage_set_version_1(void *context, int64_t a, int64_t b); +// extern void ext_storage_start_transaction_version_1(void *context); +// +// extern void ext_transaction_index_index_version_1(void *context, int32_t a, int32_t b, int32_t c); +// extern void ext_transaction_index_renew_version_1(void *context, int32_t a, int32_t b); +import "C" //skipcq: SCC-compile + import ( "encoding/binary" "fmt" @@ -10,6 +107,7 @@ import ( "math/rand" "reflect" "time" + "unsafe" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/crypto" @@ -21,7 +119,8 @@ import ( "github.com/ChainSafe/gossamer/lib/trie" "github.com/ChainSafe/gossamer/lib/trie/proof" "github.com/ChainSafe/gossamer/pkg/scale" - "github.com/wasmerio/wasmer-go/wasmer" + + wasm "github.com/wasmerio/go-ext-wasm/wasmer" ) const ( @@ -29,20 +128,12 @@ const ( ) //export ext_logging_log_version_1 -func ext_logging_log_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_logging_log_version_1(context unsafe.Pointer, level C.int32_t, targetData, msgData C.int64_t) { logger.Trace("executing...") - ctx := env.(*runtime.Context) - - level, ok := args[0].Unwrap().(int32) - if !ok { - logger.Criticalf("[ext_logging_log_version_1]", "error", "addr cannot be converted to int32") - } + instanceContext := wasm.IntoInstanceContext(context) - targetData := args[1].I64() - msgData := args[2].I64() - - target := string(asMemorySlice(ctx, targetData)) - msg := string(asMemorySlice(ctx, msgData)) + target := string(asMemorySlice(instanceContext, targetData)) + msg := string(asMemorySlice(instanceContext, msgData)) switch int(level) { case 0: @@ -58,96 +149,89 @@ func ext_logging_log_version_1(env interface{}, args []wasmer.Value) ([]wasmer.V default: logger.Errorf("level=%d target=%s message=%s", int(level), target, msg) } - return nil, nil } //export ext_logging_max_level_version_1 -func ext_logging_max_level_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_logging_max_level_version_1(context unsafe.Pointer) C.int32_t { logger.Trace("executing...") - return []wasmer.Value{wasmer.NewI32(4)}, nil + return 4 } //export ext_transaction_index_index_version_1 -func ext_transaction_index_index_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_transaction_index_index_version_1(context unsafe.Pointer, a, b, c C.int32_t) { logger.Trace("executing...") logger.Warn("unimplemented") - return nil, nil } //export ext_transaction_index_renew_version_1 -func ext_transaction_index_renew_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_transaction_index_renew_version_1(context unsafe.Pointer, a, b C.int32_t) { logger.Trace("executing...") logger.Warn("unimplemented") - return nil, nil } //export ext_sandbox_instance_teardown_version_1 -func ext_sandbox_instance_teardown_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_sandbox_instance_teardown_version_1(context unsafe.Pointer, a C.int32_t) { logger.Trace("executing...") logger.Warn("unimplemented") - return nil, nil } //export ext_sandbox_instantiate_version_1 -func ext_sandbox_instantiate_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_sandbox_instantiate_version_1(context unsafe.Pointer, a C.int32_t, x, y C.int64_t, z C.int32_t) C.int32_t { logger.Trace("executing...") logger.Warn("unimplemented") - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } //export ext_sandbox_invoke_version_1 -func ext_sandbox_invoke_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_sandbox_invoke_version_1(context unsafe.Pointer, a C.int32_t, x, y C.int64_t, z, d, e C.int32_t) C.int32_t { logger.Trace("executing...") logger.Warn("unimplemented") - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } //export ext_sandbox_memory_get_version_1 -func ext_sandbox_memory_get_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_sandbox_memory_get_version_1(context unsafe.Pointer, a, z, d, e C.int32_t) C.int32_t { logger.Trace("executing...") logger.Warn("unimplemented") - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } //export ext_sandbox_memory_new_version_1 -func ext_sandbox_memory_new_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_sandbox_memory_new_version_1(context unsafe.Pointer, a, z C.int32_t) C.int32_t { logger.Trace("executing...") logger.Warn("unimplemented") - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } //export ext_sandbox_memory_set_version_1 -func ext_sandbox_memory_set_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_sandbox_memory_set_version_1(context unsafe.Pointer, a, z, d, e C.int32_t) C.int32_t { logger.Trace("executing...") logger.Warn("unimplemented") - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } //export ext_sandbox_memory_teardown_version_1 -func ext_sandbox_memory_teardown_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_sandbox_memory_teardown_version_1(context unsafe.Pointer, a C.int32_t) { logger.Trace("executing...") logger.Warn("unimplemented") - return nil, nil } //export ext_crypto_ed25519_generate_version_1 -func ext_crypto_ed25519_generate_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_ed25519_generate_version_1(context unsafe.Pointer, keyTypeID C.int32_t, seedSpan C.int64_t) C.int32_t { logger.Trace("executing...") - runtimeCtx := env.(*runtime.Context) - memory := runtimeCtx.Memory.Data() - - keyTypeID := args[0].I32() - seedSpan := args[1].I64() + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) + memory := instanceContext.Memory().Data() id := memory[keyTypeID : keyTypeID+4] - seedBytes := asMemorySlice(runtimeCtx, seedSpan) + seedBytes := asMemorySlice(instanceContext, seedSpan) var seed *[]byte err := scale.Unmarshal(seedBytes, &seed) if err != nil { logger.Warnf("cannot generate key: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } var kp KeyPair @@ -160,59 +244,54 @@ func ext_crypto_ed25519_generate_version_1(env interface{}, args []wasmer.Value) if err != nil { logger.Warnf("cannot generate key: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } ks, err := runtimeCtx.Keystore.GetKeystore(id) if err != nil { logger.Warnf("error for id 0x%x: %s", id, err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } err = ks.Insert(kp) if err != nil { logger.Warnf("failed to insert key: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } - ret, err := toWasmMemorySized(runtimeCtx, kp.Public().Encode()) + ret, err := toWasmMemorySized(instanceContext, kp.Public().Encode()) if err != nil { logger.Warnf("failed to allocate memory: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil - } - - castedRet, err := safeCastInt32(ret) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err + return 0 } logger.Debug("generated ed25519 keypair with public key: " + kp.Public().Hex()) - return []wasmer.Value{wasmer.NewI32(castedRet)}, nil + return C.int32_t(ret) } //export ext_crypto_ed25519_public_keys_version_1 -func ext_crypto_ed25519_public_keys_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_ed25519_public_keys_version_1(context unsafe.Pointer, keyTypeID C.int32_t) C.int64_t { logger.Debug("executing...") - runtimeCtx := env.(*runtime.Context) - memory := runtimeCtx.Memory.Data() - keyTypeID := args[0].I32() + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) + memory := instanceContext.Memory().Data() + id := memory[keyTypeID : keyTypeID+4] ks, err := runtimeCtx.Keystore.GetKeystore(id) if err != nil { logger.Warnf("error for id 0x%x: %s", id, err) - ret, _ := toWasmMemory(runtimeCtx, []byte{0}) - return []wasmer.Value{wasmer.NewI64(ret)}, nil + ret, _ := toWasmMemory(instanceContext, []byte{0}) + return C.int64_t(ret) } if ks.Type() != crypto.Ed25519Type && ks.Type() != crypto.UnknownType { logger.Warnf( "error for id 0x%x: keystore type is %s and not the expected ed25519", id, ks.Type()) - ret, _ := toWasmMemory(runtimeCtx, []byte{0}) - return []wasmer.Value{wasmer.NewI64(ret)}, nil + ret, _ := toWasmMemory(instanceContext, []byte{0}) + return C.int64_t(ret) } keys := ks.PublicKeys() @@ -225,90 +304,85 @@ func ext_crypto_ed25519_public_keys_version_1(env interface{}, args []wasmer.Val prefix, err := scale.Marshal(big.NewInt(int64(len(keys)))) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - ret, _ := toWasmMemory(runtimeCtx, []byte{0}) - return []wasmer.Value{wasmer.NewI64(ret)}, nil + ret, _ := toWasmMemory(instanceContext, []byte{0}) + return C.int64_t(ret) } - ret, err := toWasmMemory(runtimeCtx, append(prefix, encodedKeys...)) + ret, err := toWasmMemory(instanceContext, append(prefix, encodedKeys...)) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - ret, _ = toWasmMemory(runtimeCtx, []byte{0}) - return []wasmer.Value{wasmer.NewI64(ret)}, nil + ret, _ = toWasmMemory(instanceContext, []byte{0}) + return C.int64_t(ret) } - return []wasmer.Value{wasmer.NewI64(ret)}, nil + return C.int64_t(ret) } //export ext_crypto_ed25519_sign_version_1 -func ext_crypto_ed25519_sign_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_ed25519_sign_version_1(context unsafe.Pointer, keyTypeID, key C.int32_t, msg C.int64_t) C.int64_t { logger.Debug("executing...") - runtimeCtx := env.(*runtime.Context) - memory := runtimeCtx.Memory.Data() + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) + memory := instanceContext.Memory().Data() - keyTypeID := args[0].I32() - key := args[1].I32() - msg := args[2].I64() id := memory[keyTypeID : keyTypeID+4] pubKeyData := memory[key : key+32] pubKey, err := ed25519.NewPublicKey(pubKeyData) if err != nil { logger.Errorf("failed to get public keys: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } ks, err := runtimeCtx.Keystore.GetKeystore(id) if err != nil { logger.Warnf("error for id 0x%x: %s", id, err) - return mustToWasmMemoryOptionalNil(runtimeCtx), nil + return mustToWasmMemoryOptionalNil(instanceContext) } signingKey := ks.GetKeypair(pubKey) if signingKey == nil { logger.Error("could not find public key " + pubKey.Hex() + " in keystore") - ret, err := toWasmMemoryOptionalNil(runtimeCtx) + ret, err := toWasmMemoryOptionalNil(instanceContext) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return ret, nil + return ret } - sig, err := signingKey.Sign(asMemorySlice(runtimeCtx, msg)) + sig, err := signingKey.Sign(asMemorySlice(instanceContext, msg)) if err != nil { logger.Error("could not sign message") } - ret, err := toWasmMemoryFixedSizeOptional(runtimeCtx, sig) + ret, err := toWasmMemoryFixedSizeOptional(instanceContext, sig) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(ret)}, nil + return C.int64_t(ret) } //export ext_crypto_ed25519_verify_version_1 -func ext_crypto_ed25519_verify_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_ed25519_verify_version_1(context unsafe.Pointer, sig C.int32_t, + msg C.int64_t, key C.int32_t) C.int32_t { logger.Debug("executing...") - runtimeCtx := env.(*runtime.Context) - memory := runtimeCtx.Memory.Data() - sigVerifier := runtimeCtx.SigVerifier - - sig := args[0].I32() - msg := args[1].I64() - key := args[2].I32() + instanceContext := wasm.IntoInstanceContext(context) + memory := instanceContext.Memory().Data() + sigVerifier := instanceContext.Data().(*runtime.Context).SigVerifier signature := memory[sig : sig+64] - message := asMemorySlice(runtimeCtx, msg) + message := asMemorySlice(instanceContext, msg) pubKeyData := memory[key : key+32] pubKey, err := ed25519.NewPublicKey(pubKeyData) if err != nil { logger.Error("failed to create public key") - return []wasmer.Value{wasmer.NewI32(0)}, err + return 0 } if sigVerifier.IsStarted() { @@ -319,26 +393,23 @@ func ext_crypto_ed25519_verify_version_1(env interface{}, args []wasmer.Value) ( VerifyFunc: ed25519.VerifySignature, } sigVerifier.Add(&signature) - return []wasmer.Value{wasmer.NewI32(1)}, nil + return 1 } if ok, err := pubKey.Verify(message, signature); err != nil || !ok { logger.Error("failed to verify") - return []wasmer.Value{wasmer.NewI32(0)}, err + return 0 } logger.Debug("verified ed25519 signature") - return []wasmer.Value{wasmer.NewI32(1)}, nil + return 1 } //export ext_crypto_secp256k1_ecdsa_recover_version_1 -func ext_crypto_secp256k1_ecdsa_recover_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_secp256k1_ecdsa_recover_version_1(context unsafe.Pointer, sig, msg C.int32_t) C.int64_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - memory := instanceContext.Memory.Data() - - sig := args[0].I32() - msg := args[1].I32() + instanceContext := wasm.IntoInstanceContext(context) + memory := instanceContext.Memory().Data() // msg must be the 32-byte hash of the message to be signed. // sig must be a 65-byte compact ECDSA signature containing the @@ -352,9 +423,9 @@ func ext_crypto_secp256k1_ecdsa_recover_version_1(env interface{}, args []wasmer ret, err := toWasmMemoryResultEmpty(instanceContext) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return ret, nil + return ret } logger.Debugf( @@ -364,29 +435,25 @@ func ext_crypto_secp256k1_ecdsa_recover_version_1(env interface{}, args []wasmer ret, err := toWasmMemoryResult(instanceContext, pub[1:]) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(ret)}, nil + return C.int64_t(ret) } //export ext_crypto_secp256k1_ecdsa_recover_version_2 -func ext_crypto_secp256k1_ecdsa_recover_version_2(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_secp256k1_ecdsa_recover_version_2(context unsafe.Pointer, sig, msg C.int32_t) C.int64_t { logger.Trace("executing...") - return ext_crypto_secp256k1_ecdsa_recover_version_1(env, args) + return ext_crypto_secp256k1_ecdsa_recover_version_1(context, sig, msg) } //export ext_crypto_ecdsa_verify_version_2 -func ext_crypto_ecdsa_verify_version_2(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_ecdsa_verify_version_2(context unsafe.Pointer, sig C.int32_t, msg C.int64_t, key C.int32_t) C.int32_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - memory := instanceContext.Memory.Data() - sigVerifier := instanceContext.SigVerifier - - sig := args[0].I32() - msg := args[1].I64() - key := args[2].I32() + instanceContext := wasm.IntoInstanceContext(context) + memory := instanceContext.Memory().Data() + sigVerifier := instanceContext.Data().(*runtime.Context).SigVerifier message := asMemorySlice(instanceContext, msg) signature := memory[sig : sig+64] @@ -396,7 +463,7 @@ func ext_crypto_ecdsa_verify_version_2(env interface{}, args []wasmer.Value) ([] err := pub.Decode(pubKey) if err != nil { logger.Errorf("failed to decode public key: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return C.int32_t(0) } logger.Debugf("pub=%s, message=0x%x, signature=0x%x", @@ -405,7 +472,7 @@ func ext_crypto_ecdsa_verify_version_2(env interface{}, args []wasmer.Value) ([] hash, err := common.Blake2bHash(message) if err != nil { logger.Errorf("failed to hash message: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return C.int32_t(0) } if sigVerifier.IsStarted() { @@ -416,7 +483,7 @@ func ext_crypto_ecdsa_verify_version_2(env interface{}, args []wasmer.Value) ([] VerifyFunc: secp256k1.VerifySignature, } sigVerifier.Add(&signature) - return []wasmer.Value{wasmer.NewI32(1)}, nil + return C.int32_t(1) } ok, err := pub.Verify(hash[:], signature) @@ -426,22 +493,18 @@ func ext_crypto_ecdsa_verify_version_2(env interface{}, args []wasmer.Value) ([] message += ": " + err.Error() } logger.Errorf(message) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return C.int32_t(0) } logger.Debug("validated signature") - return []wasmer.Value{wasmer.NewI32(1)}, nil + return C.int32_t(1) } //export ext_crypto_secp256k1_ecdsa_recover_compressed_version_1 -func ext_crypto_secp256k1_ecdsa_recover_compressed_version_1(env interface{}, - args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_secp256k1_ecdsa_recover_compressed_version_1(context unsafe.Pointer, sig, msg C.int32_t) C.int64_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - memory := instanceContext.Memory.Data() - - sig := args[0].I32() - msg := args[1].I32() + instanceContext := wasm.IntoInstanceContext(context) + memory := instanceContext.Memory().Data() // msg must be the 32-byte hash of the message to be signed. // sig must be a 65-byte compact ECDSA signature containing the @@ -452,7 +515,7 @@ func ext_crypto_secp256k1_ecdsa_recover_compressed_version_1(env interface{}, cpub, err := secp256k1.RecoverPublicKeyCompressed(message, signature) if err != nil { logger.Errorf("failed to recover public key: %s", err) - return mustToWasmMemoryResultEmpty(instanceContext), nil + return mustToWasmMemoryResultEmpty(instanceContext) } logger.Debugf( @@ -462,27 +525,25 @@ func ext_crypto_secp256k1_ecdsa_recover_compressed_version_1(env interface{}, ret, err := toWasmMemoryResult(instanceContext, cpub) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(ret)}, nil + return C.int64_t(ret) } //export ext_crypto_secp256k1_ecdsa_recover_compressed_version_2 -func ext_crypto_secp256k1_ecdsa_recover_compressed_version_2(env interface{}, - args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_secp256k1_ecdsa_recover_compressed_version_2(context unsafe.Pointer, sig, msg C.int32_t) C.int64_t { logger.Trace("executing...") - return ext_crypto_secp256k1_ecdsa_recover_compressed_version_1(env, args) + return ext_crypto_secp256k1_ecdsa_recover_compressed_version_1(context, sig, msg) } //export ext_crypto_sr25519_generate_version_1 -func ext_crypto_sr25519_generate_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_sr25519_generate_version_1(context unsafe.Pointer, keyTypeID C.int32_t, seedSpan C.int64_t) C.int32_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - memory := instanceContext.Memory.Data() - keyTypeID := args[0].I32() - seedSpan := args[1].I64() + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) + memory := instanceContext.Memory().Data() id := memory[keyTypeID : keyTypeID+4] seedBytes := asMemorySlice(instanceContext, seedSpan) @@ -491,7 +552,7 @@ func ext_crypto_sr25519_generate_version_1(env interface{}, args []wasmer.Value) err := scale.Unmarshal(seedBytes, &seed) if err != nil { logger.Warnf("cannot generate key: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } var kp KeyPair @@ -506,52 +567,43 @@ func ext_crypto_sr25519_generate_version_1(env interface{}, args []wasmer.Value) panic(err) } - ks, err := instanceContext.Keystore.GetKeystore(id) + ks, err := runtimeCtx.Keystore.GetKeystore(id) if err != nil { logger.Warnf("error for id "+common.BytesToHex(id)+": %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } err = ks.Insert(kp) if err != nil { logger.Warnf("failed to insert key: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } ret, err := toWasmMemorySized(instanceContext, kp.Public().Encode()) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil - } - - castedRet, err := safeCastInt32(ret) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err + return 0 } logger.Debug("generated sr25519 keypair with public key: " + kp.Public().Hex()) - return []wasmer.Value{wasmer.NewI32(castedRet)}, nil + return C.int32_t(ret) } //export ext_crypto_sr25519_public_keys_version_1 -func ext_crypto_sr25519_public_keys_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_sr25519_public_keys_version_1(context unsafe.Pointer, keyTypeID C.int32_t) C.int64_t { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - memory := instanceContext.Memory.Data() - keyTypeID, ok := args[0].Unwrap().(int32) - if !ok { - panic("keyTypeID is not int32") - } + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) + memory := instanceContext.Memory().Data() id := memory[keyTypeID : keyTypeID+4] - ks, err := instanceContext.Keystore.GetKeystore(id) + ks, err := runtimeCtx.Keystore.GetKeystore(id) if err != nil { logger.Warnf("error for id "+common.BytesToHex(id)+": %s", err) ret, _ := toWasmMemory(instanceContext, []byte{0}) - return []wasmer.Value{wasmer.NewI64(ret)}, nil + return C.int64_t(ret) } if ks.Type() != crypto.Sr25519Type && ks.Type() != crypto.UnknownType { @@ -559,7 +611,7 @@ func ext_crypto_sr25519_public_keys_version_1(env interface{}, args []wasmer.Val "keystore type for id 0x%x is %s and not expected sr25519", id, ks.Type()) ret, _ := toWasmMemory(instanceContext, []byte{0}) - return []wasmer.Value{wasmer.NewI64(ret)}, nil + return C.int64_t(ret) } keys := ks.PublicKeys() @@ -573,78 +625,71 @@ func ext_crypto_sr25519_public_keys_version_1(env interface{}, args []wasmer.Val if err != nil { logger.Errorf("failed to allocate memory: %s", err) ret, _ := toWasmMemory(instanceContext, []byte{0}) - return []wasmer.Value{wasmer.NewI64(ret)}, nil + return C.int64_t(ret) } ret, err := toWasmMemory(instanceContext, append(prefix, encodedKeys...)) if err != nil { logger.Errorf("failed to allocate memory: %s", err) ret, _ = toWasmMemory(instanceContext, []byte{0}) - return []wasmer.Value{wasmer.NewI64(ret)}, nil + return C.int64_t(ret) } - return []wasmer.Value{wasmer.NewI64(ret)}, nil + return C.int64_t(ret) } //export ext_crypto_sr25519_sign_version_1 -func ext_crypto_sr25519_sign_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_sr25519_sign_version_1(context unsafe.Pointer, keyTypeID, key C.int32_t, msg C.int64_t) C.int64_t { logger.Debug("executing...") - runtimeCtx := env.(*runtime.Context) - memory := runtimeCtx.Memory.Data() - keyTypeID := args[0].I32() - key := args[1].I32() - msg := args[2].I64() - - emptyRet, _ := toWasmMemoryOptional(runtimeCtx, nil) + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) + memory := instanceContext.Memory().Data() id := memory[keyTypeID : keyTypeID+4] ks, err := runtimeCtx.Keystore.GetKeystore(id) if err != nil { logger.Warnf("error for id 0x%x: %s", id, err) - return []wasmer.Value{wasmer.NewI64(emptyRet)}, nil + return mustToWasmMemoryOptionalNil(instanceContext) } var ret int64 pubKey, err := sr25519.NewPublicKey(memory[key : key+32]) if err != nil { logger.Errorf("failed to get public key: %s", err) - return []wasmer.Value{wasmer.NewI64(emptyRet)}, nil + return mustToWasmMemoryOptionalNil(instanceContext) } signingKey := ks.GetKeypair(pubKey) if signingKey == nil { logger.Error("could not find public key " + pubKey.Hex() + " in keystore") - return []wasmer.Value{wasmer.NewI64(emptyRet)}, nil + return mustToWasmMemoryOptionalNil(instanceContext) } - msgData := asMemorySlice(runtimeCtx, msg) + msgData := asMemorySlice(instanceContext, msg) sig, err := signingKey.Sign(msgData) if err != nil { logger.Errorf("could not sign message: %s", err) - return []wasmer.Value{wasmer.NewI64(emptyRet)}, nil + return mustToWasmMemoryOptionalNil(instanceContext) } - ret, err = toWasmMemoryFixedSizeOptional(runtimeCtx, sig) + ret, err = toWasmMemoryFixedSizeOptional(instanceContext, sig) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - return []wasmer.Value{wasmer.NewI64(emptyRet)}, nil + return mustToWasmMemoryOptionalNil(instanceContext) } - return []wasmer.Value{wasmer.NewI64(ret)}, nil + return C.int64_t(ret) } //export ext_crypto_sr25519_verify_version_1 -func ext_crypto_sr25519_verify_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_sr25519_verify_version_1(context unsafe.Pointer, sig C.int32_t, + msg C.int64_t, key C.int32_t) C.int32_t { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - memory := instanceContext.Memory.Data() - sigVerifier := instanceContext.SigVerifier - - sig := args[0].I32() - msg := args[1].I64() - key := args[2].I32() + instanceContext := wasm.IntoInstanceContext(context) + memory := instanceContext.Memory().Data() + sigVerifier := instanceContext.Data().(*runtime.Context).SigVerifier message := asMemorySlice(instanceContext, msg) signature := memory[sig : sig+64] @@ -652,7 +697,7 @@ func ext_crypto_sr25519_verify_version_1(env interface{}, args []wasmer.Value) ( pub, err := sr25519.NewPublicKey(memory[key : key+32]) if err != nil { logger.Error("invalid sr25519 public key") - return []wasmer.Value{wasmer.NewI32(0)}, nil //nolint + return 0 } logger.Debugf( @@ -667,7 +712,7 @@ func ext_crypto_sr25519_verify_version_1(env interface{}, args []wasmer.Value) ( VerifyFunc: sr25519.VerifySignature, } sigVerifier.Add(&signature) - return []wasmer.Value{wasmer.NewI32(1)}, nil + return 1 } ok, err := pub.VerifyDeprecated(message, signature) @@ -678,24 +723,21 @@ func ext_crypto_sr25519_verify_version_1(env interface{}, args []wasmer.Value) ( } logger.Debugf(message) // this fails at block 3876, which seems to be expected, based on discussions - return []wasmer.Value{wasmer.NewI32(1)}, nil + return 1 } logger.Debug("verified sr25519 signature") - return []wasmer.Value{wasmer.NewI32(1)}, nil + return 1 } //export ext_crypto_sr25519_verify_version_2 -func ext_crypto_sr25519_verify_version_2(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_sr25519_verify_version_2(context unsafe.Pointer, sig C.int32_t, + msg C.int64_t, key C.int32_t) C.int32_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - memory := instanceContext.Memory.Data() - sigVerifier := instanceContext.SigVerifier - - sig := args[0].I32() - msg := args[1].I64() - key := args[2].I32() + instanceContext := wasm.IntoInstanceContext(context) + memory := instanceContext.Memory().Data() + sigVerifier := instanceContext.Data().(*runtime.Context).SigVerifier message := asMemorySlice(instanceContext, msg) signature := memory[sig : sig+64] @@ -703,7 +745,7 @@ func ext_crypto_sr25519_verify_version_2(env interface{}, args []wasmer.Value) ( pub, err := sr25519.NewPublicKey(memory[key : key+32]) if err != nil { logger.Error("invalid sr25519 public key") - return []wasmer.Value{wasmer.NewI32(0)}, nil //nolint + return 0 } logger.Debugf( @@ -718,7 +760,7 @@ func ext_crypto_sr25519_verify_version_2(env interface{}, args []wasmer.Value) ( VerifyFunc: sr25519.VerifySignature, } sigVerifier.Add(&signature) - return []wasmer.Value{wasmer.NewI32(1)}, nil + return 1 } ok, err := pub.Verify(message, signature) @@ -728,40 +770,38 @@ func ext_crypto_sr25519_verify_version_2(env interface{}, args []wasmer.Value) ( message += ": " + err.Error() } logger.Errorf(message) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } logger.Debug("validated signature") - return []wasmer.Value{wasmer.NewI32(1)}, nil + return C.int32_t(1) } //export ext_crypto_start_batch_verify_version_1 -func ext_crypto_start_batch_verify_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_start_batch_verify_version_1(context unsafe.Pointer) { logger.Debug("executing...") // TODO: fix and re-enable signature verification (#1405) // beginBatchVerify(context) - return nil, nil } //export ext_crypto_finish_batch_verify_version_1 -func ext_crypto_finish_batch_verify_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_crypto_finish_batch_verify_version_1(context unsafe.Pointer) C.int32_t { logger.Debug("executing...") // TODO: fix and re-enable signature verification (#1405) // return finishBatchVerify(context) - return []wasmer.Value{wasmer.NewI32(1)}, nil + return 1 } //export ext_trie_blake2_256_root_version_1 -func ext_trie_blake2_256_root_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_trie_blake2_256_root_version_1(context unsafe.Pointer, dataSpan C.int64_t) C.int32_t { logger.Debug("executing...") - runtimeCtx := env.(*runtime.Context) - memory := runtimeCtx.Memory.Data() - dataSpan := args[0].I64() - - data := asMemorySlice(runtimeCtx, dataSpan) + instanceContext := wasm.IntoInstanceContext(context) + memory := instanceContext.Memory().Data() + runtimeCtx := instanceContext.Data().(*runtime.Context) + data := asMemorySlice(instanceContext, dataSpan) t := trie.NewEmptyTrie() @@ -773,7 +813,7 @@ func ext_trie_blake2_256_root_version_1(env interface{}, args []wasmer.Value) ([ var kvs []kv if err := scale.Unmarshal(data, &kvs); err != nil { logger.Errorf("failed scale decoding data: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } for _, kv := range kvs { @@ -781,7 +821,7 @@ func ext_trie_blake2_256_root_version_1(env interface{}, args []wasmer.Value) ([ if err != nil { logger.Errorf("failed putting key 0x%x and value 0x%x into trie: %s", kv.Key, kv.Value, err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } } @@ -789,49 +829,42 @@ func ext_trie_blake2_256_root_version_1(env interface{}, args []wasmer.Value) ([ ptr, err := runtimeCtx.Allocator.Allocate(32) if err != nil { logger.Errorf("failed allocating: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } hash, err := t.Hash() if err != nil { logger.Errorf("failed computing trie Merkle root hash: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil - } - - castedPtr, err := safeCastInt32(ptr) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err + return 0 } logger.Debugf("root hash is %s", hash) copy(memory[ptr:ptr+32], hash[:]) - return []wasmer.Value{wasmer.NewI32(castedPtr)}, nil + return C.int32_t(ptr) } //export ext_trie_blake2_256_ordered_root_version_1 -func ext_trie_blake2_256_ordered_root_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_trie_blake2_256_ordered_root_version_1(context unsafe.Pointer, dataSpan C.int64_t) C.int32_t { logger.Debug("executing...") - runtimeCtx := env.(*runtime.Context) - memory := runtimeCtx.Memory.Data() - dataSpan := args[0].I64() - - data := asMemorySlice(runtimeCtx, dataSpan) + instanceContext := wasm.IntoInstanceContext(context) + memory := instanceContext.Memory().Data() + runtimeCtx := instanceContext.Data().(*runtime.Context) + data := asMemorySlice(instanceContext, dataSpan) t := trie.NewEmptyTrie() var values [][]byte err := scale.Unmarshal(data, &values) if err != nil { logger.Errorf("failed scale decoding data: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } for i, value := range values { key, err := scale.Marshal(big.NewInt(int64(i))) if err != nil { logger.Errorf("failed scale encoding value index %d: %s", i, err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } logger.Tracef( "put key=0x%x and value=0x%x", @@ -841,7 +874,7 @@ func ext_trie_blake2_256_ordered_root_version_1(env interface{}, args []wasmer.V if err != nil { logger.Errorf("failed putting key 0x%x and value 0x%x into trie: %s", key, value, err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } } @@ -849,107 +882,93 @@ func ext_trie_blake2_256_ordered_root_version_1(env interface{}, args []wasmer.V ptr, err := runtimeCtx.Allocator.Allocate(32) if err != nil { logger.Errorf("failed allocating: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } hash, err := t.Hash() if err != nil { logger.Errorf("failed computing trie Merkle root hash: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil - } - - castedPtr, err := safeCastInt32(ptr) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err + return 0 } logger.Debugf("root hash is %s", hash) copy(memory[ptr:ptr+32], hash[:]) - return []wasmer.Value{wasmer.NewI32(castedPtr)}, nil + return C.int32_t(ptr) } //export ext_trie_blake2_256_ordered_root_version_2 -func ext_trie_blake2_256_ordered_root_version_2(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_trie_blake2_256_ordered_root_version_2(context unsafe.Pointer, + dataSpan C.int64_t, version C.int32_t) C.int32_t { // TODO: update to use state trie version 1 (#2418) - return ext_trie_blake2_256_ordered_root_version_1(env, args) + return ext_trie_blake2_256_ordered_root_version_1(context, dataSpan) } //export ext_trie_blake2_256_verify_proof_version_1 -func ext_trie_blake2_256_verify_proof_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_trie_blake2_256_verify_proof_version_1(context unsafe.Pointer, + rootSpan C.int32_t, proofSpan, keySpan, valueSpan C.int64_t) C.int32_t { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - rootSpan := args[0].I32() - proofSpan := args[1].I64() - keySpan := args[2].I64() - valueSpan := args[3].I64() + instanceContext := wasm.IntoInstanceContext(context) toDecProofs := asMemorySlice(instanceContext, proofSpan) var encodedProofNodes [][]byte err := scale.Unmarshal(toDecProofs, &encodedProofNodes) if err != nil { logger.Errorf("failed scale decoding proof data: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return C.int32_t(0) } key := asMemorySlice(instanceContext, keySpan) value := asMemorySlice(instanceContext, valueSpan) - mem := instanceContext.Memory.Data() + mem := instanceContext.Memory().Data() trieRoot := mem[rootSpan : rootSpan+32] err = proof.Verify(encodedProofNodes, trieRoot, key, value) if err != nil { logger.Errorf("failed proof verification: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return C.int32_t(0) } - return []wasmer.Value{wasmer.NewI32(1)}, nil + return C.int32_t(1) } //export ext_misc_print_hex_version_1 -func ext_misc_print_hex_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_misc_print_hex_version_1(context unsafe.Pointer, dataSpan C.int64_t) { logger.Trace("executing...") - ctx := env.(*runtime.Context) - dataSpan := args[0].I64() - data := asMemorySlice(ctx, dataSpan) + instanceContext := wasm.IntoInstanceContext(context) + data := asMemorySlice(instanceContext, dataSpan) logger.Debugf("data: 0x%x", data) - return nil, nil } //export ext_misc_print_num_version_1 -func ext_misc_print_num_version_1(_ interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_misc_print_num_version_1(_ unsafe.Pointer, data C.int64_t) { logger.Trace("executing...") - data := args[0].I64() - logger.Debugf("num: %d", data) - return nil, nil + + logger.Debugf("num: %d", int64(data)) } //export ext_misc_print_utf8_version_1 -func ext_misc_print_utf8_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_misc_print_utf8_version_1(context unsafe.Pointer, dataSpan C.int64_t) { logger.Trace("executing...") - ctx := env.(*runtime.Context) - dataSpan := args[0].I64() - data := asMemorySlice(ctx, dataSpan) + instanceContext := wasm.IntoInstanceContext(context) + data := asMemorySlice(instanceContext, dataSpan) logger.Debug("utf8: " + string(data)) - return nil, nil } //export ext_misc_runtime_version_version_1 -func ext_misc_runtime_version_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_misc_runtime_version_version_1(context unsafe.Pointer, dataSpan C.int64_t) C.int64_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - dataSpan := args[0].I64() + instanceContext := wasm.IntoInstanceContext(context) code := asMemorySlice(instanceContext, dataSpan) version, err := GetRuntimeVersion(code) if err != nil { logger.Errorf("failed to get runtime version: %s", err) - return mustToWasmMemoryOptionalNil(instanceContext), nil + return mustToWasmMemoryOptionalNil(instanceContext) } // Note the encoding contains all the latest Core_version fields as defined in @@ -962,40 +981,36 @@ func ext_misc_runtime_version_version_1(env interface{}, args []wasmer.Value) ([ encodedData, err := scale.Marshal(version) if err != nil { logger.Errorf("failed to encode result: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } out, err := toWasmMemoryOptional(instanceContext, encodedData) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(out)}, nil + return C.int64_t(out) } //export ext_default_child_storage_read_version_1 -func ext_default_child_storage_read_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_default_child_storage_read_version_1(context unsafe.Pointer, + childStorageKey, key, valueOut C.int64_t, offset C.int32_t) C.int64_t { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - memory := instanceContext.Memory.Data() - storage := instanceContext.Storage - - childStorageKey := args[0].I64() - key := args[1].I64() - valueOut := args[2].I64() - offset := args[3].I32() + instanceContext := wasm.IntoInstanceContext(context) + storage := instanceContext.Data().(*runtime.Context).Storage + memory := instanceContext.Memory().Data() keyToChild := asMemorySlice(instanceContext, childStorageKey) keyBytes := asMemorySlice(instanceContext, key) value, err := storage.GetChildStorage(keyToChild, keyBytes) if err != nil { logger.Errorf("failed to get child storage: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - valueBuf, valueLen := splitPointerSize(valueOut) + valueBuf, valueLen := splitPointerSize(int64(valueOut)) copy(memory[valueBuf:valueBuf+valueLen], value[offset:]) size := uint32(len(value[offset:])) @@ -1005,20 +1020,19 @@ func ext_default_child_storage_read_version_1(env interface{}, args []wasmer.Val sizeSpan, err := toWasmMemoryOptional(instanceContext, sizeBuf) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(sizeSpan)}, nil + return C.int64_t(sizeSpan) } //export ext_default_child_storage_clear_version_1 -func ext_default_child_storage_clear_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_default_child_storage_clear_version_1(context unsafe.Pointer, childStorageKey, keySpan C.int64_t) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - storage := instanceContext.Storage - childStorageKey := args[0].I64() - keySpan := args[1].I64() + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) + storage := ctx.Storage keyToChild := asMemorySlice(instanceContext, childStorageKey) key := asMemorySlice(instanceContext, keySpan) @@ -1027,17 +1041,15 @@ func ext_default_child_storage_clear_version_1(env interface{}, args []wasmer.Va if err != nil { logger.Errorf("failed to clear child storage: %s", err) } - return nil, nil } //export ext_default_child_storage_clear_prefix_version_1 -func ext_default_child_storage_clear_prefix_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_default_child_storage_clear_prefix_version_1(context unsafe.Pointer, childStorageKey, prefixSpan C.int64_t) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - storage := instanceContext.Storage - childStorageKey := args[0].I64() - prefixSpan := args[1].I64() + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) + storage := ctx.Storage keyToChild := asMemorySlice(instanceContext, childStorageKey) prefix := asMemorySlice(instanceContext, prefixSpan) @@ -1046,132 +1058,114 @@ func ext_default_child_storage_clear_prefix_version_1(env interface{}, args []wa if err != nil { logger.Errorf("failed to clear prefix in child: %s", err) } - return nil, nil } //export ext_default_child_storage_exists_version_1 -func ext_default_child_storage_exists_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_default_child_storage_exists_version_1(context unsafe.Pointer, + childStorageKey, key C.int64_t) C.int32_t { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - storage := instanceContext.Storage - - childStorageKey := args[0].I64() - key := args[1].I64() + instanceContext := wasm.IntoInstanceContext(context) + storage := instanceContext.Data().(*runtime.Context).Storage keyToChild := asMemorySlice(instanceContext, childStorageKey) keyBytes := asMemorySlice(instanceContext, key) child, err := storage.GetChildStorage(keyToChild, keyBytes) if err != nil { logger.Errorf("failed to get child from child storage: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } if child != nil { - return []wasmer.Value{wasmer.NewI32(1)}, nil + return 1 } - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } //export ext_default_child_storage_get_version_1 -func ext_default_child_storage_get_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_default_child_storage_get_version_1(context unsafe.Pointer, childStorageKey, key C.int64_t) C.int64_t { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - storage := instanceContext.Storage - - childStorageKey := args[0].I64() - key := args[1].I64() + instanceContext := wasm.IntoInstanceContext(context) + storage := instanceContext.Data().(*runtime.Context).Storage keyToChild := asMemorySlice(instanceContext, childStorageKey) keyBytes := asMemorySlice(instanceContext, key) child, err := storage.GetChildStorage(keyToChild, keyBytes) if err != nil { logger.Errorf("failed to get child from child storage: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } value, err := toWasmMemoryOptional(instanceContext, child) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(value)}, nil + return C.int64_t(value) } //export ext_default_child_storage_next_key_version_1 -func ext_default_child_storage_next_key_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_default_child_storage_next_key_version_1(context unsafe.Pointer, childStorageKey, key C.int64_t) C.int64_t { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - storage := instanceContext.Storage - - childStorageKey, ok := args[0].Unwrap().(int64) - if !ok { - panic("childStorageKey is not int64") - } - key, ok := args[1].Unwrap().(int64) - if !ok { - panic("key is not int64") - } + instanceContext := wasm.IntoInstanceContext(context) + storage := instanceContext.Data().(*runtime.Context).Storage keyToChild := asMemorySlice(instanceContext, childStorageKey) keyBytes := asMemorySlice(instanceContext, key) child, err := storage.GetChildNextKey(keyToChild, keyBytes) if err != nil { logger.Errorf("failed to get child's next key: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } value, err := toWasmMemoryOptional(instanceContext, child) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(value)}, nil + return C.int64_t(value) } //export ext_default_child_storage_root_version_1 -func ext_default_child_storage_root_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_default_child_storage_root_version_1(context unsafe.Pointer, + childStorageKey C.int64_t) (ptrSize C.int64_t) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - storage := instanceContext.Storage - - childStorageKey := args[0].I64() + instanceContext := wasm.IntoInstanceContext(context) + storage := instanceContext.Data().(*runtime.Context).Storage child, err := storage.GetChild(asMemorySlice(instanceContext, childStorageKey)) if err != nil { logger.Errorf("failed to retrieve child: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } childRoot, err := child.Hash() if err != nil { logger.Errorf("failed to encode child root: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } root, err := toWasmMemoryOptional(instanceContext, childRoot[:]) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(root)}, nil + return C.int64_t(root) } //export ext_default_child_storage_set_version_1 -func ext_default_child_storage_set_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_default_child_storage_set_version_1(context unsafe.Pointer, + childStorageKeySpan, keySpan, valueSpan C.int64_t) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - storage := instanceContext.Storage - - childStorageKeySpan := args[0].I64() - keySpan := args[1].I64() - valueSpan := args[2].I64() + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) + storage := ctx.Storage childStorageKey := asMemorySlice(instanceContext, childStorageKeySpan) key := asMemorySlice(instanceContext, keySpan) @@ -1183,34 +1177,31 @@ func ext_default_child_storage_set_version_1(env interface{}, args []wasmer.Valu err := storage.SetChildStorage(childStorageKey, key, cp) if err != nil { logger.Errorf("failed to set value in child storage: %s", err) - return nil, nil + return } - return nil, nil } //export ext_default_child_storage_storage_kill_version_1 -func ext_default_child_storage_storage_kill_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_default_child_storage_storage_kill_version_1(context unsafe.Pointer, childStorageKeySpan C.int64_t) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - storage := instanceContext.Storage - childStorageKeySpan := args[0].I64() + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) + storage := ctx.Storage childStorageKey := asMemorySlice(instanceContext, childStorageKeySpan) err := storage.DeleteChild(childStorageKey) panicOnError(err) - return nil, nil } //export ext_default_child_storage_storage_kill_version_2 -func ext_default_child_storage_storage_kill_version_2(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_default_child_storage_storage_kill_version_2(context unsafe.Pointer, + childStorageKeySpan, lim C.int64_t) (allDeleted C.int32_t) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - storage := instanceContext.Storage - childStorageKeySpan := args[0].I64() - lim := args[1].I64() - + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) + storage := ctx.Storage childStorageKey := asMemorySlice(instanceContext, childStorageKeySpan) limitBytes := asMemorySlice(instanceContext, lim) @@ -1219,7 +1210,7 @@ func ext_default_child_storage_storage_kill_version_2(env interface{}, args []wa err := scale.Unmarshal(limitBytes, &limit) if err != nil { logger.Warnf("cannot generate limit: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } _, all, err := storage.DeleteChildLimit(childStorageKey, limit) @@ -1228,10 +1219,10 @@ func ext_default_child_storage_storage_kill_version_2(env interface{}, args []wa } if all { - return []wasmer.Value{wasmer.NewI32(1)}, nil + return 1 } - return []wasmer.Value{wasmer.NewI32(0)}, nil + return 0 } type noneRemain uint32 @@ -1245,12 +1236,12 @@ func (someRemain) Index() uint { return 1 } func (sr someRemain) String() string { return fmt.Sprintf("someRemain(%d)", sr) } //export ext_default_child_storage_storage_kill_version_3 -func ext_default_child_storage_storage_kill_version_3(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_default_child_storage_storage_kill_version_3(context unsafe.Pointer, + childStorageKeySpan, lim C.int64_t) (pointerSize C.int64_t) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - storage := instanceContext.Storage - childStorageKeySpan := args[0].I64() - lim := args[1].I64() + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) + storage := ctx.Storage childStorageKey := asMemorySlice(instanceContext, childStorageKeySpan) limitBytes := asMemorySlice(instanceContext, lim) @@ -1264,7 +1255,7 @@ func ext_default_child_storage_storage_kill_version_3(env interface{}, args []wa deleted, all, err := storage.DeleteChildLimit(childStorageKey, limit) if err != nil { logger.Warnf("cannot get child storage: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return C.int64_t(0) } vdt, err := scale.NewVaryingDataType(noneRemain(0), someRemain(0)) @@ -1279,50 +1270,43 @@ func ext_default_child_storage_storage_kill_version_3(env interface{}, args []wa } if err != nil { logger.Warnf("cannot set varying data type: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return C.int64_t(0) } encoded, err := scale.Marshal(vdt) if err != nil { logger.Warnf("problem marshalling varying data type: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return C.int64_t(0) } out, err := toWasmMemoryOptional(instanceContext, encoded) if err != nil { logger.Warnf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(out)}, nil + return C.int64_t(out) } //export ext_allocator_free_version_1 -func ext_allocator_free_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_allocator_free_version_1(context unsafe.Pointer, addr C.int32_t) { logger.Trace("executing...") - runtimeCtx := env.(*runtime.Context) - addr, ok := args[0].Unwrap().(int32) - if !ok { - logger.Criticalf("[ext_allocator_free_version_1]", "error", "addr cannot be converted to int32") - } + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) // Deallocate memory err := runtimeCtx.Allocator.Deallocate(uint32(addr)) if err != nil { logger.Errorf("failed to free memory: %s", err) } - return nil, nil } //export ext_allocator_malloc_version_1 -func ext_allocator_malloc_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { - size, ok := args[0].Unwrap().(int32) - if !ok { - logger.Criticalf("[ext_allocator_malloc_version_1]", "error", "addr cannot be converted to int32") - } +func ext_allocator_malloc_version_1(context unsafe.Pointer, size C.int32_t) C.int32_t { logger.Tracef("executing with size %d...", int64(size)) - ctx := env.(*runtime.Context) + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) // Allocate memory res, err := ctx.Allocator.Allocate(uint32(size)) @@ -1331,26 +1315,20 @@ func ext_allocator_malloc_version_1(env interface{}, args []wasmer.Value) ([]was panic(err) } - castedRes, err := safeCastInt32(res) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err - } - - return []wasmer.Value{wasmer.NewI32(castedRes)}, nil + return C.int32_t(res) } //export ext_hashing_blake2_128_version_1 -func ext_hashing_blake2_128_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_hashing_blake2_128_version_1(context unsafe.Pointer, dataSpan C.int64_t) C.int32_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - dataSpan := args[0].I64() + instanceContext := wasm.IntoInstanceContext(context) + data := asMemorySlice(instanceContext, dataSpan) hash, err := common.Blake2b128(data) if err != nil { logger.Errorf("failed hashing data: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } logger.Debugf( @@ -1360,29 +1338,23 @@ func ext_hashing_blake2_128_version_1(env interface{}, args []wasmer.Value) ([]w out, err := toWasmMemorySized(instanceContext, hash) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil - } - - castedOut, err := safeCastInt32(out) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err + return 0 } - return []wasmer.Value{wasmer.NewI32(castedOut)}, nil + return C.int32_t(out) } //export ext_hashing_blake2_256_version_1 -func ext_hashing_blake2_256_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_hashing_blake2_256_version_1(context unsafe.Pointer, dataSpan C.int64_t) C.int32_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - dataSpan := args[0].I64() + instanceContext := wasm.IntoInstanceContext(context) + data := asMemorySlice(instanceContext, dataSpan) hash, err := common.Blake2bHash(data) if err != nil { logger.Errorf("failed hashing data: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } logger.Debugf("data 0x%x has hash %s", data, hash) @@ -1390,29 +1362,23 @@ func ext_hashing_blake2_256_version_1(env interface{}, args []wasmer.Value) ([]w out, err := toWasmMemorySized(instanceContext, hash[:]) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } - castedOut, err := safeCastInt32(out) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err - } - - return []wasmer.Value{wasmer.NewI32(castedOut)}, nil + return C.int32_t(out) } //export ext_hashing_keccak_256_version_1 -func ext_hashing_keccak_256_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_hashing_keccak_256_version_1(context unsafe.Pointer, dataSpan C.int64_t) C.int32_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - dataSpan := args[0].I64() + instanceContext := wasm.IntoInstanceContext(context) + data := asMemorySlice(instanceContext, dataSpan) hash, err := common.Keccak256(data) if err != nil { logger.Errorf("failed hashing data: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } logger.Debugf("data 0x%x has hash %s", data, hash) @@ -1420,23 +1386,17 @@ func ext_hashing_keccak_256_version_1(env interface{}, args []wasmer.Value) ([]w out, err := toWasmMemorySized(instanceContext, hash[:]) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil - } - - castedOut, err := safeCastInt32(out) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err + return 0 } - return []wasmer.Value{wasmer.NewI32(castedOut)}, nil + return C.int32_t(out) } //export ext_hashing_sha2_256_version_1 -func ext_hashing_sha2_256_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_hashing_sha2_256_version_1(context unsafe.Pointer, dataSpan C.int64_t) C.int32_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - dataSpan := args[0].I64() + instanceContext := wasm.IntoInstanceContext(context) + data := asMemorySlice(instanceContext, dataSpan) hash := common.Sha256(data) @@ -1445,29 +1405,23 @@ func ext_hashing_sha2_256_version_1(env interface{}, args []wasmer.Value) ([]was out, err := toWasmMemorySized(instanceContext, hash[:]) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil - } - - castedOut, err := safeCastInt32(out) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err + return 0 } - return []wasmer.Value{wasmer.NewI32(castedOut)}, nil + return C.int32_t(out) } //export ext_hashing_twox_256_version_1 -func ext_hashing_twox_256_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_hashing_twox_256_version_1(context unsafe.Pointer, dataSpan C.int64_t) C.int32_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - dataSpan := args[0].I64() + instanceContext := wasm.IntoInstanceContext(context) + data := asMemorySlice(instanceContext, dataSpan) hash, err := common.Twox256(data) if err != nil { logger.Errorf("failed hashing data: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } logger.Debugf("data 0x%x has hash %s", data, hash) @@ -1475,29 +1429,22 @@ func ext_hashing_twox_256_version_1(env interface{}, args []wasmer.Value) ([]was out, err := toWasmMemorySized(instanceContext, hash[:]) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil - } - - castedOut, err := safeCastInt32(out) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err + return 0 } - return []wasmer.Value{wasmer.NewI32(castedOut)}, nil + return C.int32_t(out) } //export ext_hashing_twox_128_version_1 -func ext_hashing_twox_128_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_hashing_twox_128_version_1(context unsafe.Pointer, dataSpan C.int64_t) C.int32_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - dataSpan := args[0].I64() + instanceContext := wasm.IntoInstanceContext(context) data := asMemorySlice(instanceContext, dataSpan) hash, err := common.Twox128Hash(data) if err != nil { logger.Errorf("failed hashing data: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } logger.Debugf( @@ -1507,29 +1454,23 @@ func ext_hashing_twox_128_version_1(env interface{}, args []wasmer.Value) ([]was out, err := toWasmMemorySized(instanceContext, hash) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } - castedOut, err := safeCastInt32(out) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err - } - - return []wasmer.Value{wasmer.NewI32(castedOut)}, nil + return C.int32_t(out) } //export ext_hashing_twox_64_version_1 -func ext_hashing_twox_64_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_hashing_twox_64_version_1(context unsafe.Pointer, dataSpan C.int64_t) C.int32_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - dataSpan := args[0].I64() + instanceContext := wasm.IntoInstanceContext(context) + data := asMemorySlice(instanceContext, dataSpan) hash, err := common.Twox64(data) if err != nil { logger.Errorf("failed hashing data: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } logger.Debugf( @@ -1539,86 +1480,75 @@ func ext_hashing_twox_64_version_1(env interface{}, args []wasmer.Value) ([]wasm out, err := toWasmMemorySized(instanceContext, hash) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } - castedOut, err := safeCastInt32(out) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err - } - - return []wasmer.Value{wasmer.NewI32(castedOut)}, nil + return C.int32_t(out) } //export ext_offchain_index_set_version_1 -func ext_offchain_index_set_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_index_set_version_1(context unsafe.Pointer, keySpan, valueSpan C.int64_t) { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - keySpan := args[0].I64() - valueSpan := args[1].I64() + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) storageKey := asMemorySlice(instanceContext, keySpan) newValue := asMemorySlice(instanceContext, valueSpan) cp := make([]byte, len(newValue)) copy(cp, newValue) - err := instanceContext.NodeStorage.BaseDB.Put(storageKey, cp) + err := runtimeCtx.NodeStorage.BaseDB.Put(storageKey, cp) if err != nil { logger.Errorf("failed to set value in raw storage: %s", err) } - return nil, nil } //export ext_offchain_local_storage_clear_version_1 -func ext_offchain_local_storage_clear_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_local_storage_clear_version_1(context unsafe.Pointer, kind C.int32_t, key C.int64_t) { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - kind := args[0].I32() - key := args[1].I64() + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) storageKey := asMemorySlice(instanceContext, key) - memory := instanceContext.Memory.Data() + memory := instanceContext.Memory().Data() kindInt := binary.LittleEndian.Uint32(memory[kind : kind+4]) var err error switch runtime.NodeStorageType(kindInt) { case runtime.NodeStorageTypePersistent: - err = instanceContext.NodeStorage.PersistentStorage.Del(storageKey) + err = runtimeCtx.NodeStorage.PersistentStorage.Del(storageKey) case runtime.NodeStorageTypeLocal: - err = instanceContext.NodeStorage.LocalStorage.Del(storageKey) + err = runtimeCtx.NodeStorage.LocalStorage.Del(storageKey) } if err != nil { logger.Errorf("failed to clear value from storage: %s", err) } - return nil, nil } //export ext_offchain_is_validator_version_1 -func ext_offchain_is_validator_version_1(env interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_is_validator_version_1(context unsafe.Pointer) C.int32_t { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - if instanceContext.Validator { - return []wasmer.Value{wasmer.NewI32(int32(1))}, nil + instanceContext := wasm.IntoInstanceContext(context) + + runtimeCtx := instanceContext.Data().(*runtime.Context) + if runtimeCtx.Validator { + return 1 } - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } //export ext_offchain_local_storage_compare_and_set_version_1 -func ext_offchain_local_storage_compare_and_set_version_1(env interface{}, - args []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_local_storage_compare_and_set_version_1(context unsafe.Pointer, + kind C.int32_t, key, oldValue, newValue C.int64_t) (newValueSet C.int32_t) { logger.Debug("executing...") - runtimeCtx := env.(*runtime.Context) - kind := args[0].I32() - key := args[1].I64() - oldValue := args[2].I64() - newValue := args[3].I64() + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) - storageKey := asMemorySlice(runtimeCtx, key) + storageKey := asMemorySlice(instanceContext, key) var storedValue []byte var err error @@ -1632,32 +1562,31 @@ func ext_offchain_local_storage_compare_and_set_version_1(env interface{}, if err != nil { logger.Errorf("failed to get value from storage: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } - oldVal := asMemorySlice(runtimeCtx, oldValue) - newVal := asMemorySlice(runtimeCtx, newValue) + oldVal := asMemorySlice(instanceContext, oldValue) + newVal := asMemorySlice(instanceContext, newValue) if reflect.DeepEqual(storedValue, oldVal) { cp := make([]byte, len(newVal)) copy(cp, newVal) err = runtimeCtx.NodeStorage.LocalStorage.Put(storageKey, cp) if err != nil { logger.Errorf("failed to set value in storage: %s", err) - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } } - return []wasmer.Value{wasmer.NewI32(int32(1))}, nil + return 1 } //export ext_offchain_local_storage_get_version_1 -func ext_offchain_local_storage_get_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_local_storage_get_version_1(context unsafe.Pointer, kind C.int32_t, key C.int64_t) C.int64_t { logger.Debug("executing...") - runtimeCtx := env.(*runtime.Context) - kind := args[0].I32() - key := args[1].I64() - storageKey := asMemorySlice(runtimeCtx, key) + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) + storageKey := asMemorySlice(instanceContext, key) var res []byte var err error @@ -1673,26 +1602,22 @@ func ext_offchain_local_storage_get_version_1(env interface{}, args []wasmer.Val logger.Errorf("failed to get value from storage: %s", err) } // allocate memory for value and copy value to memory - ptr, err := toWasmMemoryOptional(runtimeCtx, res) + ptr, err := toWasmMemoryOptional(instanceContext, res) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - return []wasmer.Value{wasmer.NewI64(int64(0))}, nil + return 0 } - - return []wasmer.Value{wasmer.NewI64(ptr)}, nil + return C.int64_t(ptr) } //export ext_offchain_local_storage_set_version_1 -func ext_offchain_local_storage_set_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_local_storage_set_version_1(context unsafe.Pointer, kind C.int32_t, key, value C.int64_t) { logger.Debug("executing...") - runtimeCtx := env.(*runtime.Context) - kind := args[0].I32() - key := args[1].I64() - value := args[2].I64() - - storageKey := asMemorySlice(runtimeCtx, key) - newValue := asMemorySlice(runtimeCtx, value) + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) + storageKey := asMemorySlice(instanceContext, key) + newValue := asMemorySlice(instanceContext, value) cp := make([]byte, len(newValue)) copy(cp, newValue) @@ -1707,40 +1632,40 @@ func ext_offchain_local_storage_set_version_1(env interface{}, args []wasmer.Val if err != nil { logger.Errorf("failed to set value in storage: %s", err) } - return nil, nil } //export ext_offchain_network_state_version_1 -func ext_offchain_network_state_version_1(env interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_network_state_version_1(context unsafe.Pointer) C.int64_t { logger.Debug("executing...") - runtimeCtx := env.(*runtime.Context) + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) if runtimeCtx.Network == nil { - return []wasmer.Value{wasmer.NewI64(int64(0))}, nil + return 0 } nsEnc, err := scale.Marshal(runtimeCtx.Network.NetworkState()) if err != nil { logger.Errorf("failed at encoding network state: %s", err) - return []wasmer.Value{wasmer.NewI64(int64(0))}, nil + return 0 } // allocate memory for value and copy value to memory - ptr, err := toWasmMemorySized(runtimeCtx, nsEnc) + ptr, err := toWasmMemorySized(instanceContext, nsEnc) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - return []wasmer.Value{wasmer.NewI64(int64(0))}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(int64(ptr))}, nil + return C.int64_t(ptr) } //export ext_offchain_random_seed_version_1 -func ext_offchain_random_seed_version_1(env interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_random_seed_version_1(context unsafe.Pointer) C.int32_t { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) + instanceContext := wasm.IntoInstanceContext(context) seed := make([]byte, 32) - _, err := rand.Read(seed) //nolint + _, err := rand.Read(seed) if err != nil { logger.Errorf("failed to generate random seed: %s", err) } @@ -1748,22 +1673,14 @@ func ext_offchain_random_seed_version_1(env interface{}, _ []wasmer.Value) ([]wa if err != nil { logger.Errorf("failed to allocate memory: %s", err) } - - castedPtr, err := safeCastInt32(ptr) - if err != nil { - logger.Errorf("failed to safely cast pointer: %s", err) - return []wasmer.Value{wasmer.NewI32(0)}, err - } - - return []wasmer.Value{wasmer.NewI32(castedPtr)}, nil + return C.int32_t(ptr) } //export ext_offchain_submit_transaction_version_1 -func ext_offchain_submit_transaction_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_submit_transaction_version_1(context unsafe.Pointer, data C.int64_t) C.int64_t { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - data := args[0].I64() + instanceContext := wasm.IntoInstanceContext(context) extBytes := asMemorySlice(instanceContext, data) var extrinsic []byte @@ -1776,49 +1693,48 @@ func ext_offchain_submit_transaction_version_1(env interface{}, args []wasmer.Va txv := transaction.NewValidity(0, [][]byte{{}}, [][]byte{{}}, 0, false) vtx := transaction.NewValidTransaction(extrinsic, txv) - instanceContext.Transaction.AddToPool(vtx) + runtimeCtx := instanceContext.Data().(*runtime.Context) + runtimeCtx.Transaction.AddToPool(vtx) ptr, err := toWasmMemoryOptionalNil(instanceContext) if err != nil { logger.Errorf("failed to allocate memory: %s", err) } - return ptr, nil + return ptr } //export ext_offchain_timestamp_version_1 -func ext_offchain_timestamp_version_1(_ interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_timestamp_version_1(_ unsafe.Pointer) C.int64_t { logger.Trace("executing...") now := time.Now().Unix() - return []wasmer.Value{wasmer.NewI64(now)}, nil + return C.int64_t(now) } //export ext_offchain_sleep_until_version_1 -func ext_offchain_sleep_until_version_1(_ interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_sleep_until_version_1(_ unsafe.Pointer, deadline C.int64_t) { logger.Trace("executing...") - deadline := args[0].I64() - dur := time.Until(time.UnixMilli(deadline)) + + dur := time.Until(time.UnixMilli(int64(deadline))) if dur > 0 { time.Sleep(dur) } - return nil, nil } //export ext_offchain_http_request_start_version_1 -func ext_offchain_http_request_start_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_http_request_start_version_1(context unsafe.Pointer, + methodSpan, uriSpan, metaSpan C.int64_t) (pointerSize C.int64_t) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - methodSpan := args[0].I64() - uriSpan := args[1].I64() - _ = args[2].I64() // metaSpan - unused + instanceContext := wasm.IntoInstanceContext(context) + runtimeCtx := instanceContext.Data().(*runtime.Context) httpMethod := asMemorySlice(instanceContext, methodSpan) uri := asMemorySlice(instanceContext, uriSpan) result := scale.NewResult(int16(0), nil) - reqID, err := instanceContext.OffchainHTTPSet.StartRequest(string(httpMethod), string(uri)) + reqID, err := runtimeCtx.OffchainHTTPSet.StartRequest(string(httpMethod), string(uri)) if err != nil { // StartRequest error already was logged logger.Errorf("failed to start request: %s", err) @@ -1830,36 +1746,35 @@ func ext_offchain_http_request_start_version_1(env interface{}, args []wasmer.Va // note: just check if an error occurs while setting the result data if err != nil { logger.Errorf("failed to set the result data: %s", err) - return []wasmer.Value{wasmer.NewI64(int64(0))}, nil + return C.int64_t(0) } enc, err := scale.Marshal(result) if err != nil { logger.Errorf("failed to scale marshal the result: %s", err) - return []wasmer.Value{wasmer.NewI64(int64(0))}, nil + return C.int64_t(0) } ptr, err := toWasmMemory(instanceContext, enc) if err != nil { logger.Errorf("failed to allocate result on memory: %s", err) - return []wasmer.Value{wasmer.NewI64(int64(0))}, nil + return C.int64_t(0) } - return []wasmer.Value{wasmer.NewI64(ptr)}, nil + return C.int64_t(ptr) } //export ext_offchain_http_request_add_header_version_1 -func ext_offchain_http_request_add_header_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_offchain_http_request_add_header_version_1(context unsafe.Pointer, + reqID C.int32_t, nameSpan, valueSpan C.int64_t) (pointerSize C.int64_t) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - reqID := args[0].I32() - nameSpan := args[1].I64() - valueSpan := args[2].I64() + instanceContext := wasm.IntoInstanceContext(context) name := asMemorySlice(instanceContext, nameSpan) value := asMemorySlice(instanceContext, valueSpan) - offchainReq := instanceContext.OffchainHTTPSet.Get(int16(reqID)) + runtimeCtx := instanceContext.Data().(*runtime.Context) + offchainReq := runtimeCtx.OffchainHTTPSet.Get(int16(reqID)) result := scale.NewResult(nil, nil) resultMode := scale.OK @@ -1873,31 +1788,30 @@ func ext_offchain_http_request_add_header_version_1(env interface{}, args []wasm err = result.Set(resultMode, nil) if err != nil { logger.Errorf("failed to set the result data: %s", err) - return []wasmer.Value{wasmer.NewI64(int64(0))}, nil + return C.int64_t(0) } enc, err := scale.Marshal(result) if err != nil { logger.Errorf("failed to scale marshal the result: %s", err) - return []wasmer.Value{wasmer.NewI64(int64(0))}, nil + return C.int64_t(0) } ptr, err := toWasmMemory(instanceContext, enc) if err != nil { logger.Errorf("failed to allocate result on memory: %s", err) - return []wasmer.Value{wasmer.NewI64(int64(0))}, nil + return C.int64_t(0) } - return []wasmer.Value{wasmer.NewI64(ptr)}, nil + return C.int64_t(ptr) } //export ext_storage_append_version_1 -func ext_storage_append_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_append_version_1(context unsafe.Pointer, keySpan, valueSpan C.int64_t) { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - keySpan := args[0].I64() - valueSpan := args[1].I64() - storage := instanceContext.Storage + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) + storage := ctx.Storage key := asMemorySlice(instanceContext, keySpan) valueAppend := asMemorySlice(instanceContext, valueSpan) @@ -1912,64 +1826,59 @@ func ext_storage_append_version_1(env interface{}, args []wasmer.Value) ([]wasme if err != nil { logger.Errorf("failed appending to storage: %s", err) } - return nil, nil } //export ext_storage_changes_root_version_1 -func ext_storage_changes_root_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_changes_root_version_1(context unsafe.Pointer, parentHashSpan C.int64_t) C.int64_t { logger.Trace("executing...") logger.Debug("returning None") - instanceContext := env.(*runtime.Context) - _ = args[0].I64() // parentHashSpan - unused + instanceContext := wasm.IntoInstanceContext(context) rootSpan, err := toWasmMemoryOptionalNil(instanceContext) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI64(int64(0))}, nil + return 0 } - return rootSpan, nil + return rootSpan } //export ext_storage_clear_version_1 -func ext_storage_clear_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_clear_version_1(context unsafe.Pointer, keySpan C.int64_t) { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - keySpan := args[0].I64() - storage := instanceContext.Storage + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) + storage := ctx.Storage key := asMemorySlice(instanceContext, keySpan) logger.Debugf("key: 0x%x", key) err := storage.Delete(key) panicOnError(err) - return nil, nil } //export ext_storage_clear_prefix_version_1 -func ext_storage_clear_prefix_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_clear_prefix_version_1(context unsafe.Pointer, prefixSpan C.int64_t) { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - prefixSpan := args[0].I64() - storage := instanceContext.Storage + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) + storage := ctx.Storage prefix := asMemorySlice(instanceContext, prefixSpan) logger.Debugf("prefix: 0x%x", prefix) err := storage.ClearPrefix(prefix) panicOnError(err) - return nil, nil } //export ext_storage_clear_prefix_version_2 -func ext_storage_clear_prefix_version_2(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_clear_prefix_version_2(context unsafe.Pointer, prefixSpan, lim C.int64_t) C.int64_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - prefixSpan := args[0].I64() - lim := args[1].I64() - storage := instanceContext.Storage + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) + storage := ctx.Storage prefix := asMemorySlice(instanceContext, prefixSpan) logger.Debugf("prefix: 0x%x", prefix) @@ -1980,7 +1889,7 @@ func ext_storage_clear_prefix_version_2(env interface{}, args []wasmer.Value) ([ err := scale.Unmarshal(limitBytes, &limit) if err != nil { logger.Warnf("failed scale decoding limit: %s", err) - return mustToWasmMemoryNil(instanceContext), nil + return mustToWasmMemoryNil(instanceContext) } if len(limit) == 0 { @@ -1992,49 +1901,47 @@ func ext_storage_clear_prefix_version_2(env interface{}, args []wasmer.Value) ([ numRemoved, all, err := storage.ClearPrefixLimit(prefix, limitUint) if err != nil { logger.Errorf("failed to clear prefix limit: %s", err) - return mustToWasmMemoryNil(instanceContext), nil + return mustToWasmMemoryNil(instanceContext) } encBytes, err := toKillStorageResultEnum(all, numRemoved) if err != nil { logger.Errorf("failed to allocate memory: %s", err) - return mustToWasmMemoryNil(instanceContext), nil + return mustToWasmMemoryNil(instanceContext) } valueSpan, err := toWasmMemory(instanceContext, encBytes) if err != nil { logger.Errorf("failed to allocate: %s", err) - return mustToWasmMemoryNil(instanceContext), nil + return mustToWasmMemoryNil(instanceContext) } - return []wasmer.Value{wasmer.NewI64(valueSpan)}, nil + return C.int64_t(valueSpan) } //export ext_storage_exists_version_1 -func ext_storage_exists_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_exists_version_1(context unsafe.Pointer, keySpan C.int64_t) C.int32_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - keySpan := args[0].I64() - storage := instanceContext.Storage + instanceContext := wasm.IntoInstanceContext(context) + storage := instanceContext.Data().(*runtime.Context).Storage key := asMemorySlice(instanceContext, keySpan) logger.Debugf("key: 0x%x", key) value := storage.Get(key) if value != nil { - return []wasmer.Value{wasmer.NewI32(int32(1))}, nil + return 1 } - return []wasmer.Value{wasmer.NewI32(int32(0))}, nil + return 0 } //export ext_storage_get_version_1 -func ext_storage_get_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_get_version_1(context unsafe.Pointer, keySpan C.int64_t) C.int64_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - keySpan := args[0].I64() - storage := instanceContext.Storage + instanceContext := wasm.IntoInstanceContext(context) + storage := instanceContext.Data().(*runtime.Context).Storage key := asMemorySlice(instanceContext, keySpan) logger.Debugf("key: 0x%x", key) @@ -2045,19 +1952,18 @@ func ext_storage_get_version_1(env interface{}, args []wasmer.Value) ([]wasmer.V valueSpan, err := toWasmMemoryOptional(instanceContext, value) if err != nil { logger.Errorf("failed to allocate: %s", err) - return mustToWasmMemoryOptionalNil(instanceContext), nil + return mustToWasmMemoryOptionalNil(instanceContext) } - return []wasmer.Value{wasmer.NewI64(valueSpan)}, nil + return C.int64_t(valueSpan) } //export ext_storage_next_key_version_1 -func ext_storage_next_key_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_next_key_version_1(context unsafe.Pointer, keySpan C.int64_t) C.int64_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - keySpan := args[0].I64() - storage := instanceContext.Storage + instanceContext := wasm.IntoInstanceContext(context) + storage := instanceContext.Data().(*runtime.Context).Storage key := asMemorySlice(instanceContext, keySpan) @@ -2069,22 +1975,19 @@ func ext_storage_next_key_version_1(env interface{}, args []wasmer.Value) ([]was nextSpan, err := toWasmMemoryOptional(instanceContext, next) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(nextSpan)}, nil + return C.int64_t(nextSpan) } //export ext_storage_read_version_1 -func ext_storage_read_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_read_version_1(context unsafe.Pointer, keySpan, valueOut C.int64_t, offset C.int32_t) C.int64_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - keySpan := args[0].I64() - valueOut := args[1].I64() - offset := args[2].I32() - storage := instanceContext.Storage - memory := instanceContext.Memory.Data() + instanceContext := wasm.IntoInstanceContext(context) + storage := instanceContext.Data().(*runtime.Context).Storage + memory := instanceContext.Memory().Data() key := asMemorySlice(instanceContext, keySpan) value := storage.Get(key) @@ -2093,37 +1996,36 @@ func ext_storage_read_version_1(env interface{}, args []wasmer.Value) ([]wasmer. key, value) if value == nil { - - return mustToWasmMemoryOptionalNil(instanceContext), nil + return mustToWasmMemoryOptionalNil(instanceContext) } var size uint32 if uint32(offset) <= uint32(len(value)) { size = uint32(len(value[offset:])) - valueBuf, valueLen := splitPointerSize(valueOut) + valueBuf, valueLen := splitPointerSize(int64(valueOut)) copy(memory[valueBuf:valueBuf+valueLen], value[offset:]) } sizeSpan, err := toWasmMemoryOptionalUint32(instanceContext, &size) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(sizeSpan)}, nil + return C.int64_t(sizeSpan) } //export ext_storage_root_version_1 -func ext_storage_root_version_1(env interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_root_version_1(context unsafe.Pointer) C.int64_t { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - storage := instanceContext.Storage + instanceContext := wasm.IntoInstanceContext(context) + storage := instanceContext.Data().(*runtime.Context).Storage root, err := storage.Root() if err != nil { logger.Errorf("failed to get storage root: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } logger.Debugf("root hash is: %s", root) @@ -2131,28 +2033,25 @@ func ext_storage_root_version_1(env interface{}, _ []wasmer.Value) ([]wasmer.Val rootSpan, err := toWasmMemory(instanceContext, root[:]) if err != nil { logger.Errorf("failed to allocate: %s", err) - return []wasmer.Value{wasmer.NewI64(0)}, nil + return 0 } - return []wasmer.Value{wasmer.NewI64(rootSpan)}, nil + return C.int64_t(rootSpan) } //export ext_storage_root_version_2 -func ext_storage_root_version_2(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_root_version_2(context unsafe.Pointer, version C.int32_t) C.int64_t { // TODO: update to use state trie version 1 (#2418) - instanceContext := env.(*runtime.Context) - _ = args[0].I32() // version - unused - return ext_storage_root_version_1(instanceContext, args) + return ext_storage_root_version_1(context) } //export ext_storage_set_version_1 -func ext_storage_set_version_1(env interface{}, args []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_set_version_1(context unsafe.Pointer, keySpan, valueSpan C.int64_t) { logger.Trace("executing...") - instanceContext := env.(*runtime.Context) - keySpan := args[0].I64() - valueSpan := args[1].I64() - storage := instanceContext.Storage + instanceContext := wasm.IntoInstanceContext(context) + ctx := instanceContext.Data().(*runtime.Context) + storage := ctx.Storage key := asMemorySlice(instanceContext, keySpan) value := asMemorySlice(instanceContext, valueSpan) @@ -2165,29 +2064,128 @@ func ext_storage_set_version_1(env interface{}, args []wasmer.Value) ([]wasmer.V key, value) err := storage.Put(key, cp) panicOnError(err) - return nil, nil } //export ext_storage_start_transaction_version_1 -func ext_storage_start_transaction_version_1(env interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_start_transaction_version_1(context unsafe.Pointer) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - instanceContext.Storage.BeginStorageTransaction() - return nil, nil + instanceContext := wasm.IntoInstanceContext(context) + instanceContext.Data().(*runtime.Context).Storage.BeginStorageTransaction() } //export ext_storage_rollback_transaction_version_1 -func ext_storage_rollback_transaction_version_1(env interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_rollback_transaction_version_1(context unsafe.Pointer) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - instanceContext.Storage.RollbackStorageTransaction() - return nil, nil + instanceContext := wasm.IntoInstanceContext(context) + instanceContext.Data().(*runtime.Context).Storage.RollbackStorageTransaction() } //export ext_storage_commit_transaction_version_1 -func ext_storage_commit_transaction_version_1(env interface{}, _ []wasmer.Value) ([]wasmer.Value, error) { +func ext_storage_commit_transaction_version_1(context unsafe.Pointer) { logger.Debug("executing...") - instanceContext := env.(*runtime.Context) - instanceContext.Storage.CommitStorageTransaction() - return nil, nil + instanceContext := wasm.IntoInstanceContext(context) + instanceContext.Data().(*runtime.Context).Storage.CommitStorageTransaction() +} + +// importsNodeRuntime returns the WASM imports for the node runtime. +func importsNodeRuntime() (imports *wasm.Imports, err error) { + imports = wasm.NewImports() + // Note imports are closed by the call to wasm.Instance.Close() + + for _, toRegister := range []struct { + importName string + implementation interface{} + cgoPointer unsafe.Pointer + }{ + {"ext_allocator_free_version_1", ext_allocator_free_version_1, C.ext_allocator_free_version_1}, + {"ext_allocator_malloc_version_1", ext_allocator_malloc_version_1, C.ext_allocator_malloc_version_1}, + {"ext_crypto_ecdsa_verify_version_2", ext_crypto_ecdsa_verify_version_2, C.ext_crypto_ecdsa_verify_version_2}, + {"ext_crypto_ed25519_generate_version_1", ext_crypto_ed25519_generate_version_1, C.ext_crypto_ed25519_generate_version_1}, + {"ext_crypto_ed25519_public_keys_version_1", ext_crypto_ed25519_public_keys_version_1, C.ext_crypto_ed25519_public_keys_version_1}, + {"ext_crypto_ed25519_sign_version_1", ext_crypto_ed25519_sign_version_1, C.ext_crypto_ed25519_sign_version_1}, + {"ext_crypto_ed25519_verify_version_1", ext_crypto_ed25519_verify_version_1, C.ext_crypto_ed25519_verify_version_1}, + {"ext_crypto_finish_batch_verify_version_1", ext_crypto_finish_batch_verify_version_1, C.ext_crypto_finish_batch_verify_version_1}, + {"ext_crypto_secp256k1_ecdsa_recover_compressed_version_1", ext_crypto_secp256k1_ecdsa_recover_compressed_version_1, C.ext_crypto_secp256k1_ecdsa_recover_compressed_version_1}, + {"ext_crypto_secp256k1_ecdsa_recover_compressed_version_2", ext_crypto_secp256k1_ecdsa_recover_compressed_version_2, C.ext_crypto_secp256k1_ecdsa_recover_compressed_version_2}, + {"ext_crypto_secp256k1_ecdsa_recover_version_1", ext_crypto_secp256k1_ecdsa_recover_version_1, C.ext_crypto_secp256k1_ecdsa_recover_version_1}, + {"ext_crypto_secp256k1_ecdsa_recover_version_2", ext_crypto_secp256k1_ecdsa_recover_version_2, C.ext_crypto_secp256k1_ecdsa_recover_version_2}, + {"ext_crypto_sr25519_generate_version_1", ext_crypto_sr25519_generate_version_1, C.ext_crypto_sr25519_generate_version_1}, + {"ext_crypto_sr25519_public_keys_version_1", ext_crypto_sr25519_public_keys_version_1, C.ext_crypto_sr25519_public_keys_version_1}, + {"ext_crypto_sr25519_sign_version_1", ext_crypto_sr25519_sign_version_1, C.ext_crypto_sr25519_sign_version_1}, + {"ext_crypto_sr25519_verify_version_1", ext_crypto_sr25519_verify_version_1, C.ext_crypto_sr25519_verify_version_1}, + {"ext_crypto_sr25519_verify_version_2", ext_crypto_sr25519_verify_version_2, C.ext_crypto_sr25519_verify_version_2}, + {"ext_crypto_start_batch_verify_version_1", ext_crypto_start_batch_verify_version_1, C.ext_crypto_start_batch_verify_version_1}, + {"ext_default_child_storage_clear_prefix_version_1", ext_default_child_storage_clear_prefix_version_1, C.ext_default_child_storage_clear_prefix_version_1}, + {"ext_default_child_storage_clear_version_1", ext_default_child_storage_clear_version_1, C.ext_default_child_storage_clear_version_1}, + {"ext_default_child_storage_exists_version_1", ext_default_child_storage_exists_version_1, C.ext_default_child_storage_exists_version_1}, + {"ext_default_child_storage_get_version_1", ext_default_child_storage_get_version_1, C.ext_default_child_storage_get_version_1}, + {"ext_default_child_storage_next_key_version_1", ext_default_child_storage_next_key_version_1, C.ext_default_child_storage_next_key_version_1}, + {"ext_default_child_storage_read_version_1", ext_default_child_storage_read_version_1, C.ext_default_child_storage_read_version_1}, + {"ext_default_child_storage_root_version_1", ext_default_child_storage_root_version_1, C.ext_default_child_storage_root_version_1}, + {"ext_default_child_storage_set_version_1", ext_default_child_storage_set_version_1, C.ext_default_child_storage_set_version_1}, + {"ext_default_child_storage_storage_kill_version_1", ext_default_child_storage_storage_kill_version_1, C.ext_default_child_storage_storage_kill_version_1}, + {"ext_default_child_storage_storage_kill_version_2", ext_default_child_storage_storage_kill_version_2, C.ext_default_child_storage_storage_kill_version_2}, + {"ext_default_child_storage_storage_kill_version_3", ext_default_child_storage_storage_kill_version_3, C.ext_default_child_storage_storage_kill_version_3}, + {"ext_hashing_blake2_128_version_1", ext_hashing_blake2_128_version_1, C.ext_hashing_blake2_128_version_1}, + {"ext_hashing_blake2_256_version_1", ext_hashing_blake2_256_version_1, C.ext_hashing_blake2_256_version_1}, + {"ext_hashing_keccak_256_version_1", ext_hashing_keccak_256_version_1, C.ext_hashing_keccak_256_version_1}, + {"ext_hashing_sha2_256_version_1", ext_hashing_sha2_256_version_1, C.ext_hashing_sha2_256_version_1}, + {"ext_hashing_twox_128_version_1", ext_hashing_twox_128_version_1, C.ext_hashing_twox_128_version_1}, + {"ext_hashing_twox_256_version_1", ext_hashing_twox_256_version_1, C.ext_hashing_twox_256_version_1}, + {"ext_hashing_twox_64_version_1", ext_hashing_twox_64_version_1, C.ext_hashing_twox_64_version_1}, + {"ext_logging_log_version_1", ext_logging_log_version_1, C.ext_logging_log_version_1}, + {"ext_logging_max_level_version_1", ext_logging_max_level_version_1, C.ext_logging_max_level_version_1}, + {"ext_misc_print_hex_version_1", ext_misc_print_hex_version_1, C.ext_misc_print_hex_version_1}, + {"ext_misc_print_num_version_1", ext_misc_print_num_version_1, C.ext_misc_print_num_version_1}, + {"ext_misc_print_utf8_version_1", ext_misc_print_utf8_version_1, C.ext_misc_print_utf8_version_1}, + {"ext_misc_runtime_version_version_1", ext_misc_runtime_version_version_1, C.ext_misc_runtime_version_version_1}, + {"ext_offchain_http_request_add_header_version_1", ext_offchain_http_request_add_header_version_1, C.ext_offchain_http_request_add_header_version_1}, + {"ext_offchain_http_request_start_version_1", ext_offchain_http_request_start_version_1, C.ext_offchain_http_request_start_version_1}, + {"ext_offchain_index_set_version_1", ext_offchain_index_set_version_1, C.ext_offchain_index_set_version_1}, + {"ext_offchain_is_validator_version_1", ext_offchain_is_validator_version_1, C.ext_offchain_is_validator_version_1}, + {"ext_offchain_local_storage_clear_version_1", ext_offchain_local_storage_clear_version_1, C.ext_offchain_local_storage_clear_version_1}, + {"ext_offchain_local_storage_compare_and_set_version_1", ext_offchain_local_storage_compare_and_set_version_1, C.ext_offchain_local_storage_compare_and_set_version_1}, + {"ext_offchain_local_storage_get_version_1", ext_offchain_local_storage_get_version_1, C.ext_offchain_local_storage_get_version_1}, + {"ext_offchain_local_storage_set_version_1", ext_offchain_local_storage_set_version_1, C.ext_offchain_local_storage_set_version_1}, + {"ext_offchain_network_state_version_1", ext_offchain_network_state_version_1, C.ext_offchain_network_state_version_1}, + {"ext_offchain_random_seed_version_1", ext_offchain_random_seed_version_1, C.ext_offchain_random_seed_version_1}, + {"ext_offchain_sleep_until_version_1", ext_offchain_sleep_until_version_1, C.ext_offchain_sleep_until_version_1}, + {"ext_offchain_submit_transaction_version_1", ext_offchain_submit_transaction_version_1, C.ext_offchain_submit_transaction_version_1}, + {"ext_offchain_timestamp_version_1", ext_offchain_timestamp_version_1, C.ext_offchain_timestamp_version_1}, + {"ext_sandbox_instance_teardown_version_1", ext_sandbox_instance_teardown_version_1, C.ext_sandbox_instance_teardown_version_1}, + {"ext_sandbox_instantiate_version_1", ext_sandbox_instantiate_version_1, C.ext_sandbox_instantiate_version_1}, + {"ext_sandbox_invoke_version_1", ext_sandbox_invoke_version_1, C.ext_sandbox_invoke_version_1}, + {"ext_sandbox_memory_get_version_1", ext_sandbox_memory_get_version_1, C.ext_sandbox_memory_get_version_1}, + {"ext_sandbox_memory_new_version_1", ext_sandbox_memory_new_version_1, C.ext_sandbox_memory_new_version_1}, + {"ext_sandbox_memory_set_version_1", ext_sandbox_memory_set_version_1, C.ext_sandbox_memory_set_version_1}, + {"ext_sandbox_memory_teardown_version_1", ext_sandbox_memory_teardown_version_1, C.ext_sandbox_memory_teardown_version_1}, + {"ext_storage_append_version_1", ext_storage_append_version_1, C.ext_storage_append_version_1}, + {"ext_storage_changes_root_version_1", ext_storage_changes_root_version_1, C.ext_storage_changes_root_version_1}, + {"ext_storage_clear_prefix_version_1", ext_storage_clear_prefix_version_1, C.ext_storage_clear_prefix_version_1}, + {"ext_storage_clear_prefix_version_2", ext_storage_clear_prefix_version_2, C.ext_storage_clear_prefix_version_2}, + {"ext_storage_clear_version_1", ext_storage_clear_version_1, C.ext_storage_clear_version_1}, + {"ext_storage_commit_transaction_version_1", ext_storage_commit_transaction_version_1, C.ext_storage_commit_transaction_version_1}, + {"ext_storage_exists_version_1", ext_storage_exists_version_1, C.ext_storage_exists_version_1}, + {"ext_storage_get_version_1", ext_storage_get_version_1, C.ext_storage_get_version_1}, + {"ext_storage_next_key_version_1", ext_storage_next_key_version_1, C.ext_storage_next_key_version_1}, + {"ext_storage_read_version_1", ext_storage_read_version_1, C.ext_storage_read_version_1}, + {"ext_storage_rollback_transaction_version_1", ext_storage_rollback_transaction_version_1, C.ext_storage_rollback_transaction_version_1}, + {"ext_storage_root_version_1", ext_storage_root_version_1, C.ext_storage_root_version_1}, + {"ext_storage_root_version_2", ext_storage_root_version_2, C.ext_storage_root_version_2}, + {"ext_storage_set_version_1", ext_storage_set_version_1, C.ext_storage_set_version_1}, + {"ext_storage_start_transaction_version_1", ext_storage_start_transaction_version_1, C.ext_storage_start_transaction_version_1}, + {"ext_transaction_index_index_version_1", ext_transaction_index_index_version_1, C.ext_transaction_index_index_version_1}, + {"ext_transaction_index_renew_version_1", ext_transaction_index_renew_version_1, C.ext_transaction_index_renew_version_1}, + {"ext_trie_blake2_256_ordered_root_version_1", ext_trie_blake2_256_ordered_root_version_1, C.ext_trie_blake2_256_ordered_root_version_1}, + {"ext_trie_blake2_256_ordered_root_version_2", ext_trie_blake2_256_ordered_root_version_2, C.ext_trie_blake2_256_ordered_root_version_2}, + {"ext_trie_blake2_256_root_version_1", ext_trie_blake2_256_root_version_1, C.ext_trie_blake2_256_root_version_1}, + {"ext_trie_blake2_256_verify_proof_version_1", ext_trie_blake2_256_verify_proof_version_1, C.ext_trie_blake2_256_verify_proof_version_1}, + } { + _, err = imports.AppendFunction(toRegister.importName, toRegister.implementation, toRegister.cgoPointer) + if err != nil { + return nil, fmt.Errorf("importing function: %w", err) + } + } + + return imports, nil } diff --git a/lib/runtime/wasmer/imports_func.go b/lib/runtime/wasmer/imports_func.go deleted file mode 100644 index fce74a0d0e..0000000000 --- a/lib/runtime/wasmer/imports_func.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2023 ChainSafe Systems (ON) Corp. -// This file is part of gossamer. -// -// The gossamer library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The gossamer library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the gossamer library. If not, see . - -package wasmer - -import ( - "github.com/ChainSafe/gossamer/lib/runtime" - "github.com/wasmerio/wasmer-go/wasmer" -) - -// importsNodeRuntime returns the WASM imports for the node runtime. -func importsNodeRuntime(store *wasmer.Store, memory *wasmer.Memory, ctx *runtime.Context) *wasmer.ImportObject { - importsMap := make(map[string]wasmer.IntoExtern) - - if memory != nil { - importsMap["memory"] = memory - } - - importsMap["ext_logging_log_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_logging_log_version_1) - - importsMap["ext_logging_max_level_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_logging_max_level_version_1) - - importsMap["ext_transaction_index_index_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I32, wasmer.I32), - wasmer.NewValueTypes(), - ), ctx, ext_transaction_index_index_version_1) - - importsMap["ext_transaction_index_renew_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I32), - wasmer.NewValueTypes(), - ), ctx, ext_transaction_index_renew_version_1) - - importsMap["ext_sandbox_instance_teardown_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32), - wasmer.NewValueTypes(), - ), ctx, ext_sandbox_instance_teardown_version_1) - - importsMap["ext_sandbox_instantiate_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I64, wasmer.I32), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_sandbox_instantiate_version_1) - - importsMap["ext_sandbox_invoke_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I64, wasmer.I32, wasmer.I32, wasmer.I32), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_sandbox_invoke_version_1) - - importsMap["ext_sandbox_memory_get_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I32, wasmer.I32, wasmer.I32), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_sandbox_memory_get_version_1) - - importsMap["ext_sandbox_memory_new_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I32), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_sandbox_memory_new_version_1) - - importsMap["ext_sandbox_memory_set_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I32, wasmer.I32, wasmer.I32), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_sandbox_memory_set_version_1) - - importsMap["ext_sandbox_memory_teardown_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32), - wasmer.NewValueTypes(), - ), ctx, ext_sandbox_memory_teardown_version_1) - - importsMap["ext_crypto_ed25519_generate_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_crypto_ed25519_generate_version_1) - - importsMap["ext_crypto_ed25519_public_keys_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_crypto_ed25519_public_keys_version_1) - - importsMap["ext_crypto_ed25519_sign_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I32, wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_crypto_ed25519_sign_version_1) - - importsMap["ext_crypto_ed25519_verify_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I32), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_crypto_ed25519_verify_version_1) - - importsMap["ext_crypto_secp256k1_ecdsa_recover_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I32), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_crypto_secp256k1_ecdsa_recover_version_1) - - importsMap["ext_crypto_secp256k1_ecdsa_recover_version_2"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I32), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_crypto_secp256k1_ecdsa_recover_version_2) - - importsMap["ext_crypto_ecdsa_verify_version_2"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I32), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_crypto_ecdsa_verify_version_2) - - importsMap["ext_crypto_secp256k1_ecdsa_recover_compressed_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I32), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_crypto_secp256k1_ecdsa_recover_compressed_version_1) - - importsMap["ext_crypto_secp256k1_ecdsa_recover_compressed_version_2"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I32), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_crypto_secp256k1_ecdsa_recover_compressed_version_2) - - importsMap["ext_crypto_sr25519_generate_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_crypto_sr25519_generate_version_1) - - importsMap["ext_crypto_sr25519_public_keys_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_crypto_sr25519_public_keys_version_1) - - importsMap["ext_crypto_sr25519_sign_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I32, wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_crypto_sr25519_sign_version_1) - - importsMap["ext_crypto_sr25519_verify_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I32), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_crypto_sr25519_verify_version_1) - - importsMap["ext_crypto_sr25519_verify_version_2"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I32), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_crypto_sr25519_verify_version_2) - - importsMap["ext_crypto_start_batch_verify_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(), - wasmer.NewValueTypes(), - ), ctx, ext_crypto_start_batch_verify_version_1) - - importsMap["ext_crypto_finish_batch_verify_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_crypto_finish_batch_verify_version_1) - - importsMap["ext_trie_blake2_256_root_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_trie_blake2_256_root_version_1) - - importsMap["ext_trie_blake2_256_ordered_root_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_trie_blake2_256_ordered_root_version_1) - - importsMap["ext_trie_blake2_256_ordered_root_version_2"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I32), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_trie_blake2_256_ordered_root_version_2) - - importsMap["ext_trie_blake2_256_verify_proof_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_trie_blake2_256_verify_proof_version_1) - - importsMap["ext_misc_print_hex_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_misc_print_hex_version_1) - - importsMap["ext_misc_print_num_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_misc_print_num_version_1) - - importsMap["ext_misc_print_utf8_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_misc_print_utf8_version_1) - - importsMap["ext_misc_runtime_version_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_misc_runtime_version_version_1) - - importsMap["ext_default_child_storage_read_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64, wasmer.I64, wasmer.I32), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_default_child_storage_read_version_1) - - importsMap["ext_default_child_storage_clear_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_default_child_storage_clear_version_1) - - importsMap["ext_default_child_storage_clear_prefix_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_default_child_storage_clear_prefix_version_1) - - importsMap["ext_default_child_storage_exists_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_default_child_storage_exists_version_1) - - importsMap["ext_default_child_storage_get_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_default_child_storage_get_version_1) - - importsMap["ext_default_child_storage_next_key_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_default_child_storage_next_key_version_1) - - importsMap["ext_default_child_storage_root_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_default_child_storage_root_version_1) - - importsMap["ext_default_child_storage_set_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_default_child_storage_set_version_1) - - importsMap["ext_default_child_storage_storage_kill_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_default_child_storage_storage_kill_version_1) - - importsMap["ext_default_child_storage_storage_kill_version_2"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_default_child_storage_storage_kill_version_2) - - importsMap["ext_default_child_storage_storage_kill_version_3"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_default_child_storage_storage_kill_version_3) - - importsMap["ext_allocator_free_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32), - wasmer.NewValueTypes(), - ), ctx, ext_allocator_free_version_1) - - importsMap["ext_allocator_malloc_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_allocator_malloc_version_1) - - importsMap["ext_hashing_blake2_128_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_hashing_blake2_128_version_1) - - importsMap["ext_hashing_blake2_256_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_hashing_blake2_256_version_1) - - importsMap["ext_hashing_keccak_256_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_hashing_keccak_256_version_1) - - importsMap["ext_hashing_sha2_256_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_hashing_sha2_256_version_1) - - importsMap["ext_hashing_twox_256_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_hashing_twox_256_version_1) - - importsMap["ext_hashing_twox_128_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_hashing_twox_128_version_1) - - importsMap["ext_hashing_twox_64_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_hashing_twox_64_version_1) - - importsMap["ext_offchain_index_set_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_offchain_index_set_version_1) - - importsMap["ext_offchain_local_storage_clear_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_offchain_local_storage_clear_version_1) - - importsMap["ext_offchain_is_validator_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_offchain_is_validator_version_1) - - importsMap["ext_offchain_local_storage_compare_and_set_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_offchain_local_storage_compare_and_set_version_1) - - importsMap["ext_offchain_local_storage_get_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_offchain_local_storage_get_version_1) - - importsMap["ext_offchain_local_storage_set_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_offchain_local_storage_set_version_1) - - importsMap["ext_offchain_network_state_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_offchain_network_state_version_1) - - importsMap["ext_offchain_random_seed_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_offchain_random_seed_version_1) - - importsMap["ext_offchain_submit_transaction_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_offchain_submit_transaction_version_1) - - importsMap["ext_offchain_timestamp_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_offchain_timestamp_version_1) - - importsMap["ext_offchain_sleep_until_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_offchain_sleep_until_version_1) - - importsMap["ext_offchain_http_request_start_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_offchain_http_request_start_version_1) - - importsMap["ext_offchain_http_request_add_header_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32, wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_offchain_http_request_add_header_version_1) - - importsMap["ext_storage_append_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_storage_append_version_1) - - importsMap["ext_storage_changes_root_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_storage_changes_root_version_1) - - importsMap["ext_storage_clear_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_storage_clear_version_1) - - importsMap["ext_storage_clear_prefix_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_storage_clear_prefix_version_1) - - importsMap["ext_storage_clear_prefix_version_2"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_storage_clear_prefix_version_2) - - importsMap["ext_storage_exists_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I32), - ), ctx, ext_storage_exists_version_1) - - importsMap["ext_storage_get_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_storage_get_version_1) - - importsMap["ext_storage_next_key_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_storage_next_key_version_1) - - importsMap["ext_storage_read_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64, wasmer.I32), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_storage_read_version_1) - - importsMap["ext_storage_root_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_storage_root_version_1) - - importsMap["ext_storage_root_version_2"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I32), - wasmer.NewValueTypes(wasmer.I64), - ), ctx, ext_storage_root_version_2) - - importsMap["ext_storage_set_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(wasmer.I64, wasmer.I64), - wasmer.NewValueTypes(), - ), ctx, ext_storage_set_version_1) - - importsMap["ext_storage_start_transaction_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(), - wasmer.NewValueTypes(), - ), ctx, ext_storage_start_transaction_version_1) - - importsMap["ext_storage_rollback_transaction_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(), - wasmer.NewValueTypes(), - ), ctx, ext_storage_rollback_transaction_version_1) - - importsMap["ext_storage_commit_transaction_version_1"] = wasmer.NewFunctionWithEnvironment(store, - wasmer.NewFunctionType( - wasmer.NewValueTypes(), - wasmer.NewValueTypes(), - ), ctx, ext_storage_commit_transaction_version_1) - - imports := wasmer.NewImportObject() - imports.Register("env", importsMap) - return imports -} diff --git a/lib/runtime/wasmer/imports_test.go b/lib/runtime/wasmer/imports_test.go index 1bc47992b6..553547fc73 100644 --- a/lib/runtime/wasmer/imports_test.go +++ b/lib/runtime/wasmer/imports_test.go @@ -6,7 +6,6 @@ package wasmer import ( "bytes" "encoding/binary" - "fmt" "net/http" "sort" "testing" @@ -25,10 +24,9 @@ import ( "github.com/ChainSafe/gossamer/lib/trie" "github.com/ChainSafe/gossamer/lib/trie/proof" "github.com/ChainSafe/gossamer/pkg/scale" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/wasmerio/wasmer-go/wasmer" + "github.com/wasmerio/go-ext-wasm/wasmer" ) var testChildKey = []byte("childKey") @@ -37,15 +35,14 @@ var testValue = []byte("value") func Test_ext_offchain_timestamp_version_1(t *testing.T) { inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) - runtimeFunc, err := inst.vm.Exports.GetFunction("rtm_ext_offchain_timestamp_version_1") - require.NoError(t, err) + runtimeFunc, ok := inst.vm.Exports["rtm_ext_offchain_timestamp_version_1"] + require.True(t, ok) res, err := runtimeFunc(0, 0) require.NoError(t, err) - wasmRes := wasmer.NewI64(res) - outputPtr, outputLength := splitPointerSize(wasmRes.I64()) - memory := inst.ctx.Memory.Data() + outputPtr, outputLength := splitPointerSize(res.ToI64()) + memory := inst.vm.Memory.Data() data := memory[outputPtr : outputPtr+outputLength] var timestamp int64 err = scale.Unmarshal(data, ×tamp) @@ -67,6 +64,7 @@ func Test_ext_offchain_sleep_until_version_1(t *testing.T) { } func Test_ext_hashing_blake2_128_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) data := []byte("helloworld") @@ -86,6 +84,7 @@ func Test_ext_hashing_blake2_128_version_1(t *testing.T) { } func Test_ext_hashing_blake2_256_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) data := []byte("helloworld") @@ -102,10 +101,10 @@ func Test_ext_hashing_blake2_256_version_1(t *testing.T) { expected, err := common.Blake2bHash(data) require.NoError(t, err) require.Equal(t, expected[:], hash) - } func Test_ext_hashing_keccak_256_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) data := []byte("helloworld") @@ -125,6 +124,7 @@ func Test_ext_hashing_keccak_256_version_1(t *testing.T) { } func Test_ext_hashing_twox_128_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) data := []byte("helloworld") @@ -144,6 +144,7 @@ func Test_ext_hashing_twox_128_version_1(t *testing.T) { } func Test_ext_hashing_twox_64_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) data := []byte("helloworld") @@ -160,10 +161,10 @@ func Test_ext_hashing_twox_64_version_1(t *testing.T) { expected, err := common.Twox64(data) require.NoError(t, err) require.Equal(t, expected[:], hash) - } func Test_ext_hashing_sha2_256_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) data := []byte("helloworld") @@ -182,6 +183,7 @@ func Test_ext_hashing_sha2_256_version_1(t *testing.T) { } func Test_ext_storage_clear_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("noot") @@ -198,11 +200,11 @@ func Test_ext_storage_clear_version_1(t *testing.T) { } func Test_ext_offchain_local_storage_clear_version_1_Persistent(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("key1") err := inst.NodeStorage().PersistentStorage.Put(testkey, []byte{1}) - require.NoError(t, err) kind := int32(1) @@ -221,6 +223,7 @@ func Test_ext_offchain_local_storage_clear_version_1_Persistent(t *testing.T) { } func Test_ext_offchain_local_storage_clear_version_1_Local(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("key1") @@ -243,6 +246,7 @@ func Test_ext_offchain_local_storage_clear_version_1_Local(t *testing.T) { } func Test_ext_offchain_http_request_start_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) encMethod, err := scale.Marshal([]byte("GET")) @@ -299,6 +303,8 @@ func Test_ext_offchain_http_request_start_version_1(t *testing.T) { } func Test_ext_offchain_http_request_add_header(t *testing.T) { + t.Parallel() + inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) cases := map[string]struct { @@ -320,6 +326,8 @@ func Test_ext_offchain_http_request_add_header(t *testing.T) { for tname, tcase := range cases { t.Run(tname, func(t *testing.T) { + t.Parallel() + reqID, err := inst.ctx.OffchainHTTPSet.StartRequest(http.MethodGet, "http://uri.example") require.NoError(t, err) @@ -360,6 +368,7 @@ func Test_ext_offchain_http_request_add_header(t *testing.T) { } func Test_ext_storage_clear_prefix_version_1_hostAPI(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("static") @@ -382,6 +391,7 @@ func Test_ext_storage_clear_prefix_version_1_hostAPI(t *testing.T) { } func Test_ext_storage_clear_prefix_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("noot") @@ -404,28 +414,24 @@ func Test_ext_storage_clear_prefix_version_1(t *testing.T) { } func Test_ext_storage_clear_prefix_version_2(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) - testkey := []byte("testkey") - err := inst.ctx.Storage.Put(testkey, []byte{1}) - require.NoError(t, err) + testkey := []byte("noot") + inst.ctx.Storage.Put(testkey, []byte{1}) - testkey2 := []byte("testkey2") - err = inst.ctx.Storage.Put(testkey2, []byte{1}) - require.NoError(t, err) + testkey2 := []byte("noot1") + inst.ctx.Storage.Put(testkey2, []byte{1}) - testkey3 := []byte("testkey3") - err = inst.ctx.Storage.Put(testkey3, []byte{1}) - require.NoError(t, err) + testkey3 := []byte("noot2") + inst.ctx.Storage.Put(testkey3, []byte{1}) - testkey4 := []byte("testkey4") - err = inst.ctx.Storage.Put(testkey4, []byte{1}) - require.NoError(t, err) + testkey4 := []byte("noot3") + inst.ctx.Storage.Put(testkey4, []byte{1}) - testkey5 := []byte("keyToKeep") + testkey5 := []byte("spaghet") testValue5 := []byte{2} - err = inst.ctx.Storage.Put(testkey5, testValue5) - require.NoError(t, err) + inst.ctx.Storage.Put(testkey5, testValue5) enc, err := scale.Marshal(testkey[:3]) require.NoError(t, err) @@ -442,13 +448,11 @@ func Test_ext_storage_clear_prefix_version_2(t *testing.T) { require.NoError(t, err) var decVal []byte - err = scale.Unmarshal(encValue, &decVal) - require.NoError(t, err) + scale.Unmarshal(encValue, &decVal) var numDeleted uint32 // numDeleted represents no. of actual keys deleted - err = scale.Unmarshal(decVal[1:], &numDeleted) - require.NoError(t, err) + scale.Unmarshal(decVal[1:], &numDeleted) require.Equal(t, uint32(2), numDeleted) var expectedAllDeleted byte @@ -467,10 +471,8 @@ func Test_ext_storage_clear_prefix_version_2(t *testing.T) { encValue, err = inst.Exec("rtm_ext_storage_clear_prefix_version_2", append(enc, optLimit...)) require.NoError(t, err) - err = scale.Unmarshal(encValue, &decVal) - require.NoError(t, err) - err = scale.Unmarshal(decVal[1:], &numDeleted) - require.NoError(t, err) + scale.Unmarshal(encValue, &decVal) + scale.Unmarshal(decVal[1:], &numDeleted) require.Equal(t, uint32(2), numDeleted) expectedAllDeleted = 0 @@ -485,6 +487,7 @@ func Test_ext_storage_clear_prefix_version_2(t *testing.T) { } func Test_ext_storage_get_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("noot") @@ -505,6 +508,8 @@ func Test_ext_storage_get_version_1(t *testing.T) { } func Test_ext_storage_exists_version_1(t *testing.T) { + t.Parallel() + testCases := map[string]struct { key []byte value []byte // leave to nil to not insert pair @@ -529,6 +534,7 @@ func Test_ext_storage_exists_version_1(t *testing.T) { for name, testCase := range testCases { testCase := testCase t.Run(name, func(t *testing.T) { + t.Parallel() instance := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) if testCase.value != nil { @@ -551,6 +557,7 @@ func Test_ext_storage_exists_version_1(t *testing.T) { } func Test_ext_storage_next_key_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("noot") @@ -573,6 +580,7 @@ func Test_ext_storage_next_key_version_1(t *testing.T) { } func Test_ext_storage_read_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("noot") @@ -601,6 +609,7 @@ func Test_ext_storage_read_version_1(t *testing.T) { } func Test_ext_storage_read_version_1_again(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("noot") @@ -630,6 +639,7 @@ func Test_ext_storage_read_version_1_again(t *testing.T) { } func Test_ext_storage_read_version_1_OffsetLargerThanValue(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("noot") @@ -658,6 +668,7 @@ func Test_ext_storage_read_version_1_OffsetLargerThanValue(t *testing.T) { } func Test_ext_storage_root_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) ret, err := inst.Exec("rtm_ext_storage_root_version_1", []byte{}) @@ -672,6 +683,7 @@ func Test_ext_storage_root_version_1(t *testing.T) { } func Test_ext_storage_set_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("noot") @@ -690,6 +702,7 @@ func Test_ext_storage_set_version_1(t *testing.T) { } func Test_ext_offline_index_set_version_1(t *testing.T) { + t.Parallel() // TODO this currently fails with error could not find exported function, add rtm_ func to tester wasm (#1026) t.Skip() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) @@ -711,6 +724,7 @@ func Test_ext_offline_index_set_version_1(t *testing.T) { } func Test_ext_crypto_ed25519_generate_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) idData := []byte(keystore.AccoName) @@ -733,21 +747,20 @@ func Test_ext_crypto_ed25519_generate_version_1(t *testing.T) { ptr, err := inst.ctx.Allocator.Allocate(uint32(len(params))) require.NoError(t, err) - memory := inst.ctx.Memory.Data() + memory := inst.vm.Memory.Data() copy(memory[ptr:ptr+uint32(len(params))], params) dataLen := int32(len(params)) - runtimeFunc, err := inst.vm.Exports.GetFunction("rtm_ext_crypto_ed25519_generate_version_1") - require.NoError(t, err) + + runtimeFunc, ok := inst.vm.Exports["rtm_ext_crypto_ed25519_generate_version_1"] + require.True(t, ok) ret, err := runtimeFunc(int32(ptr), dataLen) require.NoError(t, err) - mem := inst.ctx.Memory.Data() - wasmRetI64 := wasmer.NewI64(ret) - retI64 := wasmRetI64.I64() + mem := inst.vm.Memory.Data() // this SCALE encoded, but it should just be a 32 byte buffer. may be due to way test runtime is written. - pubKeyBytes := mem[int32(retI64)+1 : int32(retI64)+1+32] + pubKeyBytes := mem[ret.ToI32()+1 : ret.ToI32()+1+32] pubKey, err := ed25519.NewPublicKey(pubKeyBytes) require.NoError(t, err) @@ -757,6 +770,7 @@ func Test_ext_crypto_ed25519_generate_version_1(t *testing.T) { } func Test_ext_crypto_ed25519_public_keys_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) idData := []byte(keystore.DumyName) @@ -796,6 +810,7 @@ func Test_ext_crypto_ed25519_public_keys_version_1(t *testing.T) { } func Test_ext_crypto_ed25519_sign_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) kp, err := ed25519.GenerateKeypair() @@ -834,6 +849,7 @@ func Test_ext_crypto_ed25519_sign_version_1(t *testing.T) { } func Test_ext_crypto_ed25519_verify_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) kp, err := ed25519.GenerateKeypair() @@ -866,6 +882,8 @@ func Test_ext_crypto_ed25519_verify_version_1(t *testing.T) { } func Test_ext_crypto_ecdsa_verify_version_2(t *testing.T) { + t.Parallel() + inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) kp, err := secp256k1.GenerateKeypair() @@ -899,6 +917,7 @@ func Test_ext_crypto_ecdsa_verify_version_2(t *testing.T) { } func Test_ext_crypto_ecdsa_verify_version_2_Table(t *testing.T) { + t.Parallel() testCases := map[string]struct { sig []byte msg []byte @@ -924,23 +943,30 @@ func Test_ext_crypto_ecdsa_verify_version_2_Table(t *testing.T) { key: []byte{132, 2, 39, 0, 55, 134, 131, 142, 43, 100, 63, 134, 96, 14, 253, 15, 222, 119, 154, 110, 188, 20, 159, 62, 125, 42, 59, 127, 19, 16, 0, 161, 236, 109}, //nolint:lll expected: []byte{0, 0, 0, 0}, }, - "invalid_key_length": { + "invalid_key": { sig: []byte{5, 1, 187, 0, 0, 183, 46, 115, 242, 32, 9, 54, 141, 207, 44, 15, 238, 42, 217, 196, 111, 173, 239, 204, 128, 93, 49, 179, 137, 150, 162, 125, 226, 225, 28, 145, 122, 127, 15, 154, 185, 11, 3, 66, 27, 187, 204, 242, 107, 68, 26, 111, 245, 30, 115, 141, 85, 74, 158, 211, 161, 217, 43, 151, 120, 125, 1}, //nolint:lll msg: []byte{48, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33}, key: []byte{132, 2, 39, 55, 134, 131, 142, 43, 100, 63, 134, 96, 14, 253, 15, 222, 119, 154, 110, 188, 20, 159, 62, 125, 42, 59, 127, 19, 16, 0, 161, 236, 109}, //nolint:lll - err: fmt.Errorf("running runtime function: unreachable"), + err: wasmer.NewExportedFunctionError( + "rtm_ext_crypto_ecdsa_verify_version_2", + "running runtime function: Failed to call the `%s` exported function."), }, - "invalid_message_length": { + "invalid_message": { sig: []byte{5, 1, 187, 179, 88, 183, 46, 115, 242, 32, 9, 54, 141, 207, 44, 15, 238, 42, 217, 196, 111, 173, 239, 204, 128, 93, 49, 179, 137, 150, 162, 125, 226, 225, 28, 145, 122, 127, 15, 154, 185, 11, 3, 66, 27, 187, 204, 242, 107, 68, 26, 111, 245, 30, 115, 141, 85, 74, 158, 211, 161, 217, 43, 151, 120, 125, 1}, //nolint:lll msg: []byte{48, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100}, key: []byte{132, 2, 39, 206, 55, 134, 131, 142, 43, 100, 63, 134, 96, 14, 253, 15, 222, 119, 154, 110, 188, 20, 159, 62, 125, 42, 59, 127, 19, 16, 0, 161, 236, 109}, //nolint:lll - err: fmt.Errorf("running runtime function: unreachable"), + err: wasmer.NewExportedFunctionError( + "rtm_ext_crypto_ecdsa_verify_version_2", + "running runtime function: Failed to call the `%s` exported function."), }, } for name, tc := range testCases { tc := tc t.Run(name, func(t *testing.T) { + t.Parallel() + inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) + ret, err := inst.Exec("rtm_ext_crypto_ecdsa_verify_version_2", append(append(tc.sig, tc.msg...), tc.key...)) assert.Equal(t, tc.expected, ret) if tc.err != nil { @@ -953,6 +979,7 @@ func Test_ext_crypto_ecdsa_verify_version_2_Table(t *testing.T) { } func Test_ext_crypto_sr25519_generate_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) idData := []byte(keystore.AccoName) @@ -985,6 +1012,7 @@ func Test_ext_crypto_sr25519_generate_version_1(t *testing.T) { } func Test_ext_crypto_secp256k1_ecdsa_recover_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) msgData := []byte("Hello world!") @@ -1028,6 +1056,7 @@ func Test_ext_crypto_secp256k1_ecdsa_recover_version_1(t *testing.T) { } func Test_ext_crypto_secp256k1_ecdsa_recover_compressed_version_1(t *testing.T) { + t.Parallel() t.Skip("host API tester does not yet contain rtm_ext_crypto_secp256k1_ecdsa_recover_compressed_version_1") inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) @@ -1071,6 +1100,7 @@ func Test_ext_crypto_secp256k1_ecdsa_recover_compressed_version_1(t *testing.T) } func Test_ext_crypto_sr25519_public_keys_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) idData := []byte(keystore.DumyName) @@ -1110,6 +1140,7 @@ func Test_ext_crypto_sr25519_public_keys_version_1(t *testing.T) { } func Test_ext_crypto_sr25519_sign_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) kp, err := sr25519.GenerateKeypair() @@ -1150,6 +1181,7 @@ func Test_ext_crypto_sr25519_sign_version_1(t *testing.T) { } func Test_ext_crypto_sr25519_verify_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) kp, err := sr25519.GenerateKeypair() @@ -1182,6 +1214,7 @@ func Test_ext_crypto_sr25519_verify_version_1(t *testing.T) { } func Test_ext_default_child_storage_read_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) err := inst.ctx.Storage.SetChild(testChildKey, trie.NewEmptyTrie()) @@ -1221,6 +1254,7 @@ func Test_ext_default_child_storage_read_version_1(t *testing.T) { } func Test_ext_default_child_storage_clear_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) err := inst.ctx.Storage.SetChild(testChildKey, trie.NewEmptyTrie()) @@ -1249,6 +1283,7 @@ func Test_ext_default_child_storage_clear_version_1(t *testing.T) { } func Test_ext_default_child_storage_clear_prefix_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) prefix := []byte("key") @@ -1290,6 +1325,7 @@ func Test_ext_default_child_storage_clear_prefix_version_1(t *testing.T) { } func Test_ext_default_child_storage_exists_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) err := inst.ctx.Storage.SetChild(testChildKey, trie.NewEmptyTrie()) @@ -1314,6 +1350,7 @@ func Test_ext_default_child_storage_exists_version_1(t *testing.T) { } func Test_ext_default_child_storage_get_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) err := inst.ctx.Storage.SetChild(testChildKey, trie.NewEmptyTrie()) @@ -1338,6 +1375,7 @@ func Test_ext_default_child_storage_get_version_1(t *testing.T) { } func Test_ext_default_child_storage_next_key_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testKeyValuePair := []struct { @@ -1375,6 +1413,7 @@ func Test_ext_default_child_storage_next_key_version_1(t *testing.T) { } func Test_ext_default_child_storage_root_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) err := inst.ctx.Storage.SetChild(testChildKey, trie.NewEmptyTrie()) @@ -1407,6 +1446,7 @@ func Test_ext_default_child_storage_root_version_1(t *testing.T) { } func Test_ext_default_child_storage_set_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) err := inst.ctx.Storage.SetChild(testChildKey, trie.NewEmptyTrie()) @@ -1435,6 +1475,7 @@ func Test_ext_default_child_storage_set_version_1(t *testing.T) { } func Test_ext_default_child_storage_storage_kill_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) err := inst.ctx.Storage.SetChild(testChildKey, trie.NewEmptyTrie()) @@ -1456,6 +1497,7 @@ func Test_ext_default_child_storage_storage_kill_version_1(t *testing.T) { } func Test_ext_default_child_storage_storage_kill_version_2_limit_all(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) tr := trie.NewEmptyTrie() @@ -1489,6 +1531,7 @@ func Test_ext_default_child_storage_storage_kill_version_2_limit_all(t *testing. } func Test_ext_default_child_storage_storage_kill_version_2_limit_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) tr := trie.NewEmptyTrie() @@ -1522,6 +1565,7 @@ func Test_ext_default_child_storage_storage_kill_version_2_limit_1(t *testing.T) } func Test_ext_default_child_storage_storage_kill_version_2_limit_none(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) tr := trie.NewEmptyTrie() @@ -1552,6 +1596,7 @@ func Test_ext_default_child_storage_storage_kill_version_2_limit_none(t *testing } func Test_ext_default_child_storage_storage_kill_version_3(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) tr := trie.NewEmptyTrie() @@ -1575,7 +1620,8 @@ func Test_ext_default_child_storage_storage_kill_version_3(t *testing.T) { key: []byte(`fakekey`), limit: optLimit2, expected: []byte{0, 0, 0, 0, 0}, - errMsg: "running runtime function: unreachable", + errMsg: "running runtime function: " + + "Failed to call the `rtm_ext_default_child_storage_storage_kill_version_3` exported function.", }, {key: testChildKey, limit: optLimit2, expected: []byte{1, 2, 0, 0, 0}}, {key: testChildKey, limit: nil, expected: []byte{0, 1, 0, 0, 0}}, @@ -1603,6 +1649,7 @@ func Test_ext_default_child_storage_storage_kill_version_3(t *testing.T) { } func Test_ext_storage_append_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testkey := []byte("noot") @@ -1651,6 +1698,7 @@ func Test_ext_storage_append_version_1(t *testing.T) { } func Test_ext_storage_append_version_1_again(t *testing.T) { + t.Parallel() DefaultTestLogLvl = 5 inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) @@ -1700,6 +1748,7 @@ func Test_ext_storage_append_version_1_again(t *testing.T) { } func Test_ext_trie_blake2_256_ordered_root_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testvalues := []string{"static", "even-keeled", "Future-proofed"} @@ -1718,6 +1767,7 @@ func Test_ext_trie_blake2_256_ordered_root_version_1(t *testing.T) { } func Test_ext_trie_blake2_256_root_version_1(t *testing.T) { + t.Parallel() inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME) testinput := []string{"noot", "was", "here", "??"} @@ -1741,6 +1791,8 @@ func Test_ext_trie_blake2_256_root_version_1(t *testing.T) { } func Test_ext_trie_blake2_256_verify_proof_version_1(t *testing.T) { + t.Parallel() + tmp := t.TempDir() memdb, err := chaindb.NewBadgerDB(&chaindb.Config{ @@ -1808,6 +1860,8 @@ func Test_ext_trie_blake2_256_verify_proof_version_1(t *testing.T) { for name, testcase := range testcases { testcase := testcase t.Run(name, func(t *testing.T) { + t.Parallel() + hashEnc, err := scale.Marshal(testcase.root) require.NoError(t, err) diff --git a/lib/runtime/wasmer/instance.go b/lib/runtime/wasmer/instance.go index 91a89e23ad..e7159078d2 100644 --- a/lib/runtime/wasmer/instance.go +++ b/lib/runtime/wasmer/instance.go @@ -7,39 +7,35 @@ import ( "bytes" "errors" "fmt" - "os" - "path/filepath" "sync" "github.com/ChainSafe/gossamer/internal/log" "github.com/ChainSafe/gossamer/lib/common" - "github.com/ChainSafe/gossamer/lib/crypto" "github.com/ChainSafe/gossamer/lib/keystore" "github.com/ChainSafe/gossamer/lib/runtime" "github.com/ChainSafe/gossamer/lib/runtime/offchain" "github.com/ChainSafe/gossamer/lib/trie" + + "github.com/ChainSafe/gossamer/lib/crypto" + + wasm "github.com/wasmerio/go-ext-wasm/wasmer" + "github.com/klauspost/compress/zstd" - "github.com/wasmerio/wasmer-go/wasmer" ) // Name represents the name of the interpreter const Name = "wasmer" var ( - ErrCodeEmpty = errors.New("code is empty") - ErrWASMDecompress = errors.New("wasm decompression failed") - ErrInstanceIsStopped = errors.New("instance is stopped") - ErrExportFunctionNotFound = errors.New("export function not found") - logger = log.NewFromGlobal( log.AddContext("pkg", "runtime"), log.AddContext("module", "go-wasmer"), ) ) -// Instance represents a runtime go-wasmer instance +// Instance represents a v0.8 runtime go-wasmer instance type Instance struct { - vm *wasmer.Instance + vm wasm.Instance ctx *runtime.Context isClosed bool codeHash common.Hash @@ -73,80 +69,26 @@ func NewInstanceFromTrie(t *trie.Trie, cfg Config) (*Instance, error) { // NewInstanceFromFile instantiates a runtime from a .wasm file func NewInstanceFromFile(fp string, cfg Config) (*Instance, error) { // Reads the WebAssembly module as bytes. - fileBytes, err := os.ReadFile(filepath.Clean(fp)) + bytes, err := wasm.ReadBytes(fp) if err != nil { return nil, err } - return NewInstance(fileBytes, cfg) + return NewInstance(bytes, cfg) } // NewInstance instantiates a runtime from raw wasm bytecode -func NewInstance(code []byte, cfg Config) (*Instance, error) { +func NewInstance(code []byte, cfg Config) (instance *Instance, err error) { logger.Patch(log.SetLevel(cfg.LogLvl), log.SetCallerFunc(true)) - if len(code) == 0 { - return nil, ErrCodeEmpty - } - code, err := decompressWasm(code) + wasmInstance, allocator, err := setupVM(code) if err != nil { - // Note the sentinel error is wrapped here since the ztsd Go library - // does not return any exported sentinel errors. - return nil, fmt.Errorf("%w: %s", ErrWASMDecompress, err) - } - - // Create engine and store with default values - engine := wasmer.NewEngine() - store := wasmer.NewStore(engine) - - // Compile the module - module, err := wasmer.NewModule(store, code) - if err != nil { - return nil, err - } - - // Get memory descriptor from module, if it imports memory - moduleImports := module.Imports() - var memImport *wasmer.ImportType - for _, im := range moduleImports { - if im.Name() == "memory" { - memImport = im - break - } - } - - var memoryType *wasmer.MemoryType - if memImport != nil { - memoryType = memImport.Type().IntoMemoryType() - } - - // Check if module exports memory - hasExportedMemory := false - moduleExports := module.Exports() - for _, export := range moduleExports { - if export.Name() == "memory" { - hasExportedMemory = true - break - } - } - - var memory *wasmer.Memory - // create memory to import, if it's expecting imported memory - if !hasExportedMemory { - if memoryType == nil { - // values from newer kusama/polkadot runtimes - lim, err := wasmer.NewLimits(23, 4294967295) - if err != nil { - return nil, err - } - memoryType = wasmer.NewMemoryType(lim) - } - - memory = wasmer.NewMemory(store, memoryType) + return nil, fmt.Errorf("setting up VM: %w", err) } runtimeCtx := &runtime.Context{ Storage: cfg.Storage, + Allocator: allocator, Keystore: cfg.Keystore, Validator: cfg.Role == common.AuthorityRole, NodeStorage: cfg.NodeStorage, @@ -155,38 +97,9 @@ func NewInstance(code []byte, cfg Config) (*Instance, error) { SigVerifier: crypto.NewSignatureVerifier(logger), OffchainHTTPSet: offchain.NewHTTPSet(), } + wasmInstance.SetContextData(runtimeCtx) - imports := importsNodeRuntime(store, memory, runtimeCtx) - if err != nil { - return nil, fmt.Errorf("creating node runtime imports: %w", err) - } - wasmInstance, err := wasmer.NewInstance(module, imports) - if err != nil { - return nil, err - } - - if hasExportedMemory { - memory, err = wasmInstance.Exports.GetMemory("memory") - if err != nil { - return nil, err - } - } - - runtimeCtx.Memory = Memory{memory} - - // set heap base for allocator, start allocating at heap base - heapBase, err := wasmInstance.Exports.Get("__heap_base") - if err != nil { - return nil, err - } - - hb, err := heapBase.IntoGlobal().Get() - if err != nil { - return nil, err - } - - runtimeCtx.Allocator = runtime.NewAllocator(runtimeCtx.Memory, uint32(hb.(int32))) - instance := &Instance{ + instance = &Instance{ vm: wasmInstance, ctx: runtimeCtx, codeHash: cfg.CodeHash, @@ -196,6 +109,8 @@ func NewInstance(code []byte, cfg Config) (*Instance, error) { instance.ctx.Version = cfg.testVersion } + wasmInstance.SetContextData(instance.ctx) + return instance, nil } @@ -237,8 +152,6 @@ func GetRuntimeVersion(code []byte) (version runtime.Version, err error) { } defer instance.Stop() - logger.Info("instantiated runtime!!!") - version, err = instance.Version() if err != nil { return version, fmt.Errorf("running runtime: %w", err) @@ -247,77 +160,60 @@ func GetRuntimeVersion(code []byte) (version runtime.Version, err error) { return version, nil } -// Exec calls the given function with the given data -func (in *Instance) Exec(function string, data []byte) (result []byte, err error) { - in.mutex.Lock() - defer in.mutex.Unlock() +var ( + ErrCodeEmpty = errors.New("code is empty") + ErrWASMDecompress = errors.New("wasm decompression failed") +) - if in.isClosed { - return nil, ErrInstanceIsStopped +func setupVM(code []byte) (instance wasm.Instance, + allocator *runtime.FreeingBumpHeapAllocator, err error) { + if len(code) == 0 { + return instance, nil, ErrCodeEmpty } - dataLength := uint32(len(data)) - inputPtr, err := in.ctx.Allocator.Allocate(dataLength) + code, err = decompressWasm(code) if err != nil { - return nil, fmt.Errorf("allocating input memory: %w", err) + // Note the sentinel error is wrapped here since the ztsd Go library + // does not return any exported sentinel errors. + return instance, nil, fmt.Errorf("%w: %s", ErrWASMDecompress, err) } - defer in.ctx.Allocator.Clear() - - // Store the data into memory - memory := in.ctx.Memory.Data() - copy(memory[inputPtr:inputPtr+dataLength], data) - - runtimeFunc, err := in.vm.Exports.GetFunction(function) + imports, err := importsNodeRuntime() if err != nil { - return nil, fmt.Errorf("%w: %s", ErrExportFunctionNotFound, function) + return instance, nil, fmt.Errorf("creating node runtime imports: %w", err) } - castedInputPointer, err := safeCastInt32(inputPtr) + // Provide importable memory for newer runtimes + // TODO: determine memory descriptor size that the runtime wants from the wasm. + // should be doable w/ wasmer 1.0.0. (#1268) + memory, err := wasm.NewMemory(23, 0) if err != nil { - panic(err) + return instance, nil, fmt.Errorf("creating web assembly memory: %w", err) } - castedDataLength, err := safeCastInt32(dataLength) + _, err = imports.AppendMemory("memory", memory) if err != nil { - panic(err) + return instance, nil, fmt.Errorf("appending memory to imports: %w", err) } - wasmValue, err := runtimeFunc(castedInputPointer, castedDataLength) + // Instantiates the WebAssembly module. + instance, err = wasm.NewInstanceWithImports(code, imports) if err != nil { - if errors.Is(err, errMemoryValueOutOfBounds) { - panic(fmt.Errorf("executing runtime function: %v", err)) - } - return nil, fmt.Errorf("running runtime function: %w", err) + return instance, nil, fmt.Errorf("creating web assembly instance: %w", err) } - wasmValueAsI64 := wasmer.NewI64(wasmValue) - outputPtr, outputLength := splitPointerSize(wasmValueAsI64.I64()) - memory = in.ctx.Memory.Data() // call Data() again to get larger slice - - allocatedData := make([]byte, outputLength) - copy(allocatedData[:], memory[outputPtr:outputPtr+outputLength]) - return allocatedData, nil -} - -// NodeStorage to get reference to runtime node service -func (in *Instance) NodeStorage() runtime.NodeStorage { - return in.ctx.NodeStorage -} + // Assume imported memory is used if runtime does not export any + if !instance.HasMemory() { + instance.Memory = memory + } -// NetworkService to get referernce to runtime network service -func (in *Instance) NetworkService() runtime.BasicNetwork { - return in.ctx.Network -} + // TODO: get __heap_base exported value from runtime. + // wasmer 0.3.x does not support this, but wasmer 1.0.0 does (#1268) + heapBase := runtime.DefaultHeapBase -// Keystore to get reference to runtime keystore -func (in *Instance) Keystore() *keystore.GlobalKeystore { - return in.ctx.Keystore -} + allocator = runtime.NewAllocator(instance.Memory, heapBase) -// Validator returns the context's Validator -func (in *Instance) Validator() bool { - return in.ctx.Validator + return instance, allocator, nil } // SetContextStorage sets the runtime's storage. @@ -348,3 +244,64 @@ func (in *Instance) close() { in.ctx.Allocator.Clear() in.isClosed = true } + +var ( + ErrInstanceIsStopped = errors.New("instance is stopped") + ErrExportFunctionNotFound = errors.New("export function not found") +) + +// Exec calls the given function with the given data +func (in *Instance) Exec(function string, data []byte) (result []byte, err error) { + in.mutex.Lock() + defer in.mutex.Unlock() + + if in.isClosed { + return nil, ErrInstanceIsStopped + } + + dataLength := uint32(len(data)) + inputPtr, err := in.ctx.Allocator.Allocate(dataLength) + if err != nil { + return nil, fmt.Errorf("allocating input memory: %w", err) + } + + defer in.ctx.Allocator.Clear() + + // Store the data into memory + memory := in.vm.Memory.Data() + copy(memory[inputPtr:inputPtr+dataLength], data) + + runtimeFunc, ok := in.vm.Exports[function] + if !ok { + return nil, fmt.Errorf("%w: %s", ErrExportFunctionNotFound, function) + } + + wasmValue, err := runtimeFunc(int32(inputPtr), int32(dataLength)) + if err != nil { + return nil, fmt.Errorf("running runtime function: %w", err) + } + + outputPtr, outputLength := splitPointerSize(wasmValue.ToI64()) + memory = in.vm.Memory.Data() // call Data() again to get larger slice + return memory[outputPtr : outputPtr+outputLength], nil +} + +// NodeStorage to get reference to runtime node service +func (in *Instance) NodeStorage() runtime.NodeStorage { + return in.ctx.NodeStorage +} + +// NetworkService to get referernce to runtime network service +func (in *Instance) NetworkService() runtime.BasicNetwork { + return in.ctx.Network +} + +// Keystore to get reference to runtime keystore +func (in *Instance) Keystore() *keystore.GlobalKeystore { + return in.ctx.Keystore +} + +// Validator returns the context's Validator +func (in *Instance) Validator() bool { + return in.ctx.Validator +} diff --git a/lib/runtime/wasmer/instance_test.go b/lib/runtime/wasmer/instance_test.go index e2f20d3410..9a6677d50a 100644 --- a/lib/runtime/wasmer/instance_test.go +++ b/lib/runtime/wasmer/instance_test.go @@ -9,8 +9,9 @@ import ( "testing" "github.com/ChainSafe/gossamer/lib/runtime" - "github.com/klauspost/compress/zstd" "github.com/stretchr/testify/require" + + "github.com/klauspost/compress/zstd" ) // test used for ensuring runtime exec calls can be made concurrently diff --git a/lib/runtime/wasmer/memory.go b/lib/runtime/wasmer/memory.go deleted file mode 100644 index 13f1e0f460..0000000000 --- a/lib/runtime/wasmer/memory.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2023 ChainSafe Systems (ON) -// SPDX-License-Identifier: LGPL-3.0-only - -package wasmer - -import ( - "errors" - "fmt" - "math" - - "github.com/wasmerio/wasmer-go/wasmer" -) - -var ( - errCantGrowMemory = errors.New("failed to grow memory") - errMemoryValueOutOfBounds = errors.New("memory value is out of bounds") -) - -// Memory is a thin wrapper around Wasmer memory to support -// Gossamer runtime.Memory interface -type Memory struct { - memory *wasmer.Memory -} - -func checkBounds(value uint64) (uint32, error) { - if value > math.MaxUint32 { - return 0, fmt.Errorf("%w", errMemoryValueOutOfBounds) - } - return uint32(value), nil -} - -// Data returns the memory's data -func (m Memory) Data() []byte { - return m.memory.Data() -} - -// Length returns the memory's length -func (m Memory) Length() uint32 { - value, err := checkBounds(uint64(m.memory.DataSize())) - if err != nil { - panic(err) - } - return value -} - -// Grow grows the memory by the given number of pages -func (m Memory) Grow(numPages uint32) error { - ok := m.memory.Grow(wasmer.Pages(numPages)) - if !ok { - return fmt.Errorf("%w: by %d pages", errCantGrowMemory, numPages) - } - return nil -} diff --git a/lib/runtime/wasmer/memory_test.go b/lib/runtime/wasmer/memory_test.go deleted file mode 100644 index 5ec5b8b184..0000000000 --- a/lib/runtime/wasmer/memory_test.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2023 ChainSafe Systems (ON) -// SPDX-License-Identifier: LGPL-3.0-only - -package wasmer - -import ( - "math" - "testing" - "unsafe" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/wasmerio/wasmer-go/wasmer" -) - -func createInstance(t *testing.T) (*wasmer.Instance, error) { - t.Helper() - // We are using the text representation of the module here. Taken from: - // https://github.com/wasmerio/wasmer-go/blob/23d786b6b81ad93e2b974d2f4510bea374f0f37c/examples/example_memory_test.go#L28 - wasmBytes := []byte(` - (module - (type $mem_size_t (func (result i32))) - (type $get_at_t (func (param i32) (result i32))) - (type $set_at_t (func (param i32) (param i32))) - (memory $mem 1) - (func $get_at (type $get_at_t) (param $idx i32) (result i32) - (i32.load (local.get $idx))) - (func $set_at (type $set_at_t) (param $idx i32) (param $val i32) - (i32.store (local.get $idx) (local.get $val))) - (func $mem_size (type $mem_size_t) (result i32) - (memory.size)) - (export "get_at" (func $get_at)) - (export "set_at" (func $set_at)) - (export "mem_size" (func $mem_size)) - (export "memory" (memory $mem))) - `) - - engine := wasmer.NewEngine() - store := wasmer.NewStore(engine) - - // Compile module - module, err := wasmer.NewModule(store, wasmBytes) - require.NoError(t, err) - - importObject := wasmer.NewImportObject() - - // Instantiate the Wasm module. - return wasmer.NewInstance(module, importObject) -} - -func TestMemory_Length(t *testing.T) { - const pageLength uint32 = 65536 - instance, err := createInstance(t) - require.NoError(t, err) - - wasmerMemory, err := instance.Exports.GetMemory("memory") - require.NoError(t, err) - - memory := Memory{ - memory: wasmerMemory, - } - - memLength := memory.Length() - require.Equal(t, pageLength, memLength) -} - -func TestMemory_Grow(t *testing.T) { - const pageLength uint32 = 65536 - instance, err := createInstance(t) - require.NoError(t, err) - - wasmerMemory, err := instance.Exports.GetMemory("memory") - require.NoError(t, err) - - memory := Memory{ - memory: wasmerMemory, - } - - memLength := memory.Length() - require.Equal(t, pageLength, memLength) - - err = memory.Grow(1) - require.NoError(t, err) - - memLength = memory.Length() - require.Equal(t, pageLength*2, memLength) -} - -func TestMemory_Data(t *testing.T) { - instance, err := createInstance(t) - require.NoError(t, err) - - // Grab exported utility functions from the module - getAt, err := instance.Exports.GetFunction("get_at") - require.NoError(t, err) - - setAt, err := instance.Exports.GetFunction("set_at") - require.NoError(t, err) - - wasmerMemory, err := instance.Exports.GetMemory("memory") - require.NoError(t, err) - - memory := Memory{ - memory: wasmerMemory, - } - - memAddr := 0x0 - const val int32 = 0xFEFEFFE - _, err = setAt(memAddr, val) - require.NoError(t, err) - - // Compare bytes at address 0x0 - expectedFirstBytes := []byte{254, 239, 239, 15} - memData := memory.Data() - require.Equal(t, expectedFirstBytes, memData[:4]) - - result, err := getAt(memAddr) - require.NoError(t, err) - require.Equal(t, val, result) - - // Write value at end of page - pageSize := 0x1_0000 - memAddr = (pageSize) - int(unsafe.Sizeof(val)) - const val2 int32 = 0xFEA09 - _, err = setAt(memAddr, val2) - require.NoError(t, err) - - result, err = getAt(memAddr) - require.NoError(t, err) - require.Equal(t, val2, result) -} - -func TestMemory_CheckBounds(t *testing.T) { - testCases := []struct { - name string - value uint64 - exp uint32 - expErr error - expErrMsg string - }{ - { - name: "valid cast", - value: uint64(0), - exp: uint32(0), - }, - { - name: "max uint32", - value: uint64(math.MaxUint32), - exp: math.MaxUint32, - }, - { - name: "out of bounds", - value: uint64(math.MaxUint32 + 1), - expErr: errMemoryValueOutOfBounds, - expErrMsg: errMemoryValueOutOfBounds.Error(), - }, - } - for _, test := range testCases { - test := test - t.Run(test.name, func(t *testing.T) { - res, err := checkBounds(test.value) - assert.ErrorIs(t, err, test.expErr) - if test.expErr != nil { - assert.EqualError(t, err, test.expErrMsg) - } - assert.Equal(t, test.exp, res) - }) - } -}