From fe0ca905c8d68c2816ad8a956adafecf18530d20 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Fri, 1 Nov 2024 22:59:29 -0700 Subject: [PATCH] Using 'Node" as class name interferes with browser Node class, so revert it to 'Rpc'. --- README.md | 4 ++-- src/lib/account.ts | 14 +++++++------- src/lib/block.ts | 20 ++++++++++---------- src/lib/ledger.ts | 10 +++++----- src/lib/{node.ts => rpc.ts} | 6 ++---- src/lib/tools.ts | 20 ++++++++++---------- src/lib/wallet.ts | 22 +++++++++++----------- src/main.ts | 4 ++-- test/refresh-accounts.test.mjs | 6 +++--- test/tools.test.mjs | 4 ++-- 10 files changed, 54 insertions(+), 56 deletions(-) rename src/lib/{node.ts => rpc.ts} (93%) diff --git a/README.md b/README.md index 887278b..8a10272 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ try { #### Caculating proof-of-work from an online service ```javascript -const node = new Node('https://nano-node.example.com/') +const node = new Rpc('https://nano-node.example.com/') try { await block.pow('https://nano-node.example.com/') } catch (err) { @@ -184,7 +184,7 @@ try { #### Processing a block on the network ```javascript -const node = new Node('https://nano-node.example.com', 'nodes-api-key') +const node = new Rpc('https://nano-node.example.com', 'nodes-api-key') try { const hash = await block.process('https://nano-node.example.com/') } catch (err) { diff --git a/src/lib/account.ts b/src/lib/account.ts index 356d1ab..7a111d3 100644 --- a/src/lib/account.ts +++ b/src/lib/account.ts @@ -5,7 +5,7 @@ import { blake2b } from 'blakejs' import { ACCOUNT_KEY_LENGTH, ALPHABET, PREFIX, PREFIX_LEGACY } from './constants.js' import { base32, bytes, hex } from './convert.js' import Ed25519 from './ed25519.js' -import { Node } from './node.js' +import { Rpc } from './rpc.js' import { Safe } from './safe.js' /** @@ -157,13 +157,13 @@ export class Account { * A successful response sets the balance, frontier, and representative * properties. * - * @param {Node|string|URL} node - Node information required to call `account_info` + * @param {Rpc|string|URL} rpc - RPC node information required to call `account_info` */ - async refresh (node: Node | string | URL): Promise { - if (typeof node === 'string' || node.constructor === URL) { - node = new Node(node) + async refresh (rpc: Rpc | string | URL): Promise { + if (typeof rpc === 'string' || rpc.constructor === URL) { + rpc = new Rpc(rpc) } - if (node.constructor !== Node) { + if (rpc.constructor !== Rpc) { throw new TypeError('RPC must be a valid node') } const data = { @@ -172,7 +172,7 @@ export class Account { "representative": "true", "weight": "true" } - const { balance, frontier, receivable, representative, weight } = await node.call('account_info', data) + const { balance, frontier, receivable, representative, weight } = await rpc.call('account_info', data) if (frontier == null) { throw new Error('Account not found') } diff --git a/src/lib/block.ts b/src/lib/block.ts index f94cb16..4e23a7d 100644 --- a/src/lib/block.ts +++ b/src/lib/block.ts @@ -5,7 +5,7 @@ import { BURN_ADDRESS, PREAMBLE } from './constants.js' import { Account } from './account.js' import { bytes, dec, hex } from './convert.js' import Ed25519 from './ed25519.js' -import { Node } from './node.js' +import { Rpc } from './rpc.js' import Tools from './tools.js' /** @@ -77,19 +77,19 @@ abstract class Block { * * A successful response sets the `work` property. * - * @param {Node|string|URL} node - Node information required to call `work_generate` + * @param {Rpc|string|URL} rpc - RPC node information required to call `work_generate` */ - async pow (node: Node | string | URL): Promise { - if (typeof node === 'string' || node.constructor === URL) { - node = new Node(node) + async pow (rpc: Rpc | string | URL): Promise { + if (typeof rpc === 'string' || rpc.constructor === URL) { + rpc = new Rpc(rpc) } - if (node.constructor !== Node) { + if (rpc.constructor !== Rpc) { throw new TypeError('RPC must be a valid node') } const data = { "hash": this.previous } - const { work } = await node.call('work_generate', data) + const { work } = await rpc.call('work_generate', data) this.work = work } @@ -152,10 +152,10 @@ abstract class Block { * The block must already be signed (see `sign()` for more information). * The block must also have a `work` value. * - * @param {Node|string|URL} node - Node information required to call `process` + * @param {Rpc|string|URL} rpc - RPC node information required to call `process` * @returns {Promise} Hash of the processed block */ - async process (node: Node): Promise { + async process (rpc: Rpc): Promise { if (!this.signature) { throw new Error('Block is missing signature. Use sign() and try again.') } @@ -167,7 +167,7 @@ abstract class Block { "json_block": "true", "block": this.json() } - const res = await node.call('process', data) + const res = await rpc.call('process', data) if (res.hash == null) { throw new Error('Block could not be processed', res) } diff --git a/src/lib/ledger.ts b/src/lib/ledger.ts index 5cf5bf9..43fadd1 100644 --- a/src/lib/ledger.ts +++ b/src/lib/ledger.ts @@ -11,7 +11,7 @@ import { default as TransportUSB } from '@ledgerhq/hw-transport-webusb' import { default as TransportHID } from '@ledgerhq/hw-transport-webhid' import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET, LEDGER_STATUS_CODES } from './constants.js' import { bytes, dec, hex, utf8 } from './convert.js' -import { Node } from './node.js' +import { Rpc } from './rpc.js' import { ChangeBlock, ReceiveBlock, SendBlock } from './block.js' export class Ledger { @@ -339,11 +339,11 @@ export class Ledger { * * @param {number} index - Account number * @param {string} hash - Hexadecimal block hash - * @param {Node} node - Node class object with a node URL + * @param {Rpc} rpc - Rpc class object with a node URL */ - async updateCache (index: number, hash: string, node: Node): Promise<{ status: string }> - async updateCache (index: number, input: any, node?: Node): Promise<{ status: string }> { - if (typeof input === 'string' && node?.constructor === Node) { + async updateCache (index: number, hash: string, rpc: Rpc): Promise<{ status: string }> + async updateCache (index: number, input: any, node?: Rpc): Promise<{ status: string }> { + if (typeof input === 'string' && node?.constructor === Rpc) { const data = { 'json_block': 'true', 'hash': input diff --git a/src/lib/node.ts b/src/lib/rpc.ts similarity index 93% rename from src/lib/node.ts rename to src/lib/rpc.ts index 8bae1b7..752ce1c 100644 --- a/src/lib/node.ts +++ b/src/lib/rpc.ts @@ -1,16 +1,14 @@ // SPDX-FileCopyrightText: 2024 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -import { Safe } from './safe.js' - /** * Represents a Nano network node. It primarily consists of a URL which will * accept RPC calls, and an optional API key header construction can be passed if -* required by the node. Once instantiated, the Node object can be used to call +* required by the node. Once instantiated, the Rpc object can be used to call * any action supported by the Nano protocol. The URL protocol must be HTTPS; any * other value will be changed automatically. */ -export class Node { +export class Rpc { #u: URL #n?: string diff --git a/src/lib/tools.ts b/src/lib/tools.ts index 22b0176..aa53be5 100644 --- a/src/lib/tools.ts +++ b/src/lib/tools.ts @@ -7,7 +7,7 @@ import { Account } from './account.js' import { UNITS } from './constants.js' import { bytes, hex } from './convert.js' import Ed25519 from './ed25519.js' -import { Node } from './node.js' +import { Rpc } from './rpc.js' import { Bip44Wallet, Blake2bWallet, LedgerWallet } from './wallet.js' import { SendBlock } from './block.js' @@ -108,28 +108,28 @@ export async function sign (key: string, ...input: string[]): Promise { * Collects the funds from a specified range of accounts in a wallet and sends * them all to a single recipient address. * -* @param {Node|string|URL} node - Node information required to refresh accounts, calculate PoW, and process blocks +* @param {Rpc|string|URL} rpc - RPC node information required to refresh accounts, calculate PoW, and process blocks * @param {Blake2bWallet|Bip44Wallet|LedgerWallet} wallet - Wallet from which to sweep funds * @param {string} recipient - Destination address for all swept funds * @param {number} from - Starting account index to sweep * @param {number} to - Ending account index to sweep * @returns An array of results including both successes and failures */ -export async function sweep (node: Node | string | URL, wallet: Blake2bWallet | Bip44Wallet | LedgerWallet, recipient: string, from: number = 0, to: number = from) { - if (node == null || wallet == null || recipient == null) { +export async function sweep (rpc: Rpc | string | URL, wallet: Blake2bWallet | Bip44Wallet | LedgerWallet, recipient: string, from: number = 0, to: number = from) { + if (rpc == null || wallet == null || recipient == null) { throw new ReferenceError('Missing required sweep arguments') } - if (typeof node === 'string' || node.constructor === URL) { - node = new Node(node) + if (typeof rpc === 'string' || rpc.constructor === URL) { + rpc = new Rpc(rpc) } - if (node.constructor !== Node) { + if (rpc.constructor !== Rpc) { throw new TypeError('RPC must be a valid node') } const blockQueue = [] const results: { status: 'success' | 'error', address: string, message: string }[] = [] const recipientAccount = new Account(recipient) - const accounts = await wallet.refresh(node, from, to) + const accounts = await wallet.refresh(rpc, from, to) for (const account of accounts) { if (account.representative?.address && account.frontier) { const block = new SendBlock( @@ -142,9 +142,9 @@ export async function sweep (node: Node | string | URL, wallet: Blake2bWallet | ) blockQueue.push(new Promise(async resolve => { try { - await block.pow(node) + await block.pow(rpc) await block.sign(account.index) - const hash = await block.process(node) + const hash = await block.process(rpc) results.push({ status: 'success', address: block.account.address, message: hash }) } catch (err: any) { results.push({ status: 'error', address: block.account.address, message: err.message }) diff --git a/src/lib/wallet.ts b/src/lib/wallet.ts index 4b0c0bd..bfa6df2 100644 --- a/src/lib/wallet.ts +++ b/src/lib/wallet.ts @@ -7,7 +7,7 @@ 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 { Node } from './node.js' +import { Rpc } from './rpc.js' import { Safe } from './safe.js' import Tools from './tools.js' import type { Ledger } from './ledger.js' @@ -88,13 +88,13 @@ abstract class Wallet { * Fetches the lowest-indexed unopened account from a wallet in sequential * order. An account is unopened if it has no frontier block. * - * @param {Node|string|URL} node - Node information required to refresh accounts, calculate PoW, and process blocks + * @param {Rpc|string|URL} rpc - RPC node information required to refresh accounts, calculate PoW, and process blocks * @param {number} batchSize - Number of accounts to fetch and check per RPC callout * @param {number} from - Account index from which to start the search * @returns {Promise} The lowest-indexed unopened account belonging to the wallet */ - async getNextNewAccount (node: Node, batchSize: number = ADDRESS_GAP, from: number = 0): Promise { + async getNextNewAccount (rpc: Rpc, batchSize: number = ADDRESS_GAP, from: number = 0): Promise { if (!Number.isSafeInteger(batchSize) || batchSize < 1) { throw new RangeError(`Invalid batch size ${batchSize}`) } @@ -103,14 +103,14 @@ abstract class Wallet { const data = { "accounts": addresses } - const { errors } = await node.call('accounts_frontiers', data) + const { errors } = await rpc.call('accounts_frontiers', data) for (const key of Object.keys(errors ?? {})) { const value = errors[key] if (value === 'Account not found') { return new Account(key) } } - return await this.getNextNewAccount(node, batchSize, from + batchSize) + return await this.getNextNewAccount(rpc, batchSize, from + batchSize) } /** @@ -118,20 +118,20 @@ abstract class Wallet { * * A successful response will set these properties on each account. * - * @param {Node|string|URL} node - Node information required to refresh accounts, calculate PoW, and process blocks + * @param {Rpc|string|URL} rpc - RPC node information required to refresh accounts, calculate PoW, and process blocks * @returns {Promise} Accounts with updated balances, frontiers, and representatives */ - async refresh (node: Node | string | URL, from: number = 0, to: number = from): Promise { - if (typeof node === 'string' || node.constructor === URL) { - node = new Node(node) + async refresh (rpc: Rpc | string | URL, from: number = 0, to: number = from): Promise { + if (typeof rpc === 'string' || rpc.constructor === URL) { + rpc = new Rpc(rpc) } - if (node.constructor !== Node) { + if (rpc.constructor !== Rpc) { throw new TypeError('RPC must be a valid node') } const accounts = await this.accounts(from, to) for (let i = 0; i < accounts.length; i++) { try { - await accounts[i].refresh(node) + await accounts[i].refresh(rpc) } catch (err) { accounts.splice(i--, 1) } diff --git a/src/main.ts b/src/main.ts index c4d2553..d836cec 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,10 +3,10 @@ import { Account } from './lib/account.js' import { SendBlock, ReceiveBlock, ChangeBlock } from './lib/block.js' -import { Node } from './lib/node.js' +import { Rpc } from './lib/rpc.js' import { Rolodex } from './lib/rolodex.js' import { Safe } from './lib/safe.js' import Tools from './lib/tools.js' import { Bip44Wallet, Blake2bWallet, LedgerWallet } from './lib/wallet.js' -export { Account, SendBlock, ReceiveBlock, ChangeBlock, Node, Rolodex, Safe, Tools, Bip44Wallet, Blake2bWallet, LedgerWallet } +export { Account, SendBlock, ReceiveBlock, ChangeBlock, Rpc, Rolodex, Safe, Tools, Bip44Wallet, Blake2bWallet, LedgerWallet } diff --git a/test/refresh-accounts.test.mjs b/test/refresh-accounts.test.mjs index d0ae268..3983e67 100644 --- a/test/refresh-accounts.test.mjs +++ b/test/refresh-accounts.test.mjs @@ -6,14 +6,14 @@ import { describe, it } from 'node:test' import { strict as assert } from 'assert' import { NANO_TEST_VECTORS, STORAGE } from './TEST_VECTORS.js' -import { Account, Bip44Wallet, Node } from '../dist/main.js' +import { Account, Bip44Wallet, Rpc } from '../dist/main.js' // WARNING: Do not send any funds to the test vectors below // Test vectors from https://docs.nano.org/integration-guides/key-management/ and elsewhere const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) -const node = new Node(process.env.NODE_URL, process.env.API_KEY_NAME, process.env.API_KEY_VALUE) +const node = new Rpc(process.env.NODE_URL, process.env.API_KEY_NAME, process.env.API_KEY_VALUE) const skip = true @@ -57,7 +57,7 @@ describe('refreshing account info', { skip }, async () => { }) it('should throw with invalid node', async () => { - const invalidNode = new Node('http://invalid.com') + const invalidNode = new Rpc('http://invalid.com') const accounts = await wallet.accounts() const account = accounts[0] await assert.rejects(account.refresh(invalidNode), diff --git a/test/tools.test.mjs b/test/tools.test.mjs index ac9c252..9e7db51 100644 --- a/test/tools.test.mjs +++ b/test/tools.test.mjs @@ -6,11 +6,11 @@ import { describe, it } from 'node:test' import { strict as assert } from 'assert' import { RAW_MAX, NANO_TEST_VECTORS, STORAGE } from './TEST_VECTORS.js' -import { Bip44Wallet, Account, SendBlock, Node, Tools } from '../dist/main.js' +import { Bip44Wallet, Account, SendBlock, Rpc, Tools } from '../dist/main.js' const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) -const rpc = new Node(process.env.NODE_URL, process.env.API_KEY_NAME, process.env.API_KEY_VALUE) +const rpc = new Rpc(process.env.NODE_URL, process.env.API_KEY_NAME, process.env.API_KEY_VALUE) describe('unit conversion tests', async () => { it('should convert nano to raw', async () => { -- 2.34.1