feat: progress bar and incremental PoW generation
This commit is contained in:
parent
ad4582cc16
commit
9dfb0713ad
8 changed files with 221 additions and 137 deletions
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"); .>
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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%;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue