UNPKG

@hashgraphonline/standards-sdk

Version:

The Hashgraph Online Standards SDK provides a complete implementation of the Hashgraph Consensus Standards (HCS), giving developers all the tools needed to build applications on Hedera.

205 lines (204 loc) • 6.46 kB
import { Logger } from "./standards-sdk.es22.js"; class WasmBridge { constructor() { this.wasm = null; this.WASM_VECTOR_LEN = 0; this.cachedUint8Memory = null; this.cachedDataViewMemory = null; this.textEncoder = new TextEncoder(); this.textDecoder = new TextDecoder("utf-8", { ignoreBOM: true, fatal: true }); this.textDecoder.decode(); this.logger = Logger.getInstance({ module: "WasmBridge" }); } setLogLevel(level) { this.logger.setLogLevel(level); } get wasmInstance() { if (!this.wasm) { throw new Error("WASM not initialized"); } return this.wasm; } getUint8Memory() { if (!this.wasm) { throw new Error("WASM not initialized"); } if (this.cachedUint8Memory === null || this.cachedUint8Memory.byteLength === 0) { this.cachedUint8Memory = new Uint8Array(this.wasm.memory.buffer); } return this.cachedUint8Memory; } getDataViewMemory() { if (!this.wasm) { throw new Error("WASM not initialized"); } if (this.cachedDataViewMemory === null || this.cachedDataViewMemory.buffer !== this.wasm.memory.buffer) { this.cachedDataViewMemory = new DataView(this.wasm.memory.buffer); } return this.cachedDataViewMemory; } encodeString(arg, view) { if (arg.length === 0) { return { read: 0, written: 0 }; } const buf = this.textEncoder.encode(arg); view.set(buf); return { read: arg.length, written: buf.length }; } passStringToWasm(arg, malloc, realloc) { if (realloc === void 0) { const buf = this.textEncoder.encode(arg); const ptr2 = malloc(buf.length, 1); const view = this.getUint8Memory(); view.set(buf, ptr2); this.WASM_VECTOR_LEN = buf.length; return ptr2; } let len = this.textEncoder.encode(arg).length; let ptr = malloc(len, 1); const mem = this.getUint8Memory(); let offset = 0; for (; offset < len; offset++) { const code = arg.charCodeAt(offset); if (code > 127) break; mem[ptr + offset] = code; } if (offset !== len) { if (offset !== 0) { arg = arg.slice(offset); } ptr = realloc( ptr, len, len = offset + this.textEncoder.encode(arg).length * 3, 1 ); const view = this.getUint8Memory().subarray(ptr + offset, ptr + len); const ret = this.encodeString(arg, view); offset += ret.written; } this.WASM_VECTOR_LEN = offset; return ptr; } getStringFromWasm(ptr, len) { ptr = ptr >>> 0; return this.textDecoder.decode( this.getUint8Memory().subarray(ptr, ptr + len) ); } createWasmFunction(wasmFn) { if (!this.wasm) { throw new Error("WASM not initialized"); } return (...args) => { const retptr = this.wasm.__wbindgen_add_to_stack_pointer(-16); let deferred = [0, 0]; try { const ptrLenPairs = args.map((arg) => { const ptr = this.passStringToWasm( arg, this.wasm.__wbindgen_malloc, this.wasm.__wbindgen_realloc ); return [ptr, this.WASM_VECTOR_LEN]; }); const wasmArgs = [retptr, ...ptrLenPairs.flat()]; wasmFn.apply(this.wasm, wasmArgs); const r0 = this.getDataViewMemory().getInt32(retptr + 4 * 0, true); const r1 = this.getDataViewMemory().getInt32(retptr + 4 * 1, true); deferred = [r0, r1]; return this.getStringFromWasm(r0, r1); } finally { this.wasm.__wbindgen_add_to_stack_pointer(16); this.wasm.__wbindgen_free(deferred[0], deferred[1], 1); } }; } async initWasm(wasmBytes) { const bridge = this; const imports = { __wbindgen_placeholder__: { __wbindgen_throw: function(ptr, len) { const message = bridge.getStringFromWasm(ptr, len); bridge.logger.error(`WASM error: ${message}`); throw new Error(message); } } }; try { this.logger.debug("Compiling WASM module"); const wasmModule = await WebAssembly.compile(wasmBytes); this.logger.debug("Instantiating WASM module"); const wasmInstance = await WebAssembly.instantiate(wasmModule, imports); this.wasm = wasmInstance.exports; this.logger.info("WASM module initialized successfully"); return this.wasm; } catch (error) { this.logger.error("Failed to initialize WASM module", error); throw error; } } createStateData(wasmConfig, stateData = {}) { let dynamicStateData = {}; if (wasmConfig?.c?.inputType?.stateData) { if (stateData.latestRoundData && Object.keys(wasmConfig.c.inputType.stateData).every( (key) => key in stateData.latestRoundData )) { dynamicStateData.latestRoundData = {}; Object.entries(wasmConfig.c.inputType.stateData).forEach(([key, _]) => { dynamicStateData.latestRoundData[key] = String( stateData.latestRoundData[key] ); }); } else { Object.entries(wasmConfig.c.inputType.stateData).forEach( ([key, type]) => { const result = stateData[key]; if (result && typeof result === "object" && "values" in result && result.values.length > 0) { dynamicStateData[key] = String(result.values[0]); } else { dynamicStateData[key] = this.getDefaultValueForType( type ); } } ); } } return dynamicStateData; } getDefaultValueForType(type) { if (type.startsWith("uint") || type.startsWith("int") || type === "number") { return "0"; } else if (type === "bool") { return "false"; } else { return ""; } } executeWasm(stateData, messages) { if (!this.wasm) { this.logger.error("WASM not initialized"); throw new Error("WASM not initialized"); } try { this.logger.debug("Executing WASM with stateData", stateData); const fn = this.createWasmFunction(this.wasmInstance.process_state); return fn(JSON.stringify(stateData), JSON.stringify(messages)); } catch (error) { this.logger.error("Error executing WASM", error); throw error; } } getParams() { const fn = this.createWasmFunction(this.wasmInstance.get_params); return fn(); } } export { WasmBridge }; //# sourceMappingURL=standards-sdk.es3.js.map