fix(js): use pure JS SHA256 library, refactor (#471)
* fix(js): use pure JS SHA256 library, refactor Closes #458 Additionally, I made a horrifying discovery: Firefox seems to actively hinder performance if you are using more than one Worker per page. It does not spread the load out across cores like I expected. Instead it seems to make that one Worker thrash and have to constantly context switch, which caused a lot of slowdown. The benchmarks in #155 continue to be the best contribution ever made to Anubis. What clued me into there being a problem here was the fact that the "slow" algorithm was faster than the "fast" algorithm on my laptop. This made no intuitive sense to me so I dug further. Either way I think this is a Firefox bug at its core, but for now we have to work around it by doing the hacky terrible thing that I hate. I also swapped the SHA256 operations to @aws-crypto/sha256-js on the advice of a trusted cryptography expert. I don't know what performance differences this makes, but I'm getting 150-225 kilohashes per second, which is pretty dang good. Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(js): apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(js): use fast algo for fast worker Signed-off-by: Xe Iaso <me@xeiaso.net> --------- Signed-off-by: Xe Iaso <me@xeiaso.net> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
7f0f691ba5
commit
7b84904d15
13 changed files with 335 additions and 234 deletions
67
web/js/algorithms/fast.mjs
Normal file
67
web/js/algorithms/fast.mjs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
const determineThreadCount = () => {
|
||||
if (navigator.userAgent.includes("Firefox")) {
|
||||
return Math.min(navigator.hardwareConcurrency, 4);
|
||||
}
|
||||
|
||||
if (!!navigator.hardwareConcurrency) {
|
||||
return navigator.hardwareConcurrency;
|
||||
}
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
export default function process(
|
||||
{ basePrefix, version },
|
||||
data,
|
||||
difficulty = 5,
|
||||
signal = null,
|
||||
progressCallback = null,
|
||||
threads = determineThreadCount(),
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let webWorkerURL = `${basePrefix}/.within.website/x/cmd/anubis/static/js/worker/fast.mjs?cacheBuster=${version}`;
|
||||
|
||||
const workers = [];
|
||||
const terminate = () => {
|
||||
workers.forEach((w) => w.terminate());
|
||||
if (signal != null) {
|
||||
// clean up listener to avoid memory leak
|
||||
signal.removeEventListener("abort", terminate);
|
||||
if (signal.aborted) {
|
||||
console.log("PoW aborted");
|
||||
reject(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (signal != null) {
|
||||
signal.addEventListener("abort", terminate, { 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 {
|
||||
terminate();
|
||||
resolve(event.data);
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = (event) => {
|
||||
terminate();
|
||||
reject(event);
|
||||
};
|
||||
|
||||
worker.postMessage({
|
||||
data,
|
||||
difficulty,
|
||||
nonce: i,
|
||||
threads,
|
||||
});
|
||||
|
||||
workers.push(worker);
|
||||
}
|
||||
});
|
||||
}
|
||||
48
web/js/algorithms/slow.mjs
Normal file
48
web/js/algorithms/slow.mjs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// https://dev.to/ratmd/simple-proof-of-work-in-javascript-3kgm
|
||||
|
||||
export default function process(
|
||||
{ basePrefix, version },
|
||||
data,
|
||||
difficulty = 5,
|
||||
signal = null,
|
||||
progressCallback = null,
|
||||
_threads = 1,
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let worker = new Worker(`${basePrefix}/.within.website/x/cmd/anubis/static/js/worker/slow.mjs?cacheBuster=${version}`);
|
||||
const terminate = () => {
|
||||
worker.terminate();
|
||||
if (signal != null) {
|
||||
// clean up listener to avoid memory leak
|
||||
signal.removeEventListener("abort", terminate);
|
||||
if (signal.aborted) {
|
||||
console.log("PoW aborted");
|
||||
reject(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (signal != null) {
|
||||
signal.addEventListener("abort", terminate, { once: true });
|
||||
}
|
||||
|
||||
worker.onmessage = (event) => {
|
||||
if (typeof event.data === "number") {
|
||||
progressCallback?.(event.data);
|
||||
} else {
|
||||
terminate();
|
||||
resolve(event.data);
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = (event) => {
|
||||
terminate();
|
||||
reject(event);
|
||||
};
|
||||
|
||||
worker.postMessage({
|
||||
data,
|
||||
difficulty
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue