]> git.codecow.com Git - libnemo.git/commitdiff
Extract frontier block caching.
authorChris Duncan <chris@zoso.dev>
Sat, 16 May 2026 07:27:58 +0000 (00:27 -0700)
committerChris Duncan <chris@zoso.dev>
Sat, 16 May 2026 07:27:58 +0000 (00:27 -0700)
src/lib/ledger/cache.ts [new file with mode: 0644]
src/lib/ledger/index.ts

diff --git a/src/lib/ledger/cache.ts b/src/lib/ledger/cache.ts
new file mode 100644 (file)
index 0000000..145556e
--- /dev/null
@@ -0,0 +1,53 @@
+//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
+//! SPDX-License-Identifier: GPL-3.0-or-later
+
+import { APDU_CODES, LedgerResponse, LedgerTransport, STATUS_CODES, listenTimeout, openTimeout } from '.'
+import { Account } from '../account'
+import { Block } from '../block'
+import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET } from '../constants'
+import { bytes, dec, hex } from '../convert'
+import { queue } from './queue'
+
+export async function _cache (transport: LedgerTransport, index: number = 0, block: Block): Promise<LedgerResponse> {
+       return queue(async () => {
+               try {
+                       if (typeof index !== 'number' || index < 0 || index >= HARDENED_OFFSET) {
+                               throw new TypeError('Invalid account index')
+                       }
+                       if (!(block instanceof Block)) {
+                               throw new TypeError('Invalid block format')
+                       }
+                       if (!(block.link instanceof Uint8Array)) {
+                               throw new TypeError('Invalid block link')
+                       }
+                       if (!(block.representative instanceof Account)) {
+                               throw new TypeError('Invalid block link')
+                       }
+                       if (!block.signature) {
+                               throw new ReferenceError('Cannot cache unsigned block')
+                       }
+
+                       const purpose = dec.toBytes(BIP44_PURPOSE + HARDENED_OFFSET, 4)
+                       const coin = dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4)
+                       const account = dec.toBytes(index + HARDENED_OFFSET, 4)
+                       const previous = block.previous
+                       const link = block.link
+                       const representative = hex.toBytes(block.representative.publicKey, 32)
+                       const balance = hex.toBytes(block.balance.toString(16), 16)
+                       const signature = hex.toBytes(block.signature, 64)
+                       const data = new Uint8Array([APDU_CODES.bip32DerivationLevel, ...purpose, ...coin, ...account, ...previous, ...link, ...representative, ...balance, ...signature])
+
+                       const t = await transport.create(openTimeout, listenTimeout)
+                       const response = await t
+                               .send(APDU_CODES.class, APDU_CODES.cacheBlock, APDU_CODES.paramUnused, APDU_CODES.paramUnused, data as Buffer)
+                               .then((res: Buffer) => bytes.toDec(res))
+                               .catch((err: any) => err.statusCode)
+                               .finally(async () => await t.close()) as number
+
+                       return { status: STATUS_CODES[response] }
+               } catch (err: any) {
+                       console.error('Ledger.#cacheBlock()', err)
+                       return { status: err.message }
+               }
+       })
+}
index ecf70f40b42cec3890734c0639797c5fac0b0378..aa1a1bdb63ca956d89dac044224f1f88e532b59a 100644 (file)
@@ -12,6 +12,7 @@ import { bytes, dec, hex, utf8 } from '../convert'
 import { Rpc } from '../rpc'
 import { Wallet } from '../wallet'
 import { _account } from './account'
+import { _cache } from './cache'
 import { _connect } from './connect'
 import { queue } from './queue'
 
@@ -230,7 +231,7 @@ export class Ledger {
                                throw new TypeError('Data to be signed must be a string nonce or a Block', { cause: data })
                        }
                        if (frontier != null) {
-                               const { status } = await this.#cacheBlock(index, frontier)
+                               const { status } = await _cache(this.#transport, index, frontier)
                                if (status !== 'OK') {
                                        throw new Error('Failed to cache frontier block in ledger', { cause: status })
                                }
@@ -283,7 +284,7 @@ export class Ledger {
                        }
                        input = res.contents
                }
-               const { status } = await this.#cacheBlock(index, input)
+               const { status } = await _cache(this.#transport, index, input)
                if (status !== 'OK') {
                        throw new Error('failed to cache frontier block in ledger', { cause: status })
                }
@@ -325,57 +326,6 @@ export class Ledger {
                }
        }
 
-       /**
-       * Cache frontier block in device memory.
-       *
-       * @param {number} index - Account number
-       * @param {any} block - Block data to cache
-       * @returns Status of command
-       */
-       static async #cacheBlock (index: number = 0, block: Block): Promise<LedgerResponse> {
-               return queue(async () => {
-                       try {
-                               if (typeof index !== 'number' || index < 0 || index >= HARDENED_OFFSET) {
-                                       throw new TypeError('Invalid account index')
-                               }
-                               if (!(block instanceof Block)) {
-                                       throw new TypeError('Invalid block format')
-                               }
-                               if (!(block.link instanceof Uint8Array)) {
-                                       throw new TypeError('Invalid block link')
-                               }
-                               if (!(block.representative instanceof Account)) {
-                                       throw new TypeError('Invalid block link')
-                               }
-                               if (!block.signature) {
-                                       throw new ReferenceError('Cannot cache unsigned block')
-                               }
-
-                               const purpose = dec.toBytes(BIP44_PURPOSE + HARDENED_OFFSET, 4)
-                               const coin = dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4)
-                               const account = dec.toBytes(index + HARDENED_OFFSET, 4)
-                               const previous = block.previous
-                               const link = block.link
-                               const representative = hex.toBytes(block.representative.publicKey, 32)
-                               const balance = hex.toBytes(block.balance.toString(16), 16)
-                               const signature = hex.toBytes(block.signature, 64)
-                               const data = new Uint8Array([APDU_CODES.bip32DerivationLevel, ...purpose, ...coin, ...account, ...previous, ...link, ...representative, ...balance, ...signature])
-
-                               const transport = await this.#transport.create(openTimeout, listenTimeout)
-                               const response = await transport
-                                       .send(APDU_CODES.class, APDU_CODES.cacheBlock, APDU_CODES.paramUnused, APDU_CODES.paramUnused, data as Buffer)
-                                       .then((res: Buffer) => bytes.toDec(res))
-                                       .catch((err: any) => err.statusCode)
-                                       .finally(async () => await transport.close()) as number
-
-                               return { status: STATUS_CODES[response] }
-                       } catch (err: any) {
-                               console.error('Ledger.#cacheBlock()', err)
-                               return { status: err.message }
-                       }
-               })
-       }
-
        /**
        * Close the currently running app and return to the device dashboard.
        *