]> git.codecow.com Git - libnemo.git/commitdiff
Refactor address validation as boolean instead of assertion.
authorChris Duncan <chris@codecow.com>
Sat, 8 Aug 2026 21:17:37 +0000 (14:17 -0700)
committerChris Duncan <chris@codecow.com>
Sat, 8 Aug 2026 21:17:37 +0000 (14:17 -0700)
src/lib/account/index.ts
src/lib/account/validate.ts
src/lib/rpc/accounts_balances.ts
src/lib/rpc/accounts_frontiers.ts
src/lib/rpc/block_info.ts
src/lib/rpc/blocks_info.ts
src/lib/wallet/refresh.ts

index 5560878a1f21b14c1996fa88f157c665957cb335..9d779a1226fc4bb36b1de46b178f3a33e259930d 100644 (file)
@@ -230,7 +230,7 @@ export class Account {
        * @param {unknown} address - Nano address to validate\r
        * @throws Error if address is undefined, not a string, or an invalid format\r
        */\r
-       static validate (address: unknown): asserts address is string {\r
+       static isValid (address: unknown): address is string {\r
                return _validate(address)\r
        }\r
 }\r
index 23fe21847b45444d4ad8dd7235219f6a561344fa..c1d7f059b4d29b70229fbc17e88be24fcaf30af2 100644 (file)
@@ -7,7 +7,7 @@ import { Blake2b } from "../crypto"
 
 const pattern = new RegExp(`^(${PREFIX}|${PREFIX_LEGACY})[13][${ALPHABET}]{59}$`)
 
-export function _validate (address: unknown): asserts address is string {
+export function _validate (address: unknown): address is string {
        if (address === undefined) {
                throw new ReferenceError('Address is undefined.')
        }
@@ -25,7 +25,5 @@ export function _validate (address: unknown): asserts address is string {
        actualChecksumBuf.reverse()
        const actualChecksum = bytes.toBase32(actualChecksumBuf)
 
-       if (expectedChecksum !== actualChecksum) {
-               throw new Error('Incorrect address checksum')
-       }
+       return expectedChecksum === actualChecksum
 }
index 464f04ab07ff71571e1e800099b2686b6b404005..3ab1fc8ea6ad45291fd9f6cee9c56011f7d02b43 100644 (file)
@@ -21,9 +21,11 @@ export function accounts_balances (body: unknown): AccountsBalancesResponse {
                if ('errors' in body && body.errors != null && typeof body.errors === 'object') {
                        for (const [address, error] of Object.entries(body.errors) as [string, unknown][]) {
                                try {
-                                       Account.validate(address)
+                                       if (!Account.isValid(address)) {
+                                               throw new RpcError('Invalid account address')
+                                       }
                                        if (typeof error === 'string') {
-                                               throw new Error(error)
+                                               throw new RpcError(error)
                                        }
                                } catch (err: any) {
                                        response.errors ??= {}
@@ -35,9 +37,11 @@ export function accounts_balances (body: unknown): AccountsBalancesResponse {
                if ('balances' in body && body.balances != null && typeof body.balances === 'object') {
                        for (const [address, data] of Object.entries(body.balances) as [string, unknown][]) {
                                try {
-                                       Account.validate(address)
+                                       if (!Account.isValid(address)) {
+                                               throw new RpcError('Invalid account address')
+                                       }
                                        if (data == null || typeof data !== 'object') {
-                                               throw new Error('Invalid account balance data')
+                                               throw new RpcError('Invalid account balance data')
                                        }
                                        response.balances ??= {}
                                        response.balances[address] = account_balance(data)
index 35fdb834cf6ffb46c42c6283a7afaa4a311de8e0..56c6955019f8041472fbeeaafb886415f4bbdc82 100644 (file)
@@ -3,8 +3,9 @@
 
 import { Account } from '../account'
 import { hex } from '../convert'
+import { RpcError } from '../errors'
 
-type AccountsFrontiers = {
+export type AccountsFrontiersResponse = {
        frontiers?: {
                [address: string]: Hex
        }
@@ -13,8 +14,8 @@ type AccountsFrontiers = {
        }
 }
 
-export function accounts_frontiers (body: unknown): AccountsFrontiers {
-       const response: AccountsFrontiers = {}
+export function accounts_frontiers (body: unknown): AccountsFrontiersResponse {
+       const response: AccountsFrontiersResponse = {}
        if (body == null || typeof body !== 'object') {
                return response
        }
@@ -25,7 +26,9 @@ export function accounts_frontiers (body: unknown): AccountsFrontiers {
                if (typeof frontiers === 'object') {
                        for (const [address, frontier] of Object.entries(frontiers) as [string, unknown][]) {
                                try {
-                                       Account.validate(address)
+                                       if (!Account.isValid(address)) {
+                                               throw new RpcError('Invalid account address')
+                                       }
                                        if (hex.is(frontier, 64)) {
                                                response.frontiers ??= {}
                                                response.frontiers[address] = frontier
@@ -42,7 +45,9 @@ export function accounts_frontiers (body: unknown): AccountsFrontiers {
                if (typeof errors === 'object') {
                        for (const [address, error] of Object.entries(errors) as [string, unknown][]) {
                                try {
-                                       Account.validate(address)
+                                       if (!Account.isValid(address)) {
+                                               throw new RpcError('Invalid account address')
+                                       }
                                        if (typeof error === 'string') {
                                                throw new Error(error)
                                        }
index eaa2e3ca4007afe14da80bd1deda14fdca216726..fdbdc6736b6a45f04878bc4681b047b7f6e76046 100644 (file)
@@ -51,9 +51,9 @@ export function block_info (body: unknown): BlockInfoResponse {
                        && 'account' in body.contents && typeof body.contents.account === 'string'
                        && 'balance' in body.contents && typeof body.contents.balance === 'string'
                        && 'link' in body.contents && hex.is(body.contents.link, 64)
-                       && 'link_as_account' in body.contents && Account.validate(body.contents.link_as_account)
+                       && 'link_as_account' in body.contents && Account.isValid(body.contents.link_as_account)
                        && 'previous' in body.contents && hex.is(body.contents.previous, 64)
-                       && 'representative' in body.contents && typeof body.contents.representative === 'string'
+                       && 'representative' in body.contents && Account.isValid(body.contents.representative)
                        && 'signature' in body.contents && hex.is(body.contents.signature, 128)
                        && 'type' in body.contents && body.contents.type === 'state'
                        && 'work' in body.contents && typeof body.contents.work === 'string'
index cc8bc357686b384c41156cf20906c69ab45ea2d2..12de6e5b3a0a91a73eaaf9a98eec8d42edbde8cb 100644 (file)
@@ -6,7 +6,7 @@ import { hex } from '../convert'
 import { RpcError } from '../errors'
 import { BlockInfoResponse, block_info } from './block_info'
 
-type BlocksInfoResponse = {
+export type BlocksInfoResponse = {
        blocks?: {
                [hash: Hex]: BlockInfoResponse
        }
index 25c1f3264112848df2ef85c772acc3aa17a8d647..28473a29efbb68170c513e2be22f35fc2d1e48d4 100644 (file)
@@ -5,6 +5,8 @@ import { Account } from '../account'
 import { Block } from '../block'
 import { Rpc } from '../rpc'
 import { AccountInfoRequest, AccountInfoResponse } from '../rpc/account_info'
+import { AccountsFrontiersResponse } from '../rpc/accounts_frontiers'
+import { BlocksInfoResponse } from '../rpc/blocks_info'
 import { Wallet } from '../wallet'
 
 export async function _refresh (wallet: Wallet, rpc: Rpc | string | URL, from: number, to: number): Promise<Map<number, Account>>
@@ -29,8 +31,8 @@ export async function _refresh (wallet: Wallet, rpc: unknown, from: unknown, to:
                        json_block: true,
                        accounts: addresses
                }
-               const { frontiers } = await rpc.post('accounts_frontiers', data)
-               const { blocks } = await rpc.post('blocks_info', { json_block: true, include_not_found: true, hashes: Object.values(frontiers ?? {}) })
+               const { frontiers }: AccountsFrontiersResponse = await rpc.post('accounts_frontiers', data)
+               const { blocks }: BlocksInfoResponse = await rpc.post('blocks_info', { json_block: true, include_not_found: true, hashes: Object.values(frontiers ?? {}) })
 
                for (const account of accounts.values()) {
                        const reqAccountInfo: AccountInfoRequest = {
@@ -59,7 +61,7 @@ export async function _refresh (wallet: Wallet, rpc: unknown, from: unknown, to:
                                if (typeof frontierBlock[subtype] !== 'function') {
                                        throw new TypeError('Unknown frontier block subtype', { cause: subtype })
                                }
-                               const arg = subtype === 'epoch' ? account.version : subtype === 'change' ? representative : link
+                               const arg = subtype === 'epoch' ? account_version : subtype === 'change' ? representative : link
                                frontierBlock[subtype](arg, 0).signature = signature
                                account.frontier_block = frontierBlock
                        }