]> zoso.dev Git - libnemo.git/commitdiff
Refactor pool and ckd.
authorChris Duncan <chris@zoso.dev>
Sun, 10 Nov 2024 10:42:30 +0000 (02:42 -0800)
committerChris Duncan <chris@zoso.dev>
Sun, 10 Nov 2024 10:42:30 +0000 (02:42 -0800)
package.json
src/lib/ckd.ts
src/lib/pool.ts
src/lib/wallet.ts

index 61389ae17c4b6b9b4b9ca871a4a49550e4410995..7dee5a72231f659ce0155f8d152534618996d63c 100644 (file)
@@ -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"
index 29864fc406f763fbb0c7a3a472d9c089bc8155a7..f7e2d050d9ee7c7b6fe4baabb7e8131c70c804c4 100644 (file)
@@ -13,10 +13,7 @@ import type { Ledger } from './ledger.js'
 * @param {number} index - Index of the account
 * @returns {Promise<Account>}
 */
-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)
 }
 
 /**
index 3829e2cadd8bb9d1ce1033ef21b580e7747b5c1c..d98f7bc87d8cf9d41bd3398be57b0c20619c6919 100644 (file)
@@ -1,21 +1,18 @@
 // SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>
 // 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<any> {
-               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)
+       }
 }
index 0d4aed030f65b50039c54c4610359e6208186663..08bb55a940f6bfe7f92309b3ebf53aa2f37396ea 100644 (file)
@@ -7,13 +7,13 @@ import { nanoCKD } from './bip32-key-derivation.js'
 import { ADDRESS_GAP, SEED_LENGTH_BIP44, SEED_LENGTH_BLAKE2B } from './constants.js'\r
 import { bytes, dec } from './convert.js'\r
 import { Entropy } from './entropy.js'\r
-import { Pool } from './pool.js'\r
+// import { Pool } from './pool.js'\r
 import { Rpc } from './rpc.js'\r
 import { Safe } from './safe.js'\r
 import Tools from './tools.js'\r
 import type { Ledger } from './ledger.js'\r
 \r
-const ckdPool = new Pool('./ckd.js')\r
+// const ckdPool = new Pool('./ckd.js')\r
 \r
 /**\r
 * Represents a wallet containing numerous Nano accounts derived from a single\r
@@ -72,19 +72,22 @@ abstract class Wallet {
                        from = to\r
                        to = swap\r
                }\r
-               const accounts: Account[] = []\r
+               const accountQueue = Array(to + 1)\r
                for (let i = from; i <= to; i++) {\r
-                       if (this.#accounts[i]) {\r
-                               accounts.push(this.#accounts[i])\r
-                       } else {\r
-                               const account = await this.ckd(i)\r
-                               if (account != null) {\r
-                                       this.#accounts[i] = account\r
-                                       accounts.push(account)\r
+                       if (this.#accounts[i] == null) {\r
+                               accountQueue[i] = this.ckd(i)\r
+                       }\r
+               }\r
+               if (accountQueue.length > 0) {\r
+                       const results = await Promise.allSettled(accountQueue)\r
+                       for (let i = results.length - 1; i >= 0; i--) {\r
+                               const result = results[i] as PromiseFulfilledResult<Account>\r
+                               if (result?.value != null) {\r
+                                       this.#accounts[i] = result.value\r
                                }\r
                        }\r
                }\r
-               return accounts\r
+               return this.#accounts.slice(from, to + 1)\r
        }\r
 \r
        /**\r
@@ -400,7 +403,9 @@ export class Bip44Wallet extends Wallet {
        * @returns {Promise<Account>}\r
        */\r
        async ckd (index: number): Promise<Account> {\r
-               return await ckdPool.work({ type: 'bip44', seed: this.seed, index })\r
+               const key = await nanoCKD(this.seed, index)\r
+               return await Account.fromPrivateKey(key, index)\r
+               // return await ckdPool.work({ type: 'bip44', seed: this.seed, index })\r
        }\r
 }\r
 \r
@@ -541,7 +546,10 @@ export class Blake2bWallet extends Wallet {
        * @returns {Promise<Account>}\r
        */\r
        async ckd (index: number): Promise<Account> {\r
-               return await ckdPool.work({ type: 'blake2b', seed: this.seed, index })\r
+               const hash = await Tools.blake2b([this.seed, dec.toHex(index, 4)])\r
+               const key = bytes.toHex(hash)\r
+               return await Account.fromPrivateKey(key, index)\r
+               // return await ckdPool.work({ type: 'blake2b', seed: this.seed, index })\r
        }\r
 }\r
 \r