mirror of
https://github.com/TecharoHQ/anubis.git
synced 2025-08-03 17:59:24 -04:00

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>
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();
|