mirror of
https://github.com/TecharoHQ/anubis.git
synced 2025-08-03 09:48:08 -04:00

* chore(web/js): delete proof-of-work-slow.mjs This code has served its purpose and now needs to be retired to the great beyond. There is no replacement for this, the fast implementation will be used instead. Signed-off-by: Xe Iaso <me@xeiaso.net> * chore(web): handle building multiple JS entrypoints and web workers Signed-off-by: Xe Iaso <me@xeiaso.net> * feat(web): rewrite frontend worker handling This completely rewrites how the proof of work challenge works based on feedback from browser engine developers and starts the process of making the proof of work function easier to change out. - Import @aws-crypto/sha256-js to use in Firefox as its implementation of WebCrypto doesn't jump directly from highly optimized browser internals to JIT-ed JavaScript like Chrome's seems to. - Move the worker code to `web/js/worker/*` with each worker named after the hashing method and hash method implementation it uses. - Update bench.mjs to import algorithms the new way. - Delete video.mjs, it was part of a legacy experiment that I never had time to finish. - Update LibreJS comment to add info about the use of @aws-crypto/sha256-js. - Also update my email to my @techaro.lol address. Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(web): don't hard dep webcrypto anymore Signed-off-by: Xe Iaso <me@xeiaso.net> * chore(lib/policy): start the deprecation process for slow This mostly adds a warning, but the "slow" method is in the process of being removed. Warn admins with slog.Warn. Signed-off-by: Xe Iaso <me@xeiaso.net> * docs: update CHANGELOG Signed-off-by: Xe Iaso <me@xeiaso.net> * feat(web/js): allow running Anubis in non-secure contexts Signed-off-by: Xe Iaso <me@xeiaso.net> * Update metadata check-spelling run (pull_request) for Xe/purge-slow Signed-off-by: check-spelling-bot <check-spelling-bot@users.noreply.github.com> on-behalf-of: @check-spelling <check-spelling-bot@check-spelling.dev> --------- Signed-off-by: Xe Iaso <me@xeiaso.net> Signed-off-by: check-spelling-bot <check-spelling-bot@users.noreply.github.com>
148 lines
4.3 KiB
JavaScript
148 lines
4.3 KiB
JavaScript
import algorithms from "./algorithms/index.mjs";
|
|
|
|
const defaultDifficulty = 4;
|
|
|
|
const status = document.getElementById("status");
|
|
const difficultyInput = document.getElementById("difficulty-input");
|
|
const algorithmSelect = document.getElementById("algorithm-select");
|
|
const compareSelect = document.getElementById("compare-select");
|
|
const header = document.getElementById("table-header");
|
|
const headerCompare = document.getElementById("table-header-compare");
|
|
const results = document.getElementById("results");
|
|
|
|
const setupControls = () => {
|
|
difficultyInput.value = defaultDifficulty;
|
|
for (const alg of Object.keys(algorithms)) {
|
|
const option1 = document.createElement("option");
|
|
algorithmSelect.append(option1);
|
|
const option2 = document.createElement("option");
|
|
compareSelect.append(option2);
|
|
option1.value = option1.innerText = option2.value = option2.innerText = alg;
|
|
}
|
|
};
|
|
|
|
const benchmarkTrial = async (stats, difficulty, algorithm, signal) => {
|
|
if (!(difficulty >= 1)) {
|
|
throw new Error(`Invalid difficulty: ${difficulty}`);
|
|
}
|
|
const process = algorithms[algorithm];
|
|
if (process == null) {
|
|
throw new Error(`Unknown algorithm: ${algorithm}`);
|
|
}
|
|
|
|
const rawChallenge = new Uint8Array(32);
|
|
crypto.getRandomValues(rawChallenge);
|
|
const challenge = Array.from(rawChallenge)
|
|
.map((c) => c.toString(16).padStart(2, "0"))
|
|
.join("");
|
|
|
|
const t0 = performance.now();
|
|
const { hash, nonce } = await process({ basePrefix: "/", version: "devel" }, challenge, Number(difficulty), signal);
|
|
const t1 = performance.now();
|
|
console.log({ hash, nonce });
|
|
|
|
stats.time += t1 - t0;
|
|
stats.iters += nonce;
|
|
|
|
return { time: t1 - t0, nonce };
|
|
};
|
|
|
|
const stats = { time: 0, iters: 0 };
|
|
const comparison = { time: 0, iters: 0 };
|
|
const updateStatus = () => {
|
|
const mainRate = stats.iters / stats.time;
|
|
const compareRate = comparison.iters / comparison.time;
|
|
if (Number.isFinite(mainRate)) {
|
|
status.innerText = `Average hashrate: ${mainRate.toFixed(3)}kH/s`;
|
|
if (Number.isFinite(compareRate)) {
|
|
const change = ((mainRate - compareRate) / mainRate) * 100;
|
|
status.innerText += ` vs ${compareRate.toFixed(3)}kH/s (${change.toFixed(2)}% change)`;
|
|
}
|
|
} else {
|
|
status.innerText = "Benchmarking...";
|
|
}
|
|
};
|
|
|
|
const tableCell = (text) => {
|
|
const td = document.createElement("td");
|
|
td.innerText = text;
|
|
td.style.padding = "0 0.25rem";
|
|
return td;
|
|
};
|
|
|
|
const benchmarkLoop = async (controller) => {
|
|
const difficulty = difficultyInput.value;
|
|
const algorithm = algorithmSelect.value;
|
|
const compareAlgorithm = compareSelect.value;
|
|
updateStatus();
|
|
|
|
try {
|
|
const { time, nonce } = await benchmarkTrial(
|
|
stats,
|
|
difficulty,
|
|
algorithm,
|
|
controller.signal,
|
|
);
|
|
|
|
const tr = document.createElement("tr");
|
|
tr.style.display = "contents";
|
|
tr.append(tableCell(`${time}ms`), tableCell(nonce));
|
|
|
|
// auto-scroll to new rows
|
|
const atBottom =
|
|
results.scrollHeight - results.clientHeight <= results.scrollTop;
|
|
results.append(tr);
|
|
if (atBottom) {
|
|
results.scrollTop = results.scrollHeight - results.clientHeight;
|
|
}
|
|
updateStatus();
|
|
|
|
if (compareAlgorithm !== "NONE") {
|
|
const { time, nonce } = await benchmarkTrial(
|
|
comparison,
|
|
difficulty,
|
|
compareAlgorithm,
|
|
controller.signal,
|
|
);
|
|
tr.append(tableCell(`${time}ms`), tableCell(nonce));
|
|
}
|
|
} catch (e) {
|
|
if (e !== false) {
|
|
status.innerText = e;
|
|
}
|
|
return;
|
|
}
|
|
|
|
await benchmarkLoop(controller);
|
|
};
|
|
|
|
let controller = null;
|
|
const reset = () => {
|
|
stats.time = stats.iters = 0;
|
|
comparison.time = comparison.iters = 0;
|
|
results.innerHTML = status.innerText = "";
|
|
|
|
const table = results.parentElement;
|
|
if (compareSelect.value !== "NONE") {
|
|
table.style.gridTemplateColumns = "repeat(4,auto)";
|
|
header.style.display = "none";
|
|
headerCompare.style.display = "contents";
|
|
} else {
|
|
table.style.gridTemplateColumns = "repeat(2,auto)";
|
|
header.style.display = "contents";
|
|
headerCompare.style.display = "none";
|
|
}
|
|
|
|
if (controller != null) {
|
|
controller.abort();
|
|
}
|
|
controller = new AbortController();
|
|
void benchmarkLoop(controller);
|
|
};
|
|
|
|
setupControls();
|
|
difficultyInput.addEventListener("change", reset);
|
|
algorithmSelect.addEventListener("change", reset);
|
|
compareSelect.addEventListener("change", reset);
|
|
reset();
|