feat: progress bar and incremental PoW generation

This commit is contained in:
Aravinth Manivannan 2023-10-29 06:28:05 +05:30
parent ad4582cc16
commit 9dfb0713ad
No known key found for this signature in database
GPG key ID: F8F50389936984FF
8 changed files with 221 additions and 137 deletions

View file

@ -37,8 +37,8 @@
"webpack-dev-server": "^4.15.1" "webpack-dev-server": "^4.15.1"
}, },
"dependencies": { "dependencies": {
"@mcaptcha/pow-wasm": "^0.1.0-rc1", "@mcaptcha/pow_sha256-polyfill": "^0.1.0-rc2",
"@mcaptcha/pow_sha256-polyfill": "^0.1.0-rc1", "@mcaptcha/vanilla-glue": "^0.1.0-rc1",
"@mcaptcha/vanilla-glue": "^0.1.0-rc1" "@mcaptcha/pow-wasm": "^0.1.0-rc2"
} }
} }

View file

@ -6,7 +6,8 @@ SPDX-License-Identifier: MIT OR Apache-2.0
<. include!("../components/headers/widget-headers.html"); .> <. include!("../components/headers/widget-headers.html"); .>
<body> <body>
<form class="widget__contaienr"> <main class="widget__container">
<form class="widget__inner-container">
<noscript> <noscript>
<div class="widget__noscript-container"> <div class="widget__noscript-container">
<span class="widget__noscript-warning"> <span class="widget__noscript-warning">
@ -53,4 +54,6 @@ SPDX-License-Identifier: MIT OR Apache-2.0
</div> </div>
</div> </div>
</form> </form>
<div class="progress__bar"><div class="progress__fill"></div></div>
</main>
<.include!("./footer.html"); .> <.include!("./footer.html"); .>

View file

@ -3,7 +3,7 @@
// //
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
import { Work, ServiceWorkerWork } from "./types"; import { Work, ServiceWorkerMessage } from "./types";
import fetchPoWConfig from "./fetchPoWConfig"; import fetchPoWConfig from "./fetchPoWConfig";
import sendWork from "./sendWork"; import sendWork from "./sendWork";
import sendToParent from "./sendToParent"; import sendToParent from "./sendToParent";
@ -24,6 +24,9 @@ export const registerVerificationEventHandler = (): void => {
}; };
export const solveCaptchaRunner = async (e: Event): Promise<void> => { export const solveCaptchaRunner = async (e: Event): Promise<void> => {
const PROGRESS_FILL = <HTMLElement>document.querySelector(".progress__fill");
let width = 0;
if (LOCK) { if (LOCK) {
e.preventDefault(); e.preventDefault();
return; return;
@ -32,6 +35,8 @@ export const solveCaptchaRunner = async (e: Event): Promise<void> => {
try { try {
LOCK = true; LOCK = true;
if (CONST.btn().checked == false) { if (CONST.btn().checked == false) {
width = 0;
PROGRESS_FILL.style.width = `${width}%`;
CONST.messageText().before(); CONST.messageText().before();
LOCK = false; LOCK = false;
return; return;
@ -43,32 +48,49 @@ export const solveCaptchaRunner = async (e: Event): Promise<void> => {
CONST.messageText().during(); CONST.messageText().during();
// 1. get config // 1. get config
const config = await fetchPoWConfig(); const config = await fetchPoWConfig();
const max_recorded_nonce = config.max_recorded_nonce;
// 2. prove work // 2. prove work
worker.postMessage(config); worker.postMessage(config);
worker.onmessage = async (event: MessageEvent) => { worker.onmessage = async (event: MessageEvent) => {
const resp: ServiceWorkerWork = event.data; const resp: ServiceWorkerMessage = event.data;
if (resp.type === "work") {
width = 80;
PROGRESS_FILL.style.width = `${width}%`;
console.log( console.log(
`Proof generated. Difficuly: ${config.difficulty_factor} Duration: ${resp.work.time}` `Proof generated. Difficuly: ${config.difficulty_factor} Duration: ${resp.value.work.time}`
); );
const proof: Work = { const proof: Work = {
key: CONST.sitekey(), key: CONST.sitekey(),
string: config.string, string: config.string,
nonce: resp.work.nonce, nonce: resp.value.work.nonce,
result: resp.work.result, result: resp.value.work.result,
time: Math.trunc(resp.work.time), time: Math.trunc(resp.value.work.time),
worker_type: resp.work.worker_type, worker_type: resp.value.work.worker_type,
}; };
width = 90;
PROGRESS_FILL.style.width = `${width}%`;
// 3. submit work // 3. submit work
const token = await sendWork(proof); const token = await sendWork(proof);
// 4. send token // 4. send token
sendToParent(token); sendToParent(token);
// 5. mark checkbox checked // 5. mark checkbox checked
CONST.btn().checked = true; CONST.btn().checked = true;
width = 100;
PROGRESS_FILL.style.width = `${width}%`;
CONST.messageText().after(); CONST.messageText().after();
LOCK = false; LOCK = false;
}
if (resp.type === "progress") {
if (width < 80) {
width = (resp.nonce / max_recorded_nonce) * 100;
PROGRESS_FILL.style.width = `${width}%`;
}
console.log(`received nonce ${resp.nonce}`);
}
}; };
} catch (e) { } catch (e) {
CONST.messageText().error(); CONST.messageText().error();

View file

@ -7,11 +7,27 @@
@import "../reset"; @import "../reset";
.widget__contaienr { body {
display: flex;
flex-direction: column;
width: 100%;
}
.widget__container {
align-items: center;
box-sizing: border-box;
display: flex;
flex-direction: column;
height: 100%;
margin: auto 0;
}
.widget__inner-container {
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
height: 100%; height: 100%;
width: 100%;
} }
.widget__noscript-container { .widget__noscript-container {
@ -110,3 +126,19 @@
font-size: 0.5rem; font-size: 0.5rem;
margin: 2px; margin: 2px;
} }
/* progress bar courtesy of https://codepen.io/Bizzy-Coding/pen/poOymVJ?editors=1111 */
.progress__bar {
position: relative;
height: 5px;
width: 100%;
background: #fff;
border-radius: 15px;
}
.progress__fill {
background: #65a2e0;
border-radius: 15px;
height: 100%;
width: 0%;
}

View file

@ -3,7 +3,7 @@
// //
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
import { gen_pow } from "@mcaptcha/pow-wasm"; import { stepped_gen_pow } from "@mcaptcha/pow-wasm";
import * as p from "@mcaptcha/pow_sha256-polyfill"; import * as p from "@mcaptcha/pow_sha256-polyfill";
import { WasmWork, PoWConfig, SubmitWork } from "./types"; import { WasmWork, PoWConfig, SubmitWork } from "./types";
@ -12,19 +12,25 @@ import { WasmWork, PoWConfig, SubmitWork } from "./types";
* @param {PoWConfig} config - the proof-of-work configuration using which * @param {PoWConfig} config - the proof-of-work configuration using which
* work needs to be computed * work needs to be computed
* */ * */
const prove = async (config: PoWConfig): Promise<SubmitWork> => { const prove = async (
config: PoWConfig,
progress: (nonce: number) => void
): Promise<SubmitWork> => {
const WASM = "wasm"; const WASM = "wasm";
const JS = "js"; const JS = "js";
const STEPS = 5000;
if (WasmSupported) { if (WasmSupported) {
let proof: WasmWork = null; let proof: WasmWork = null;
let res: SubmitWork = null; let res: SubmitWork = null;
let time: number = null; let time: number = null;
const t0 = performance.now(); const t0 = performance.now();
const proofString = gen_pow( const proofString = stepped_gen_pow(
config.salt, config.salt,
config.string, config.string,
config.difficulty_factor config.difficulty_factor,
STEPS,
progress
); );
const t1 = performance.now(); const t1 = performance.now();
time = t1 - t0; time = t1 - t0;
@ -47,10 +53,12 @@ const prove = async (config: PoWConfig): Promise<SubmitWork> => {
const t0 = performance.now(); const t0 = performance.now();
proof = await p.generate_work( proof = await p.stepped_generate_work(
config.salt, config.salt,
config.string, config.string,
config.difficulty_factor config.difficulty_factor,
STEPS,
progress
); );
const t1 = performance.now(); const t1 = performance.now();
time = t1 - t0; time = t1 - t0;

View file

@ -6,17 +6,31 @@
import log from "../logger"; import log from "../logger";
import prove from "./prove"; import prove from "./prove";
import { PoWConfig, ServiceWorkerWork } from "./types"; import { PoWConfig, ServiceWorkerMessage, ServiceWorkerWork } from "./types";
log.log("worker registered"); log.log("worker registered");
onmessage = async (e) => { onmessage = async (e) => {
console.debug("message received at worker"); console.debug("message received at worker");
const config: PoWConfig = e.data; const config: PoWConfig = e.data;
const work = await prove(config); const progressCallback = (nonce: number) => {
const res: ServiceWorkerWork = { const res: ServiceWorkerMessage = {
type: "progress",
nonce: nonce,
};
postMessage(res);
};
const work = await prove(config, progressCallback);
const w: ServiceWorkerWork = {
work, work,
}; };
const res: ServiceWorkerMessage = {
type: "work",
value: w,
};
postMessage(res); postMessage(res);
}; };

View file

@ -32,8 +32,13 @@ export type PoWConfig = {
string: string; string: string;
difficulty_factor: number; difficulty_factor: number;
salt: string; salt: string;
max_recorded_nonce: number;
}; };
export type Token = { export type Token = {
token: string; token: string;
}; };
export type ServiceWorkerMessage =
| { type: "work"; value: ServiceWorkerWork }
| { type: "progress"; nonce: number };

View file

@ -631,15 +631,15 @@
resolved "https://registry.yarnpkg.com/@mcaptcha/core-glue/-/core-glue-0.1.0-rc1.tgz#76d665a3fc537062061e12e274f969ac3e053685" resolved "https://registry.yarnpkg.com/@mcaptcha/core-glue/-/core-glue-0.1.0-rc1.tgz#76d665a3fc537062061e12e274f969ac3e053685"
integrity sha512-P4SgUioJDR38QpnP9sPY72NyaYex8MXD6RbzrfKra+ngamT26XjqVZEHBiZU2RT7u0SsWhuko4N1ntNOghsgpg== integrity sha512-P4SgUioJDR38QpnP9sPY72NyaYex8MXD6RbzrfKra+ngamT26XjqVZEHBiZU2RT7u0SsWhuko4N1ntNOghsgpg==
"@mcaptcha/pow-wasm@^0.1.0-rc1": "@mcaptcha/pow-wasm@^0.1.0-rc2":
version "0.1.0-rc1" version "0.1.0-rc2"
resolved "https://registry.yarnpkg.com/@mcaptcha/pow-wasm/-/pow-wasm-0.1.0-rc1.tgz#eef8409e0c74e9c7261587bdebd80a8c4af92f9e" resolved "https://registry.yarnpkg.com/@mcaptcha/pow-wasm/-/pow-wasm-0.1.0-rc2.tgz#c7aaa678325600a178b11a702e2aeb9f8143e605"
integrity sha512-7+PGKoe1StFRsa9TEqztzK4/obbdY4OfavFX+geTk8b3K26D+eHPyimJ9BPlpI1VZl8ujR3CnbfbnQSRaqS7ZQ== integrity sha512-2G0nQ2GQWECRcE5kzfULDsQ032s6/PDzE1rncMdQAR1Mu2YQfFZHgnX4zLJmQnjKIhy9meIjXvatVSyIllrbtg==
"@mcaptcha/pow_sha256-polyfill@^0.1.0-rc1": "@mcaptcha/pow_sha256-polyfill@^0.1.0-rc2":
version "0.1.0-rc1" version "0.1.0-rc2"
resolved "https://registry.yarnpkg.com/@mcaptcha/pow_sha256-polyfill/-/pow_sha256-polyfill-0.1.0-rc1.tgz#dfeee88f5f6fd99aeae65dbcff6fbb09fe8a1696" resolved "https://registry.yarnpkg.com/@mcaptcha/pow_sha256-polyfill/-/pow_sha256-polyfill-0.1.0-rc2.tgz#253320e7a6666e395ef9dfb123d1102066d72b87"
integrity sha512-OFA4W3/vh8ORUnifbm8c/8eP22CbiXr4Un6/l4fMyqLj1aoQLMGAiuqab0trGqBnY0DU2bwTMyxflx26/cWgIw== integrity sha512-ERIbxIo+ZnQKtti/T4FLmcY0neuc5R05L97qYc62Hm++i+3dx/W6A8oC4V9U0XKCPYnHZFoZozAZlbsGXjrsVQ==
"@mcaptcha/vanilla-glue@^0.1.0-rc1": "@mcaptcha/vanilla-glue@^0.1.0-rc1":
version "0.1.0-rc1" version "0.1.0-rc1"