diff --git a/package.json b/package.json index 46db8fad..c499f91e 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "fast-copy": "^3.0.0", "level": "^8.0.0", "memory-level": "^1.0.0", + "msgpackr": "^1.8.1", "redstone-isomorphic": "1.1.8", "redstone-wasm-metering": "1.0.5", "safe-stable-stringify": "2.4.1", @@ -89,7 +90,7 @@ "arlocal": "1.1.42", "cheerio": "^1.0.0-rc.10", "colors": "^1.4.0", - "esbuild": "0.15.12", + "esbuild": "0.17.2", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^3.4.1", diff --git a/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/README.md b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/README.md new file mode 100644 index 00000000..e737fab0 --- /dev/null +++ b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/README.md @@ -0,0 +1,6 @@ +This directory includes the build and the types of Pianity's ERC1155 WASM contract written in Rust. + +The specific commit used to make this build is available here +. +It includes patches that makes it use Msgpack instead of JSON (that is the default at the time of +writing) as its serialization format for the WASM<->JS bridge. diff --git a/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/package.json b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/package.json new file mode 100644 index 00000000..61f8d6fc --- /dev/null +++ b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/package.json @@ -0,0 +1,14 @@ +{ + "name": "warp-erc1155-implementation", + "collaborators": [ + "Eyal Chojnowski" + ], + "version": "0.1.0", + "files": [ + "rust-contract_bg.wasm", + "rust-contract.js", + "rust-contract.d.ts" + ], + "main": "rust-contract.js", + "types": "rust-contract.d.ts" +} \ No newline at end of file diff --git a/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract.d.ts b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract.d.ts new file mode 100644 index 00000000..63c1f3a0 --- /dev/null +++ b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract.d.ts @@ -0,0 +1,23 @@ +/* tslint:disable */ +/* eslint-disable */ +/** +* @param {Uint8Array} interaction +* @returns {Promise} +*/ +export function handle(interaction: Uint8Array): Promise; +/** +* @param {Uint8Array} state +*/ +export function initState(state: Uint8Array): void; +/** +* @returns {Uint8Array} +*/ +export function currentState(): Uint8Array; +/** +* @returns {number} +*/ +export function version(): number; +/** +* @returns {number} +*/ +export function lang(): number; diff --git a/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract.js b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract.js new file mode 100644 index 00000000..f93d692e --- /dev/null +++ b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract.js @@ -0,0 +1,322 @@ +let imports = {}; +imports['__wbindgen_placeholder__'] = module.exports; +let wasm; +const { TextDecoder, TextEncoder } = require(`util`); + +const heap = new Array(32).fill(undefined); + +heap.push(undefined, null, true, false); + +function getObject(idx) { return heap[idx]; } + +let heap_next = heap.length; + +function dropObject(idx) { + if (idx < 36) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); + +cachedTextDecoder.decode(); + +let cachegetUint8Memory0 = null; +function getUint8Memory0() { + if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) { + cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachegetUint8Memory0; +} + +function getStringFromWasm0(ptr, len) { + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); +} + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +function makeMutClosure(arg0, arg1, dtor, f) { + const state = { a: arg0, b: arg1, cnt: 1, dtor }; + const real = (...args) => { + // First up with a closure we increment the internal reference + // count. This ensures that the Rust closure environment won't + // be deallocated while we're invoking it. + state.cnt++; + const a = state.a; + state.a = 0; + try { + return f(a, state.b, ...args); + } finally { + if (--state.cnt === 0) { + wasm.__wbindgen_export_0.get(state.dtor)(a, state.b); + + } else { + state.a = a; + } + } + }; + real.original = state; + + return real; +} +function __wbg_adapter_10(arg0, arg1, arg2) { + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb281bc39dbcfb59f(arg0, arg1, addHeapObject(arg2)); +} + +/** +* @param {Uint8Array} interaction +* @returns {Promise} +*/ +module.exports.handle = function(interaction) { + var ret = wasm.handle(addHeapObject(interaction)); + return takeObject(ret); +}; + +/** +* @param {Uint8Array} state +*/ +module.exports.initState = function(state) { + wasm.initState(addHeapObject(state)); +}; + +let cachegetInt32Memory0 = null; +function getInt32Memory0() { + if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) { + cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachegetInt32Memory0; +} + +function getArrayU8FromWasm0(ptr, len) { + return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); +} +/** +* @returns {Uint8Array} +*/ +module.exports.currentState = function() { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.currentState(retptr); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var v0 = getArrayU8FromWasm0(r0, r1).slice(); + wasm.__wbindgen_free(r0, r1 * 1); + return v0; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +}; + +/** +* @returns {number} +*/ +module.exports.version = function() { + var ret = wasm.version(); + return ret; +}; + +/** +* @returns {number} +*/ +module.exports.lang = function() { + var ret = wasm.lang(); + return ret; +}; + +let WASM_VECTOR_LEN = 0; + +let cachedTextEncoder = new TextEncoder('utf-8'); + +const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); +} + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; +}); + +function passStringToWasm0(arg, malloc, realloc) { + + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length); + getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len); + + const mem = getUint8Memory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3); + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_exn_store(addHeapObject(e)); + } +} +function __wbg_adapter_24(arg0, arg1, arg2, arg3) { + wasm.wasm_bindgen__convert__closures__invoke2_mut__he0b27a323ce8a8e6(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); +} + +module.exports.__wbindgen_object_drop_ref = function(arg0) { + takeObject(arg0); +}; + +module.exports.__wbg_owner_8557539ae4390681 = function(arg0) { + var ret = Transaction.owner(); + var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; +}; + +module.exports.__wbg_caller_d4b16475811bcec3 = function(arg0) { + var ret = SmartWeave.caller(); + var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; +}; + +module.exports.__wbg_id_9dc3f8f1cb3d8f46 = function(arg0) { + var ret = Transaction.id(); + var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; +}; + +module.exports.__wbindgen_cb_drop = function(arg0) { + const obj = takeObject(arg0).original; + if (obj.cnt-- == 1) { + obj.a = 0; + return true; + } + var ret = false; + return ret; +}; + +module.exports.__wbg_call_94697a95cb7e239c = function() { return handleError(function (arg0, arg1, arg2) { + var ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); +}, arguments) }; + +module.exports.__wbg_new_4beacc9c71572250 = function(arg0, arg1) { + try { + var state0 = {a: arg0, b: arg1}; + var cb0 = (arg0, arg1) => { + const a = state0.a; + state0.a = 0; + try { + return __wbg_adapter_24(a, state0.b, arg0, arg1); + } finally { + state0.a = a; + } + }; + var ret = new Promise(cb0); + return addHeapObject(ret); + } finally { + state0.a = state0.b = 0; + } +}; + +module.exports.__wbg_resolve_4f8f547f26b30b27 = function(arg0) { + var ret = Promise.resolve(getObject(arg0)); + return addHeapObject(ret); +}; + +module.exports.__wbg_then_a6860c82b90816ca = function(arg0, arg1) { + var ret = getObject(arg0).then(getObject(arg1)); + return addHeapObject(ret); +}; + +module.exports.__wbg_buffer_5e74a88a1424a2e0 = function(arg0) { + var ret = getObject(arg0).buffer; + return addHeapObject(ret); +}; + +module.exports.__wbg_newwithbyteoffsetandlength_278ec7532799393a = function(arg0, arg1, arg2) { + var ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); + return addHeapObject(ret); +}; + +module.exports.__wbg_new_e3b800e570795b3c = function(arg0) { + var ret = new Uint8Array(getObject(arg0)); + return addHeapObject(ret); +}; + +module.exports.__wbg_set_5b8081e9d002f0df = function(arg0, arg1, arg2) { + getObject(arg0).set(getObject(arg1), arg2 >>> 0); +}; + +module.exports.__wbg_length_30803400a8f15c59 = function(arg0) { + var ret = getObject(arg0).length; + return ret; +}; + +module.exports.__wbindgen_throw = function(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); +}; + +module.exports.__wbindgen_memory = function() { + var ret = wasm.memory; + return addHeapObject(ret); +}; + +module.exports.__wbindgen_closure_wrapper336 = function(arg0, arg1, arg2) { + var ret = makeMutClosure(arg0, arg1, 92, __wbg_adapter_10); + return addHeapObject(ret); +}; + +const path = require('path').join(__dirname, 'rust-contract_bg.wasm'); +const bytes = require('fs').readFileSync(path); + +const wasmModule = new WebAssembly.Module(bytes); +const wasmInstance = new WebAssembly.Instance(wasmModule, imports); +wasm = wasmInstance.exports; +module.exports.__wasm = wasm; + diff --git a/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract_bg.wasm b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract_bg.wasm new file mode 100644 index 00000000..8b86dfa2 Binary files /dev/null and b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract_bg.wasm differ diff --git a/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract_bg.wasm.d.ts b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract_bg.wasm.d.ts new file mode 100644 index 00000000..51878ec4 --- /dev/null +++ b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/build/rust-contract_bg.wasm.d.ts @@ -0,0 +1,16 @@ +/* tslint:disable */ +/* eslint-disable */ +export const memory: WebAssembly.Memory; +export function handle(a: number): number; +export function initState(a: number): void; +export function currentState(a: number): void; +export function version(): number; +export function lang(): number; +export const __wbindgen_export_0: WebAssembly.Table; +export function _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb281bc39dbcfb59f(a: number, b: number, c: number): void; +export function __wbindgen_add_to_stack_pointer(a: number): number; +export function __wbindgen_free(a: number, b: number): void; +export function __wbindgen_malloc(a: number): number; +export function __wbindgen_realloc(a: number, b: number, c: number): number; +export function __wbindgen_exn_store(a: number): void; +export function wasm_bindgen__convert__closures__invoke2_mut__he0b27a323ce8a8e6(a: number, b: number, c: number, d: number): void; diff --git a/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/Action.ts b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/Action.ts new file mode 100644 index 00000000..b3de2d59 --- /dev/null +++ b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/Action.ts @@ -0,0 +1,64 @@ +export type Action = + | { + function: "balanceOf"; + target: string; + tokenId?: string | null; + } + | { + from?: string | null; + function: "transfer"; + qty: string; + to: string; + tokenId?: string | null; + } + | { + allowFreeTransfer?: boolean | null; + canEvolve?: boolean | null; + function: "configure"; + operators?: string[] | null; + paused?: boolean | null; + proxies?: string[] | null; + superOperators?: string[] | null; + } + | { + approved: boolean; + function: "setApprovalForAll"; + operator: string; + } + | { + function: "isApprovedForAll"; + operator: string; + owner: string; + } + | { + function: "evolve"; + value: string; + } + | { + baseId?: string | null; + function: "mint"; + prefix?: string | null; + qty: string; + } + | { + function: "burn"; + owner?: string | null; + qty: string; + tokenId?: string | null; + } + | { + actions: Action[]; + function: "batch"; + }; + +/** + * This type allows to restrict the type of an interaction to a specific action. + * + * Example: + * ```typescript + * const specificAction: Actions["specificAction"] = { function: "specificAction", foo: "bar" }; + * ``` + */ +export type Actions = { + [K in Action["function"]]: Action & { function: K }; +}; \ No newline at end of file diff --git a/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/ContractError.ts b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/ContractError.ts new file mode 100644 index 00000000..fa8cda33 --- /dev/null +++ b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/ContractError.ts @@ -0,0 +1,54 @@ +export type ContractError = + | { + data: string; + kind: "RuntimeError"; + } + | { + kind: "TransferAmountMustBeHigherThanZero"; + } + | { + kind: "TransferFromAndToCannotBeEqual"; + } + | { + data: string; + kind: "TokenNotFound"; + } + | { + kind: "IDontLikeThisContract"; + } + | { + data: string; + kind: "OwnerBalanceNotEnough"; + } + | { + kind: "OnlyOwnerCanEvolve"; + } + | { + kind: "EvolveNotAllowed"; + } + | { + kind: "ForbiddenNestedBatch"; + } + | { + kind: "CannotMixeReadAndWrite"; + } + | { + kind: "EmptyBatch"; + } + | { + kind: "UnauthorizedConfiguration"; + } + | { + data: string; + kind: "UnauthorizedAddress"; + } + | { + data: string; + kind: "UnauthorizedTransfer"; + } + | { + kind: "TokenAlreadyExists"; + } + | { + kind: "ContractIsPaused"; + }; diff --git a/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/State.ts b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/State.ts new file mode 100644 index 00000000..6d630a2a --- /dev/null +++ b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/State.ts @@ -0,0 +1,30 @@ +export interface State { + approvals: { + [k: string]: { + [k: string]: boolean; + }; + }; + defaultToken: string; + evolve?: string | null; + name: string; + settings: Settings; + tickerNonce: number; + tokens: { + [k: string]: Token; + }; +} +export interface Settings { + allowFreeTransfer: boolean; + canEvolve: boolean; + operators: string[]; + paused: boolean; + proxies: string[]; + superOperators: string[]; +} +export interface Token { + balances: { + [k: string]: string; + }; + ticker: string; + txId?: string | null; +} diff --git a/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/index.ts b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/index.ts new file mode 100644 index 00000000..21a79f80 --- /dev/null +++ b/src/__tests__/integration/data/wasm/rust-erc1155-msgpack/types/index.ts @@ -0,0 +1,3 @@ +export * from "./Action"; +export * from "./State"; +export * from "./ContractError"; diff --git a/src/__tests__/integration/wasm/rust-erc1155-msgpack-deploy-write-read.test.ts b/src/__tests__/integration/wasm/rust-erc1155-msgpack-deploy-write-read.test.ts new file mode 100644 index 00000000..068fc2da --- /dev/null +++ b/src/__tests__/integration/wasm/rust-erc1155-msgpack-deploy-write-read.test.ts @@ -0,0 +1,138 @@ +import fs from 'fs'; +import path from 'path'; + +import ArLocal from 'arlocal'; +import { JWKInterface } from 'arweave/node/lib/wallet'; +import { pack } from 'msgpackr'; + +import { mineBlock } from '../_helpers'; +import { WasmSrc } from '../../../core/modules/impl/wasm/WasmSrc'; +import { SmartWeaveTags } from '../../../core/SmartWeaveTags'; +import { Warp } from '../../../core/Warp'; +import { WarpFactory } from '../../../core/WarpFactory'; +import { LoggerFactory } from '../../../logging/LoggerFactory'; +import { ArweaveWrapper } from '../../../utils/ArweaveWrapper'; +import { TagsParser } from '../../../core/modules/impl/TagsParser'; +import { SerializationFormat } from '../../../core/modules/StateEvaluator'; + +import * as Erc1155 from '../data/wasm/rust-erc1155-mspack/types'; +import { Contract, WriteInteractionResponse } from 'contract/Contract'; + +const DEFAULT_TOKEN = 'PTY'; +const ARLOCAL_PORT = 1210; + +describe('Testing a Rust contract that uses Msgpack as its WASM<->JS serialization format', () => { + LoggerFactory.INST.logLevel('error'); + + let wallet: JWKInterface; + let walletAddress: string; + + let initialState: Erc1155.State; + + let arlocal: ArLocal; + let warp: Warp; + + let contractTxId: string; + let contract: Contract; + let interact: (input: Erc1155.Action) => Promise; + + let arweaveWrapper: ArweaveWrapper; + let tagsParser: TagsParser; + + beforeAll(async () => { + // note: each tests suit (i.e. file with tests that Jest is running concurrently + // with another files has to have ArLocal set to a different port!) + arlocal = new ArLocal(ARLOCAL_PORT, false); + await arlocal.start(); + + warp = WarpFactory.forLocal(ARLOCAL_PORT); + arweaveWrapper = new ArweaveWrapper(warp.arweave); + tagsParser = new TagsParser(); + + ({ jwk: wallet, address: walletAddress } = await warp.generateWallet()); + + const contractSrc = fs.readFileSync( + path.join(__dirname, '../data/wasm/rust-erc1155-mspack/build/rust-contract_bg.wasm') + ); + + initialState = { + defaultToken: DEFAULT_TOKEN, + name: 'TEST-ERC1155-MSGPACK', + tickerNonce: 0, + tokens: { + [DEFAULT_TOKEN]: { + ticker: DEFAULT_TOKEN, + balances: { + [walletAddress]: '200' + } + } + }, + approvals: {}, + settings: { + allowFreeTransfer: true, + paused: false, + proxies: [], + canEvolve: false, + operators: [], + superOperators: [] + } + }; + + // deploying contract using the new SDK. + contractTxId = ( + await warp.deploy({ + wallet, + stateFormat: SerializationFormat.MSGPACK, + initState: pack(initialState), + src: contractSrc, + wasmSrcCodeDir: path.join(__dirname, '../data/wasm/rust/src'), + wasmGlueCode: path.join(__dirname, '../data/wasm/rust/rust-pst.js') + }) + ).contractTxId; + + contract = warp + .contract(contractTxId) + .setEvaluationOptions({ wasmSerializationFormat: SerializationFormat.MSGPACK }) + .connect(wallet); + + interact = async (input: Erc1155.Action) => contract.writeInteraction(input); + + await mineBlock(warp); + }, 50000); + + afterAll(async () => { + await arlocal.stop(); + }); + + it('should properly deploy contract', async () => { + const contractTx = await warp.arweave.transactions.get(contractTxId); + expect(contractTx).not.toBeNull(); + expect(tagsParser.getTag(contractTx, SmartWeaveTags.CONTENT_TYPE)).toEqual(SerializationFormat.MSGPACK); + + const contractSrcTxId = tagsParser.getTag(contractTx, SmartWeaveTags.CONTRACT_SRC_TX_ID); + const contractSrcTx = await warp.arweave.transactions.get(contractSrcTxId); + + expect(tagsParser.getTag(contractSrcTx, SmartWeaveTags.CONTENT_TYPE)).toEqual('application/wasm'); + expect(tagsParser.getTag(contractSrcTx, SmartWeaveTags.WASM_LANG)).toEqual('rust'); + expect(tagsParser.getTag(contractSrcTx, SmartWeaveTags.WASM_META)).toEqual(JSON.stringify({ dtor: 74 })); + + const srcTxData = await arweaveWrapper.txData(contractSrcTxId); + const wasmSrc = new WasmSrc(srcTxData); + expect(wasmSrc.wasmBinary()).not.toBeNull(); + expect(wasmSrc.additionalCode()).toEqual( + fs.readFileSync(path.join(__dirname, '../data/wasm/rust/rust-pst.js'), 'utf-8') + ); + expect((await wasmSrc.sourceCode()).size).toEqual(11); + }); + + it('should properly transfer tokens', async () => { + await interact({ function: 'transfer', qty: '100', to: 'bob' }); + + await mineBlock(warp); + + const { state } = (await contract.readState()).cachedValue; + + expect(state.tokens['PTY'].balances[walletAddress]).toEqual('100'); + expect(state.tokens['PTY'].balances['bob']).toEqual('100'); + }); +}); diff --git a/src/contract/EvaluationOptionsEvaluator.ts b/src/contract/EvaluationOptionsEvaluator.ts index 58527369..3312a568 100644 --- a/src/contract/EvaluationOptionsEvaluator.ts +++ b/src/contract/EvaluationOptionsEvaluator.ts @@ -102,7 +102,8 @@ export class EvaluationOptionsEvaluator { allowBigInt: () => this.rootOptions['allowBigInt'], // not sure about this walletBalanceUrl: () => this.rootOptions['walletBalanceUrl'], mineArLocalBlocks: () => this.rootOptions['mineArLocalBlocks'], - cacheEveryNInteractions: () => this.rootOptions['cacheEveryNInteractions'] + cacheEveryNInteractions: () => this.rootOptions['cacheEveryNInteractions'], + wasmSerializationFormat: () => this.rootOptions['wasmSerializationFormat'] }; /** diff --git a/src/contract/deploy/CreateContract.ts b/src/contract/deploy/CreateContract.ts index 5b8d9729..e1051e3b 100644 --- a/src/contract/deploy/CreateContract.ts +++ b/src/contract/deploy/CreateContract.ts @@ -1,4 +1,5 @@ import { JWKInterface } from 'arweave/node/lib/wallet'; +import { SerializationFormat } from 'core/modules/StateEvaluator'; import { CustomSignature } from '../../contract/Signature'; import { Source } from './Source'; import { EvaluationOptions } from '../../core/modules/StateEvaluator'; @@ -28,9 +29,10 @@ export type EvaluationManifest = { export const BUNDLR_NODES = ['node1', 'node2'] as const; export type BundlrNodeType = typeof BUNDLR_NODES[number]; -export interface CommonContractData { +export interface CommonContractData { wallet: ArWallet | CustomSignature; - initState: string; + stateFormat: T; + initState: T extends SerializationFormat.JSON ? string : Buffer; tags?: Tags; transfer?: ArTransfer; data?: { @@ -40,13 +42,13 @@ export interface CommonContractData { evaluationManifest?: EvaluationManifest; } -export interface ContractData extends CommonContractData { +export interface ContractData extends CommonContractData { src: string | Buffer; wasmSrcCodeDir?: string; wasmGlueCode?: string; } -export interface FromSrcTxContractData extends CommonContractData { +export interface FromSrcTxContractData extends CommonContractData { srcTxId: string; } @@ -56,9 +58,15 @@ export interface ContractDeploy { } export interface CreateContract extends Source { - deploy(contractData: ContractData, disableBundling?: boolean): Promise; + deploy( + contractData: ContractData, + disableBundling?: boolean + ): Promise; - deployFromSourceTx(contractData: FromSrcTxContractData, disableBundling?: boolean): Promise; + deployFromSourceTx( + contractData: FromSrcTxContractData, + disableBundling?: boolean + ): Promise; deployBundled(rawDataItem: Buffer): Promise; diff --git a/src/contract/deploy/impl/DefaultCreateContract.ts b/src/contract/deploy/impl/DefaultCreateContract.ts index 86ea8a5a..00207549 100644 --- a/src/contract/deploy/impl/DefaultCreateContract.ts +++ b/src/contract/deploy/impl/DefaultCreateContract.ts @@ -18,6 +18,7 @@ import { } from '../CreateContract'; import { SourceData, SourceImpl } from './SourceImpl'; import { Buffer } from 'redstone-isomorphic'; +import { SerializationFormat } from 'core/modules/StateEvaluator'; export class DefaultCreateContract implements CreateContract { private readonly logger = LoggerFactory.INST.create('DefaultCreateContract'); @@ -32,8 +33,11 @@ export class DefaultCreateContract implements CreateContract { this.warpFetchWrapper = new WarpFetchWrapper(this.warp); } - async deploy(contractData: ContractData, disableBundling?: boolean): Promise { - const { wallet, initState, tags, transfer, data, evaluationManifest } = contractData; + async deploy( + contractData: ContractData, + disableBundling?: boolean + ): Promise { + const { wallet, stateFormat, initState, tags, transfer, data, evaluationManifest } = contractData; const effectiveUseBundler = disableBundling == undefined ? this.warp.definitionLoader.type() == 'warp' : !disableBundling; @@ -49,6 +53,7 @@ export class DefaultCreateContract implements CreateContract { { srcTxId: srcTx.id, wallet, + stateFormat, initState, tags, transfer, @@ -60,13 +65,13 @@ export class DefaultCreateContract implements CreateContract { ); } - async deployFromSourceTx( - contractData: FromSrcTxContractData, + async deployFromSourceTx( + contractData: FromSrcTxContractData, disableBundling?: boolean, srcTx: Transaction = null ): Promise { this.logger.debug('Creating new contract from src tx'); - const { wallet, srcTxId, initState, tags, transfer, data, evaluationManifest } = contractData; + const { wallet, srcTxId, stateFormat, initState, tags, transfer, data, evaluationManifest } = contractData; this.signature = new Signature(this.warp, wallet); const signer = this.signature.signer; @@ -97,9 +102,13 @@ export class DefaultCreateContract implements CreateContract { contractTX.addTag(SmartWeaveTags.SDK, 'RedStone'); if (data) { contractTX.addTag(SmartWeaveTags.CONTENT_TYPE, data['Content-Type']); - contractTX.addTag(SmartWeaveTags.INIT_STATE, initState); + contractTX.addTag(SmartWeaveTags.INIT_STATE_FORMAT, stateFormat); + contractTX.addTag( + SmartWeaveTags.INIT_STATE, + typeof initState === 'string' ? initState : new TextDecoder().decode(initState) + ); } else { - contractTX.addTag(SmartWeaveTags.CONTENT_TYPE, 'application/json'); + contractTX.addTag(SmartWeaveTags.CONTENT_TYPE, stateFormat); } if (this.warp.environment === 'testnet') { diff --git a/src/core/SmartWeaveTags.ts b/src/core/SmartWeaveTags.ts index d0a5ed85..a8182ba8 100644 --- a/src/core/SmartWeaveTags.ts +++ b/src/core/SmartWeaveTags.ts @@ -11,6 +11,7 @@ export enum SmartWeaveTags { SDK = 'SDK', MIN_FEE = 'Min-Fee', INIT_STATE = 'Init-State', + INIT_STATE_FORMAT = 'Init-State-Format', INIT_STATE_TX = 'Init-State-TX', INTERACT_WRITE = 'Interact-Write', WASM_LANG = 'Wasm-Lang', diff --git a/src/core/Warp.ts b/src/core/Warp.ts index 6775eee6..941036dc 100644 --- a/src/core/Warp.ts +++ b/src/core/Warp.ts @@ -17,7 +17,7 @@ import { DefinitionLoader } from './modules/DefinitionLoader'; import { ExecutorFactory } from './modules/ExecutorFactory'; import { HandlerApi } from './modules/impl/HandlerExecutorFactory'; import { InteractionsLoader } from './modules/InteractionsLoader'; -import { EvalStateResult, StateEvaluator } from './modules/StateEvaluator'; +import { EvalStateResult, SerializationFormat, StateEvaluator } from './modules/StateEvaluator'; import { WarpBuilder } from './WarpBuilder'; import { WarpPluginType, @@ -81,11 +81,17 @@ export class Warp { return new HandlerBasedContract(contractTxId, this, callingContract, innerCallData); } - async deploy(contractData: ContractData, disableBundling?: boolean): Promise { + async deploy( + contractData: ContractData, + disableBundling?: boolean + ): Promise { return await this.createContract.deploy(contractData, disableBundling); } - async deployFromSourceTx(contractData: FromSrcTxContractData, disableBundling?: boolean): Promise { + async deployFromSourceTx( + contractData: FromSrcTxContractData, + disableBundling?: boolean + ): Promise { return await this.createContract.deployFromSourceTx(contractData, disableBundling); } diff --git a/src/core/modules/StateEvaluator.ts b/src/core/modules/StateEvaluator.ts index 8c5d80c4..0f4237fa 100644 --- a/src/core/modules/StateEvaluator.ts +++ b/src/core/modules/StateEvaluator.ts @@ -1,3 +1,7 @@ +import { pack, unpack } from 'msgpackr'; +import stringify from 'safe-stable-stringify'; + +import { exhaustive } from '../../utils/utils'; import { SortKeyCache, SortKeyCacheResult } from '../../cache/SortKeyCache'; import { CurrentTx } from '../../contract/Contract'; import { ExecutionContext } from '../../core/ExecutionContext'; @@ -140,8 +144,46 @@ export class DefaultEvaluationOptions implements EvaluationOptions { throwOnInternalWriteError = true; cacheEveryNInteractions = -1; + + wasmSerializationFormat = SerializationFormat.JSON; +} + +export enum SerializationFormat { + JSON = 'application/json', + // NOTE: There is still no officially registered Media Type for Messagepack and there are + // apparently multiple different versions used in the wild like: + // - application/msgpack + // - application/x-msgpack + // - application/x.msgpack + // - [...] + // See . I've decided to use the first one + // as it looks like the one that makes the most sense. + MSGPACK = 'application/msgpack' } +export const stringToSerializationFormat = (format: string): SerializationFormat => { + const formatTyped = format as SerializationFormat; + + switch (formatTyped) { + case SerializationFormat.JSON: + return SerializationFormat.JSON; + case SerializationFormat.MSGPACK: + return SerializationFormat.MSGPACK; + default: + return exhaustive(formatTyped, `Unsupported serialization format: "${formatTyped}"`); + } +}; + +export const Serializers = { + [SerializationFormat.JSON]: stringify, + [SerializationFormat.MSGPACK]: pack +} as const satisfies Record; + +export const Deserializers = { + [SerializationFormat.JSON]: JSON.parse, + [SerializationFormat.MSGPACK]: unpack +} as const satisfies Record; + // an interface for the contract EvaluationOptions - can be used to change the behaviour of some features. export interface EvaluationOptions { // whether exceptions from given transaction interaction should be ignored @@ -217,4 +259,11 @@ export interface EvaluationOptions { // force SDK to cache the state after evaluating each N interactions // defaults to -1, which effectively turns off this feature cacheEveryNInteractions: number; + + /** + * What serialization format should be used for the WASM<->JS bridge. Note that changing this + * currently only affects Rust smartcontracts. AssemblyScript and Go smartcontracts will always + * use JSON. Defaults to JSON. + */ + wasmSerializationFormat: SerializationFormat; } diff --git a/src/core/modules/impl/CacheableStateEvaluator.ts b/src/core/modules/impl/CacheableStateEvaluator.ts index 12652330..652e10d6 100644 --- a/src/core/modules/impl/CacheableStateEvaluator.ts +++ b/src/core/modules/impl/CacheableStateEvaluator.ts @@ -6,7 +6,7 @@ import { ExecutionContextModifier } from '../../../core/ExecutionContextModifier import { GQLNodeInterface } from '../../../legacy/gqlResult'; import { LoggerFactory } from '../../../logging/LoggerFactory'; import { indent } from '../../../utils/utils'; -import { EvalStateResult } from '../StateEvaluator'; +import { EvalStateResult, SerializationFormat } from '../StateEvaluator'; import { DefaultStateEvaluator } from './DefaultStateEvaluator'; import { HandlerApi } from './HandlerExecutorFactory'; import { genesisSortKey } from './LexicographicalInteractionsSorter'; @@ -35,11 +35,12 @@ export class CacheableStateEvaluator extends DefaultStateEvaluator { currentTx: CurrentTx[] ): Promise>> { const cachedState = executionContext.cachedState; + const { wasmSerializationFormat: serializationFormat } = executionContext.evaluationOptions; if (cachedState && cachedState.sortKey == executionContext.requestedSortKey) { this.cLogger.info( `Exact cache hit for sortKey ${executionContext?.contractDefinition?.txId}:${cachedState.sortKey}` ); - executionContext.handler?.initState(cachedState.cachedValue.state); + executionContext.handler?.initState(cachedState.cachedValue.state, serializationFormat); return cachedState; } @@ -71,10 +72,10 @@ export class CacheableStateEvaluator extends DefaultStateEvaluator { if (missingInteractions.length == 0) { this.cLogger.info(`No missing interactions ${contractTxId}`); if (cachedState) { - executionContext.handler?.initState(cachedState.cachedValue.state); + executionContext.handler?.initState(cachedState.cachedValue.state, serializationFormat); return cachedState; } else { - executionContext.handler?.initState(executionContext.contractDefinition.initState); + executionContext.handler?.initState(executionContext.contractDefinition.initState, serializationFormat); this.cLogger.debug('Inserting initial state into cache'); const stateToCache = new EvalStateResult(executionContext.contractDefinition.initState, {}, {}); // no real sort-key - as we're returning the initial state diff --git a/src/core/modules/impl/ContractDefinitionLoader.ts b/src/core/modules/impl/ContractDefinitionLoader.ts index 810e0f60..021e0843 100644 --- a/src/core/modules/impl/ContractDefinitionLoader.ts +++ b/src/core/modules/impl/ContractDefinitionLoader.ts @@ -11,6 +11,8 @@ import { GW_TYPE } from '../InteractionsLoader'; import { TagsParser } from './TagsParser'; import { WasmSrc } from './wasm/WasmSrc'; import { WarpEnvironment } from '../../Warp'; +import { Deserializers, SerializationFormat, stringToSerializationFormat } from '../StateEvaluator'; +import { exhaustive } from '../../../utils/utils'; import { SortKeyCache } from '../../../cache/SortKeyCache'; const supportedSrcContentTypes = ['application/javascript', 'application/wasm']; @@ -61,9 +63,7 @@ export class ContractDefinitionLoader implements DefinitionLoader { this.logger.debug('Tags decoding', benchmark.elapsed()); benchmark.reset(); - const s = await this.evalInitialState(contractTx); - this.logger.debug('init state', s); - const initState = JSON.parse(await this.evalInitialState(contractTx)); + const initState = await this.evalInitialState(contractTx); this.logger.debug('Parsing src and init state', benchmark.elapsed()); const { src, srcBinary, srcWasmLang, contractType, metadata, srcTx } = await this.loadContractSource( @@ -128,14 +128,42 @@ export class ContractDefinitionLoader implements DefinitionLoader { }; } - private async evalInitialState(contractTx: Transaction): Promise { + private async evalInitialState(contractTx: Transaction): Promise { if (this.tagsParser.getTag(contractTx, SmartWeaveTags.INIT_STATE)) { - return this.tagsParser.getTag(contractTx, SmartWeaveTags.INIT_STATE); + const format = stringToSerializationFormat( + this.tagsParser.getTag(contractTx, SmartWeaveTags.INIT_STATE_FORMAT) ?? SerializationFormat.JSON + ); + const initState = this.tagsParser.getTag(contractTx, SmartWeaveTags.INIT_STATE); + + switch (format) { + case SerializationFormat.JSON: + return Deserializers[format](initState); + case SerializationFormat.MSGPACK: + return Deserializers[format](new TextEncoder().encode(initState)); + default: + exhaustive(format); + } } else if (this.tagsParser.getTag(contractTx, SmartWeaveTags.INIT_STATE_TX)) { const stateTX = this.tagsParser.getTag(contractTx, SmartWeaveTags.INIT_STATE_TX); - return this.arweaveWrapper.txDataString(stateTX); + + return this.getInitialStateFromTx(await this.arweave.transactions.get(stateTX)); } else { - return this.arweaveWrapper.txDataString(contractTx.id); + return this.getInitialStateFromTx(contractTx); + } + } + + private async getInitialStateFromTx(tx: Transaction): Promise { + const format = stringToSerializationFormat( + this.tagsParser.getTag(tx, SmartWeaveTags.CONTENT_TYPE) ?? SerializationFormat.JSON + ); + + switch (format) { + case SerializationFormat.JSON: + return Deserializers[format](await this.arweaveWrapper.txDataString(tx.id)); + case SerializationFormat.MSGPACK: + return Deserializers[format](await this.arweaveWrapper.txData(tx.id)); + default: + exhaustive(format); } } diff --git a/src/core/modules/impl/DefaultStateEvaluator.ts b/src/core/modules/impl/DefaultStateEvaluator.ts index 575d624d..1e850e93 100644 --- a/src/core/modules/impl/DefaultStateEvaluator.ts +++ b/src/core/modules/impl/DefaultStateEvaluator.ts @@ -53,8 +53,13 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { executionContext: ExecutionContext>, currentTx: CurrentTx[] ): Promise>> { - const { ignoreExceptions, stackTrace, internalWrites, cacheEveryNInteractions } = - executionContext.evaluationOptions; + const { + ignoreExceptions, + stackTrace, + internalWrites, + cacheEveryNInteractions, + wasmSerializationFormat: serializationFormat + } = executionContext.evaluationOptions; const { contract, contractDefinition, sortedInteractions, warp } = executionContext; let currentState = baseState.state; @@ -62,7 +67,7 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { const validity = baseState.validity; const errorMessages = baseState.errorMessages; - executionContext?.handler.initState(currentState); + executionContext?.handler.initState(currentState, serializationFormat); const depth = executionContext.contract.callDepth(); @@ -76,7 +81,7 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { let lastConfirmedTxState: { tx: GQLNodeInterface; state: EvalStateResult } = null; const missingInteractionsLength = missingInteractions.length; - executionContext.handler.initState(currentState); + executionContext.handler.initState(currentState, serializationFormat); const evmSignatureVerificationPlugin = warp.hasPlugin('evm-signature-verification') ? warp.loadPlugin>('evm-signature-verification') @@ -188,7 +193,7 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { if (newState !== null) { currentState = newState.cachedValue.state; // we need to update the state in the wasm module - executionContext?.handler.initState(currentState); + executionContext?.handler.initState(currentState, serializationFormat); validity[missingInteraction.id] = newState.cachedValue.validity[missingInteraction.id]; if (newState.cachedValue.errorMessages?.[missingInteraction.id]) { diff --git a/src/core/modules/impl/HandlerExecutorFactory.ts b/src/core/modules/impl/HandlerExecutorFactory.ts index ee231d2f..9008dac1 100644 --- a/src/core/modules/impl/HandlerExecutorFactory.ts +++ b/src/core/modules/impl/HandlerExecutorFactory.ts @@ -1,7 +1,8 @@ import Arweave from 'arweave'; import loader from '@assemblyscript/loader'; import { asWasmImports } from './wasm/as-wasm-imports'; -import { rustWasmImports } from './wasm/rust-wasm-imports'; +import { rustWasmImportsJson } from './wasm/rust-wasm-imports-json'; +import { rustWasmImportsMsgpack } from './wasm/rust-wasm-imports-msgpack'; import { Go } from './wasm/go-wasm-imports'; import * as vm2 from 'vm2'; import { WarpCache } from '../../../cache/WarpCache'; @@ -12,14 +13,14 @@ import { SmartWeaveGlobal } from '../../../legacy/smartweave-global'; import { Benchmark } from '../../../logging/Benchmark'; import { LoggerFactory } from '../../../logging/LoggerFactory'; import { ExecutorFactory } from '../ExecutorFactory'; -import { EvalStateResult, EvaluationOptions } from '../StateEvaluator'; +import { EvalStateResult, EvaluationOptions, SerializationFormat } from '../StateEvaluator'; import { JsHandlerApi } from './handler/JsHandlerApi'; import { WasmHandlerApi } from './handler/WasmHandlerApi'; import { normalizeContractSource } from './normalize-source'; import { MemCache } from '../../../cache/impl/MemCache'; import BigNumber from '../../../legacy/bignumber'; import { Warp } from '../../Warp'; -import { isBrowser } from '../../../utils/utils'; +import { exhaustive, isBrowser } from '../../../utils/utils'; import { Buffer } from 'redstone-isomorphic'; export class ContractError extends Error { @@ -111,6 +112,18 @@ export class HandlerExecutorFactory implements ExecutorFactory imp.name); + let rustWasmImports; + switch (evaluationOptions.wasmSerializationFormat) { + case SerializationFormat.JSON: + rustWasmImports = rustWasmImportsJson; + break; + case SerializationFormat.MSGPACK: + rustWasmImports = rustWasmImportsMsgpack; + break; + default: + return exhaustive(evaluationOptions.wasmSerializationFormat); + } + const { imports, exports } = rustWasmImports( swGlobal, wbindgenImports, @@ -275,7 +288,7 @@ export interface HandlerApi { interactionData: InteractionData ): Promise>; - initState(state: State): void; + initState(state: State, format: SerializationFormat): void; } export type HandlerFunction = ( diff --git a/src/core/modules/impl/handler/AbstractContractHandler.ts b/src/core/modules/impl/handler/AbstractContractHandler.ts index 88ca1408..4e21ee12 100644 --- a/src/core/modules/impl/handler/AbstractContractHandler.ts +++ b/src/core/modules/impl/handler/AbstractContractHandler.ts @@ -1,7 +1,7 @@ import { CurrentTx } from '../../../../contract/Contract'; import { ContractDefinition } from '../../../../core/ContractDefinition'; import { ExecutionContext } from '../../../../core/ExecutionContext'; -import { EvalStateResult } from '../../../../core/modules/StateEvaluator'; +import { EvalStateResult, SerializationFormat } from '../../../../core/modules/StateEvaluator'; import { GQLNodeInterface } from '../../../../legacy/gqlResult'; import { SmartWeaveGlobal } from '../../../../legacy/smartweave-global'; import { LoggerFactory } from '../../../../logging/LoggerFactory'; @@ -27,7 +27,7 @@ export abstract class AbstractContractHandler implements HandlerApi ): Promise>; - abstract initState(state: State): void; + abstract initState(state: State, format: SerializationFormat): void; async dispose(): Promise { // noop by default; diff --git a/src/core/modules/impl/handler/WasmHandlerApi.ts b/src/core/modules/impl/handler/WasmHandlerApi.ts index 7ec7cd2f..b824974d 100644 --- a/src/core/modules/impl/handler/WasmHandlerApi.ts +++ b/src/core/modules/impl/handler/WasmHandlerApi.ts @@ -1,11 +1,17 @@ /* eslint-disable */ import { ContractDefinition } from '../../../../core/ContractDefinition'; import { ExecutionContext } from '../../../../core/ExecutionContext'; -import { EvalStateResult } from '../../../../core/modules/StateEvaluator'; +import { + Deserializers, + EvalStateResult, + SerializationFormat, + Serializers +} from '../../../../core/modules/StateEvaluator'; import { SmartWeaveGlobal } from '../../../../legacy/smartweave-global'; import stringify from 'safe-stable-stringify'; -import { InteractionData, InteractionResult } from '../HandlerExecutorFactory'; +import { ContractInteraction, InteractionData, InteractionResult } from '../HandlerExecutorFactory'; import { AbstractContractHandler } from './AbstractContractHandler'; +import { exhaustive } from 'utils/utils'; export class WasmHandlerApi extends AbstractContractHandler { constructor( @@ -24,21 +30,22 @@ export class WasmHandlerApi extends AbstractContractHandler { ): Promise> { try { const { interaction, interactionTx, currentTx } = interactionData; + const { gasLimit, wasmSerializationFormat } = executionContext.evaluationOptions; this.swGlobal._activeTx = interactionTx; this.swGlobal.caller = interaction.caller; // either contract tx id (for internal writes) or transaction.owner - this.swGlobal.gasLimit = executionContext.evaluationOptions.gasLimit; + this.swGlobal.gasLimit = gasLimit; this.swGlobal.gasUsed = 0; this.assignReadContractState(executionContext, currentTx, currentResult, interactionTx); this.assignWrite(executionContext, currentTx); - const handlerResult = await this.doHandle(interaction); + const handlerResult = await this.doHandle(interaction, wasmSerializationFormat); return { type: 'ok', result: handlerResult, - state: this.doGetCurrentState(), // TODO: return only at the end of evaluation and when caching is required + state: this.doGetCurrentState(wasmSerializationFormat), // TODO: return only at the end of evaluation and when caching is required gasUsed: this.swGlobal.gasUsed }; } catch (e) { @@ -73,7 +80,7 @@ export class WasmHandlerApi extends AbstractContractHandler { } } - initState(state: State): void { + initState(state: State, format: SerializationFormat): void { switch (this.contractDefinition.srcWasmLang) { case 'assemblyscript': { const statePtr = this.wasmExports.__newString(stringify(state)); @@ -81,7 +88,7 @@ export class WasmHandlerApi extends AbstractContractHandler { break; } case 'rust': { - this.wasmExports.initState(state); + this.wasmExports.initState(Serializers[format](state)); break; } case 'go': { @@ -94,7 +101,7 @@ export class WasmHandlerApi extends AbstractContractHandler { } } - private async doHandle(action: any): Promise { + private async doHandle(action: ContractInteraction, format: SerializationFormat): Promise { switch (this.contractDefinition.srcWasmLang) { case 'assemblyscript': { const actionPtr = this.wasmExports.__newString(stringify(action.input)); @@ -104,7 +111,8 @@ export class WasmHandlerApi extends AbstractContractHandler { return JSON.parse(result); } case 'rust': { - let handleResult = await this.wasmExports.handle(action.input); + const handleResult = await this.wasmExports.handle(Serializers[format](action.input)); + if (!handleResult) { return; } @@ -138,14 +146,14 @@ export class WasmHandlerApi extends AbstractContractHandler { } } - private doGetCurrentState(): State { + private doGetCurrentState(format: SerializationFormat): State { switch (this.contractDefinition.srcWasmLang) { case 'assemblyscript': { const currentStatePtr = this.wasmExports.currentState(); return JSON.parse(this.wasmExports.__getString(currentStatePtr)); } case 'rust': { - return this.wasmExports.currentState(); + return Deserializers[format](this.wasmExports.currentState()); } case 'go': { const result = this.wasmExports.currentState(); diff --git a/src/core/modules/impl/wasm/rust-wasm-imports.ts b/src/core/modules/impl/wasm/rust-wasm-imports-json.ts similarity index 99% rename from src/core/modules/impl/wasm/rust-wasm-imports.ts rename to src/core/modules/impl/wasm/rust-wasm-imports-json.ts index 86609b04..0adaae70 100644 --- a/src/core/modules/impl/wasm/rust-wasm-imports.ts +++ b/src/core/modules/impl/wasm/rust-wasm-imports-json.ts @@ -6,7 +6,7 @@ import { LoggerFactory } from '../../../../logging/LoggerFactory'; // note: this is (somewhat heavily) modified code // of the js that is normally generated by the wasm-bindgen -export const rustWasmImports = (swGlobal, wbindgenImports, wasmInstance, dtorValue): any => { +export const rustWasmImportsJson = (swGlobal, wbindgenImports, wasmInstance, dtorValue): any => { const wasmLogger = LoggerFactory.INST.create('WASM:Rust'); // the raw functions, that we want to make available from the diff --git a/src/core/modules/impl/wasm/rust-wasm-imports-msgpack.ts b/src/core/modules/impl/wasm/rust-wasm-imports-msgpack.ts new file mode 100644 index 00000000..00ffb77c --- /dev/null +++ b/src/core/modules/impl/wasm/rust-wasm-imports-msgpack.ts @@ -0,0 +1,549 @@ +/* tslint:disable */ +/* eslint-disable */ +/* a kind of magic */ + +import { LoggerFactory } from '../../../../logging/LoggerFactory'; + +// note: this is (somewhat heavily) modified code +// of the js that is normally generated by the wasm-bindgen +export const rustWasmImportsMsgpack = (swGlobal, wbindgenImports, wasmInstance, dtorValue): any => { + const wasmLogger = LoggerFactory.INST.create('WASM:Rust'); + + // the raw functions, that we want to make available from the + // wasm module + const rawImports = { + metering: { + usegas: swGlobal.useGas + }, + console: { + log: function (value) { + wasmLogger.error(`${swGlobal.contract.id}: ${value}`); + } + }, + Block: { + height: function () { + return swGlobal.block.height; + }, + indep_hash: function () { + return swGlobal.block.indep_hash; + }, + timestamp: function () { + return swGlobal.block.timestamp; + } + }, + Transaction: { + id: function () { + return swGlobal.transaction.id; + }, + owner: function () { + return swGlobal.transaction.owner; + }, + target: function () { + return swGlobal.transaction.target; + } + }, + Contract: { + id: function () { + return swGlobal.contract.id; + }, + owner: function () { + return swGlobal.contract.owner; + } + }, + SmartWeave: { + caller: function (): string { + return swGlobal.caller; + }, + readContractState: async function (contractTxId): Promise { + return await swGlobal.contracts.readContractState(contractTxId); + }, + write: async function (contractId: string, input: any) { + return await swGlobal.contracts.write(contractId, input); + } + }, + Vrf: { + value: function (): string { + return swGlobal.vrf.value; + }, + + randomInt: function (maxValue: number): number { + return swGlobal.vrf.randomInt(maxValue); + } + } + }; + + const baseImports = { + __wbg_log_: function (arg0, arg1) { + rawImports.console.log(getStringFromWasm0(arg0, arg1)); + }, + __wbindgen_object_drop_ref: function (arg0) { + takeObject(arg0); + }, + __wbg_owner: function (arg0) { + var ret = rawImports.Transaction.owner(); + var ptr0 = passStringToWasm0( + ret, + wasmInstance.exports.__wbindgen_malloc, + wasmInstance.exports.__wbindgen_realloc + ); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }, + __wbg_caller: function (arg0) { + var ret = rawImports.SmartWeave.caller(); + var ptr0 = passStringToWasm0( + ret, + wasmInstance.exports.__wbindgen_malloc, + wasmInstance.exports.__wbindgen_realloc + ); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }, + __wbg_id: function (arg0) { + var ret = rawImports.Transaction.id(); + var ptr0 = passStringToWasm0( + ret, + wasmInstance.exports.__wbindgen_malloc, + wasmInstance.exports.__wbindgen_realloc + ); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }, + __wbindgen_cb_drop: function (arg0) { + const obj = takeObject(arg0).original; + if (obj.cnt-- == 1) { + obj.a = 0; + return true; + } + var ret = false; + return ret; + }, + __wbg_call: function () { + return handleError(function (arg0, arg1, arg2) { + var ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); + }, arguments); + }, + __wbg_new_4: function (arg0, arg1) { + try { + var state0 = { a: arg0, b: arg1 }; + var cb0 = (arg0, arg1) => { + const a = state0.a; + state0.a = 0; + try { + return __wbg_adapter_26(a, state0.b, arg0, arg1); + } finally { + state0.a = a; + } + }; + var ret = new Promise(cb0); + return addHeapObject(ret); + } finally { + state0.a = state0.b = 0; + } + }, + __wbg_new_e: function (arg0) { + var ret = new Uint8Array(getObject(arg0)); + return addHeapObject(ret); + }, + // __wbg_new: function (arg0, arg1) { + // if (arg1 === undefined) { + // try { + // var state0 = { a: arg0, b: arg1 }; + // var cb0 = (arg0, arg1) => { + // const a = state0.a; + // state0.a = 0; + // try { + // return __wbg_adapter_26(a, state0.b, arg0, arg1); + // } finally { + // state0.a = a; + // } + // }; + // var ret = new Promise(cb0) as any; + // return addHeapObject(ret); + // } finally { + // state0.a = state0.b = 0; + // } + // } else { + // var ret = new Uint8Array(getObject(arg0)) as any; + // return addHeapObject(ret); + // } + // }, + __wbg_resolve: function (arg0) { + var ret = Promise.resolve(getObject(arg0)); + return addHeapObject(ret); + }, + __wbg_then: function (arg0, arg1) { + var ret = getObject(arg0).then(getObject(arg1)); + return addHeapObject(ret); + }, + __wbg_buffer: function (arg0) { + var ret = getObject(arg0).buffer; + return addHeapObject(ret); + }, + __wbg_newwithbyteoffsetandlength: function (arg0, arg1, arg2) { + var ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); + return addHeapObject(ret); + }, + __wbindgen_throw: function (arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }, + __wbindgen_memory: function () { + var ret = wasmInstance.exports.memory; + return addHeapObject(ret); + }, + __wbindgen_closure_wrapper: function (arg0, arg1, arg2) { + var ret = makeMutClosure(arg0, arg1, dtorValue, __wbg_adapter_10); + return addHeapObject(ret); + }, + __wbg_set: function (arg0, arg1, arg2) { + getObject(arg0).set(getObject(arg1), arg2 >>> 0); + }, + __wbg_length: function (arg0) { + var ret = getObject(arg0).length; + return ret; + } + }; + + const baseImportsKeys = Object.keys(baseImports); + + // assigning functions to "real" import names from the currently + // compiled wasm module + let module: any = wbindgenImports.reduce((acc, wbindgenKey) => { + const baseImportsKey = baseImportsKeys.find((key) => wbindgenKey.startsWith(key)); + if (baseImportsKey === undefined) { + throw new Error(`Cannot find import mapping for ${wbindgenKey}`); + } + acc[wbindgenKey] = baseImports[baseImportsKey]; + return acc; + }, {}); + + // the rest of the code is basically left untouched from what + // wasm-bindgen generates + let imports: any = {}; + + imports['__wbindgen_placeholder__'] = module; + + let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); + + cachedTextDecoder.decode(); + + let cachegetUint8Memory0 = null; + + function getUint8Memory0() { + if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasmInstance.exports.memory.buffer) { + cachegetUint8Memory0 = new Uint8Array(wasmInstance.exports.memory.buffer); + } + return cachegetUint8Memory0; + } + + function getStringFromWasm0(ptr, len) { + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); + } + + const heap = new Array(32).fill(undefined); + + heap.push(undefined, null, true, false); + + let heap_next = heap.length; + + function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; + } + + function getObject(idx) { + return heap[idx]; + } + + let WASM_VECTOR_LEN = 0; + + // @ts-ignore + let cachedTextEncoder = new TextEncoder('utf-8'); + + const encodeString = + typeof cachedTextEncoder.encodeInto === 'function' + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); + } + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; + }; + + function passStringToWasm0(arg, malloc, realloc) { + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length); + getUint8Memory0() + .subarray(ptr, ptr + buf.length) + .set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len); + + const mem = getUint8Memory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7f) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, (len = offset + arg.length * 3)); + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + } + + WASM_VECTOR_LEN = offset; + return ptr; + } + + let cachegetInt32Memory0 = null; + + function getInt32Memory0() { + if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasmInstance.exports.memory.buffer) { + cachegetInt32Memory0 = new Int32Array(wasmInstance.exports.memory.buffer); + } + return cachegetInt32Memory0; + } + + function dropObject(idx) { + if (idx < 36) return; + heap[idx] = heap_next; + heap_next = idx; + } + + function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; + } + + function debugString(val) { + // primitive types + const type = typeof val; + if (type == 'number' || type == 'boolean' || val == null) { + return `${val}`; + } + if (type == 'string') { + return `"${val}"`; + } + if (type == 'symbol') { + const description = val.description; + if (description == null) { + return 'Symbol'; + } else { + return `Symbol(${description})`; + } + } + if (type == 'function') { + const name = val.name; + if (typeof name == 'string' && name.length > 0) { + return `Function(${name})`; + } else { + return 'Function'; + } + } + // objects + if (Array.isArray(val)) { + const length = val.length; + let debug = '['; + if (length > 0) { + debug += debugString(val[0]); + } + for (let i = 1; i < length; i++) { + debug += ', ' + debugString(val[i]); + } + debug += ']'; + return debug; + } + // Test for built-in + const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); + let className; + if (builtInMatches.length > 1) { + className = builtInMatches[1]; + } else { + // Failed to match the standard '[object ClassName]' + return toString.call(val); + } + if (className == 'Object') { + // we're a user defined class or Object + // JSON.stringify avoids problems with cycles, and is generally much + // easier than looping through ownProperties of `val`. + try { + return 'Object(' + JSON.stringify(val) + ')'; + } catch (_) { + return 'Object'; + } + } + // errors + if (val instanceof Error) { + return `${val.name}: ${val.message}\n${val.stack}`; + } + // TODO we could test for more things here, like `Set`s and `Map`s. + return className; + } + + function makeMutClosure(arg0, arg1, dtor, f) { + const state = { a: arg0, b: arg1, cnt: 1, dtor }; + const real = (...args) => { + // First up with a closure we increment the internal reference + // count. This ensures that the Rust closure environment won't + // be deallocated while we're invoking it. + state.cnt++; + const a = state.a; + state.a = 0; + try { + return f(a, state.b, ...args); + } finally { + if (--state.cnt === 0) { + wasmInstance.exports.__wbindgen_export_2.get(state.dtor)(a, state.b); + } else { + state.a = a; + } + } + }; + real.original = state; + + return real; + } + + function __wbg_adapter_10(arg0, arg1, arg2) { + wasmInstance.modifiedExports._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__( + arg0, + arg1, + addHeapObject(arg2) + ); + } + + function passArray8ToWasm0(arg, malloc) { + const ptr = malloc(arg.length * 1); + getUint8Memory0().set(arg, ptr / 1); + WASM_VECTOR_LEN = arg.length; + return ptr; + } + + function getArrayU8FromWasm0(ptr, len) { + return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); + } + + /** + * @param {any} interaction + * @returns {Promise} + */ + module.handle = function (interaction) { + var ret = wasmInstance.exports.handle(addHeapObject(interaction)); + return takeObject(ret); + }; + + /** + * @param {any} state + */ + module.initState = function (state) { + wasmInstance.exports.initState(addHeapObject(state)); + }; + + /** + * @returns {any} + */ + module.currentState = function () { + try { + const retptr = wasmInstance.exports.__wbindgen_add_to_stack_pointer(-16); + wasmInstance.exports.currentState(retptr); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var v0 = getArrayU8FromWasm0(r0, r1).slice(); + wasmInstance.exports.__wbindgen_free(r0, r1 * 1); + return v0; + } finally { + wasmInstance.exports.__wbindgen_add_to_stack_pointer(16); + } + }; + + /** + * @returns {string} + */ + module.lang = function () { + try { + const retptr = wasmInstance.exports.__wbindgen_add_to_stack_pointer(-16); + wasmInstance.exports.lang(retptr); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + return getStringFromWasm0(r0, r1); + } finally { + wasmInstance.exports.__wbindgen_add_to_stack_pointer(16); + wasmInstance.exports.__wbindgen_free(r0, r1); + } + }; + + /** + * @returns {number} + */ + module.type = function () { + var ret = wasmInstance.exports.type(); + return ret; + }; + + function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasmInstance.exports.__wbindgen_exn_store(addHeapObject(e)); + } + } + + function __wbg_adapter_26(arg0, arg1, arg2, arg3) { + wasmInstance.modifiedExports.wasm_bindgen__convert__closures__invoke2_mut__( + arg0, + arg1, + addHeapObject(arg2), + addHeapObject(arg3) + ); + } + + /** + */ + class StateWrapper { + __destroy_into_raw() { + // @ts-ignore + const ptr = this.ptr; + // @ts-ignore + this.ptr = 0; + + return ptr; + } + + free() { + const ptr = this.__destroy_into_raw(); + wasmInstance.exports.__wbg_statewrapper_free(ptr); + } + } + + module.StateWrapper = StateWrapper; + imports.metering = rawImports.metering; + + return { imports, exports: module }; +}; diff --git a/src/plugins/Evolve.ts b/src/plugins/Evolve.ts index c6c55a63..f8063588 100644 --- a/src/plugins/Evolve.ts +++ b/src/plugins/Evolve.ts @@ -47,7 +47,7 @@ export class Evolve implements ExecutionContextModifier { //FIXME: side-effect... executionContext.contractDefinition = newContractDefinition; executionContext.handler = newHandler; - executionContext.handler.initState(state); + executionContext.handler.initState(state, executionContext.evaluationOptions.wasmSerializationFormat); this.logger.debug('evolved to:', { evolve: evolvedSrcTxId, newSrcTxId: executionContext.contractDefinition.srcTxId, diff --git a/src/utils/utils.ts b/src/utils/utils.ts index d314c981..73ec521e 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -3,6 +3,10 @@ import copy from 'fast-copy'; import { Buffer } from 'redstone-isomorphic'; import { randomUUID } from 'crypto'; +export const exhaustive = (_: never, errorMessage = 'Exhaustive check failed') => { + throw new Error(errorMessage); +}; + export const sleep = (ms: number): Promise => { return new Promise((resolve) => setTimeout(resolve, ms)); }; diff --git a/yarn.lock b/yarn.lock index 506508f4..12e3778f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -417,15 +417,115 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@esbuild/android-arm@0.15.12": - version "0.15.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.12.tgz#e548b10a5e55b9e10537a049ebf0bc72c453b769" - integrity sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA== - -"@esbuild/linux-loong64@0.15.12": - version "0.15.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.12.tgz#475b33a2631a3d8ca8aa95ee127f9a61d95bf9c1" - integrity sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw== +"@esbuild/android-arm64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.2.tgz#73aa058f1fdc43770afd9a7b39654ce7e1b2e774" + integrity sha512-QSkmYISXr2uFoR+NdmmKyR5svYb0cXDCfzwNblLsrC8wTpx/I1L7u/zrjrf4aLoHoRTycZFIewJwBiUrO5DWtQ== + +"@esbuild/android-arm@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.2.tgz#7cdb67672350177edbaa1de1bedd71b295989fab" + integrity sha512-Art7v3xYfqH1gEMUSP0Nx67pNAlC/Y3qSg3mOw8Wg7MP9bJLXL0DrmJaV1Qz1o4FwagtvDgkVOeBDpZgxdj13Q== + +"@esbuild/android-x64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.2.tgz#58cb40ea9502a619551dab8145ec19de3192f3d8" + integrity sha512-5VOaFBI0RK8jJVDHdeU1YJmpxXoOf1RPoiOBhk/Tvpulw7R1SwCsxHvC3eDQcoF0gV7YM4V2wJO0PR9tem6gCQ== + +"@esbuild/darwin-arm64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.2.tgz#d9d60f704e13611db85acf2cc1ce2ed34fe5e46a" + integrity sha512-iQJu1Zn1Wi91D5x/sslEn/jwae1tgSAEHK0R/kYzIr5jO992IJwDDuWhSGll23jHt18RECxahhGG0BWY/bVUTw== + +"@esbuild/darwin-x64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.2.tgz#4ae5735e1cd09b584cff4b8066a246cc62b06c97" + integrity sha512-j750nyrwoRZd3VnPo5sd12/5U27TxFGmvmoDv93G2jiaGJPYKJ/+5IfRAvHahGePTUIRPyOlE5YLFw9MlzuBnw== + +"@esbuild/freebsd-arm64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.2.tgz#0265bd51eb1951b27eb693fd4989a4154e32bd58" + integrity sha512-ti7GU+/KUQQXEPmSUep7efZpA3KR2SkKsVuSL2FE7Yxka9apuqKfymAgQmVPMxstzAgCRBIu8uEu0KFmTfs3/Q== + +"@esbuild/freebsd-x64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.2.tgz#7b29d68def0ab7c5a21e3d8ec67a7a47db5f9993" + integrity sha512-NgooSKWSnrNKRuiumY1dg7KAGpsyXIMcwyOXN9imnqe8VFjqqrEOMqZRik0C1wlfLjiSCuMsj+YUSmBMAJMt0A== + +"@esbuild/linux-arm64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.2.tgz#4ac9edc5011e0d5e3f8673c3c3b00dc5c9bf4459" + integrity sha512-jcJ4cxwQyqEqgDwkqj7820nKx9cM5WBPCCU4oUXvTeG+DkkJE6/P75od0VPHmItFfEJu+/2vV85ebvFVomZcBg== + +"@esbuild/linux-arm@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.2.tgz#5b3f46608b682e32255f6dce10ddcc150826df4d" + integrity sha512-8dfrRTd39n+THdAetwQKNwK6zBPR5oPjMtgRNXvRq8gsn/J5o69zTaOWVi3QO09BljqdShxU2dxDA09lDhdIqQ== + +"@esbuild/linux-ia32@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.2.tgz#21e123e2557236c847b38c2ea4dac3d8fbd1081c" + integrity sha512-dXZ3m++zaRVD2fqOUPP8QTh1Lfg6WO6uZDo/QJ3KdfnIR7dDToDtaA12AgKYvCed9Nuzf/gpKs/7/f6I02b/sg== + +"@esbuild/linux-loong64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.2.tgz#05e2ca319a925de0a28fe2d8a31e158f8172dac9" + integrity sha512-/vntXkzSe9TUp0Rh35Wgye1EOhDtmIMjwC4rtahHcALmDXL+iuQGvwGFvXrP+sBigia/ltLryMAvCiqGV6plqw== + +"@esbuild/linux-mips64el@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.2.tgz#98f0e25b86153d725d4379bc267a2cd4c9bcdd24" + integrity sha512-guYcNHjMRO1BMxWAeb8LDfgQaU8oeUO65xtlclwBD+hX3163KBifEHyao1hK96J10BP9n0UmZug6GhtGZaNm2Q== + +"@esbuild/linux-ppc64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.2.tgz#45252f5343c5178dae93f8f7fc97aa4304cc5cca" + integrity sha512-fzHTnIGIVqgUGZcFnnisguKD4UneF4uwWwkG+i8kBspMDdU1wJ0jha1VdtxWP7Ob1KGxuXcoUlrQkCVO+Z5iOw== + +"@esbuild/linux-riscv64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.2.tgz#6c4446ad19a4d8b070ea0ddf124b6ea53750d5e2" + integrity sha512-Sa+z7csvNVeAsTD83tVSggOb8CAU7EdDuihC8WhtoJfuDVkF5+Vi0imaiCjXQ7Ci5rz/a8IJ1H1MWX3eI9AmuQ== + +"@esbuild/linux-s390x@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.2.tgz#5c03feb73b0c3fa80834eb150cd9c14206681b4e" + integrity sha512-jUFCO+/VA1Y/oeauSNBubp2UtGu4xjBUEFVgMPm0qLuw6xw18yOagKwBOPVmyE3ZSFqGd9BAPZM/JrtadgBryA== + +"@esbuild/linux-x64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.2.tgz#60405f2a40fb792557293a11ba0c380cfe744fcc" + integrity sha512-naygxkSmr6x9tuvpa8iGefnXo3Rc3Noz7c4+Dn0MSfSWJwLaN2YR686e7HkI09irfjDdU5UAq9wcxUwjkYQNUA== + +"@esbuild/netbsd-x64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.2.tgz#be8afb6d91827ecb8a8f42a43c63b528bbdd9c53" + integrity sha512-Hagbdq4EpiG9XXJY6Ozfrl2RN5jkXZXd6BD39f43tWz0d8yyOrRZlofM1eA6JYQbdv6c8BUsUOcgopavIqwx4Q== + +"@esbuild/openbsd-x64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.2.tgz#18e9f4c8284ade701039df1de246a35161dd382e" + integrity sha512-Pkby+VEXY7+aWP8J2RUCfqWbbZz2M1GavRGGnE2kEPzwarba/BOk3B45PSaKwc3iKdK2rgCPCTjC/p9JoKNejA== + +"@esbuild/sunos-x64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.2.tgz#c45c5b6fa406af451e3ebe2ba610bfaad106d20b" + integrity sha512-WAyg4dBTUsAPJ9cRnuQ23cwJWYRhP4e4y0M/l2+EpRjWW+g1MNAXKQQNNhRQ71zc8UixRVrqj+43ReHeZC8mJQ== + +"@esbuild/win32-arm64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.2.tgz#6b6d31077cba24bd8bc9e173b9ae052b0bef5b0c" + integrity sha512-rMbO3gPpxuENd+AnZLgo4J/g+BkwxT3NK7nYpSZ0KlYtSdlxYMIMG5pznX7a1ISZKo67aGStne+K41jdkBywpA== + +"@esbuild/win32-ia32@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.2.tgz#88bb3a510006114d8291506b6ec9ff93f66d0d5c" + integrity sha512-73dWKDMhFk+4owS19OjEVbEDGFPRS1fyga3qOu5HPd5eTxJTjtlVTT/fG/S7AchA0vXS7hOqY70AAir1CkmICg== + +"@esbuild/win32-x64@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.2.tgz#a7ce1ae475e14febb80e2690430e399491206a61" + integrity sha512-QFJlhf73HCBjTqAWWSIlD8JQBtmue0Dd6UV+KGccycJ3HKj1dCkXdRKJGwc5bZWiI9hrxcWsVEa1kVFaltC4vQ== "@eslint/eslintrc@^0.4.3": version "0.4.3" @@ -1158,6 +1258,36 @@ semver "^7.3.5" tar "^6.1.11" +"@msgpackr-extract/msgpackr-extract-darwin-arm64@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.2.0.tgz#901c5937e1441572ea23e631fe6deca68482fe76" + integrity sha512-Z9LFPzfoJi4mflGWV+rv7o7ZbMU5oAU9VmzCgL240KnqDW65Y2HFCT3MW06/ITJSnbVLacmcEJA8phywK7JinQ== + +"@msgpackr-extract/msgpackr-extract-darwin-x64@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.2.0.tgz#fb877fe6bae3c4d3cea29786737840e2ae689066" + integrity sha512-vq0tT8sjZsy4JdSqmadWVw6f66UXqUCabLmUVHZwUFzMgtgoIIQjT4VVRHKvlof3P/dMCkbMJ5hB1oJ9OWHaaw== + +"@msgpackr-extract/msgpackr-extract-linux-arm64@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.2.0.tgz#986179c38b10ac41fbdaf7d036c825cbc72855d9" + integrity sha512-hlxxLdRmPyq16QCutUtP8Tm6RDWcyaLsRssaHROatgnkOxdleMTgetf9JsdncL8vLh7FVy/RN9i3XR5dnb9cRA== + +"@msgpackr-extract/msgpackr-extract-linux-arm@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.2.0.tgz#15f2c6fe9e0adc06c21af7e95f484ff4880d79ce" + integrity sha512-SaJ3Qq4lX9Syd2xEo9u3qPxi/OB+5JO/ngJKK97XDpa1C587H9EWYO6KD8995DAjSinWvdHKRrCOXVUC5fvGOg== + +"@msgpackr-extract/msgpackr-extract-linux-x64@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.2.0.tgz#30cae5c9a202f3e1fa1deb3191b18ffcb2f239a2" + integrity sha512-94y5PJrSOqUNcFKmOl7z319FelCLAE0rz/jPCWS+UtdMZvpa4jrQd+cJPQCLp2Fes1yAW/YUQj/Di6YVT3c3Iw== + +"@msgpackr-extract/msgpackr-extract-win32-x64@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.2.0.tgz#016d855b6bc459fd908095811f6826e45dd4ba64" + integrity sha512-XrC0JzsqQSvOyM3t04FMLO6z5gCuhPE6k4FXuLK5xf52ZbdvcFe1yBmo7meCew9B8G2f0T9iu9t3kfTYRYROgA== + "@noble/ed25519@^1.6.1": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.1.tgz#6899660f6fbb97798a6fbd227227c4589a454724" @@ -3165,133 +3295,33 @@ es6-weak-map@~0.1.4: es6-iterator "~0.1.3" es6-symbol "~2.0.1" -esbuild-android-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.12.tgz#5e8151d5f0a748c71a7fbea8cee844ccf008e6fc" - integrity sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q== - -esbuild-android-arm64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.12.tgz#5ee72a6baa444bc96ffcb472a3ba4aba2cc80666" - integrity sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA== - -esbuild-darwin-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.12.tgz#70047007e093fa1b3ba7ef86f9b3fa63db51fe25" - integrity sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q== - -esbuild-darwin-arm64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.12.tgz#41c951f23d9a70539bcca552bae6e5196696ae04" - integrity sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw== - -esbuild-freebsd-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.12.tgz#a761b5afd12bbedb7d56c612e9cfa4d2711f33f0" - integrity sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw== - -esbuild-freebsd-arm64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.12.tgz#6b0839d4d58deabc6cbd96276eb8cbf94f7f335e" - integrity sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g== - -esbuild-linux-32@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.12.tgz#bd50bfe22514d434d97d5150977496e2631345b4" - integrity sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA== - -esbuild-linux-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.12.tgz#074bb2b194bf658245f8490f29c01ffcdfa8c931" - integrity sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA== - -esbuild-linux-arm64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.12.tgz#3bf789c4396dc032875a122988efd6f3733f28f5" - integrity sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ== - -esbuild-linux-arm@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.12.tgz#b91b5a8d470053f6c2c9c8a5e67ec10a71fe4a67" - integrity sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A== - -esbuild-linux-mips64le@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.12.tgz#2fb54099ada3c950a7536dfcba46172c61e580e2" - integrity sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A== - -esbuild-linux-ppc64le@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.12.tgz#9e3b8c09825fb27886249dfb3142a750df29a1b7" - integrity sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg== - -esbuild-linux-riscv64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.12.tgz#923d0f5b6e12ee0d1fe116b08e4ae4478fe40693" - integrity sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA== - -esbuild-linux-s390x@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.12.tgz#3b1620220482b96266a0c6d9d471d451a1eab86f" - integrity sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww== - -esbuild-netbsd-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.12.tgz#276730f80da646859b1af5a740e7802d8cd73e42" - integrity sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w== - -esbuild-openbsd-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.12.tgz#bd0eea1dd2ca0722ed489d88c26714034429f8ae" - integrity sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw== - -esbuild-sunos-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.12.tgz#5e56bf9eef3b2d92360d6d29dcde7722acbecc9e" - integrity sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg== - -esbuild-windows-32@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.12.tgz#a4f1a301c1a2fa7701fcd4b91ef9d2620cf293d0" - integrity sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw== - -esbuild-windows-64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.12.tgz#bc2b467541744d653be4fe64eaa9b0dbbf8e07f6" - integrity sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA== - -esbuild-windows-arm64@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.12.tgz#9a7266404334a86be800957eaee9aef94c3df328" - integrity sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA== - -esbuild@0.15.12: - version "0.15.12" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.12.tgz#6c8e22d6d3b7430d165c33848298d3fc9a1f251c" - integrity sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng== +esbuild@0.17.2: + version "0.17.2" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.2.tgz#c37ee608434be1c0e79f872c8bd484fb46af59df" + integrity sha512-odaHSgtYafOXt2nSISwdWlfRkb4ceMX3akY1mWspQpT08jsqVYEK1XtVusr250Rmbx8AVNWjMPI/yyvKqxOKMw== optionalDependencies: - "@esbuild/android-arm" "0.15.12" - "@esbuild/linux-loong64" "0.15.12" - esbuild-android-64 "0.15.12" - esbuild-android-arm64 "0.15.12" - esbuild-darwin-64 "0.15.12" - esbuild-darwin-arm64 "0.15.12" - esbuild-freebsd-64 "0.15.12" - esbuild-freebsd-arm64 "0.15.12" - esbuild-linux-32 "0.15.12" - esbuild-linux-64 "0.15.12" - esbuild-linux-arm "0.15.12" - esbuild-linux-arm64 "0.15.12" - esbuild-linux-mips64le "0.15.12" - esbuild-linux-ppc64le "0.15.12" - esbuild-linux-riscv64 "0.15.12" - esbuild-linux-s390x "0.15.12" - esbuild-netbsd-64 "0.15.12" - esbuild-openbsd-64 "0.15.12" - esbuild-sunos-64 "0.15.12" - esbuild-windows-32 "0.15.12" - esbuild-windows-64 "0.15.12" - esbuild-windows-arm64 "0.15.12" + "@esbuild/android-arm" "0.17.2" + "@esbuild/android-arm64" "0.17.2" + "@esbuild/android-x64" "0.17.2" + "@esbuild/darwin-arm64" "0.17.2" + "@esbuild/darwin-x64" "0.17.2" + "@esbuild/freebsd-arm64" "0.17.2" + "@esbuild/freebsd-x64" "0.17.2" + "@esbuild/linux-arm" "0.17.2" + "@esbuild/linux-arm64" "0.17.2" + "@esbuild/linux-ia32" "0.17.2" + "@esbuild/linux-loong64" "0.17.2" + "@esbuild/linux-mips64el" "0.17.2" + "@esbuild/linux-ppc64" "0.17.2" + "@esbuild/linux-riscv64" "0.17.2" + "@esbuild/linux-s390x" "0.17.2" + "@esbuild/linux-x64" "0.17.2" + "@esbuild/netbsd-x64" "0.17.2" + "@esbuild/openbsd-x64" "0.17.2" + "@esbuild/sunos-x64" "0.17.2" + "@esbuild/win32-arm64" "0.17.2" + "@esbuild/win32-ia32" "0.17.2" + "@esbuild/win32-x64" "0.17.2" escalade@^3.1.1: version "3.1.1" @@ -5341,6 +5371,27 @@ ms@2.1.3, ms@^2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +msgpackr-extract@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-2.2.0.tgz#4bb749b58d9764cfdc0d91c7977a007b08e8f262" + integrity sha512-0YcvWSv7ZOGl9Od6Y5iJ3XnPww8O7WLcpYMDwX+PAA/uXLDtyw94PJv9GLQV/nnp3cWlDhMoyKZIQLrx33sWog== + dependencies: + node-gyp-build-optional-packages "5.0.3" + optionalDependencies: + "@msgpackr-extract/msgpackr-extract-darwin-arm64" "2.2.0" + "@msgpackr-extract/msgpackr-extract-darwin-x64" "2.2.0" + "@msgpackr-extract/msgpackr-extract-linux-arm" "2.2.0" + "@msgpackr-extract/msgpackr-extract-linux-arm64" "2.2.0" + "@msgpackr-extract/msgpackr-extract-linux-x64" "2.2.0" + "@msgpackr-extract/msgpackr-extract-win32-x64" "2.2.0" + +msgpackr@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.8.1.tgz#2298aed8a14f83e99df77d344cbda3e436f29b5b" + integrity sha512-05fT4J8ZqjYlR4QcRDIhLCYKUOHXk7C/xa62GzMKj74l3up9k2QZ3LgFc6qWdsPHl91QA2WLWqWc8b8t7GLNNw== + optionalDependencies: + msgpackr-extract "^2.2.0" + multistream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/multistream/-/multistream-4.1.0.tgz#7bf00dfd119556fbc153cff3de4c6d477909f5a8" @@ -5425,6 +5476,11 @@ node-fetch@2.6.7, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" +node-gyp-build-optional-packages@5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" + integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA== + node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: version "4.5.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40"