mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-13 03:58:45 +00:00
feat(wasm): support "pure JS" mode
Closes #1159 This uses the binaryen tool wasm2js to compile the Anubis WASM blobs to JavaScript. This produces biblically large (520Ki) outputs when you inline both hashx and sha256 solvers, but this is a tradeoff that I'm willing to accept. The performance is good enough in my testing with JIT enabled. I fear that this may end up being terrible with JIT disabled. I have no idea if this will work on big endian or not. Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
23
web/js/algorithms/wasm/hashx.ts
Normal file
23
web/js/algorithms/wasm/hashx.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import {
|
||||
memory,
|
||||
data_ptr,
|
||||
set_data_length,
|
||||
anubis_work,
|
||||
anubis_validate,
|
||||
result_hash_ptr,
|
||||
result_hash_size,
|
||||
verification_hash_ptr,
|
||||
verification_hash_size,
|
||||
} from "../../../static/wasm/baseline/hashx.mjs";
|
||||
|
||||
export default {
|
||||
memory,
|
||||
data_ptr,
|
||||
set_data_length,
|
||||
anubis_work,
|
||||
anubis_validate,
|
||||
result_hash_ptr,
|
||||
result_hash_size,
|
||||
verification_hash_ptr,
|
||||
verification_hash_size
|
||||
};
|
||||
111
web/js/algorithms/wasm/index.ts
Normal file
111
web/js/algorithms/wasm/index.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { u } from "../../../lib/xeact";
|
||||
import { simd } from "wasm-feature-detect";
|
||||
// import { compile } from '@haribala/wasm2js';
|
||||
|
||||
type ProgressCallback = (nonce: number | string) => void;
|
||||
|
||||
interface ProcessOptions {
|
||||
basePrefix: string;
|
||||
version: string;
|
||||
algorithm: string;
|
||||
}
|
||||
|
||||
const getHardwareConcurrency = () =>
|
||||
navigator.hardwareConcurrency !== undefined ? navigator.hardwareConcurrency : 1;
|
||||
|
||||
// // https://stackoverflow.com/questions/47879864/how-can-i-check-if-a-browser-supports-webassembly
|
||||
// const isWASMSupported = (() => {
|
||||
// try {
|
||||
// if (typeof WebAssembly === "object"
|
||||
// && typeof WebAssembly.instantiate === "function") {
|
||||
// const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
|
||||
// if (module instanceof WebAssembly.Module)
|
||||
// return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
|
||||
// }
|
||||
// } catch (e) {
|
||||
// return false;
|
||||
// }
|
||||
// return false;
|
||||
// })();
|
||||
const isWASMSupported = false;
|
||||
|
||||
export default function process(
|
||||
options: ProcessOptions,
|
||||
data: string,
|
||||
difficulty: number = 5,
|
||||
signal: AbortSignal | null = null,
|
||||
progressCallback?: ProgressCallback,
|
||||
threads: number = Math.trunc(Math.max(getHardwareConcurrency() / 2, 1)),
|
||||
): Promise<string> {
|
||||
const { basePrefix, version, algorithm } = options;
|
||||
|
||||
let worker = "wasm";
|
||||
|
||||
if (!isWASMSupported) {
|
||||
worker = "wasm2js";
|
||||
}
|
||||
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let wasmFeatures = "baseline";
|
||||
|
||||
if (await simd()) {
|
||||
wasmFeatures = "simd128";
|
||||
}
|
||||
|
||||
const webWorkerURL = `${basePrefix}/.within.website/x/cmd/anubis/static/js/worker/${worker}.mjs?cacheBuster=${version}`;
|
||||
|
||||
const workers: Worker[] = [];
|
||||
let settled = false;
|
||||
|
||||
const onAbort = () => {
|
||||
console.log("PoW aborted");
|
||||
cleanup();
|
||||
reject(new DOMException("Aborted", "AbortError"));
|
||||
};
|
||||
|
||||
const cleanup = () => {
|
||||
if (settled) {
|
||||
return;
|
||||
}
|
||||
settled = true;
|
||||
workers.forEach((w) => w.terminate());
|
||||
if (signal != null) {
|
||||
signal.removeEventListener("abort", onAbort);
|
||||
}
|
||||
};
|
||||
|
||||
if (signal != null) {
|
||||
if (signal.aborted) {
|
||||
return onAbort();
|
||||
}
|
||||
signal.addEventListener("abort", onAbort, { once: true });
|
||||
}
|
||||
|
||||
for (let i = 0; i < threads; i++) {
|
||||
let worker = new Worker(webWorkerURL);
|
||||
|
||||
worker.onmessage = (event) => {
|
||||
if (typeof event.data === "number") {
|
||||
progressCallback?.(event.data);
|
||||
} else {
|
||||
cleanup();
|
||||
resolve(event.data);
|
||||
}
|
||||
}
|
||||
|
||||
worker.onerror = (event) => {
|
||||
cleanup();
|
||||
reject(event);
|
||||
}
|
||||
|
||||
worker.postMessage({
|
||||
data,
|
||||
difficulty,
|
||||
nonce: i,
|
||||
threads,
|
||||
algorithm,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
23
web/js/algorithms/wasm/sha256.ts
Normal file
23
web/js/algorithms/wasm/sha256.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import {
|
||||
memory,
|
||||
data_ptr,
|
||||
set_data_length,
|
||||
anubis_work,
|
||||
anubis_validate,
|
||||
result_hash_ptr,
|
||||
result_hash_size,
|
||||
verification_hash_ptr,
|
||||
verification_hash_size,
|
||||
} from "../../../static/wasm/baseline/sha256.mjs";
|
||||
|
||||
export default {
|
||||
memory,
|
||||
data_ptr,
|
||||
set_data_length,
|
||||
anubis_work,
|
||||
anubis_validate,
|
||||
result_hash_ptr,
|
||||
result_hash_size,
|
||||
verification_hash_ptr,
|
||||
verification_hash_size
|
||||
};
|
||||
Reference in New Issue
Block a user