diff --git a/packages/client-wasm/src/create/imports.js b/packages/client-wasm/src/create/imports.js index 62f66cf0..d876ae95 100644 --- a/packages/client-wasm/src/create/imports.js +++ b/packages/client-wasm/src/create/imports.js @@ -1,27 +1,16 @@ // ISC, Copyright 2017-2018 Jaco Greeff // @flow -const runtime = require('@polkadot/client-wasm-runtime'); +import type { RuntimeExports } from '@polkadot/client-wasm-runtime/types'; -const createMemory = require('./memory'); -const createTable = require('./table'); - -module.exports = function createImports (imports?: WebAssemblyImports = {}, initialMemory?: number, maximumMemory?: number): WebAssemblyImports { - imports.env = imports.env || {}; - imports.env.memoryBase = imports.env.memoryBase || 0; - imports.env.tableBase = imports.env.tableBase || 0; - - if (!imports.env.memory) { - // $FlowFixMe imports.env gets a value above - imports.env.memory = createMemory(initialMemory, maximumMemory); - } - - if (!imports.env.table) { - // $FlowFixMe imports.env gets a value above - imports.env.table = createTable(); - } - - imports.env = Object.assign(imports.env, runtime(imports.env.memory)); - - return imports; +// flowlint-next-line unclear-type:off +module.exports = function createImports (memory: WebAssembly.Memory, table: WebAssembly.Table, runtime: RuntimeExports, imports?: Object = {}): WebAssemblyImports { + return Object.assign({}, imports, { + env: Object.assign({}, runtime, { + memory, + memoryBase: 0, + table, + tableBase: 0 + }) + }); }; diff --git a/packages/client-wasm/src/create/imports.spec.js b/packages/client-wasm/src/create/imports.spec.js index 160de8fc..8453c9ae 100644 --- a/packages/client-wasm/src/create/imports.spec.js +++ b/packages/client-wasm/src/create/imports.spec.js @@ -1,116 +1,42 @@ // ISC, Copyright 2017-2018 Jaco Greeff -const runtime = require('@polkadot/client-wasm-runtime'); -const isInstanceOf = require('@polkadot/util/is/instanceOf'); - const { createImports } = require('./index'); describe('createImports', () => { - let imports; - let origWebAssembly; - let memOptions; - - beforeEach(() => { - imports = {}; - origWebAssembly = global.WebAssembly; - - global.WebAssembly = class { - static Memory = class { - constructor (options) { - this.buffer = new Uint8Array(10); - memOptions = options; - } - }; - static Table = class {}; - }; - }); - - afterEach(() => { - global.WebAssembly = origWebAssembly; - }); - - it('works when import has not been specified', () => { + it('sets the memoryBase & tableBase', () => { expect( - createImports() - ).toBeDefined(); - }); - - it('exposes the default imports on env', () => { - expect( - createImports({}).env - ).toMatchObject( - Object.keys(runtime).reduce((env, key) => { - env[key] = expect.anything(); - - return env; - }, {}) - ); - }); - - it('uses env.memoryBase when supplied', () => { - imports.env = { memoryBase: 'test' }; - imports = createImports(imports); - - expect(imports.env.memoryBase).toEqual('test'); - }); - - it('uses env.tableBase when supplied', () => { - imports.env = { tableBase: 'test' }; - imports = createImports(imports); - - expect(imports.env.tableBase).toEqual('test'); - }); - - it('uses env.memory when supplied', () => { - const memory = { buffer: new Uint8Array(10) }; - - imports.env = { memory }; - imports = createImports(imports); - - expect(imports.env.memory).toEqual(memory); + createImports({}, {}, {}).env + ).toMatchObject({ + memoryBase: 0, + tableBase: 0 + }); }); - it('creates env.memory when none supplied', () => { - imports = createImports(imports); + it('uses supplied memory', () => { + const memory = { 'some': { 'memory': { 'object': true } } }; expect( - isInstanceOf( - imports.env.memory, WebAssembly.Memory - ) - ).toEqual(true); + createImports(memory, {}, {}).env + ).toMatchObject({ + memory + }); }); - it('creates env.memory using the supplied initial/maximum', () => { - createImports(imports, 4, 6); + it('uses supplied table', () => { + const table = { 'some': { 'table': { 'object': true } } }; expect( - memOptions - ).toEqual({ - initial: (4 * 1024) / 64, - maximum: (6 * 1024) / 64 + createImports({}, table, {}).env + ).toMatchObject({ + table }); }); - it('uses env.table when supplied', () => { - imports.env = { table: 'test' }; - imports = createImports(imports); - - expect(imports.env.table).toEqual('test'); - }); - - it('creates env.table when none supplied', () => { - imports = createImports(imports); + it('exposes the runtime imports on the env', () => { + const runtime = { 'ext_foo': 1, 'ext_bar': 2, 'ext_baz': 3 }; expect( - isInstanceOf( - imports.env.table, WebAssembly.Table - ) - ).toEqual(true); - }); - - it('sets default environment when none supplied', () => { - imports = createImports(); - - expect(imports.env).toBeDefined(); + createImports({}, {}, runtime).env + ).toMatchObject(runtime); }); }); diff --git a/packages/client-wasm/src/create/instance.js b/packages/client-wasm/src/create/instance.js index ba3af284..4872c75f 100644 --- a/packages/client-wasm/src/create/instance.js +++ b/packages/client-wasm/src/create/instance.js @@ -1,6 +1,6 @@ // ISC, Copyright 2017-2018 Jaco Greeff // @flow -module.exports = function createInstance (module: WebAssemblyModule, imports: WebAssemblyImports): WebAssemblyInstance { - return new WebAssembly.Instance(module, imports); +module.exports = function createInstance (wasmModule: WebAssemblyModule, imports: WebAssemblyImports): WebAssemblyInstance { + return new WebAssembly.Instance(wasmModule, imports); }; diff --git a/packages/client-wasm/src/index.js b/packages/client-wasm/src/index.js index d4214e6d..db8e0049 100644 --- a/packages/client-wasm/src/index.js +++ b/packages/client-wasm/src/index.js @@ -1,6 +1,6 @@ // ISC, Copyright 2017-2018 Jaco Greeff // @flow -const Wasm = require('./wasm'); +const wasm = require('./wasm'); -module.exports = Wasm; +module.exports = wasm; diff --git a/packages/client-wasm/src/wasm.js b/packages/client-wasm/src/wasm.js index a499a40c..ea58e31e 100644 --- a/packages/client-wasm/src/wasm.js +++ b/packages/client-wasm/src/wasm.js @@ -1,31 +1,21 @@ // ISC, Copyright 2017-2018 Jaco Greeff // @flow -const assert = require('@polkadot/util/assert'); -const isObject = require('@polkadot/util/is/object'); +import type { ConfigType } from '@polkadot/client/types'; +import type { DbInterface } from '@polkadot/client-db/types'; +import type { WasmExtraImports } from './types'; -const { createImports, createInstance, createModule } = require('./create'); +const createRuntime = require('@polkadot/client-wasm-runtime'); -module.exports = class Wasm { - constructor (instance: WebAssemblyInstance) { - const exports = instance.exports; +const { createImports, createInstance, createMemory, createModule, createTable } = require('./create'); - assert(isObject(exports), 'Expected function exports'); +module.exports = function wasm ({ wasm: { memoryInitial, memoryMaximum } }: ConfigType, db: DbInterface, bytecode: Uint8Array, imports?: WasmExtraImports = {}): WebAssemblyInstance$Exports { + const memory = createMemory(memoryInitial, memoryMaximum); + const table = createTable(); + const runtime = createRuntime(memory, db); - Object.keys(exports).forEach((key: string) => { - Object.defineProperty(this, key, { - configurable: false, - enumerable: true, - value: exports[key] - }); - }); - } - - static fromCode (bytecode: Uint8Array, _imports?: WebAssemblyImports): Wasm { - const module = createModule(bytecode); - const imports = createImports(_imports); - const instance = createInstance(module, imports); - - return new Wasm(instance); - } + return createInstance( + createModule(bytecode), + createImports(memory, table, runtime, imports) + ).exports; }; diff --git a/packages/client-wasm/src/wasm.spec.js b/packages/client-wasm/src/wasm.spec.js index fe2e2838..e636ba10 100644 --- a/packages/client-wasm/src/wasm.spec.js +++ b/packages/client-wasm/src/wasm.spec.js @@ -1,95 +1,60 @@ // ISC, Copyright 2017-2018 Jaco Greeff -const isInstanceOf = require('@polkadot/util/is/instanceOf'); - const { loadWasm } = require('../test/helpers'); -const Wasm = require('./wasm'); +const wasm = require('./wasm'); -describe('Wasm', () => { - describe('checks', () => { - let origWebAssembly; +describe('wasm', () => { + let instance; + describe('valid modules', () => { beforeEach(() => { - origWebAssembly = global.WebAssembly; - - global.WebAssembly = class { - static Module = class {}; - static Memory = class {}; - static Table = class {}; - static Instance = class {}; - }; - }); - - afterEach(() => { - global.WebAssembly = origWebAssembly; + instance = wasm( + { wasm: {} }, {}, + loadWasm('addTwo.wasm') + ); }); - it('disallows empty exports', () => { + it('allows calls into the module', () => { expect( - () => new Wasm(new WebAssembly.Instance()) - ).toThrow(/Expected function exports/); + instance.addTwo(22, 33) + ).toEqual(55); }); }); - describe('instance', () => { - let wasm; + describe('imports', () => { + let callback; + let instance; - describe('valid modules', () => { - beforeEach(() => { - wasm = Wasm.fromCode( - loadWasm('addTwo.wasm') - ); - }); - - it('creates a valid instance via fromCode', () => { - expect( - isInstanceOf(wasm, Wasm) - ).toEqual(true); - }); - - it('allows calls into the module', () => { - expect( - wasm.addTwo(22, 33) - ).toEqual(55); - }); + beforeEach(() => { + callback = jest.fn(); + instance = wasm( + { wasm: {} }, {}, + loadWasm('import.wasm'), + { js: { callback } } + ); }); - describe('imports', () => { - let callback; - let wasm; + it('allows imports to be called', () => { + instance.go(123); - beforeEach(() => { - callback = jest.fn(); - wasm = Wasm.fromCode( - loadWasm('import.wasm'), - { js: { callback } } - ); - }); - - it('allows imports to be called', () => { - wasm.go(123); - - expect(callback).toHaveBeenCalledWith(123); - }); + expect(callback).toHaveBeenCalledWith(123); }); + }); - describe('start', () => { - let callback; - // let wasm; - - beforeEach(() => { - callback = jest.fn(); - Wasm.fromCode( - loadWasm('start.wasm'), - { js: { callback } } - ); - }); + describe('start', () => { + let callback; - it('allows imports to be called', () => { - // wasm.go(123); + beforeEach(() => { + callback = jest.fn(); + instance = wasm( + { wasm: {} }, {}, + loadWasm('start.wasm'), + { js: { callback } } + ); + }); - expect(callback).toHaveBeenCalledWith(1337); - }); + it('allows imports to be called', () => { + expect(callback).toHaveBeenCalledWith(1337); }); }); }); diff --git a/packages/client/src/types.js b/packages/client/src/types.js index fdbd576a..708915a1 100644 --- a/packages/client/src/types.js +++ b/packages/client/src/types.js @@ -5,6 +5,7 @@ import type { ChainNameType } from '@polkadot/client-chains/types'; import type { DbConfigType } from '@polkadot/client-db/types'; import type { P2pConfigType } from '@polkadot/client-p2p/types'; import type { RpcConfigType, HandlerType } from '@polkadot/client-rpc/types'; +import type { WasmConfigType } from '@polkadot/client-wasm/types'; import type { RoleType } from '@polkadot/primitives/role'; export type ConfigType = { @@ -12,7 +13,8 @@ export type ConfigType = { db: DbConfigType, p2p: P2pConfigType, rpc: RpcConfigType, - roles: Array + roles: Array, + wasm: WasmConfigType }; export type EndpointType = {