From: Chris Duncan Date: Sat, 6 Sep 2025 04:54:23 +0000 (-0700) Subject: Deprecate AccountList for built-in Map. X-Git-Tag: v0.10.5~24^2~10 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=4ba2db74c441d0c9b56c051ef3ef8ea0b6126a58;p=libnemo.git Deprecate AccountList for built-in Map. --- diff --git a/src/lib/account/index.ts b/src/lib/account/index.ts index 222536f..612bb2a 100644 --- a/src/lib/account/index.ts +++ b/src/lib/account/index.ts @@ -353,25 +353,3 @@ export class Account { return true } } - -export class AccountList extends Object { - [index: number]: Account - - get length (): number { - return Object.keys(this).length - } - - *[Symbol.iterator] (): Iterator { - const indexes = Object.keys(this) - .map(key => parseInt(key)) - .filter(index => Number.isFinite(index)) - .sort((a, b) => a - b) - for (const i of indexes) { - yield this[i] - } - } - - static { - Object.defineProperty(this, 'length', { enumerable: false }) - } -} diff --git a/src/lib/tools.ts b/src/lib/tools.ts index db16d7f..7ab2c9f 100644 --- a/src/lib/tools.ts +++ b/src/lib/tools.ts @@ -163,16 +163,16 @@ export async function sweep ( const recipientAccount = Account.load(recipient) const accounts = await wallet.refresh(rpc, from, to) - for (const account of accounts) { + for (const [index, account] of accounts) { const blockRequest: Promise = new Promise(async (resolve) => { let block try { - if (account.index == null) { + if (index == null && account.index == null) { throw new TypeError('Account index is required', { cause: account }) } block = await new Block(account) .send(recipientAccount, account.balance ?? 0n) - .sign(wallet, account.index) + .sign(wallet, account.index ?? index) await block.pow() const hash = await block.process(rpc) results.push({ status: 'success', address: block.account.address, message: hash }) diff --git a/src/lib/wallet/accounts.ts b/src/lib/wallet/accounts.ts index f5aa720..d5331e2 100644 --- a/src/lib/wallet/accounts.ts +++ b/src/lib/wallet/accounts.ts @@ -2,22 +2,24 @@ //! SPDX-License-Identifier: GPL-3.0-or-later import { KeyPair, WalletType } from '#types' -import { Account, AccountList } from '../account' +import { Account } from '../account' import { Vault } from '../vault' -export async function _accounts (type: WalletType, accounts: AccountList, vault: Vault, from: number, to: number): Promise -export async function _accounts (type: WalletType, accounts: AccountList, vault: Vault, from: unknown, to: unknown): Promise { +export async function _accounts (type: WalletType, accounts: Map, vault: Vault, index: number): Promise +export async function _accounts (type: WalletType, accounts: Map, vault: Vault, from: number, to: number): Promise> +export async function _accounts (type: WalletType, accounts: Map, vault: Vault, from: unknown, to: unknown = from): Promise> { if (typeof from !== 'number' || typeof to !== 'number') { throw new TypeError('Invalid account range', { cause: `${from}-${to}` }) } if (from > to) [from as number, to as number] = [to, from] - const output = new AccountList() + const output = new Map() const indexes: number[] = [] for (let i = from; i <= to; i++) { - if (accounts[i] == null) { + const account = accounts.get(i) + if (account == null) { indexes.push(i) } else { - output[i] = accounts[i] + output.set(i, account) } } if (indexes.length > 0) { @@ -48,8 +50,16 @@ export async function _accounts (type: WalletType, accounts: AccountList, vault: if (a.index == null) { throw new RangeError('Index missing for Account') } - output[a.index] = accounts[a.index] = a + output.set(a.index, a) + accounts.set(a.index, a) } } + if (from === to) { + const account = output.get(from) + if (account === undefined) { + throw new Error(`Failed to get account at index ${from}`) + } + return account + } return output } diff --git a/src/lib/wallet/index.ts b/src/lib/wallet/index.ts index b036571..6f5ecfe 100644 --- a/src/lib/wallet/index.ts +++ b/src/lib/wallet/index.ts @@ -2,7 +2,7 @@ //! SPDX-License-Identifier: GPL-3.0-or-later import { NamedData, WalletType } from '#types' -import { Account, AccountList } from '../account' +import { Account } from '../account' import { Block } from '../block' import { ADDRESS_GAP } from '../constants' import { bytes } from '../convert' @@ -124,7 +124,7 @@ export class Wallet { throw new TypeError('Invalid wallet type', { cause: type }) } Wallet.#isInternal = false - this.#accounts = new AccountList() + this.#accounts = new Map() this.#id = id ?? crypto.randomUUID() this.#type = type this.#vault = new Vault() @@ -195,7 +195,7 @@ export class Wallet { * @returns Promise for the Account at the specified index */ async account (index: number = 0): Promise { - return (await this.accounts(index))[index] + return await _accounts(this.type, this.#accounts, this.#vault, index) } /** @@ -232,9 +232,9 @@ export class Wallet { * If `from` is greater than `to`, their values will be swapped. * @param {number} [from=0] - Start index of accounts. Default: 0 * @param {number} [to=from] - End index of accounts. Default: `from` - * @returns {Promise} Promise for a list of Accounts at the specified indexes + * @returns {Promise>} Promise for a list of Accounts at the specified indexes */ - async accounts (from: number = 0, to: number = from): Promise { + async accounts (from: number = 0, to: number = from): Promise> { return await _accounts(this.type, this.#accounts, this.#vault, from, to) } @@ -265,9 +265,9 @@ export class Wallet { * A successful response will set these properties on each account. * * @param {(Rpc|string|URL)} rpc - RPC node information required to refresh accounts, calculate PoW, and process blocks - * @returns {Promise} Promise for accounts with updated balances, frontiers, and representatives + * @returns {Promise>} Promise for accounts with updated balances, frontiers, and representatives */ - async refresh (rpc: Rpc | string | URL, from: number = 0, to: number = from): Promise { + async refresh (rpc: Rpc | string | URL, from: number = 0, to: number = from): Promise> { return await _refresh(this, rpc, from, to) } @@ -366,7 +366,7 @@ export class Wallet { } static #isInternal: boolean = false - #accounts: AccountList + #accounts: Map #id: string #mnemonic?: ArrayBuffer #seed?: ArrayBuffer diff --git a/src/lib/wallet/refresh.ts b/src/lib/wallet/refresh.ts index 69b5651..3166a81 100644 --- a/src/lib/wallet/refresh.ts +++ b/src/lib/wallet/refresh.ts @@ -2,13 +2,13 @@ //! SPDX-License-Identifier: GPL-3.0-or-later import { BlockInfo } from '#types' -import { AccountList } from '../account' +import { Account } from '../account' import { Block } from '../block' import { Rpc } from '../rpc' import { Wallet } from '../wallet' -export async function _refresh (wallet: Wallet, rpc: Rpc | string | URL, from: number, to: number): Promise -export async function _refresh (wallet: Wallet, rpc: unknown, from: unknown, to: unknown): Promise { +export async function _refresh (wallet: Wallet, rpc: Rpc | string | URL, from: number, to: number): Promise> +export async function _refresh (wallet: Wallet, rpc: unknown, from: unknown, to: unknown): Promise> { try { if (typeof rpc === 'string' || rpc instanceof URL) { rpc = new Rpc(rpc) @@ -22,7 +22,7 @@ export async function _refresh (wallet: Wallet, rpc: unknown, from: unknown, to: if (from > to) [from as number, to as number] = [to, from] const accounts = await wallet.accounts(from, to) const addresses = [] - for (const account of accounts) { + for (const [index, account] of accounts) { addresses.push(account.address) } const data = { @@ -33,7 +33,7 @@ export async function _refresh (wallet: Wallet, rpc: unknown, from: unknown, to: const { frontiers } = await rpc.call('accounts_frontiers', data) as { frontiers: { [address: string]: string } } const { representatives } = await rpc.call('accounts_representatives', data) as { representatives: { [address: string]: string } } const { blocks } = await rpc.call('blocks_info', { json_block: true, hashes: Object.values(frontiers) }) as BlockInfo - for (const account of accounts) { + for (const [index, account] of accounts) { account.balance = balances[account.address]?.balance account.receivable = balances[account.address]?.receivable account.representative = representatives?.[account.address] diff --git a/src/lib/wallet/unopened.ts b/src/lib/wallet/unopened.ts index 6023bb8..6ffaa3b 100644 --- a/src/lib/wallet/unopened.ts +++ b/src/lib/wallet/unopened.ts @@ -19,7 +19,7 @@ export async function _unopened (wallet: Wallet, rpc: unknown, batchSize: unknow const to = from + batchSize const accounts = await wallet.accounts(from, to - 1) const addresses = [] - for (const account of accounts) { + for (const [index, account] of accounts) { addresses.push(account.address) } const data = { @@ -27,11 +27,13 @@ export async function _unopened (wallet: Wallet, rpc: unknown, batchSize: unknow } const { errors } = await rpc.call('accounts_frontiers', data) if (errors != null) { - for (let i = from; i < to; i++) { - const account = accounts[i] - const value = errors[account.address] + for (const a of addresses) { + const value = errors[a] if (value === 'Account not found') { - return account + const account = accounts.values().find(({ address }) => a === address) + if (account !== undefined) { + return account + } } } } diff --git a/src/types.d.ts b/src/types.d.ts index 7bd8d6f..ae0c0ab 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -135,11 +135,6 @@ export declare class Account { */ static validate (address: string): asserts address is string } -export declare class AccountList extends Object { - [index: number]: Account - get length (): number - [Symbol.iterator] (): Iterator -} /** * Represents a mnemonic phrase that identifies a wallet as defined by BIP-39. @@ -527,6 +522,7 @@ export declare function convert (amount: bigint | number | string, inputUnit: st declare function hash (data: string | string[], encoding?: 'hex'): Uint8Array /** * Signs arbitrary strings with a private key using the Ed25519 signature scheme. +* The strings are first hashed to a 32-byte value using BLAKE2b. * * @param {string | Uint8Array} key - Hexadecimal-formatted private key to use for signing * @param {...string} input - Data to be signed @@ -704,7 +700,7 @@ export declare class Wallet { * @param {number} [to=from] - End index of accounts. Default: `from` * @returns {Promise} Promise for a list of Accounts at the specified indexes */ - accounts (from?: number, to?: number): Promise + accounts (from?: number, to?: number): Promise> /** * Removes encrypted secrets in storage, releases variable references to * allow garbage collection, and terminates vault worker. @@ -728,7 +724,7 @@ export declare class Wallet { * @param {(Rpc|string|URL)} rpc - RPC node information required to refresh accounts, calculate PoW, and process blocks * @returns {Promise} Promise for accounts with updated balances, frontiers, and representatives */ - refresh (rpc: Rpc | string | URL, from?: number, to?: number): Promise + refresh (rpc: Rpc | string | URL, from?: number, to?: number): Promise> /** * Signs arbitrary strings using the private key of the account at the wallet * index specified and returns a detached signature as a hexadecimal string. diff --git a/test/test.derive-accounts.mjs b/test/test.derive-accounts.mjs index 1fee8fd..bc0cde7 100644 --- a/test/test.derive-accounts.mjs +++ b/test/test.derive-accounts.mjs @@ -40,7 +40,7 @@ await Promise.all([ await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) const accounts = await wallet.accounts(1, 2) - assert.equal(accounts.length, 2) + assert.equal(accounts.size, 2) assert.equal(accounts[1].publicKey, NANO_TEST_VECTORS.PUBLIC_1) assert.equal(accounts[1].address, NANO_TEST_VECTORS.ADDRESS_1) assert.equal(accounts[1].index, 1) @@ -56,7 +56,7 @@ await Promise.all([ await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) const accounts = await wallet.accounts(0x70000000, 0x7000000f) - assert.equal(accounts.length, 0x10) + assert.equal(accounts.size, 0x10) for (let i = 0x70000000; i < 0x7000000f; i++) { const a = accounts[i] assert.exists(a) @@ -94,7 +94,7 @@ await Promise.all([ await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) const accounts = await wallet.accounts(2, 3) - assert.equal(accounts.length, 2) + assert.equal(accounts.size, 2) assert.exists(accounts[2].publicKey) assert.exists(accounts[2].address) assert.equal(accounts[2].index, 2) @@ -110,7 +110,7 @@ await Promise.all([ await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) const accounts = await wallet.accounts(0x70000000, 0x7000000f) - assert.equal(accounts.length, 0x10) + assert.equal(accounts.size, 0x10) for (let i = 0x70000000; i < 0x7000000f; i++) { const a = accounts[i] assert.exists(a) diff --git a/test/test.import-wallet.mjs b/test/test.import-wallet.mjs index 37b389c..b5fdf77 100644 --- a/test/test.import-wallet.mjs +++ b/test/test.import-wallet.mjs @@ -114,9 +114,9 @@ await Promise.all([ assert.ok('seed' in wallet) assert.ok(await wallet.verify(TREZOR_TEST_VECTORS.MNEMONIC_0)) assert.ok(await wallet.verify(TREZOR_TEST_VECTORS.SEED_0)) - assert.equal(accounts.length, 4) + assert.equal(accounts.size, 4) - for (let i = 0; i < accounts.length; i++) { + for (let i = 0; i < accounts.size; i++) { assert.exists(accounts[i]) assert.exists(accounts[i].address) assert.exists(accounts[i].publicKey) @@ -136,9 +136,9 @@ await Promise.all([ assert.ok(wallet.seed === undefined) assert.ok(await wallet.verify(TREZOR_TEST_VECTORS.MNEMONIC_0)) assert.ok(await wallet.verify(TREZOR_TEST_VECTORS.ENTROPY_0)) - assert.equal(accounts.length, 4) + assert.equal(accounts.size, 4) - for (let i = 0; i < accounts.length; i++) { + for (let i = 0; i < accounts.size; i++) { assert.exists(accounts[i]) assert.exists(accounts[i].address) assert.exists(accounts[i].publicKey) diff --git a/test/test.refresh-accounts.mjs b/test/test.refresh-accounts.mjs index af7b78e..6544340 100644 --- a/test/test.refresh-accounts.mjs +++ b/test/test.refresh-accounts.mjs @@ -38,7 +38,6 @@ await Promise.all([ assert.exists(account.balance) assert.notEqual(account.balance, '') assert.equal(typeof account.balance, 'bigint') - //@ts-expect-error assert.ok(account.balance >= 0n) assert.exists(account.frontier) @@ -184,13 +183,14 @@ await Promise.all([ await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) const accounts = await wallet.refresh(rpc, 0, 2) - assert.equal(accounts.length, 3) + assert.equal(accounts.size, 3) for (let i = 0; i < 2; i++) { - assert.exists(accounts[i]) - assert.ok(accounts[i] instanceof Account) - assert.equal(accounts[i].index, i) - assert.equal(accounts[i].balance, 0n) - assert.equal(accounts[i].receivable, 0n) + const account = accounts.get(i) + assert.exists(account) + assert.ok(account instanceof Account) + assert.equal(account.index, i) + assert.equal(account.balance, 0n) + assert.equal(account.receivable, 0n) } assert.equal(accounts[0].address, 'nano_1pu7p5n3ghq1i1p4rhmek41f5add1uh34xpb94nkbxe8g4a6x1p69emk8y1d') assert.equal(accounts[1].address, 'nano_3phqgrqbso99xojkb1bijmfryo7dy1k38ep1o3k3yrhb7rqu1h1k47yu78gz')