diff --git a/js/build.js b/js/build.js index 86f3015..2193e4a 100644 --- a/js/build.js +++ b/js/build.js @@ -1,46 +1,36 @@ const fs = require("fs"); const path = require("path"); -const { execSync } = require("child_process"); const { minify } = require("terser"); +const SOLJSON_URI = + "https://binaries.soliditylang.org/wasm/soljson-v0.8.28+commit.7893614a.js"; +const RESOLC_WASM_URI = "http://127.0.0.1:8080/resolc.wasm"; const RESOLC_WASM_TARGET_DIR = path.join( __dirname, "../target/wasm32-unknown-emscripten/release", ); -const RESOLC_WASM = path.join(RESOLC_WASM_TARGET_DIR, "resolc.wasm"); const RESOLC_JS = path.join(RESOLC_WASM_TARGET_DIR, "resolc.js"); const RESOLC_JS_PACKED = path.join(RESOLC_WASM_TARGET_DIR, "resolc_packed.js"); -const execShellCommand = (cmd) => { - return execSync(cmd, { - encoding: "utf-8", - maxBuffer: 1024 * 1024 * 100, - }).trim(); -}; - -const wasmBase64 = execShellCommand( - `lz4c --no-frame-crc --best --favor-decSpeed "${RESOLC_WASM}" - | tail -c +8 | base64 -w 0`, -); - -const wasmSize = fs.statSync(RESOLC_WASM).size; - -const miniLz4 = fs.readFileSync( - path.join(__dirname, "utils/mini-lz4.js"), - "utf-8", -); -const base64DecToArr = fs.readFileSync( - path.join(__dirname, "utils/base64DecToArr.js"), - "utf-8", -); const resolcJs = fs.readFileSync(RESOLC_JS, "utf-8"); const packedJsContent = ` -let moduleArgs = { wasmBinary: (function(source, uncompressedSize) { - ${miniLz4} - ${base64DecToArr} - return uncompress(base64DecToArr(source), uncompressedSize); -})("${wasmBase64}", ${wasmSize}), -}; +if (typeof importScripts === "function") { + importScripts("${SOLJSON_URI}"); + + var moduleArgs = { + wasmBinary: (function () { + var xhr = new XMLHttpRequest(); + xhr.open("GET", "${RESOLC_WASM_URI}", false); + xhr.responseType = "arraybuffer"; + xhr.send(null); + return new Uint8Array(xhr.response); + })(), + soljson: Module + }; +} else { + console.log("Not a WebWorker, skipping Soljson and WASM loading."); +} ${resolcJs} diff --git a/js/e2e/web.test.js b/js/e2e/web.test.js index a44d530..652ede6 100644 --- a/js/e2e/web.test.js +++ b/js/e2e/web.test.js @@ -7,6 +7,13 @@ function loadFixture(fixture) { return JSON.parse(fs.readFileSync(fixturePath, "utf-8")); } +async function loadTestPage(page) { + await page.goto("http://127.0.0.1:8080"); + const outputElement = page.locator("#output"); + await outputElement.waitFor({ state: "visible" }); + await page.setContent(""); +} + async function runWorker(page, input) { return await page.evaluate((input) => { return new Promise((resolve, reject) => { @@ -29,8 +36,7 @@ async function runWorker(page, input) { test("should successfully compile valid Solidity code in browser", async ({ page, }) => { - await page.goto("http://127.0.0.1:8080"); - await page.setContent(""); + await loadTestPage(page); const standardInput = loadFixture("storage.json"); const result = await runWorker(page, standardInput); @@ -52,8 +58,7 @@ test("should successfully compile valid Solidity code in browser", async ({ test("should successfully compile large valid Solidity code in browser", async ({ page, }) => { - await page.goto("http://127.0.0.1:8080"); - await page.setContent(""); + await loadTestPage(page); const standardInput = loadFixture("token.json"); const result = await runWorker(page, standardInput); @@ -71,8 +76,7 @@ test("should successfully compile large valid Solidity code in browser", async ( test("should throw an error for invalid Solidity code in browser", async ({ page, }) => { - await page.goto("http://127.0.0.1:8080"); - await page.setContent(""); + await loadTestPage(page); const standardInput = loadFixture("invalid_contract_content.json"); const result = await runWorker(page, standardInput); @@ -88,8 +92,7 @@ test("should throw an error for invalid Solidity code in browser", async ({ test("should return not found error for missing imports in browser", async ({ page, }) => { - await page.goto("http://127.0.0.1:8080"); - await page.setContent(""); + await loadTestPage(page); const standardInput = loadFixture("missing_import.json"); const result = await runWorker(page, standardInput); diff --git a/js/examples/web/resolc.js b/js/examples/web/resolc.js deleted file mode 120000 index ed95f38..0000000 --- a/js/examples/web/resolc.js +++ /dev/null @@ -1 +0,0 @@ -../../../target/wasm32-unknown-emscripten/release/resolc.js \ No newline at end of file diff --git a/js/examples/web/resolc_packed.js b/js/examples/web/resolc_packed.js new file mode 120000 index 0000000..a29d3c1 --- /dev/null +++ b/js/examples/web/resolc_packed.js @@ -0,0 +1 @@ +../../../target/wasm32-unknown-emscripten/release/resolc_packed.js \ No newline at end of file diff --git a/js/examples/web/worker.js b/js/examples/web/worker.js index 82dba14..e066a22 100644 --- a/js/examples/web/worker.js +++ b/js/examples/web/worker.js @@ -1,10 +1,8 @@ -importScripts("./soljson.js"); -importScripts("./resolc.js"); +importScripts("./resolc_packed.js"); // Handle messages from the main thread onmessage = async function (e) { const m = createRevive(); - m.soljson = Module; // Set input data for stdin m.writeToStdin(e.data); diff --git a/js/package.json b/js/package.json index aadcb63..57cd9f1 100644 --- a/js/package.json +++ b/js/package.json @@ -5,8 +5,7 @@ "solc": "^0.8.28" }, "scripts": { - "fetch:soljson": "wget https://binaries.soliditylang.org/wasm/soljson-v0.8.28+commit.7893614a.js -O ./examples/web/soljson.js", - "example:web": "npm run fetch:soljson && http-server ./examples/web/", + "example:web": "http-server ./examples/web/", "example:node": "node ./examples/node/run_revive.js", "test:node": "mocha --timeout 60000 ./tests", "test:bun": "bun test --timeout 60000 node.test", diff --git a/js/utils/base64DecToArr.js b/js/utils/base64DecToArr.js deleted file mode 100644 index e1f4729..0000000 --- a/js/utils/base64DecToArr.js +++ /dev/null @@ -1,46 +0,0 @@ -function base64DecToArr (sBase64) { -/*\ -|*| -|*| Base64 / binary data / UTF-8 strings utilities -|*| -|*| https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding -|*| -\*/ - -/* Array of bytes to Base64 string decoding */ - -function b64ToUint6 (nChr) { - - return nChr > 64 && nChr < 91 ? - nChr - 65 - : nChr > 96 && nChr < 123 ? - nChr - 71 - : nChr > 47 && nChr < 58 ? - nChr + 4 - : nChr === 43 ? - 62 - : nChr === 47 ? - 63 - : - 0; - -} - - var - nInLen = sBase64.length, - nOutLen = nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen); - - for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) { - nMod4 = nInIdx & 3; - nUint24 |= b64ToUint6(sBase64.charCodeAt(nInIdx)) << 6 * (3 - nMod4); - if (nMod4 === 3 || nInLen - nInIdx === 1) { - for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) { - taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255; - } - nUint24 = 0; - - } - } - - return taBytes; -} diff --git a/js/utils/mini-lz4.js b/js/utils/mini-lz4.js deleted file mode 100644 index 1c1ab33..0000000 --- a/js/utils/mini-lz4.js +++ /dev/null @@ -1,118 +0,0 @@ -function uncompress(source, uncompressedSize) { -/* -Source https://github.com/ethereum/solidity/blob/develop/scripts/ci/mini-lz4.js -==== -based off https://github.com/emscripten-core/emscripten/blob/main/third_party/mini-lz4.js -The license only applies to the body of this function (``uncompress``). -==== -MiniLZ4: Minimal LZ4 block decoding and encoding. - -based off of node-lz4, https://github.com/pierrec/node-lz4 - -==== -Copyright (c) 2012 Pierre Curto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -==== - -changes have the same license -*/ -/** - * Decode a block. Assumptions: input contains all sequences of a - * chunk, output is large enough to receive the decoded data. - * If the output buffer is too small, an error will be thrown. - * If the returned value is negative, an error occurred at the returned offset. - * - * @param {ArrayBufferView} input input data - * @param {ArrayBufferView} output output data - * @param {number=} sIdx - * @param {number=} eIdx - * @return {number} number of decoded bytes - * @private - */ -function uncompressBlock (input, output, sIdx, eIdx) { - sIdx = sIdx || 0 - eIdx = eIdx || (input.length - sIdx) - // Process each sequence in the incoming data - for (var i = sIdx, n = eIdx, j = 0; i < n;) { - var token = input[i++] - - // Literals - var literals_length = (token >> 4) - if (literals_length > 0) { - // length of literals - var l = literals_length + 240 - while (l === 255) { - l = input[i++] - literals_length += l - } - - // Copy the literals - var end = i + literals_length - while (i < end) output[j++] = input[i++] - - // End of buffer? - if (i === n) return j - } - - // Match copy - // 2 bytes offset (little endian) - var offset = input[i++] | (input[i++] << 8) - - // XXX 0 is an invalid offset value - if (offset === 0) return j - if (offset > j) return -(i-2) - - // length of match copy - var match_length = (token & 0xf) - var l = match_length + 240 - while (l === 255) { - l = input[i++] - match_length += l - } - // Copy the match - var pos = j - offset // position of the match copy in the current output - var end = j + match_length + 4 // minmatch = 4 - while (j < end) output[j++] = output[pos++] - } - - return j -} -var result = new ArrayBuffer(uncompressedSize); -var sourceIndex = 0; -var destIndex = 0; -var blockSize; -while((blockSize = (source[sourceIndex] | (source[sourceIndex + 1] << 8) | (source[sourceIndex + 2] << 16) | (source[sourceIndex + 3] << 24))) > 0) -{ - sourceIndex += 4; - if (blockSize & 0x80000000) - { - blockSize &= 0x7FFFFFFFF; - for (var i = 0; i < blockSize; i++) { - result[destIndex++] = source[sourceIndex++]; - } - } - else - { - destIndex += uncompressBlock(source, new Uint8Array(result, destIndex, uncompressedSize - destIndex), sourceIndex, sourceIndex + blockSize); - sourceIndex += blockSize; - } -} -return new Uint8Array(result, 0, uncompressedSize); -}