From 4b0db8de7d056ce6a4a082b296d1b3f0e996c5af Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Thu, 3 Jul 2025 17:56:09 -0700 Subject: [PATCH] Abort long-running RPC calls after 10 seconds. Throw if any BIP-44 keys are invalid instead of continuing. Fix refresh account tests. --- src/lib/rpc.ts | 8 ++++++- src/lib/wallets/bip44-wallet.ts | 2 +- test/test.refresh-accounts.mjs | 38 +++++++++++++++------------------ 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/lib/rpc.ts b/src/lib/rpc.ts index 555db0e..0497a91 100644 --- a/src/lib/rpc.ts +++ b/src/lib/rpc.ts @@ -41,17 +41,23 @@ export class Rpc { .replaceAll('>', '\\u003d') .replaceAll('\\', '\\u005c') + const aborter = new AbortController() const req = new Request(this.#u, { + signal: aborter.signal, method: 'POST', headers, body }) + const kill = setTimeout(() => { + aborter.abort() + }, 10000) try { const res = await fetch(req) return await res.json() } catch (err) { - console.error(err) return JSON.stringify(err) + } finally { + clearTimeout(kill) } } diff --git a/src/lib/wallets/bip44-wallet.ts b/src/lib/wallets/bip44-wallet.ts index 9df7fc6..45bd381 100644 --- a/src/lib/wallets/bip44-wallet.ts +++ b/src/lib/wallets/bip44-wallet.ts @@ -206,7 +206,7 @@ export class Bip44Wallet extends Wallet { const privateKeys: KeyPair[] = await this.#poolBip44Ckd.assign(data) for (let i = 0; i < privateKeys.length; i++) { if (privateKeys[i].privateKey == null) { - privateKeys.splice(i, 1) + throw new Error('Failed to derive private keys') } } return privateKeys diff --git a/test/test.refresh-accounts.mjs b/test/test.refresh-accounts.mjs index 59e76aa..ef69584 100644 --- a/test/test.refresh-accounts.mjs +++ b/test/test.refresh-accounts.mjs @@ -12,33 +12,28 @@ let rpc var process = process || env || null rpc = new Rpc(process?.env?.NODE_URL ?? '', process?.env?.API_KEY_NAME) -await suite('refreshing account info', { skip: true }, async () => { +await suite('refreshing account info', { skip: false }, async () => { await test('fetch balance, frontier, and representative', async () => { const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - const accounts = await wallet.accounts() - const account = accounts[0] + const account = await wallet.account() await account.refresh(rpc) assert.equals(typeof account.balance, 'bigint') - assert.notEqual(account.balance, undefined) - assert.notEqual(account.balance, null) + assert.exists(account.balance) assert.notEqual(account.balance, '') assert.notEqual(account.balance && account.balance < 0, true) + assert.exists(account.frontier) assert.equals(typeof account.frontier, 'string') - assert.notEqual(account.frontier, undefined) - assert.notEqual(account.frontier, null) assert.notEqual(account.frontier, '') - assert.match(account.frontier ?? '', /^[0-9A-F]{64}$/i) + assert.ok(/^[A-Fa-f0-9]{64}$/.test(account.frontier)) assert.equals(account.representative && account.representative.constructor, Account) - assert.notEqual(account.representative, undefined) - assert.notEqual(account.representative, null) + assert.exists(account.representative) assert.notEqual(account.representative, '') - assert.notEqual(account.representative?.address, undefined) - assert.notEqual(account.representative?.address, null) + assert.exists(account.representative?.address) assert.notEqual(account.representative?.address, '') await wallet.destroy() @@ -47,8 +42,8 @@ await suite('refreshing account info', { skip: true }, async () => { await test('throw when refreshing unopened account', async () => { const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - const accounts = await wallet.accounts(0x7fffffff) - const account = accounts[0] + const account = await wallet.account(0x7fffffff) + await assert.rejects(account.refresh(rpc), { message: 'Account not found' }) @@ -58,16 +53,18 @@ await suite('refreshing account info', { skip: true }, async () => { await test('throw when referencing invalid account index', async () => { const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - await assert.rejects(wallet.accounts(0x80000000), + await assert.rejects(wallet.account(0x80000000), { message: 'Invalid child key index 0x80000000' }) + + await wallet.destroy() }) await test('throw with invalid node', async () => { const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) const invalidNode = new Rpc('http://invalid.com') - const accounts = await wallet.accounts() - const account = accounts[0] + const account = await wallet.account() + await assert.rejects(account.refresh(invalidNode), { message: 'Account not found' }) @@ -75,7 +72,7 @@ await suite('refreshing account info', { skip: true }, async () => { }) }) -await suite('Fetch next unopened account', { skip: true }, async () => { +await suite('Fetch next unopened account', { skip: false }, async () => { await test('return correct account from test vector', async () => { const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED) @@ -140,7 +137,7 @@ await suite('Fetch next unopened account', { skip: true }, async () => { }) }) -await suite('Refreshing wallet accounts', { skip: true }, async () => { +await suite('Refreshing wallet accounts', { skip: false }, async () => { await test('should get balance, frontier, and representative for one account', async () => { const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED) @@ -149,8 +146,7 @@ await suite('Refreshing wallet accounts', { skip: true }, async () => { const account = accounts[0] assert.ok(account instanceof Account) assert.equals(typeof account.balance, 'bigint') - assert.notEqual(account.frontier, undefined) - assert.notEqual(account.frontier, null) + assert.exists(account.frontier) assert.equals(typeof account.frontier, 'string') await wallet.destroy() -- 2.47.3