From: Chris Duncan Date: Sun, 20 Jul 2025 10:31:43 +0000 (-0700) Subject: Refactor types for data passed to workers and reduce back to one parameter with buffe... X-Git-Tag: v0.10.5~55^2~57 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=e0763f6541c84b488d7d20bd91b68b20de5cbc58;p=libnemo.git Refactor types for data passed to workers and reduce back to one parameter with buffers extracted for transfer. Rename worker queue file for clarity. Get node test runner half working. --- diff --git a/src/lib/account.ts b/src/lib/account.ts index 8674c5e..7367d0f 100644 --- a/src/lib/account.ts +++ b/src/lib/account.ts @@ -6,7 +6,7 @@ import { ChangeBlock, ReceiveBlock, SendBlock } from './block' import { ACCOUNT_KEY_BYTE_LENGTH, ACCOUNT_KEY_HEX_LENGTH, ALPHABET, PREFIX, PREFIX_LEGACY } from './constants' import { base32, bytes, hex, utf8 } from './convert' import { Rpc } from './rpc' -import { Data, Key, KeyPair } from '#types' +import { Key, KeyPair, NamedData } from '#types' import { NanoNaClWorker, SafeWorker } from '#workers' /** @@ -253,15 +253,13 @@ export class Account { async sign (block: ChangeBlock | ReceiveBlock | SendBlock, password: Key): Promise { if (typeof password === 'string') password = utf8.toBytes(password) try { - const headers = { - method: 'detached' - } - const result = await NanoNaClWorker.assign(headers, { + const { signature } = await NanoNaClWorker.assign({ + method: 'detached', privateKey: (await this.#export(password)).buffer, msg: hex.toBytes(block.hash).buffer }) - block.signature = result - return result + block.signature = bytes.toHex(new Uint8Array(signature)) + return block.signature } catch (err) { throw new Error(`Failed to sign block`, { cause: err }) } finally { @@ -329,15 +327,13 @@ export class Account { throw new Error('Password must be string or bytes') } try { - const headers = { + const response = await SafeWorker.assign({ method: 'get', name: this.publicKey, - store: 'Account' - } - const response = await SafeWorker.assign(headers, { + store: 'Account', password: password.buffer }) - return new Uint8Array(response[this.publicKey] as ArrayBuffer) + return new Uint8Array(response[this.publicKey]) } catch (err) { throw new Error(`Failed to export private key for Account ${this.address}`, { cause: err }) } finally { @@ -361,7 +357,11 @@ export class Account { } const accounts: Account[] = [] - const privateAccounts: Data = {} + const privateAccounts: NamedData = { + method: 'set', + store: 'Account', + password: password.buffer + } for (let keypair of keypairs) { let { index, privateKey } = keypair if (index == null) { @@ -370,14 +370,13 @@ export class Account { this.#validateKey(privateKey) if (typeof privateKey === 'string') privateKey = hex.toBytes(privateKey) try { - const headers = { - method: 'convert' - } - const publicKey = await NanoNaClWorker.assign(headers, { + const result = await NanoNaClWorker.assign({ + method: 'convert', privateKey: new Uint8Array(privateKey).buffer }) - privateAccounts[publicKey] = privateKey.buffer - const address = this.#keyToAddress(hex.toBytes(publicKey)) + const publicKey = new Uint8Array(result.publicKey) + privateAccounts[bytes.toHex(publicKey)] = privateKey.buffer + const address = this.#keyToAddress(publicKey) this.#isInternal = true accounts.push(new this(address, publicKey, index)) } catch (err) { @@ -386,12 +385,7 @@ export class Account { } try { - const headers = { - method: 'set', - store: 'Account' - } - privateAccounts.password = password.buffer - const isLocked = await SafeWorker.assign(headers, privateAccounts) + const isLocked = await SafeWorker.assign(privateAccounts) if (!isLocked) { throw null } diff --git a/src/lib/blake2b.ts b/src/lib/blake2b.ts index b9e25df..c4f07a1 100644 --- a/src/lib/blake2b.ts +++ b/src/lib/blake2b.ts @@ -264,10 +264,10 @@ export class Blake2b { return this } - digest (): Uint8Array + digest (): Uint8Array digest (out: 'hex'): string - digest (out: 'binary' | Uint8Array): Uint8Array - digest (out?: 'binary' | 'hex' | Uint8Array): string | Uint8Array { + digest (out: 'binary' | Uint8Array): Uint8Array + digest (out?: 'binary' | 'hex' | Uint8Array): string | Uint8Array { const buf = (!out || out === 'binary' || out === 'hex') ? new Uint8Array(this.#outlen) : out if (!(buf instanceof Uint8Array)) throw new TypeError(`out must be "binary", "hex", Uint8Array, or Buffer`) if (buf.length < this.#outlen) throw new RangeError(`out must have at least outlen bytes of space`) diff --git a/src/lib/block.ts b/src/lib/block.ts index 1eec2c9..bc2d2b6 100644 --- a/src/lib/block.ts +++ b/src/lib/block.ts @@ -191,14 +191,13 @@ abstract class Block { throw new Error('Provide a key for block signature verification.') } try { - const headers = { - method: 'verify' - } - return await NanoNaClWorker.assign(headers, { + const { isVerified } = await NanoNaClWorker.assign({ + method: 'verify', msg: hex.toBytes(this.hash).buffer, signature: hex.toBytes(this.signature ?? '').buffer, publicKey: hex.toBytes(key).buffer }) + return isVerified } catch (err) { throw new Error(`Failed to derive public key from private key`, { cause: err }) } diff --git a/src/lib/rpc.ts b/src/lib/rpc.ts index be6fc4c..1fc8d25 100644 --- a/src/lib/rpc.ts +++ b/src/lib/rpc.ts @@ -19,12 +19,13 @@ export class Rpc { } /** - * - * @param {string} action - Nano protocol RPC call to execute - * @param {object} [data] - JSON to send to the node as defined by the action - * @returns {Promise} JSON-formatted RPC results from the node - */ - async call (action: string, data?: { [key: string]: any }): Promise { + * Sends a nano RPC call to a node endpoint. + * + * @param {string} action - Nano protocol RPC call to execute + * @param {object} [data] - JSON to send to the node as defined by the action + * @returns {Promise} JSON-formatted RPC results from the node + */ + async call (action: string, data?: { [key: string]: unknown }): Promise { var process: any = process || null this.#validate(action) const headers: { [key: string]: string } = {} diff --git a/src/lib/tools.ts b/src/lib/tools.ts index eeeaac2..a61bece 100644 --- a/src/lib/tools.ts +++ b/src/lib/tools.ts @@ -17,7 +17,8 @@ type SweepResult = { message: string } -function hash (data: string | string[], encoding?: 'hex', format?: 'hex'): string | Uint8Array { +function hash (data: string | string[], encoding?: 'hex'): Uint8Array +function hash (data: string | string[], encoding?: 'hex', format?: 'hex'): string | Uint8Array { if (!Array.isArray(data)) data = [data] const hash = new Blake2b(32) if (encoding === 'hex') { @@ -90,15 +91,13 @@ export async function convert (amount: bigint | string, inputUnit: string, outpu */ export async function sign (key: Key, ...input: string[]): Promise { if (typeof key === 'string') key = hex.toBytes(key) - let signature: string try { - const headers = { - method: 'detached' - } - return await NanoNaClWorker.assign(headers, { + const { signature } = await NanoNaClWorker.assign({ + method: 'detached', privateKey: key.buffer, - msg: (hash(input) as Uint8Array).buffer + msg: hash(input).buffer }) + return bytes.toHex(new Uint8Array(signature)) } catch (err) { throw new Error(`Failed to sign message with private key`, { cause: err }) } finally { @@ -178,14 +177,13 @@ export async function sweep ( export async function verify (key: Key, signature: string, ...input: string[]): Promise { if (typeof key === 'string') key = hex.toBytes(key) try { - const headers = { - method: 'verify' - } - return await NanoNaClWorker.assign(headers, { - msg: (hash(input) as Uint8Array).buffer, + const { isVerified } = await NanoNaClWorker.assign({ + method: 'verify', + msg: hash(input).buffer, signature: hex.toBytes(signature).buffer, publicKey: new Uint8Array(key).buffer }) + return isVerified } catch (err) { throw new Error('Failed to verify signature', { cause: err }) } finally { diff --git a/src/lib/wallets/bip44-wallet.ts b/src/lib/wallets/bip44-wallet.ts index 8ea9276..1a1e368 100644 --- a/src/lib/wallets/bip44-wallet.ts +++ b/src/lib/wallets/bip44-wallet.ts @@ -212,10 +212,8 @@ export class Bip44Wallet extends Wallet { * @returns {Promise} */ async ckd (indexes: number[]): Promise { - const headers = { - indexes - } - const results = await Bip44CkdWorker.assign(headers, { + const results = await Bip44CkdWorker.assign({ + indexes, seed: hex.toBytes(this.seed).buffer }) const privateKeys: KeyPair[] = [] diff --git a/src/lib/wallets/wallet.ts b/src/lib/wallets/wallet.ts index d6069b4..f14029b 100644 --- a/src/lib/wallets/wallet.ts +++ b/src/lib/wallets/wallet.ts @@ -7,7 +7,7 @@ import { ADDRESS_GAP } from '#src/lib/constants.js' import { bytes, hex, utf8 } from '#src/lib/convert.js' import { Entropy } from '#src/lib/entropy.js' import { Rpc } from '#src/lib/rpc.js' -import { Key, KeyPair } from '#types' +import { Key, KeyPair, NamedData } from '#types' import { SafeWorker } from '#workers' /** @@ -146,6 +146,7 @@ export abstract class Wallet { method: 'destroy', name: this.id }) + // NODE: await SafeWorker.assign({ method: 'STOP' }) } /** @@ -169,11 +170,9 @@ export abstract class Wallet { seed: this.seed }) const encoded = utf8.toBytes(serialized) - const headers = { + const success = await SafeWorker.assign({ method: 'set', - store: 'Wallet' - } - const success = await SafeWorker.assign(headers, { + store: 'Wallet', [this.id]: encoded.buffer, password: password.buffer }) @@ -232,15 +231,13 @@ export abstract class Wallet { throw new Error('Failed to unlock wallet') } try { - const headers = { + const response = await SafeWorker.assign({ method: 'get', name: this.id, store: 'Wallet', - } - const response = await SafeWorker.assign(headers, { password: password.buffer }) - const decoded = bytes.toUtf8(response[this.id]) + const decoded = bytes.toUtf8(new Uint8Array(response[this.id])) const deserialized = JSON.parse(decoded) let { id, mnemonic, seed } = deserialized if (id == null) { diff --git a/src/lib/workers/bip44-ckd.ts b/src/lib/workers/bip44-ckd.ts index 2076cca..da67264 100644 --- a/src/lib/workers/bip44-ckd.ts +++ b/src/lib/workers/bip44-ckd.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later import { WorkerInterface } from './worker-interface' -import { Data, Headers } from '#types' +import { Data, NamedData } from '#types' type ExtendedKey = { privateKey: DataView @@ -19,14 +19,22 @@ export class Bip44Ckd extends WorkerInterface { this.listen() } - static async work (headers: Headers, data: Data): Promise { - let { coin, indexes } = headers - let { seed } = data - if (coin != null && (typeof coin !== 'number' || !Number.isInteger(coin))) { + static async work (data: NamedData): Promise> { + if (data.coin != null && (typeof data.coin !== 'number' || !Number.isInteger(data.coin))) { throw new TypeError('BIP-44 coin derivation level must be an integer') } - if (!Array.isArray(indexes)) indexes = [indexes] - const privateKeys: Data = {} + if (!Array.isArray(data.indexes) || data.indexes.some(i => !Number.isInteger(i))) { + throw new TypeError('BIP-44 account indexes must be an array of integers') + } + if (!(data.seed instanceof ArrayBuffer)) { + throw new TypeError('BIP-44 seed must be an ArrayBuffer') + } + const coin: number = data.coin + const indexes = Array.isArray(data.indexes) + ? data.indexes + : [data.indexes] + const seed = data.seed + const privateKeys: NamedData = {} for (const i of indexes) { if (typeof i !== 'number' || !Number.isInteger(i)) { throw new TypeError('BIP-44 account derivation level must be an integer') diff --git a/src/lib/workers/index.ts b/src/lib/workers/index.ts index e363171..2b8c811 100644 --- a/src/lib/workers/index.ts +++ b/src/lib/workers/index.ts @@ -1,4 +1,4 @@ // SPDX-FileCopyrightText: 2025 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -export { Bip44CkdWorker, NanoNaClWorker, SafeWorker } from './queue' +export { Bip44CkdWorker, NanoNaClWorker, SafeWorker } from './worker-queue' diff --git a/src/lib/workers/nano-nacl.ts b/src/lib/workers/nano-nacl.ts index d6b1ed1..58c7616 100644 --- a/src/lib/workers/nano-nacl.ts +++ b/src/lib/workers/nano-nacl.ts @@ -6,7 +6,7 @@ import { WorkerInterface } from './worker-interface' import { Blake2b } from '#src/lib/blake2b.js' import { default as Convert, bytes, hex } from '#src/lib/convert.js' -import { Data, Headers, Key } from '#types' +import { Data, NamedData, Key } from '#types' /** * Ported in 2014 by Dmitry Chestnykh and Devi Mandiri. @@ -26,8 +26,16 @@ export class NanoNaCl extends WorkerInterface { this.listen() } - static async work (headers: Headers, data: Data): Promise { - const { method } = headers + static async work (data: NamedData): Promise { + if (typeof data.method !== 'string' + || !(data.msg == null || data.msg instanceof ArrayBuffer) + || !(data.privateKey == null || data.privateKey instanceof ArrayBuffer) + || !(data.publicKey == null || data.publicKey instanceof ArrayBuffer) + || !(data.signature == null || data.signature instanceof ArrayBuffer) + ) { + throw new TypeError('Invalid NanoNaCl input') + } + const method = data.method const msg = new Uint8Array(data.msg) const privateKey = new Uint8Array(data.privateKey) const publicKey = new Uint8Array(data.publicKey) @@ -35,13 +43,13 @@ export class NanoNaCl extends WorkerInterface { try { switch (method) { case 'convert': { - return bytes.toHex(await this.convert(privateKey)) + return { publicKey: (await this.convert(privateKey)).buffer } } case 'detached': { - return bytes.toHex(await this.detached(msg, privateKey)) + return { signature: (await this.detached(msg, privateKey)).buffer } } case 'verify': { - return await this.verify(msg, signature, publicKey) + return { isVerified: await this.verify(msg, signature, publicKey) } } default: { throw new TypeError(`unknown NanoNaCl method ${method}`) diff --git a/src/lib/workers/safe.ts b/src/lib/workers/safe.ts index 824599e..5ddbb8b 100644 --- a/src/lib/workers/safe.ts +++ b/src/lib/workers/safe.ts @@ -7,7 +7,7 @@ import { WorkerInterface } from './worker-interface' import { PBKDF2_ITERATIONS } from '#src/lib/constants.js' import { default as Convert, bytes } from '#src/lib/convert.js' import { Entropy } from '#src/lib/entropy.js' -import { Data, Headers, SafeRecord } from '#types' +import { NamedData, SafeRecord } from '#types' /** * Encrypts and stores data in the browser using IndexedDB. @@ -22,25 +22,33 @@ export class Safe extends WorkerInterface { this.listen() } - static async work (headers: Headers, data: Data): Promise { - const { method, name, store } = headers - const password = data?.password - if (data != null) delete data.password + static async work (data: NamedData): Promise> { + const { method, name, store } = data + if (typeof method !== 'string') { + throw new TypeError('Invalid method') + } + delete data.method + if (name != null && typeof name !== 'string') { + throw new TypeError('Invalid name') + } + delete data.name + if (typeof store !== 'string') { + throw new TypeError('Invalid store') + } + delete data.store + const password = data.password + delete data.password this.#storage = await this.#open(this.DB_NAME) - let result try { switch (method) { case 'set': { - result = await this.set(data, store, password) - break + return { result: await this.set(data, store, password) } } case 'get': { - result = await this.get(name, store, password) - break + return await this.get(name, store, password) } case 'destroy': { - result = await this.destroy(name, store) - break + return { result: await this.destroy(name, store) } } default: { throw new Error(`unknown Safe method ${method}`) @@ -50,7 +58,6 @@ export class Safe extends WorkerInterface { console.log(err) throw new Error('Safe error', { cause: err }) } - return result } /** @@ -68,7 +75,7 @@ export class Safe extends WorkerInterface { /** * Encrypts data with a password byte array and stores it in the Safe. */ - static async set (data: Data | unknown, store: string | unknown, password: ArrayBuffer | unknown): Promise { + static async set (data: NamedData | unknown, store: string | unknown, password: ArrayBuffer | unknown): Promise { this.#isDataValid(data) if (typeof store !== 'string' || store === '') { throw new Error('Invalid database store name') @@ -103,7 +110,7 @@ export class Safe extends WorkerInterface { /** * Retrieves data from the Safe and decrypts it with a password byte array. */ - static async get (name: string | string[] | unknown, store: string | unknown, password: ArrayBuffer | unknown): Promise { + static async get (name: string | string[] | unknown, store: string | unknown, password: ArrayBuffer | unknown): Promise> { const names = Array.isArray(name) ? name : [name] if (names.some(v => typeof v !== 'string')) { throw new Error('Invalid fields') @@ -116,7 +123,7 @@ export class Safe extends WorkerInterface { throw new Error('Invalid password') } - const results: Data = {} + const results: NamedData = {} try { const records: SafeRecord[] = await this.#get(fields, store) if (records == null || records.length === 0) { @@ -184,7 +191,7 @@ export class Safe extends WorkerInterface { }) } - static #isDataValid (data: unknown): asserts data is Data { + static #isDataValid (data: unknown): asserts data is { [key: string]: ArrayBuffer } { if (typeof data !== 'object') { throw new Error('Invalid data') } diff --git a/src/lib/workers/worker-interface.ts b/src/lib/workers/worker-interface.ts index 9b801e6..76b03d7 100644 --- a/src/lib/workers/worker-interface.ts +++ b/src/lib/workers/worker-interface.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later import { parentPort } from 'node:worker_threads' -import { Data, Headers } from '#types' +import { Data, NamedData } from '#types' /** * Provides basic worker event messaging to extending classes. @@ -32,22 +32,16 @@ export abstract class WorkerInterface { * function signature and providing their own processing call in the try-catch * block. * - * @param {Header} headers - Flat object of header data - * @param {Data} data - String keys for ArrayBuffer values to transfer and process + * @param {NamedData} data - Flat object of data key-value pairs * @returns Promise for processed data */ - static async work (headers: Headers | null, data?: Data): Promise { - return new Promise(async (resolve, reject): Promise => { + static work (data: NamedData): Promise { + return new Promise((resolve, reject): void => { try { - let x, y = new ArrayBuffer(0) - if (headers != null) { - const { sample } = headers - x = sample - } - if (data != null) { - const { buf } = data - y = buf + if (data == null) { + throw new Error('Missing data') } + const { x, y } = data resolve({ x, y }) } catch (err) { reject(err) @@ -58,15 +52,15 @@ export abstract class WorkerInterface { /** * Transfers buffers of worker results back to the main thread. * - * @param {Headers} results - Key-value pairs of processed data + * @param {NamedData} data - Key-value pairs of processed data */ - static report (results: Headers): void { + static report (data: NamedData): void { const buffers = [] try { - if (typeof results === 'object') { - for (const d of Object.keys(results)) { - if (results[d] instanceof ArrayBuffer) { - buffers.push(results[d]) + if (typeof data === 'object') { + for (const d of Object.keys(data)) { + if (data[d] instanceof ArrayBuffer) { + buffers.push(data[d]) } } } @@ -75,8 +69,8 @@ export abstract class WorkerInterface { throw new Error('Failed to report results', { cause: err }) } //@ts-expect-error - BROWSER: postMessage(results, buffers) - NODE: parentPort?.postMessage(results, buffers) + BROWSER: postMessage(data, buffers) + NODE: parentPort?.postMessage({ data }, buffers) } /** @@ -91,12 +85,14 @@ export abstract class WorkerInterface { */ static listen (): void { const listener = async (message: MessageEvent): Promise => { - const { name, headers, data } = message.data - if (name === 'STOP') { - close() + // console.log(message) + const { data } = message + if (data.method === 'STOP') { this.report({}) + BROWSER: close() + NODE: process.exit() } else { - this.work(headers, data).then(this.report).catch(this.report) + this.work(data).then(this.report).catch(this.report) } } BROWSER: addEventListener('message', listener) diff --git a/src/lib/workers/queue.ts b/src/lib/workers/worker-queue.ts similarity index 67% rename from src/lib/workers/queue.ts rename to src/lib/workers/worker-queue.ts index 5a49dac..6cea63b 100644 --- a/src/lib/workers/queue.ts +++ b/src/lib/workers/worker-queue.ts @@ -5,12 +5,11 @@ import { Worker as NodeWorker } from 'node:worker_threads' import { default as bip44 } from './bip44-ckd' import { default as nacl } from './nano-nacl' import { default as safe } from './safe' -import { Data, Headers } from '#types' +import { Data, NamedData } from '#types' type Task = { id: number - headers: Headers | null - data?: Data + data: NamedData reject: (value: any) => void resolve: (value: any) => void } @@ -18,9 +17,9 @@ type Task = { /** * Processes a queue of tasks using Web Workers. */ -export class Queue { - static #instances: Queue[] = [] - static get instances (): Queue[] { return this.#instances } +export class WorkerQueue { + static #instances: WorkerQueue[] = [] + static get instances (): WorkerQueue[] { return this.#instances } #job?: Task #isIdle: boolean @@ -50,15 +49,15 @@ export class Queue { NODE: this.#worker.on('message', message => { this.#report(message) }) - Queue.#instances.push(this) + WorkerQueue.#instances.push(this) } - async assign (headers: Headers | null, data?: Data): Promise { - return this.#assign(task => this.#queue.push(task), headers, data) + async assign (data: NamedData): Promise> { + return this.#assign(data, task => this.#queue.push(task)) } - async prioritize (headers: Headers | null, data?: Data): Promise { - return this.#assign(task => this.#queue.unshift(task), headers, data) + async prioritize (data: NamedData): Promise> { + return this.#assign(data, task => this.#queue.unshift(task)) } terminate (): void { @@ -66,11 +65,10 @@ export class Queue { this.#worker.terminate() } - async #assign (enqueue: (task: Task) => number, headers: Headers | null, data?: Data): Promise { + async #assign (data: NamedData, enqueue: (task: Task) => number): Promise> { return new Promise(async (resolve, reject): Promise => { const task: Task = { id: performance.now(), - headers, data, resolve, reject @@ -84,16 +82,16 @@ export class Queue { this.#job = this.#queue.shift() this.#isIdle = this.#job == null if (this.#job != null) { - const { id, headers, data, reject } = this.#job + const { data, reject } = this.#job try { const buffers: ArrayBuffer[] = [] - if (data != null) { - for (let d of Object.keys(data)) { + for (let d of Object.keys(data)) { + if (data[d] instanceof ArrayBuffer) { buffers.push(data[d]) } } - BROWSER: this.#worker.postMessage({ headers, data }, buffers) - NODE: this.#worker.postMessage({ data: { headers, data } }, buffers) + BROWSER: this.#worker.postMessage(data, buffers) + NODE: this.#worker.postMessage({ data }, buffers) } catch (err) { reject(err) } @@ -115,6 +113,6 @@ export class Queue { } } -export const Bip44CkdWorker = new Queue(bip44) -export const NanoNaClWorker = new Queue(nacl) -export const SafeWorker = new Queue(safe) +export const Bip44CkdWorker = new WorkerQueue(bip44) +export const NanoNaClWorker = new WorkerQueue(nacl) +export const SafeWorker = new WorkerQueue(safe) diff --git a/src/types.d.ts b/src/types.d.ts index 50a9415..d3a73b7 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -276,12 +276,10 @@ export declare class ChangeBlock extends Block { constructor (account: Account | string, balance: string, representative: Account | string, frontier: string, work?: string) } -export type Data = { - [key: string]: ArrayBuffer -} +export type Data = boolean | number[] | string | ArrayBuffer -export type Headers = { - [key: string]: any +export type NamedData = { + [key: string]: T } export type Key = string | Uint8Array @@ -304,8 +302,8 @@ export declare class Queue { * @param {number} [count=1] - Integer between 1 and CPU thread count shared among all Pools */ constructor (worker: string) - assign (headers: Headers | null, data?: Data): Promise - prioritize (headers: Headers | null, data?: Data): Promise + assign (data: NamedData): Promise + prioritize (data: NamedData): Promise terminate (): void } export declare const Bip44CkdWorker: Queue diff --git a/test/GLOBALS.mjs b/test/GLOBALS.mjs index ea87e35..96da91c 100644 --- a/test/GLOBALS.mjs +++ b/test/GLOBALS.mjs @@ -1,13 +1,12 @@ // SPDX-FileCopyrightText: 2025 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later +export { env } from '../env.mjs' import { Queue } from './QUEUE.mjs' -import { process } from '../env.mjs' const queue = new Queue() -export { process } -export const isNode = process.versions?.node != null +export const isNode = globalThis !== globalThis.window let NodeTestSuite, NodeTestTest if (isNode) { diff --git a/test/perf.account.js b/test/perf.account.js index e33296a..1e1b948 100644 --- a/test/perf.account.js +++ b/test/perf.account.js @@ -7,7 +7,7 @@ import { assert, stats, suite, test } from './GLOBALS.mjs' import { NANO_TEST_VECTORS } from './VECTORS.js' import { Bip44Wallet, Blake2bWallet } from '../dist/main.min.js' -await suite('Account performance', async () => { +await suite('Account performance', { skip: true }, async () => { const COUNT = 0x200 await test(`Time to create ${COUNT} BIP-44 accounts`, async () => { @@ -18,7 +18,7 @@ await suite('Account performance', async () => { const end = performance.now() console.log(`Total: ${end - start} ms`) console.log(`Average: ${(end - start) / COUNT} ms`) - assert.equals(accounts.length, COUNT) + assert.equal(accounts.length, COUNT) await wallet.destroy() }) @@ -30,7 +30,7 @@ await suite('Account performance', async () => { const end = performance.now() console.log(`Total: ${end - start} ms`) console.log(`Average: ${(end - start) / COUNT} ms`) - assert.equals(accounts.length, COUNT) + assert.equal(accounts.length, COUNT) await wallet.destroy() }) diff --git a/test/perf.block.js b/test/perf.block.js index 567a29f..20b8350 100644 --- a/test/perf.block.js +++ b/test/perf.block.js @@ -3,11 +3,11 @@ 'use strict' -import { assert, stats, suite, test } from './GLOBALS.mjs' +import { stats, suite, test } from './GLOBALS.mjs' import { NANO_TEST_VECTORS } from './VECTORS.js' import { SendBlock } from '../dist/main.min.js' -await suite('Block performance', async () => { +await suite('Block performance', { skip: true }, async () => { const COUNT = 0x200 await test(`libnemo: Time to calculate proof-of-work for a send block ${COUNT} times`, { skip: true }, async () => { diff --git a/test/perf.wallet.js b/test/perf.wallet.js index e1dd75c..b58adc7 100644 --- a/test/perf.wallet.js +++ b/test/perf.wallet.js @@ -3,11 +3,11 @@ 'use strict' -import { assert, stats, suite, test } from './GLOBALS.mjs' +import { stats, suite, test } from './GLOBALS.mjs' import { NANO_TEST_VECTORS } from './VECTORS.js' import { Bip44Wallet, Blake2bWallet } from '../dist/main.min.js' -await suite(`Wallet performance`, async () => { +await suite(`Wallet performance`, { skip: true }, async () => { const COUNT = 0x20 await test(`Time to create ${COUNT} BIP-44 wallets`, async () => { diff --git a/test/test.calculate-pow.mjs b/test/test.calculate-pow.mjs index 2844d50..29b6bdb 100644 --- a/test/test.calculate-pow.mjs +++ b/test/test.calculate-pow.mjs @@ -3,11 +3,11 @@ 'use strict' -import { assert, suite, test } from './GLOBALS.mjs' +import { assert, isNode, suite, test } from './GLOBALS.mjs' import { NANO_TEST_VECTORS } from './VECTORS.js' import { SendBlock, Blake2b } from '../dist/main.min.js' -await suite('Calculate proof-of-work', async () => { +await suite('Calculate proof-of-work', { skip: isNode }, async () => { await test('SendBlock PoW', async () => { const block = new SendBlock( diff --git a/test/test.ledger.mjs b/test/test.ledger.mjs index 28c2173..812dda7 100644 --- a/test/test.ledger.mjs +++ b/test/test.ledger.mjs @@ -3,11 +3,11 @@ 'use strict' -import { assert, click, isNode, process, suite, test } from './GLOBALS.mjs' +import { assert, click, env, isNode, suite, test } from './GLOBALS.mjs' import { NANO_TEST_VECTORS } from './VECTORS.js' import { Account, LedgerWallet, ReceiveBlock, Rpc, SendBlock } from '../dist/main.min.js' -const rpc = new Rpc(process.env.NODE_URL ?? '', process.env.API_KEY_NAME) +const rpc = new Rpc(env.NODE_URL ?? '', env.API_KEY_NAME) /** * HID interactions require user gestures, so to reduce clicks, the variables diff --git a/test/test.refresh-accounts.mjs b/test/test.refresh-accounts.mjs index 5d07051..409a077 100644 --- a/test/test.refresh-accounts.mjs +++ b/test/test.refresh-accounts.mjs @@ -3,11 +3,11 @@ 'use strict' -import { assert, process, suite, test } from './GLOBALS.mjs' +import { assert, env, suite, test } from './GLOBALS.mjs' import { NANO_TEST_VECTORS } from './VECTORS.js' import { Account, Bip44Wallet, Rpc } from '../dist/main.min.js' -const rpc = new Rpc(process.env.NODE_URL ?? '', process.env.API_KEY_NAME) +const rpc = new Rpc(env.NODE_URL ?? '', env.API_KEY_NAME) await suite('Refreshing account info', { skip: true }, async () => { diff --git a/test/test.runner-check.mjs b/test/test.runner-check.mjs index 2295d30..1f2bd9e 100644 --- a/test/test.runner-check.mjs +++ b/test/test.runner-check.mjs @@ -1,42 +1,45 @@ // SPDX-FileCopyrightText: 2025 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -import { failures, passes, suite, test } from './GLOBALS.mjs' +import { failures, isNode, passes, suite, test } from './GLOBALS.mjs' -await suite('TEST RUNNER CHECK', async () => { - await new Promise(r => setTimeout(r, 0)) +if (!isNode) { + await suite('TEST RUNNER CHECK', async () => { + await new Promise(r => setTimeout(r, 0)) - console.assert(failures.length === 0) - console.assert(passes.length === 0) + console.assert(failures.length === 0) + console.assert(passes.length === 0) - //@ts-expect-error - await test('promise should pass', new Promise(resolve => resolve(null))) - console.assert(failures.some(call => /.*promise should pass.*/.test(call[0])) === false, `good promise errored`) - console.assert(passes.some(call => /.*promise should pass.*/.test(call)) === true, `good promise not logged`) + //@ts-expect-error + await test('promise should pass', new Promise(resolve => resolve(null))) + console.assert(failures.some(call => /.*promise should pass.*/.test(call[0])) === false, `good promise errored`) + console.assert(passes.some(call => /.*promise should pass.*/.test(call)) === true, `good promise not logged`) - //@ts-expect-error - await test('promise should fail', new Promise((resolve, reject) => reject('FAILURE EXPECTED HERE'))) - console.assert(failures.some(call => /.*promise should fail.*/.test(call)) === true, `bad promise not errored`) - console.assert(passes.some(call => /.*promise should fail.*/.test(call)) === false, 'bad promise logged') + //@ts-expect-error + await test('promise should fail', new Promise((resolve, reject) => reject('FAILURE EXPECTED HERE'))) + console.assert(failures.some(call => /.*promise should fail.*/.test(call)) === true, `bad promise not errored`) + console.assert(passes.some(call => /.*promise should fail.*/.test(call)) === false, 'bad promise logged') - await test('async should pass', async () => {}) - console.assert(failures.some(call => /.*async should pass.*/.test(call)) === false, 'good async errored') - console.assert(passes.some(call => /.*async should pass.*/.test(call)) === true, 'good async not logged') + await test('async should pass', async () => {}) + console.assert(failures.some(call => /.*async should pass.*/.test(call)) === false, 'good async errored') + console.assert(passes.some(call => /.*async should pass.*/.test(call)) === true, 'good async not logged') - await test('async should fail', async () => { throw new Error('FAILURE EXPECTED HERE') }) - console.assert(failures.some(call => /.*async should fail.*/.test(call)) === true, 'bad async not errored') - console.assert(passes.some(call => /.*async should fail.*/.test(call)) === false, 'bad async logged') + await test('async should fail', async () => { throw new Error('FAILURE EXPECTED HERE') }) + console.assert(failures.some(call => /.*async should fail.*/.test(call)) === true, 'bad async not errored') + console.assert(passes.some(call => /.*async should fail.*/.test(call)) === false, 'bad async logged') - await test('function should pass', () => {}) - console.assert(failures.some(call => /.*function should pass.*/.test(call)) === false, 'good function errored') - console.assert(passes.some(call => /.*function should pass.*/.test(call)) === true, 'good function not logged') + await test('function should pass', () => {}) + console.assert(failures.some(call => /.*function should pass.*/.test(call)) === false, 'good function errored') + console.assert(passes.some(call => /.*function should pass.*/.test(call)) === true, 'good function not logged') - //@ts-expect-error - await test('function should fail', 'FAILURE EXPECTED HERE') - console.assert(failures.some(call => /.*function should fail.*/.test(call)) === true, 'bad function not errored') - console.assert(passes.some(call => /.*function should fail.*/.test(call)) === false, 'bad function logged') + //@ts-expect-error + await test('function should fail', 'FAILURE EXPECTED HERE') + console.assert(failures.some(call => /.*function should fail.*/.test(call)) === true, 'bad function not errored') + console.assert(passes.some(call => /.*function should fail.*/.test(call)) === false, 'bad function logged') - failures.splice(0) - passes.splice(0) -}) -console.log(`%cTEST RUNNER CHECK DONE`, 'font-weight:bold') + failures.splice(0) + passes.splice(0) + }) + + console.log(`%cTEST RUNNER CHECK DONE`, 'font-weight:bold') +} diff --git a/test/test.tools.mjs b/test/test.tools.mjs index 903a5ec..e5a4599 100644 --- a/test/test.tools.mjs +++ b/test/test.tools.mjs @@ -3,17 +3,11 @@ 'use strict' -import { assert, suite, test } from './GLOBALS.mjs' +import { assert, env, suite, test } from './GLOBALS.mjs' import { RAW_MAX, NANO_TEST_VECTORS } from './VECTORS.js' import { Bip44Wallet, Account, SendBlock, Rpc, Tools } from '../dist/main.min.js' -let rpc -//@ts-ignore -var process = process || null -if (process) { - //@ts-expect-error - rpc = new Rpc(process?.env?.NODE_URL ?? '', process?.env?.API_KEY_NAME) -} +const rpc = new Rpc(env?.NODE_URL ?? '', env?.API_KEY_NAME) await suite('unit conversion tests', async () => {