diff --git a/solver/bun.lock b/solver/bun.lock new file mode 100644 index 0000000..212c30e --- /dev/null +++ b/solver/bun.lock @@ -0,0 +1,14 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "@cap.js/solver", + "dependencies": { + "@cap.js/wasm": "^0.0.3", + }, + }, + }, + "packages": { + "@cap.js/wasm": ["@cap.js/wasm@0.0.3", "", {}, "sha512-1HqjjRjHSD+2pnNj5yziCb9LfrVDsPWGV+Mr6epRag0o3nAhgEGC+AopQV01BV61BVjEQbhgyjNJBV+1Gc/SGw=="], + } +} diff --git a/solver/example.js b/solver/example.js index f0bb688..9d8fd46 100644 --- a/solver/example.js +++ b/solver/example.js @@ -18,7 +18,7 @@ const CHALLENGES = [ ["308758072931bb3b254a7b1ed351d04a", "3e49"], ["724f89bb167db4b881e1dc7b0949ac8f", "b82e"], ["8b79506e4630de15be225c18623eff65", "f0e5"], - ["0c21ade6e63a4e37b13cb8b087f31863", "65c9e"], + ["0c21ade6e63a4e37b13cb8b087f31863", "65c9"], ]; const timeStart = new Date().getTime(); diff --git a/solver/index.js b/solver/index.js index 7af072c..9ca3927 100644 --- a/solver/index.js +++ b/solver/index.js @@ -1,61 +1,58 @@ import { Worker } from "worker_threads"; import os from "os"; +import { performance } from "perf_hooks"; const workerBlob = new Blob( [ ` -import crypto from "crypto"; import { parentPort, workerData } from "worker_threads"; +import { solve_pow } from "@cap.js/wasm"; -const { salt, target } = workerData; +const { salt, target, challengeIndex } = workerData; -const saltBuffer = Buffer.from(salt); -const targetLen = target.length; -const targetBytes = Math.ceil(targetLen / 2); - -let nonce = 0; - -while (true) { - const nonceStr = nonce.toString(); - - const hash = crypto.createHash("sha256"); - - hash.update(saltBuffer); - hash.update(nonceStr); - - const hashBuffer = hash.digest(); - - const hashPrefixHex = hashBuffer.toString("hex", 0, targetBytes); - - if (hashPrefixHex.startsWith(target)) { - parentPort.postMessage({ - nonce: Number(nonce), - salt, - target, - }); - break; - } - - nonce++; -}`, +try { + const startTime = performance.now(); + const nonce = solve_pow(salt, target); + const endTime = performance.now(); + const duration = (endTime - startTime) / 1000; // seconds + + parentPort.postMessage({ + nonce, + salt, + target, + challengeIndex, + duration + }); +} catch (error) { + parentPort.postMessage({ + error: error.message, + salt, + target, + challengeIndex + }); +} +`, ], { type: "application/typescript", } ); + const workerUrl = URL.createObjectURL(workerBlob); -export default function solver(challenges, config) { +export default function wasmSolver(challenges, config = {}) { const totalChallenges = challenges.length; const numWorkers = - config?.workerCount || Math.min(totalChallenges, 14, os.cpus().length); + config?.workerCount || Math.min(totalChallenges, os.cpus().length); let challengesProcessed = 0; let nextChallengeIndex = 0; let activeWorkers = 0; - const results = []; + const results = new Array(totalChallenges); + + return new Promise((resolve, reject) => { + const startTime = performance.now(); - return new Promise((resolve) => { function startWorker() { if (nextChallengeIndex < totalChallenges && activeWorkers < numWorkers) { const currentChallengeIndex = nextChallengeIndex; @@ -68,25 +65,50 @@ export default function solver(challenges, config) { }); worker.on("message", (result) => { - results.push([result.salt, result.target, result.nonce]); - challengesProcessed++; + worker.terminate(); activeWorkers--; + if (result.error) { + console.error( + `Error in worker for challenge ${currentChallengeIndex}:`, + result.error + ); + reject(new Error(`Worker error: ${result.error}`)); + return; + } + + results[result.challengeIndex] = [ + result.salt, + result.target, + result.nonce, + ]; + challengesProcessed++; + if (config?.onProgress) { config.onProgress({ - progress: Math.floor((challengesProcessed / totalChallenges) * 100), + progress: Math.floor( + (challengesProcessed / totalChallenges) * 100 + ), currentChallenge: currentChallengeIndex, challengesProcessed, + totalChallenges, result, }); } if (challengesProcessed === totalChallenges) { - resolve(results); + resolve(results.filter(Boolean)); } else { startWorker(); } }); + + worker.on("error", (err) => { + console.error(`Worker error:`, err); + worker.terminate(); + activeWorkers--; + reject(err); + }); } } diff --git a/solver/package.json b/solver/package.json index a6560d1..ceb3d03 100644 --- a/solver/package.json +++ b/solver/package.json @@ -226,5 +226,8 @@ "bugs": { "url": "https://github.com/tiagorangel1/cap/issues" }, - "homepage": "https://github.com/tiagorangel1/cap#readme" + "homepage": "https://github.com/tiagorangel1/cap#readme", + "dependencies": { + "@cap.js/wasm": "^0.0.3" + } }