From 0293ae300a7a62bc3a6c624d1a34dd5722066bcf Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sun, 10 Nov 2024 02:42:30 -0800 Subject: [PATCH] Refactor pool and ckd. --- package.json | 2 +- src/lib/ckd.ts | 7 ++---- src/lib/pool.ts | 54 ++++++++++++++++++++++++++++------------------- src/lib/wallet.ts | 34 +++++++++++++++++------------ 4 files changed, 56 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index 61389ae..7dee5a7 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "url": "git+https://zoso.dev/libnemo.git" }, "scripts": { - "build": "rm -rf dist && tsc && esbuild main.min=dist/main.js global.min=dist/global.js --outdir=dist --target=es2022 --format=esm --platform=node --bundle --minify --sourcemap", + "build": "rm -rf dist && tsc && esbuild main.min=dist/main.js global.min=dist/global.js --outdir=dist --target=es2022 --format=esm --platform=browser --bundle --minify --sourcemap", "test": "npm run build && node --test --env-file .env", "test:coverage": "npm run test -- --experimental-test-coverage", "test:coverage:report": "npm run test:coverage -- --test-reporter=lcov --test-reporter-destination=coverage.info && genhtml coverage.info --output-directory test/coverage && rm coverage.info && xdg-open test/coverage/index.html" diff --git a/src/lib/ckd.ts b/src/lib/ckd.ts index 29864fc..f7e2d05 100644 --- a/src/lib/ckd.ts +++ b/src/lib/ckd.ts @@ -13,10 +13,7 @@ import type { Ledger } from './ledger.js' * @param {number} index - Index of the account * @returns {Promise} */ -globalThis.onmessage = async (event) => { - console.log('ckd') - console.dir(event) - console.dir(event.data) +onmessage = async (event) => { let result = null const { type, seed, index } = event.data switch (type) { @@ -33,7 +30,7 @@ globalThis.onmessage = async (event) => { break } } - globalThis.postMessage(result) + postMessage(result) } /** diff --git a/src/lib/pool.ts b/src/lib/pool.ts index 3829e2c..d98f7bc 100644 --- a/src/lib/pool.ts +++ b/src/lib/pool.ts @@ -1,21 +1,18 @@ // SPDX-FileCopyrightText: 2024 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -const Worker = globalThis.Worker ?? (await import('node:worker_threads')).Worker +type Task = { + data: object, + resolve: Function +} class Thread { + isAvailable: boolean worker: Worker - tasks: any[] - get isAvailable () { return this.tasks.length === 0 } constructor (url: string | URL) { + this.isAvailable = true this.worker = new Worker(new URL(url, import.meta.url)) - this.worker.addEventListener('message', (event) => { - if (this.tasks.length > 0) { - this.worker.postMessage(this.tasks.shift()) - } - }) - this.tasks = new Array() } } @@ -28,27 +25,40 @@ class Thread { * @returns {boolean} True if the data was signed by the public key's matching private key */ export class Pool { - #threads: Thread[] = new Array() + #tasks: any[] + #threads: Thread[] #url constructor (url: string | URL) { + this.#tasks = [] this.#url = new URL(url, import.meta.url) - this.#threads = [...Array(navigator.hardwareConcurrency)] - this.#threads = this.#threads.map(() => { return new Thread(this.#url) }) + this.#threads = Array(navigator.hardwareConcurrency) + .fill(undefined) + .map(() => { return new Thread(this.#url) }) } async work (data: object): Promise { - const thread = this.#threads.reduce((curr, next) => { - return (next.tasks.length < curr.tasks.length) - ? next - : curr - }) - thread.tasks.push(data) - thread.worker.postMessage(thread.tasks.shift()) return new Promise(resolve => { - thread.worker.addEventListener('message', (event: any) => { - resolve(event.data) - }, { once: true }) + const thread = this.#threads.find(t => t.isAvailable) + if (thread) { + this.assign(thread, { data, resolve }) + } else { + this.#tasks.push({ data, resolve }) + } }) } + + assign (thread: Thread, task: Task) { + thread.isAvailable = false + thread.worker.addEventListener('message', (event) => { + if (this.#tasks.length > 0) { + const task = this.#tasks.shift() + this.assign(thread, task.data) + } else { + thread.isAvailable = true + } + task.resolve(event.data) + }, { once: true }) + thread.worker.postMessage(task.data) + } } diff --git a/src/lib/wallet.ts b/src/lib/wallet.ts index 0d4aed0..08bb55a 100644 --- a/src/lib/wallet.ts +++ b/src/lib/wallet.ts @@ -7,13 +7,13 @@ import { nanoCKD } from './bip32-key-derivation.js' import { ADDRESS_GAP, SEED_LENGTH_BIP44, SEED_LENGTH_BLAKE2B } from './constants.js' import { bytes, dec } from './convert.js' import { Entropy } from './entropy.js' -import { Pool } from './pool.js' +// import { Pool } from './pool.js' import { Rpc } from './rpc.js' import { Safe } from './safe.js' import Tools from './tools.js' import type { Ledger } from './ledger.js' -const ckdPool = new Pool('./ckd.js') +// const ckdPool = new Pool('./ckd.js') /** * Represents a wallet containing numerous Nano accounts derived from a single @@ -72,19 +72,22 @@ abstract class Wallet { from = to to = swap } - const accounts: Account[] = [] + const accountQueue = Array(to + 1) for (let i = from; i <= to; i++) { - if (this.#accounts[i]) { - accounts.push(this.#accounts[i]) - } else { - const account = await this.ckd(i) - if (account != null) { - this.#accounts[i] = account - accounts.push(account) + if (this.#accounts[i] == null) { + accountQueue[i] = this.ckd(i) + } + } + if (accountQueue.length > 0) { + const results = await Promise.allSettled(accountQueue) + for (let i = results.length - 1; i >= 0; i--) { + const result = results[i] as PromiseFulfilledResult + if (result?.value != null) { + this.#accounts[i] = result.value } } } - return accounts + return this.#accounts.slice(from, to + 1) } /** @@ -400,7 +403,9 @@ export class Bip44Wallet extends Wallet { * @returns {Promise} */ async ckd (index: number): Promise { - return await ckdPool.work({ type: 'bip44', seed: this.seed, index }) + const key = await nanoCKD(this.seed, index) + return await Account.fromPrivateKey(key, index) + // return await ckdPool.work({ type: 'bip44', seed: this.seed, index }) } } @@ -541,7 +546,10 @@ export class Blake2bWallet extends Wallet { * @returns {Promise} */ async ckd (index: number): Promise { - return await ckdPool.work({ type: 'blake2b', seed: this.seed, index }) + const hash = await Tools.blake2b([this.seed, dec.toHex(index, 4)]) + const key = bytes.toHex(hash) + return await Account.fromPrivateKey(key, index) + // return await ckdPool.work({ type: 'blake2b', seed: this.seed, index }) } } -- 2.34.1